Hello you smart people of the Stackoverflow. I have a challenge on a webpack build I am trying to set up.
What I am trying to acheive
I am trying to create a build that generates two version of my JS files. One that uses ES 6/7+ which will be used by the latest browsers and one that is transpiled back to ES 5.
The reason is that I want to minimize code sent to the "decent" browsers and to leverage any performance optimizations that can be drawn from using pure ES 6/7, not to mention adding less polyfills to the code.
The problem
Currently I have achieved my goal by running two parallel builds; one that transpiles the code with only few Babel transforms for a ES 6/7+ version and a second that uses the es2015 preset to transpile back to ES 5 and this generally works as intended. However my problem is that the full build that transpiles both versions is SUUUUUPER slow. We are talking 5+ min slow which is far from ideal.
One of the problem I see right away with this setup is that there is a lot of code that is being reparsed that might not need reparsing, such as CSS (stylus), images, SVGs, fonts etc. All of these assets really only need to be treated once, as it will be exactly the same for each version of the JS files. So in reality I only need to transform the JS part of the code, which is why I created the rebabel-webpack-plugin module, which really just takes the emitted files, transpiles them again and save the code under another name. This works fine, but it feels hacky and it kinda circumvents the original webpack build flow with some possible drawbacks as a consequence:
I don't really think that SourceMaps will be working properly, as it is not transpiling the original code.
Adding polyfills with a babel-preset-env babel-polyfill combo could be challenging and/or hacky
Bundle analyzers could be messed up
Unable to do a shared code file for regenerated files
I have not verified these drawbacks, but they are what I can see of immediate possible issues.
I have tried running a subsequent build on the emitted files, which works, but generally it is kinda the same as using the rebabel-webpack-plugin, but with a more awkward setup (collecting list of emitted files -> setting up new config -> run new build).
The actual question
So my question for you bright minds out there boils down to: How do one achieve a proper "re-targeting" of our JS files using webpack, without having to run two parallel builds?
Related
This is vague - I apologize in advance, I am trying to be as succinct as I can with my limited understanding, while exposing my potentially incorrect assumptions.
I have a website that's literally one huge HTML file. It runs scripts defined in-line in a <scripts> tag.
My goal is to move all the scripts into individual .js files and pull them into index.html (or into one another where required). I am familiar with the usage of Node's require and I am familiar with import, as used in Angular. I stress usage because I don't really know how they work.
Assumption 1: I cannot use require - it is purely for Node.js. The reason I bring it up is that I am pretty sure I have seen require in AngularJS 1.5 code, so assuming makes me uncomfortable. I am guessing this was stitched together by WebPack, Gulp, or similar.
Assumption 2: I should use import, but import only works with a URL address, if I have my .js hosted on a server or CDN, it will be be pulled. BUT, I cannot give local pathing (on the server) here - index.html will NOT automatically pull in the dependencies while being served. I need npm/Webpack/other to pre-compile my index.html if I want the deps pulled in on the server.
Assumption 3: Pre-compiling into a single, ready-to-go, html file is the desired way to build things, because the file can be served quickly (assuming it's ready to go). I make the assumption with the recent trend of serving Markdown from CDNs, the appearance of the JAMstack, and the number of sites using Jekyll and such (though admittedly for traditional Jekyll sites).
Assumption 4: I also want to go to Typescript eventually, but I assume that changes nothing, since I will just pull in TS to compile it down to .js and then use whatever solution I used above
Question: If it's clear what I am trying to do and what confuses me, is a decent solution to look into npm/Webpack to stich together my .js files? What would prepare them for being stiched together, using import/export? If so, is there an example of how this is usually done?
As you mentioned, require cannot be used for your purposes, since it is a part of CommonJS and NodeJS's module system. More info on require can be found here: What is this Javascript "require"?
Import is a ES2015 standard JS syntax. But ES2015 standard and everything above it has very limited browser support. You can read more about it here: Import Reference
However, you can still code in the latest standard (thereby enabling the use of import/export etc.,) and then transpile the code to be able to run on the browser. Inorder to do this, you require a transpiler. You can refer Babel which is one of the most popular transpilers : https://babeljs.io/
For your exact purpose, you need to use a module bundler. Webpack/Rollup etc., are some popular module bundlers. They can automatically identify all the JS files referenced through import, combine them and then transpile code to be able to run on the browser (they also use a transpiler) and produce a single JS file (or multiple, based on your configurations).
You can refer the getting started guides of Webpack: https://webpack.js.org/guides/getting-started/
or RollupJS: https://rollupjs.org/guide/en#quick-start
I have quite huge project (production bundle file is around 400kB) written in coffee script. And I have no idea how to plan migration to ES6. I know that there are tools like Decaffeinate but I am not sure if it really works in bussiness practise.
I suppose that I can use ES6 and coffee in one project but is it possible to write components in coffee which import and use code written in ES6 and vice versa and all works in production?
Is this migration possible to be done step by step or there is no other option than doing everything in one release?
How does webpack work (proper loader)? What is the sequence? Does it firstly convert ES6 to JS (or coffee to JS) and then do all imports or import files first and then convert to JS?
Finally are there some best practices to have code written in both coffee script and ES6 in similar situation?
I'm the main person working on decaffeinate recently. It has been used on large production codebases and currently has no known bugs, so it's likely stable enough for you to use it. Still, you should convert your codebase a small piece at a time rather than all at once.
You can configure webpack to allow both CoffeeScript and JavaScript in the same project by specifying coffee-loader for .coffee files and babel-loader for .js files in your module.rules (or module.loaders for webpack 1).
If you use require syntax, importing code between CoffeeScript and JavaScript should just work without any problems. If you use JS import/export syntax, you may need to use require('./foo').default in some cases when requiring JavaScript from within a CoffeeScript file. But in most cases interop should just work even with import/export syntax.
Probably a good idea is to convert one or two files and make sure eslint, babel, and other JavaScript config are configured they way you want them to. From there, you should convert the code one or two files at a time, and increase the number of files you convert at once as you get more comfortable with it and depending on what your needs are.
One approach is to convert CoffeeScript files to JS slowly over time, converting and cleaning up the ones you touch. The problem I've seen with this approach is that it can be a very long time before you move off of CoffeeScript. It depends on your situation, but generally I would recommend running decaffeinate in larger and larger batches without focusing too much on manual cleanup, then once the codebase is 100% JavaScript, manually clean up files as you work with them.
A while ago, I wrote up some thoughts on how to think about different conversion strategies, which you might find useful:
https://github.com/decaffeinate/decaffeinate/blob/master/docs/conversion-guide.md#converting-a-whole-project
Working on building JavaScript sourcemaps into my workflow and I've been looking for some documentation on a particular part of debugging source maps. In the picture below I'm running compressed Javascript code, but through the magic of source maps Chrome debugger was able to reconstruct the seemingly uncompressed code for me to debug:
However, if you look at the local variables, someNumber and someOtherNumber are not defined. Instead, we have a and r, which are the compiled variable names for this function. This is the same for both Mozilla Firefox and Chrome.
I tried looking through the Chrome DevTools Documentation on sourcemaps, but I didn't see anything written about this. Is it a current limitation of sourcemap debugging and are there any workarounds for this?
update:
I've since found this thread in chromium project issues. It doesn't look like it has been or is being implemented. This is becoming an increasingly more important problem as teams are beginning to implement Babel in their build systems to write ES2015 code. Have any teams found a way around this?
Using Watch Expressions on the right hand side, usually solves this.
Expand the menu, and use the plus button to add your variables.
You can use someNumber and someOtherNumber, and even someNumber + someOtherNumber.
Looks like it's been addressed and will become available in the next Chromium update
There's still no solution to mapping variable names in Javascript source maps, but there's a solution for Babel 6. As we've adopted ES2015, the mangled import names became a major pain point during development. So I created an alternative to the CommonJS module transform that does not change the import names called babel-plugin-transform-es2015-modules-commonjs-simple.
As long as you aren't writing modules that depend on exporting dynamic bindings it is a drop-in replacement for the default babel commonjs module transform:
npm install --save-dev babel-plugin-transform-es2015-modules-commonjs-simple
and .babelrc:
"plugins": ["transform-es2015-modules-commonjs-simple"]
This will compile ES2015 modules to CommonJS without changing any of the symbol names of imported modules. Caveats are described in the readme.
This won't help you with minifying/uglifying, though, so the best solution seems to be to just don't use minification during development. Then at least it's only a problem if you have to debug something on a production web site.
In the process of evaluating the various approaches available to developers to use javascript modules, module loaders and build tools, i'd like some suggestions on what tools you use, and why.
I'm currently after something that is able to:
-encourage modular code
-allow features to be added based on necessity to a given module [think mixins/inheritance]
-produce a BUILD that contains a development release, and at the very minimum a production release with different layers (say, i want a layer [a script] which contains my bootstrap code, module 1, 2 and 3; and then another layer which contains modules 4,5 and 6. This way I can defer loading of code based on what's actually going on in the application.)
-Work [when built for production] in an extremely low bandwidth scenario, with xfer speeds of 1kbps and high latency (think worst case mobile connection over GPRS to get the picture).
I've seen the following:
Using prototype inheritance, as in:
myNS.thing = function(){};
myns.thing.prototype = {
something: "foo"
}
Which can be built by simply taking the contents of this script, and appending it to the next one one wants to include in a production optimized package as a single script. Loaders in this case are simple script tag injections/eval's or similar, based on a known file.
I've also seen other approaches, such as:
function(){
return function(){
something: "foo"
}
}();
Building this already gets more complex because one has to manipulate the script, removing the wrapping self executing function and combining the return values into one object. I am not aware of an "easy" way to use available build tools. The loader approach works the same as above.
Both of these approaches lack dependencies.
Then we have AMD:
define("mymodule", ["dep1"], function(dep1){
return {something: dep1}
});
Some might be nauseated by its indenting, and its "ceremony", but still its quite effective, the google closure compiler knows about it natively, it knows about dependencies, and seems to have widespread adoption across the board. There are a bunch of module loaders available for it (https://docs.google.com/spreadsheet/ccc?key=0Aqln2akPWiMIdERkY3J2OXdOUVJDTkNSQ2ZsV3hoWVE#gid=2) and quite a few build tools as well.
What other options do you know of, or have you seen used in production?
As said, i'm interested in a combination of code syntax, loader tools and build tools. These three must exist and be working together properly. The rest is an academic excercise i'm not interested in.
I personally use RequireJS, an AMD solution. If I'm whipping up quick proof-of-concepts I won't bother setting that up, but the most common source/dep-mapping solutions I know of now include:
RequireJS
CommonJS
Google Closure
YepNope (a conditional loader, can be used in combination with the others)
I have started a boilerplate that uses Require in combination with Backbone to get all the ugly setup code out of the way:
https://github.com/nick-jonas/assemblejs
So you can type assemble init to scaffold the basic project and assemble build to run the compilers and get a final production-ready build.
You might be interested in looking at Grunt a command line tool with various modules for building javascript projects. It uses npm for dependencies and it will work with amd modules, but you can just configure it to concatenate the files you need using grunt-buildconcat.
I am using jquery fileupload plugin and it has 7-8 js files which it loads.
Now others developers are also working on site and sometime it cause confusion and difficult to find which js file is used where.
So i am thinking if i can combine 7 files in one file so that i can know that thats my file
Try this to compile your javascript file or code.
http://closure-compiler.appspot.com
While possibly overkill in this particular case, it might be worth checking out grunt. It will let you keep your files divided into multiple files for when you are working on them, and as soon as any file change compiling, minifying and combining them into a single/groups of files as desired, while also allowing you to define the load order of your code.
It requires some setup the first time you run it (which you can later use as a template) but greatly improves the process of combining/minifying files, and also has support for processing coffescript and sass among others, as well as writing unit tests for your code.
I use Rake to compile Javascript (and SASS to CSS, as well). It minifies the files in a unique JS. It's written in Ruby, but it's easy to configure and it works very fine.
But if more developers are working on the same code, another good idea I strongly suggest is to to use a SVN (sub-version control system), as TortoiseSVN or Git. This will allow many developers to work on the same source files, without losing any change.