It's a common way in most web developers that write JavaScript with ES6+ and then bundle it to ES5, so that it can run in all browsers. However, the modern browsers support ES6 natively so it's unnecessary to shipping a lot of polyfills.html
I'm really excited to share you a technique that you can compile and serve two separate JavaScript bundles:webpack
That is <script type="module">
as a way to load ES modules. You can also load code with <script nomodule>
for legacy browsers.git
The rest of this article explains how to implement this technique and the bundle solution for webpack.github
How does it works? let's look at a example:web
<!-- For modern browsers -->
<script type="module" src="main.mjs"></script>
<!-- For legacy browsers -->
<script nomodule src="main.js"></script>
複製代碼
In modern browsers, script with type="module"
will be loaded and executed, and script with nomodule
will be ignored.npm
And in legacy browsers, script with type="module"
will be ignored because they can't recognize this attrbute, script with nomodule
has no effect, it will be treated as usual.json
Note: There's something you should know about <script type="module">
.babel
<script defer>
.Warning: Safari 10 doesn’t support the nomodule attribute, but you can solve this by inlining a JavaScript snippet in your HTML (This has been fixed in Safari 11).app
I really appreciate it that @babel/preset-env
provides a convenient config for esmodules.less
babel for legacy:
{
"presets": [
[
"@babel/preset-env", {
"modules": false,
"useBuiltIns": "entry",
"targets": {
"browsers": [
"> 1%",
"last 2 versions",
"Firefox ESR"
]
}
}
]
]
}
複製代碼
babel for modern:
{
"presets": [
[
"@babel/preset-env", {
"modules": false,
"useBuiltIns": false,
"targets": {
"esmodules": true
}
}
]
]
}
複製代碼
It's a bit complex for webpack to bundle two different JavaScript, there are some details you should know. So I wrote a esmodules-webpack-plugin to simplify configuration and bundle thest JavaScript just run webpack once.
Is it worth a try?
I think it's definitely worth a try, the size of polyfills that bundles by babel is more than what we think, and ES Modules code has an average reduction of 50% or even more, it all depends on your source code.
Besides, larger files not only take longer to download, but also take longer to parse and execute. So reduce file size is a efficient way to improve the performance of website.
<script type="module">
is really a fascinating technique that helps us shipping less code to users who use modern browsers and improve our website's performance.
However, there are also some limitations. for example, most module authors don’t publish ES6+ versions of their source code, a few browsers support <script type="module">
, but will still download <script nomodule>
(but won't execute).
A convenient webpack plugin for esmodules that I wrote: esmodules-webpack-plugin