I'm new to Elm and trying to build a web app with elm-html. I'm having trouble setting up my workflow to develop and see my results quickly.
I've used elm-reactor to serve and reload my changes but that serves my app from localhost:8000/Foo.elm which doesn't include any external stylesheets. I have to use inline styles for all my components, which is discouraged by most HTML guidelines. I'd rather use CSS (or a CSS preprocessor).
I can use elm-make to build to a *.js file and include that in an index.html that I maintain, but it won't watch changes.
Is it the wrong approach to include CSS files in an Elm project, and if not, how do I maintain stylesheets outside of Elm and still serve my project locally, while watching for changes?
You're probably better off not using elm-reactor for your main development because of those limitations. It is perfectly acceptable to use your own external CSS file and I agree, that's a much better practice than embedding styling in the output html.
I've used gulp and the gulp-elm package to set up a file watching task that compiles all Elm code (as well as SCSS files) on save, and that works wonderfully.
There is a Grunt plug-in for Elm if you're into that.
There is a webpack loader for Elm if you prefer that over gulp or grunt.
There is a young project that offers a Single Page Application generator for Yeoman which bundles together some of the live-reloading tasks. It is very opinionated on some of the decisions it makes, but it's a good reference if you want to get running quickly.
I found a good solution for those who want quick prototyping in elm-reactor with full CSS but don't want to figure out build tooling or more sophisticated elm CSS packages. You can get started pretty fast using basic elm, elm-html, and css.
This solution uses standard Elm to generate inline styles and Html.node to create a style tag so you can apply a CSS rule to the body of the document.
-- VIEWS
view model =
main_
[ cssMain ]
[
styleTag
, div
[ cssControlPanel ]
[
button
[ cssBtn
, cssBtnGenerate
, onClick GenerateMap
]
[ text "GENERATE MAP" ]
]
-- STYLES
styleTag : Html Msg
styleTag =
let
styles =
"""
body { overflow: hidden; }
"""
in
node "style" [] [ text styles ]
cssMain : Attribute Msg
cssMain =
style
[ ("backgroundColor", "#eee")
, ("position", "relative")
, ("width", "100vw")
, ("height", "100vh")
]
...
https://github.com/elm-community/elm-webpack-starter was my first attempt to graduate beyond elm-reactor + inline styles. It seemed kind of heavy.
I currently use elm-live (https://github.com/tomekwi/elm-live), like so:
$ cat <<——— > index.html
<!doctype html>
<link rel="stylesheet" href="style.css" />
<body>
<div></div>
<script src="elm.js"></script>
<script>Elm.Main.embed(document.querySelector("div"));</script>
</body>
———
$ elm-live Main.elm --output=elm.js --open
Code is in Main.elm and styles are in style.css.
I'm just a beginner, but I find myself using the browser CSS editor a lot.
The style editor is usually placed close to the JS console and HTML inspector, press F12 and you'll find it.
You can just create your regular elm markup without any styling and then manually import the stylesheet when testing it out in the browser. After you've finished your project, just add the stylesheet to the finished app manually (standard <link> tag).
The plus side to this is that the browser provides live preview while you're writing your CSS. The downside to it is that you'll have to work with your browser's editor, which may not be the best option out there compared to something like VS Code or Atom.
Note: I use Firefox Developer Edition, their styles editor is great. Can't comment on Chrome's.
Related
Currently I'm developing a website using the following stack:
vue.js
#vue/server-renderer
vite
tailwind CSS
SSG was chosen as the rendering mode.
Tailwind, as described in the documentation, allows you to specify directories and file extensions (content property) , in which he will try to find the classes, in order to leave only those that are actually used in the project.
As a result, the 'main.css' file is formed, in which only those classes that are used remain.
Next, I just take this file and include it in every page that was rendered during the build phase of the project.
This results in:
index.html - main.css
about.html - main.css
blog.html - main.css
It turns out that main.css file may contain classes that are needed only for one of the pages and are not needed for others.
I would like to implement the following:
Take main.css which turned out
Render a page, for examle about.html
take only those styles that are needed for about.html page from the main.css file
create a new about.css file
link the resulting about.css styles to about.html
I’ve already tried to implement this using an awesome PurgeCSS tool as following:
render page content usind #vue/server-renderer's renderToString() method;
Pass an resulting css and html sources to PurgeCSS
here is an example
But there are too many corner cases around this solution, such as:
Dynamic classes which can be added to the html on the client side
Some components may be missing in rendered html and their content will be added later (for example, v-if directive was used on the component)
A few takeaways:
PurgeCSS is not needed anymore since Tailwind v2 (the latest being v3.x)
as far as I know, you cannot have code-splitting with Tailwind, not that it matters anyway since it will still perform okay with further optmizations
the classes that will be generated, will be only once for the whole app (hence no need to have a bg-red-500 for index or about page, both are referencing the same unique declaration)
if you want to have SSR/SSG, I recommend the usage of Nuxt (in it's v3 if you're using Vue3 or plan to have anything long-term)
dynamic classes are not possible with Tailwind, you can create things like bg-[#ccc] but it goes on the opposite side of what Tailwind is achieving and should be used exceptionally
for Tailwind's content, still the defaults on this page, section Configure your template paths, no need to do anything crazy or complicated
if you want to have some scoped/local style, style to using style scoped, you can still use Tailwind inside of those tags tho
if you want to write vanilla CSS into dedicated CSS files like index, about, blog etc, then Tailwind is probably not the best approach because this is not how it is supposed to work
stay simple, the performance will still be amazing. Only focus on not having too many screens, colors etc that you're not using
you could run some bundle size tests to see if the CSS is taking a huge chunk in terms of size. Will probably not, but if it still is: you can then start making complex configurations
JS will be far harder to reduce and be more impactful regarding the performance (because of how a browser works with it: parsing, executing is indeed blocking the main thread)
I have a very, very simple set of Vue components that all work. These are a simple addition on top of an existing C# app.
At the moment, these are .html files (brought into the app inside <script> tags) and .js files loaded by reference.
These all work, are very light weight, and I love it.
Now I want to compile the HTML for each component into a Vue render function, and the .js into one minified .js file.
The .js to .min.js is pretty standard, but I cannot figure out how to get the HTML to compile into the Vue render function. Everything I've found involves a LOT of overhead and running a web server which seems a massive overkill for an html->script transform, and I don't need a full web application spun up. I only need my existing, simple templates transformed to something more friendly for production than my long-form html templates getting dumped to the page.
I'm not entirely opposed to turning the .html+.js into .vue files, but just doing that doesn't seem to overcome my issue.
I cannot figure out how to get the HTML to compile into the Vue render function
To generate a render function from a Vue template string (e.g., read from an HTML file), you could use vue-template-compiler like this:
const compiler = require('vue-template-compiler')
const output = compiler.compile('<div>{{msg}}</div>')
console.log(output) // => { render: "with(this){return _c('div',[_v(_s(msg))])}" }
Everything I've found involves a LOT of overhead and running a web server which seems a massive overkill for an html->script transform
The "web server" you mention is provided by Webpack CLI, and is intended to faciliate development. You don't need to use the dev server. The article indeed describes several steps in manually setting up a project to build Vue single-file-components, but a simpler method is to use Vue CLI to automatically scaffold such a project.
Hi I am new to elm and would like to know if it would be possible to set up elm such that it manages only one section of a website. the rest of the site would be in plain javascript, html, css.
but i would like to load up the compiled elm app in a separate script tag and it should manage only a particular section
let us say that the website is divided into 10 divs vertically of height 300px. i would want only the 3rd div to be an elm app.
is such a thing possible? if so how can i get this working
You can use Html packages embed function for this. I once did this just to try it out, but unfortunately cannot recall any details of it. I did found some source code though.
The html page would be something like this
<html>
<head>
</head>
<body>
<div id="personnel"></div>
</body>
<script src="elm.js"></script>
<script>
Elm.Person.embed(document.getElementById('personnel'));
</script>
</html>
By including elm.js, you'll get the Elm runtime. Here Person is my compiled Elm module. Something like
module Person exposing (..)
-- Module details here...
main =
Html.beginnerProgram { model = init, view = view, update = update }
Elm code is compiled to JavaScript with command
elm-make Person.elm --output elm.js
My knowledge on this is quite limited, but I did investigate it enough to be certain that with by doing this, one can add multiple components made with Elm to an html page / existing application.
Addendum: I found the source of my information
In addition to previous answer perhps you would like to take a look on:
https://ellie-app.com/h7vqHrPdWa1/0
I am using Vue.js for one of my frontend projects.
As you know, Vue comes with special syntax for components - each component can be declared in a single .vue file. That means, that you can define all related stuff in a single file like this:
<tamplate>
...component template goes here...
</template>
<script>
...component code goes here...
</script>
<style>
...component style goes here...
</style>
Of course vue support in various IDEs isn't perfect yet. Vue is relatively young framework, but I think it will be popular very soon. It looks so straightforward and predictable after Angular that I even decide to use it in all upcoming frontend projects, but it is, of course, another story.
Ok, WebStorm doesn't know anything about .vue files, but vue looks like html, so you can solve that problem easely - just add *.vue pattern to list of patterns for HTML file type (settings -> editor -> file types).
After that tweak everything works fine until you try to use non-css styles - for some reasons WebStorm fails to highlight embedded styles with type text/less and so on. I tried to solve it in a different ways:
<style type="text/css></style>
or
<style rel="stylesheet/less"></style>
...but without any success.
Fortunately vue-loader (that I am using with WebPack in order to build my project) supports another syntax of .vue files, which allows to declare template, code and style in a separate files. It is ok, but I think that single file per component is better (at least it's easier to manage). And now I am forced to declare my styles separately because I can't let WebStorm to highlight embedded LESS styles.
I tried to use WebStorm language injections, but without any success too (or I just miss something in my WebStorm configuration).
So, the final question is: how to enable syntax highlighting for embedded LESS styles in WebStorm 11?
Such support is not possible in WebStorm v11/PhpStorm v10 -- only CSS is available as injectable language.
However the next version (WebStorm v12/PhpStorm v11) already supports it -- just use appropriate rel="stylesheet/less" (in case of LESS) attribute on your <style> tag.
If you want to use another attribute or value to identify what language is meant to be used in your <style> tags or enable this for another (already supported by IDE) CSS-preprocessor (e.g. Sass/SCSS/etc) -- create custom injection rule at Settings/Preferences | Editor | Language Injections.
As of 2017.1 version some other improvements/changes were made -- see WEB-20921 : Add support for valid HTML syntax for including LESS/SCSS in <style> tags
ticket for details.
A while back, I looked into a solution for the "flash of unstyled content" when using Dojo and Dojo themes. Someone suggested to combine everything by creating a build, and it'll reduce the load/parse time and remove the need to use preloader overlays, etc.
However, it seems like Dojo is severely lacking in straightforward, "real world" useage examples and tutorials for a lot of its functionality, this especially. A lot of the resources tell you how to set up a build, but not how to implement it.
Let's say I have this in "pageinit.js":
require([
'dojo/parser',
'dojo/dom',
'dojo/dom-class',
//etc...
'dijit/form/ValidationTextBox',
'dijit/form/CheckBox',
// etc...
// Dom Ready call
'dojo/domReady!']
function(
Parser,
Dom,
Class,
// etc...){
// do stuff with parser, dijits, so on.
}
)
Some of the require calls were removed for brevity, but there's a handful of dom requires, style classes, some dijits, etc. When this page loads, there's the flash of unstyled content and then it's fine.
Using the Dojo Web Builder, I selected the modules I'm using, and ran it. It downloaded a zip with a lot of files under it, including a new dojo.js and custom_layer.js.
So my question is now, how do I use these new combined and minified files in place of my "non-build" version? What do I require? Or do I?
So confused...
First, let's understand how the AMD(require/define) API works.
require([
'dojo/parser',
'dojo/dom',
'dojo/dom-class'
], function(parser, dom, domClass){
});
This is going to call the require function, specifying that I need three modules in order to do some work. require will get each module. If will determine if the module has been loaded. If it hasn't it will asynchronously get the file, and load the module into the javascript runtime. Once require has retrieved all of your required modules, it will execute your callback (the function) passing the modules as arguments to the function.
Next, let's understand the build. The dojo build does exactly what you describe. It will compress a bunch of the individual files into a single file. this will make the page load quicker and prevent that 'flash' that you describe.
Finally, putting it all together, you should include the custom_layer.js file along with the dojo.js file.
<script type="text/javascript" src="path/to/dojo/dojo.js" />
<script type="text/javascript" src="path/to/custom_layer.js" />
The web browser will load these two files and evaluate the code. Instead of lazily loading each module in it's own file, the module will already be loaded because it was defined in the custom_layer.js.
So, the answer to your final question is that you should NOT change any of your code based on the specific version of code (source vs custom build) that you are using. Using the AMD api, it should just work.
Not sure if it's best practice or not, but I was seeing the flash of unstyled content when I first started (a few days ago), and saw several examples somewhere that takes care of by just hiding the <body>. Parse will unhide it when it's ready to show something.
<body style="visibility: hidden;">