Building websites that work well on all major browsers is a core tenet of an open web ecosystem. However, this means additional work of ensuring that all of the code you write is supported in each browser that you plan to target. If you want to use new JavaScript language features, you need to transpile these features to backwards-compatible formats for browsers that do not yet support them.
Babel is the most widely used tool to compile code
that contains newer syntax into code that different browsers and environments
(such as Node) can understand. This guide assumes you are using Babel, so you
need to follow the setup instructions to
include it into your application if you haven't already. Select webpack
in Build Systems
if you are using webpack as the module bundler in your app.
To use Babel to only transpile what is needed for your users, you need to:
- Identify which browsers you want to target.
- Use
@babel/preset-env
with appropriate browser targets. - Use
<script type="module">
to stop sending transpiled code to browsers that don't need it.
Identify which browsers you want to target
Before you begin to modify how the code in your application is transpiled, you need to identify which browsers access your application. Analyze which browsers your users are currently using as well as those that you plan to target to make an informed decision.
Use @babel/preset-env
Transpiling code usually results in a file that is larger in file size than their original forms. By minimizing the amount of compilation that you do you can reduce the size of your bundles to improve the performance of a web page.
Instead of including specific plugins to selectively compile certain language features you are using, Babel provides a number of presets that bundles plugins together. Use @babel/preset-env to only include the transforms and polyfills needed for the browsers you plan on targeting.
Include @babel/preset-env
within the presets
array in your Babel
configurations file, .babelrc
:
{
"presets": [
[
"@babel/preset-env",
{
"targets": ">0.25%"
}
]
]
}
Use the targets
field to specify which browser versions you want to include
by adding an appropriate query to the browsers
field. @babel/preset-env
integrates with browserslist, an open-source configuration shared between different
tools for targeting browsers. A full list of compatible queries is in the
browserslist documentation.
Another option is to use a .browserslistrc
file to list the environments
you wish to target.
The ">0.25%"
value tells Babel to only include the transforms
needed to support browsers that make up more than 0.25% of global
usage. This ensures your bundle does not contain unnecessary transpiled
code for browsers that are used by a very small percentage of users.
In most cases, this is a better approach than using the following configuration:
"targets": "last 2 versions"
The "last 2 versions"
value transpiles your code for the
last two versions of every browser,
which means support is provided for discontinued browsers such as Internet Explorer.
This can unnecessarily increase the size of your bundle if you do not expect these
browsers to be used to access your application.
Ultimately, you should select the appropriate combination of queries to only target browsers that fit your needs.
Enable modern bugfixes
@babel/preset-env
groups multiple JavaScript syntax features into collections and enables/disables
them based on the target browsers specified. Although this works well, an entire collection of
syntax features is transformed when a targeted browser contains a bug with just a single feature.
This often results in more transformed code than is necessary.
Originally developed as a separate preset, the
bugfixes option in @babel/preset-env
solves this problem by converting modern syntax that is broken in some browsers to the closest
equivalent syntax that is not broken in those browsers. The result is nearly identical modern code
with a few small syntax tweaks that guarantee compatibility in all target browsers. To use this
optimization, make sure you have @babel/preset-env
7.10 or later installed, then set the
bugfixes
property to true
:
{
"presets": [
[
"@babel/preset-env",
{
"bugfixes": true
}
]
]
}
In Babel 8, the bugfixes
option will be enabled by default.
Use <script type="module">
JavaScript modules, or ES modules, are a relatively new feature supported in
all major browsers. You can use modules
to create scripts that can import and export from other modules, but you can
also use them with @babel/preset-env
to only target browsers that support
them.
Instead of querying for specific browser versions or market share, consider
specifying "esmodules" : true
inside your .babelrc
file's targets
field.
{
"presets":[
[
"@babel/preset-env",
{
"targets":{
"esmodules": true
}
}
]
]
}
Many newer ECMAScript features compiled with Babel are already supported in environments that support JavaScript modules. So by doing this, you simplify the process of making sure that only transpiled code is used for browsers that actually need it.
Browsers that support modules ignore scripts with a nomodule
attribute.
Conversely, browsers that do not support modules ignore script elements with
type="module"
. This means you can include a module as well as a compiled fallback.
Ideally, the two version scripts of an application are included like this:
<script type="module" src="main.mjs"></script>
<script nomodule src="compiled.js" defer></script>
Browsers that support modules fetch and execute main.mjs
and ignore compiled.js
.
The browsers that do not support modules do the opposite.
If you use webpack, you can set different targets in your configurations for two separate versions of your application:
- A version only for browsers that support modules.
- A version that includes a compiled script which works in any legacy browser. This has a larger file size, since transpilation needs to support a wider range of browsers.
With thanks to Connor Clark and Jason Miller for their reviews.