-
Notifications
You must be signed in to change notification settings - Fork 46.8k
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
Initial work to support advanced compilation of UMD bundles using GCC #11967
Conversation
This makes closure options dynamic, based on bundle type, since UMD and Node bundles expect different things in their externs. At this point, this can build the UMD_PROD versions of core and dom-client and load the babel-standalone fixture with the compiled react and react-dom files.
The built bundle is not correct yet because it's missing module.exports.
That error is likely caused by renaming isReactComponent. |
React.version; | ||
|
||
React.createClass = function(specification) {}; | ||
React.createFactory = function(reactClass) {}; |
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.
A lot of these are outdated. Once we get the tests passing we should trim these down significantly.
@sophiebits yeah that was it. I got the node bundles to build correctly last night and got a handful of |
Can't wait 😍 |
The Angular team has tools (tsickle and clutz) to convert between TypeScript and Closure annotations. I haven't tested them myself yet, so I don't know how well they work, but I believe the goal is to enable TypeScript applications to use advanced GCC. It may be worth exploring using tsickle to auto-gen your Closure externs. I'm not sure if it would work on Flow code, but I bet @evmar is amenable to PRs. I suspect that automatically generating them is better in the long run than maintaining the externs by hand. |
The missing isReactComponent was causing Component subclasses to be treated as functional components. The missing properties on ReactElement were breaking other type dependant behavior.
The browser environment helps ensure that dom attributes don't get renamed, for example. With processCommonJsModules set to true, gcc was removing the module.exports from the compiled bundles.
So we don't have to keep defining these for each bundle
Event -> FakeEvent hasOwnProperty -> objHasOwnProperty escape -> escapeKey Suppressed the error on ReactART.Text since it's exported
Also suppress duplicate warnings because now that we don't use processCommonJsModules, these are treated as global variables.
This is needed by both UMD and NODE bundles, even though the NODE bundle generates a duplicate warning.
These are treated as external dependencies in node bundles, so have to prevent renaming them. We should eventually still rename these in UMD bundles.
One thing that’s nice in our case is that the API surface is relatively small. So once we get them right for the first time they’re not as much pain to maintain. |
GCC seems to incorrectly remove all of the properties from `RESERVED_PROPS` because they are never accessed by name. Replaced this with a Set since that was the intent anyway.
This allows us to run prettier even after compiling in ADVANCED mode, which can be really useful when debugging problems with the minified output.
@appsforartists Within Google we do generate externs for React from the DefinitelyTyped React d.ts files. The API surface is a bit larger than you'd expect due to including all the CSS properties etc. But it's also probably more complicated than what you want because:
Oh, and now that I think harder about it, these d.ts files are for clients of React to use the minified bundle, while here you are concerned about preventing bits of React's internal API from getting renamed. (You might find this section of the docs useful in that respect.) |
Yeah, the more challenging part seems to be the non-public API shared between the bundles (e.g. |
When Dan twitted about using GCC for minification I thought about "GNU Compiler Collection", but this was about "Google Closure Compiler" 🤣 |
…_FIRED These are used extensively by react-dom etc., so best to keep them all in externs instead of trying to whack-a-mole.
These are needed in both UMD and NODE bundles, plus these were outdated.
These are useful for understanding why a test is failing in prod.
Removed unnecessary annotations and updated the externs for React 16
Ok now all |
We probably don’t need to apply advanced mode to any bundles except React and ReactDOM. Others’ size is less critical / important. |
It’s also worth exploring a subset of this PR that only applies advanced to the React bundle. It’s not as important as ReactDOM but it’s a good way to get started since it’s fairly small and won’t need a ton of externs. That would be relatively safe to merge while we continue to iterate on ReactDOM. |
If we do run it on all bundles, let’s have separate externs for each bundle. There are some names we want to munge in react-dom but not react-reconciler, for instance. |
@gaearon sounds good. Should I start a separate PR for just compiling the react bundle? @sophiebits yup, I’ve been keeping the externs separate by bundle type, although some bundles need to pull in externs for others (eg react-dom needs react externs) |
Yes, a separate more scoped PR that can pass a CI would be great. Thank you for working on this! |
As described in #11092, this PR adds support for passing in externs to GCC to allow it to compile bundles in advanced mode without renaming properties that are part of the public API. Most of the externs were taken from https://github.com/cljsjs/packages/tree/master/react/resources/cljsjs/, although some more needed to be added. I've split them into various files with necessary comments so they should be reasonably easy to follow.
At this point, the node bundles do not build correctly (the module.exports part is stripped out), so we can't run tests just yet. So I just tested by pointing the babel-standalone fixture to the built prod files and loading it. The current fixture works successfully, and I was able to create a functional component as well. But when I tried creating a component by extending
React.Component
, I sawclass constructor cannot be invoked without 'new'
, indicating that another property is getting renamed and causing the functional component codepath to execute for non-functional components.(This is my first PR to an FB project, so I just submitted the CLA.)
test-build-prod
tests to pass