Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Differential bundling for <script type="module"> #2792

Closed
ascorbic opened this issue Mar 14, 2019 · 10 comments
Closed

Differential bundling for <script type="module"> #2792

ascorbic opened this issue Mar 14, 2019 · 10 comments

Comments

@ascorbic
Copy link

🙋 feature request

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?

🤔 Expected Behavior

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.

😯 Current Behavior

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.

💁 Possible Solution

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.

🔦 Context

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.

💻 Examples

@mischnic
Copy link
Member

mischnic commented Mar 14, 2019

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).

#41
#1168

but would be worth supporting if browser support lands.

When browsers adopt it, we can talk about that again.

@ascorbic
Copy link
Author

ascorbic commented Mar 14, 2019

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.

@ascorbic
Copy link
Author

For context, this is the syntax proposal: whatwg/html#4432

@theKashey
Copy link
Contributor

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.
  • you dont need 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

@ascorbic
Copy link
Author

@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.

@hagabaka
Copy link

hagabaka commented Mar 28, 2019

@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?

@theKashey
Copy link
Contributor

  1. build an application targeting esmodules (lets assume to the /dist folder)
  2. devolute
 yarn devolution ./dist ./dist index.js true
  1. include scripts using feature detection.
 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);

@hagabaka
Copy link

hagabaka commented Mar 28, 2019

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?

@theKashey
Copy link
Contributor

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.

@devongovett
Copy link
Member

Closing. This is already covered by #41 and #1168 and will be included in parcel 2.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants