Created by: prichodko
This PR is currently a proof of concept. If @Timer or @gaearon would agree to have this in CRA, there are some other improvements I would do before landing.
Background
All modern browsers support ES modules via script tag. That means that they support things like async/await, classes, arrow functions, fetch etc., which allows us to skip a lot of transpilation and polyfills and therefore build less verbose code, which should be faster to parse and run.
For more in depth explanation I recommend reading this great article by @philipwalton.
Implementation
It's based on my recent PR - https://github.com/facebook/create-react-app/pull/4852, which switches from unmaintained uglify-es to terser.
The implementation is inspired by an awesome work of the Vue team - link.
A new --modern
flag is added to a build
command.
Code is built twice using webpack's multi-compiler. Firstly it's built using current configuration, secondly with babel-preset-env
targets option set to esmodules.
Then script tags in index.html
are concatenated with correct attributes - type="module"
for modern code and nomodule
(+ safari fix) for legacy code.
Improvements
For this PR I decided to go with webpack's multi-compiler
, so I didn't have to modify build
command, but if we decide to ship it to CRA, I would separate it to two separate builds to improve overall DX (making in it clear what's being built, better handling of messages, diff between legacy and modern assets).
Potentially extracting webpack plugin to separate module and making it less naive.
Other improvements could be to add support for rel=preload, but I think it's out of scope of this PR.
Results
There are some small improvements already when I tried that on the base template:
38.01 KB build/static/js/vendors.c5915f63.chunk.js
31.58 KB build/static/js/vendors.8f7a7647.chunk.m.js
1.74 KB build/static/js/main.9f0bbc18.chunk.js
1.01 KB build/static/js/main.f6d883db.chunk.m.js
619 B build/static/js/runtime~main.6dc408cf.m.js
617 B build/static/js/runtime~main.41117e05.js
257 B build/static/css/main.5c4bc340.chunk.css
257 B build/static/css/main.72f56e40.chunk.css
With a little custom configuration I was able to build Spectrum (cc @mxstbr):
337.59 KB build/static/js/vendors.a558cfde.chunk.js
323.47 KB build/static/js/vendors.5f3218c3.chunk.m.js
186.38 KB build/static/js/main.e89ef961.chunk.js
165.06 KB build/static/js/main.64166e32.chunk.m.js
25.92 KB build/static/js/Splash.46e74c85.chunk.js
23.87 KB build/static/js/Splash.7ffab923.chunk.m.js
17.47 KB build/static/js/communitySettings.0ac076e5.chunk.js
13.56 KB build/static/js/communitySettings.22122a1f.chunk.m.js
11.54 KB build/static/js/Thread.91502d68.chunk.js
10 KB build/static/js/Thread.cb8fdd14.chunk.m.js
...
While building Spectrum I found out that template literals are not minified, so size differences are not that huge.
Try it out
git clone https://github.com/prichodko/create-react-app.git
cd create-react-app/packages/react-scripts
yarn link
cd ~/your-project
yarn link react-scripts
yarn build --modern