-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Build: Transpile whitelisted packages in node_modules #30196
Conversation
An idea how we could auto-test for untranspiled code: parse the production JS chunks with an ES5-only parser (does one exist? can existing popular parser to be configured to be ES5-only?) and verify that the parse succeeds. |
I think I'd rather just transpile it all if we can and avoid trying to detect what really needs it. Transpilation is pretty fast now and babel has a quality cache. |
Looking at how CRA does it, they have a separate config for babel for dependencies. This is due to babel@7 now assuming that esm is in use. There's a config flag to make it autodetect like webpack that we should turn on. |
Interesting. TIL that CRA does that and that transpiling all |
@jsnajdr should work now? |
Open questions:
|
We transpile tests with current Node as a target: https://github.com/Automattic/wp-calypso/blob/master/babel.config.js#L100-L107 Standard ES2018 should therefore transpile without any changes. The target is JSX and nonstandard extensions like class properties. Do any NPM modules ship that kind of syntax? |
Not that I've seen. This is mostly motivated by packages that are dropping old Node support and in the process picking up ES6 features, like |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Build speed doesn't seem to be significantly affected. It turns out that the modules from node_modules
are in minority. There are 8520 files transpiled, only 3540 of them coming from node_modules
.
I gathered all this data by placing a console.log
statement to the babel-loader
source.
'@babel/react', | ||
], | ||
plugins: [ | ||
'@babel/plugin-syntax-dynamic-import', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This transform is also not needed. We don't expect import( ... ).then( ... )
statements in NPM packages, do we?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so, but CRA has it.... It would be odd.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To CRA it was added by @Timer in facebook/create-react-app#5047. The PR description doesn't mention that any published NPM package would use it.
It's a very minor issue that doesn't really matter at all. It's just my curiosity that's not 100% satisfied 😃
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This transform is also not needed. We don't expect import( ... ).then( ... ) statements in NPM packages, do we?
We expect npm packages to use it in Create React App.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, compiling node_modules
is not without its pitfalls, it's very unsafe.
You should avoid compiling node_modules
if you can. 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
though that does make me revisit the choice to use a blacklist. Maybe we need a whitelist instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suggest keeping a list of "bad actors". If packages are intended to be used in the browser (even if they're Node packages) the publisher is responsible for compiling.
We always told users who tried to import non-ES5 that the publisher had to fix, and most of the time, they did.
Bad actors would contain often-used packages that refuse to compile themselves.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Insider tip: be sure to disable transform-typeof-symbol
. This should fix mapbox and reduce some of the side effects of compiling node_modules
if you go through with it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Timer I saw that in CRA@2 and wondered about it.. IE11 doesn't support Symbol at all, so dropping support for the typeof check seems ... chancy?
Ah, facebook/create-react-app#5278 has more background.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
switch all this over to using a whitelist
webpack.config.js
Outdated
{ | ||
test: /\.jsx?$/, | ||
include: /node_modules\//, | ||
exclude: /@babel(?:\/|\\{1,2})runtime/, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are several libraries that we can trust to be ES5:
babel-runtime
-- the 6 version used still by many libraries:react-virtualized
,click-outside
,wpcom
(!)core-js
- everything in
@wordpress/*
lodash
regenerate-unicode-properties
-- used by the@babel/plugin-proposal-unicode-property-regex
transformgridicons
fbjs
react
and relatedwpcom
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One strange file that gets transpiled by Babel:
node_modules/css-loader/lib/css-base.js
I don't know why exactly, but it's probably the JS code that's added by css-loader
and then removed again by the extract plugin?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like exclude
can be a function instead of a regex. Perhaps that would make building and maintaining that list easier. https://webpack.js.org/configuration/module/#condition
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
btw, react
is not safe. They use Map and Set. :) https://reactjs.org/docs/javascript-environment-requirements.html
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
btw, react is not safe. They use Map and Set.
That is safe for us. We import @babel/polyfill
at the very beginning, and it polyfills the Map
and Set
globals, according to the browser requirements in @babel/preset-env
.
It wouldn't be safe if we:
- used
useBuiltins: 'usage'
inpreset-env
. Babel needs to transpile a module to see that a polyfill is needed. - used
corejs: true
intransform-runtime
. Then Babel transpiles usages of theMap
global to imports frombabel-runtime-corejs
, avoiding the need for global namespace pollution.
In both cases, Babel would need to see the React module to polyfill correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
switched to a function based exclude in 40d46b8
also looked at trying to automate the set of includes with a function that parses each package.json and checks the engines
property, but it looks like that won't fly because at least some of the packages that have dropped node 4 support have not updated engines
.
c225570
to
40d46b8
Compare
See facebook/create-react-app#5278 for details. It makes all code slower and can break some libraries. Pulled out of #30196
I tend to agree with @Timer that it might make sense to err on the safe side when transpiling Some prior art here: #19698. FWIW, the heuristics I was using was based on the presence of a |
@ockham I agree, we'll want to use a whitelist, not transpile everything. I'm not in love with using module / esnext as a heuristic, as it means we'll likely be transpiling more than we need to, but it might serve as a check. Maybe we also come up with a new thing that scans the source and yells if it sees things that need transpilation? |
See facebook/create-react-app#5278 for details. It makes all code slower and can break some libraries. Pulled out of #30196
* Disable babel transform-typeof-symbol See facebook/create-react-app#5278 for details. It makes all code slower and can break some libraries. Pulled out of #30196 * Move the exclude option to preset-env config
b6e9f7b
to
4166bbd
Compare
b1aa6f9
to
aea84cf
Compare
Switched this to use a whitelist in aea84cf |
Noting that Mapbox dependency might go away soon (~this week) in Calypso after migrating the block's code from Calypso to Jetpack. In Calypso Line 143 in e486289
In Jetpack |
@simison with the new whitelist, we're no longer trying to transpile mapbox-gl. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Posted two nits, looks good to 🚢
webpack.config.js
Outdated
@@ -160,6 +193,27 @@ function getWebpackConfig( { | |||
cacheIdentifier, | |||
exclude: /node_modules\//, | |||
} ), | |||
{ | |||
test: /\.jsx?$/, | |||
include: _.memoize( shouldTranspileDependency ), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The memoize
here is probably an insignificant optimization. It will maintain a map with several thousands entries, and webpack does so many checks on each filename so that this extra one is unlikely to make any impact.
babel.dependencies.config.js
Outdated
], | ||
], | ||
// Exclude transforms that make all code slower, see https://github.com/facebook/create-react-app/pull/5278 | ||
exclude: [ 'transform-typeof-symbol' ], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the exclude
need to be there in two copies?
This would let us use many of the newer NPM modules that are dropping support for ES6 and requiring Node 4, 6, 10.
Teach that config to detect the module type. Teach webpack about the new config.
d486c02
to
fcaf566
Compare
webpack.config.js
Outdated
}, | ||
}, | ||
], | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we use the Transpile
shard from @automattic/calypso-build
for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
possibly, i'll try it out
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done!
Thanks for fixing the nits! Looks good to me 👍 |
In the past, we've tried very hard to avoid transpiling code in node_modules. This was because most code shipped in node_modules was plain ES5 that worked in all of our target browsers, so transpiling would be extra work with no benefit. Modules were typically ES5 because they wanted to support Node 4, which was on par with IE11 for language features.
Fast forward to today, where Node 4 is no longer supported. Some modules (debug, d3-*, striptags, ...) are dropping support for Node 4 and adding ES6 features to the code they ship to NPM, like
let
andfor of
. This breaks IE11, so we have to transpile these packages to use them in IE11.This PR proposes to transpile some things in node_modules, provided by a whitelist. This hasn't seemed to affect total compilation time very much, especially for incremental runs when the babel cache is hot. We also use a reduced babel config that only transpiles the set of plugins supported by
@babel/preset-env
, reducing the surface area of features we'll transpile. We're not really expecting anything outside of thenode@6
feature set, but using preset-env gives us a bit of future proofing.The whitelist is path based, so it has no notion of a package's version. It would be a nice enhancement to only transpile packages that are past a certain version.
debug@4
, for instance, requires transpilation, butdebug@3
does not. We may have both versions in the tree as transitive dependencies.Original PR Description follows