Using <script type="module"> alongside <script nomodule> should allow different bundles to be served to modern browsers. Bundles targeting modern browers are usually significantly smaller than ones that need to target legacy browsers.
It appears that the Chrome team also has plans to support a syntax property to allow <picture>-style serving of different syntaxes. The benefits of this are unlikely to be as big as the basic behaviour described above, but would be worth supporting if browser support lands.
Are there any plans now to support either of these behaviours?
If an HTML file contains <script type="module"> alongside <script nomodule>, then generate an .mjs bundle with modern syntax as well as a normal bundle. If a script tag includes a syntax attribute then also transpile bundles targeting those syntaxes.
If an HTML file has both <script type=module> and <script nomodule> with the same entrypoint, then the generated HTML only has one script tag and one bundle.
The example tweeted by @developit uses package.json to specify targets, but Parcel could read it directly from the script tags. The mjs bundle would use something like babel preset-env target: {esmodules: true}.
Support for the syntax attribute could either read different configs from a babelrc, or could infer the required targets from the content of the syntax attribute.
Filenames for the entry point and code-split bundles could either use subdirectories or filenames. e.g. 2017/main.js or 2017.main.js.
I'm currently trying to approximate the basic version of this in webpack, using two webpack configs, each with a different output path and babel env name. This is messy, as it also bundles two copies of all other files, and can't generate HTML.
Are there any plans now to support either of these behaviours?
There are two open issues about the module/nomodule part. This will be natively supported by Parcel 2 (exited about that myself).
https://github.com/parcel-bundler/parcel/issues/41
https://github.com/parcel-bundler/parcel/issues/1168
but would be worth supporting if browser support lands.
When browsers adopt it, we can talk about that again.
That's great. I did search for old issues but those don't have great names. Are there any details about how this will work in Parcel 2? Has it been implemented already?
I agree that there's no point in starting to implement syntax before browser support is finalised, but it is probably worth bearing in mind when implementing module/nomodule in case it affects implementation choices.
For context, this is the syntax proposal: whatwg/html#4432
A few things to keep in mind:
mjs shall not be used at frontend. It's always just application/javascript - so .js. mjs is needed for some node.js magic, and not related to the browser.multiple bundles and multiple builds - _This is messy_ and so on. How transpilation works - it gets your code written in _higher language_, and transpiles it to _lower language_, acceptable by a browser.
Your original code -> esmodules target -> es5 target
According to this - to create es5 target you might use a previous state - esm bundle. According to this you might use parcel to generate a _top language_(esm) bundle, and then use another, a less complex tool, to _devolute_ it to a _lower language_. Basically - apply babel to the result bundle.
As long as this operation is needed only to create a production build (you are not using browser requiring a lower language during dev), and no cache is present - that could be a quite efficient solution.
Plus - you might use not babel, but swc - a faster, rust based solution, cos all babel plugins already did the job, and we need only _devolute_ the language itself and add some missing polyfills.
If you will place result bundles into separate directories, not _separate filenames_ - parcel will autodetect script location and everything would work out of box without any configuration needed. Magic.
And you already might do it - https://github.com/thekashey/devolution
@theKashey That's awesome. I'd not seen that before. I think that pattern is a lot neater than the Webpack chicanery I'm currently using. I think I'll try the switch to Parcel + Devolution tomorrow.
@theKashey Could you explain how to do this?
If you will place result bundles into separate directories, not separate filenames - parcel will autodetect script location and everything would work out of box without any configuration needed. Magic.
To clarify, to use devolution with Parcel, should we build the application as normal with Parcel, maybe customize browserslist to exclude IE11, and then run devolution as a second step, and then insert the feature detection script?
esmodules (lets assume to the /dist folder) yarn devolution ./dist ./dist index.js true
var script = document.createElement('script');
var prefix = (!('noModule' in check)) ? "/ie11" : "/esm";
script.src = 'dist' + prefix + "/index.js"; // dist/target/script
document.head.appendChild(script);
What about using .html Parcel entry points? For me Parcel generates dist/index.html, which includes a script tag pointing to dist/src.<hash>.js. When running devolution dist dist, it does compile dist/src.<hash>.js, but I need to edit the html to replace the script tag with the feature detection script.
Also, why does devolution need to make symlinks to all other files in dist, including stylesheets, images, and fonts? Wouldn't it be easier if instead of creating sub directories for the bundles, it just puts the "prefix" as part of the file names like dist/ie11-index.js and dist/esm-index.js?
but I need to edit the html to replace the script tag with the feature detection script.
That is yet unsolved. You may use assets plugin to generate scripts independently, and then construct your index.html with the "right" script name.
Also, why does devolution need to make symlinks
By default, a script will prefix all used images with the current directory.
it just puts the "prefix" as part of the file names like dist/ie11-index.js and dist/esm-index.js
This is changing file names, and breaks code splitting, as long as you will have to rename all chunks, and then rebuild chunks map, which is impossible without deep integration with a bundler.
Moving files to subdirs is the one zero configuration way.
Closing. This is already covered by #41 and #1168 and will be included in parcel 2.
Most helpful comment
A few things to keep in mind:
mjsshall not be used at frontend. It's always justapplication/javascript- so .js.mjsis needed for some node.js magic, and not related to the browser.multiplebundles and multiple builds - _This is messy_ and so on.How transpilation works - it gets your code written in _higher language_, and transpiles it to _lower language_, acceptable by a browser.
Your original code->esmodules target->es5 targetAccording to this - to create es5 target you might use a
previousstate - esm bundle. According to this you might useparcelto generate a _top language_(esm) bundle, and then use another, a less complex tool, to _devolute_ it to a _lower language_. Basically - apply babel to the result bundle.As long as this operation is needed only to create a production build (you are not using browser requiring a lower language during dev), and no cache is present - that could be a quite efficient solution.
Plus - you might use not babel, but
swc- a faster, rust based solution, cos all babel plugins already did the job, and we need only _devolute_ the language itself and add some missing polyfills.If you will place result bundles into separate directories, not _separate filenames_ -
parcelwill autodetect script location and everything would work out of box without any configuration needed. Magic.And you already might do it - https://github.com/thekashey/devolution