Skip to content
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

Run Closure on non-minified prod builds, too #28827

Merged
merged 1 commit into from
Apr 19, 2024

Conversation

acdlite
Copy link
Collaborator

@acdlite acdlite commented Apr 11, 2024

In #26446 we started publishing non-minified versions of our production build artifacts, along with source maps, for easier debugging of React when running in production mode.

The way it's currently set up is that these builds are generated before Closure compiler has run. Which means it's missing many of the optimizations that are in the final build, like dead code elimination.

This PR changes the build process to run Closure on the non-minified production builds, too, by moving the sourcemap generation to later in the pipeline.

The non-minified builds will still preserve the original symbol names, and we'll use Prettier to add back whitespace. This is the exact same approach we've been using for years to generate production builds for Meta.

The idea is that the only difference between the minified and non- minified builds is whitespace and symbol mangling. The semantic structure of the program should be identical.

To implement this, I disabled symbol mangling when running Closure compiler. Then, in a later step, the symbols are mangled by Terser. This is when the source maps are generated.

@facebook-github-bot facebook-github-bot added CLA Signed React Core Team Opened by a member of the React Core Team labels Apr 11, 2024
@hoxyq
Copy link
Contributor

hoxyq commented Apr 11, 2024

What could be important:

  • fb artifacts should preserve specific header format, it is required by Haste.
  • The reason why I've changed these steps is the fact that Closure compiler was optimizing these multi-line comment headers, and the resulting format didn't work well with Haste

@acdlite
Copy link
Collaborator Author

acdlite commented Apr 11, 2024

The headers are still there, I added them post-Closure

@eps1lon
Copy link
Collaborator

eps1lon commented Apr 11, 2024

Failing tests should be fixed after rebase on master now that #28593 landed.

@markerikson
Copy link
Contributor

Nice!

@acdlite acdlite force-pushed the run-closure-on-non-minified-too branch 3 times, most recently from 604dea8 to cd1f695 Compare April 11, 2024 23:50
@acdlite acdlite marked this pull request as ready for review April 12, 2024 00:08
@kassens
Copy link
Member

kassens commented Apr 15, 2024

Why don't we let Closure generate the source maps and just conditionally enable the renaming there?

Alternatively, do we even need the renaming? Wouldn't that typically happen anyway as a minification step in product bundling (in various build systems?)

Since the build is already pretty complicated and slow it'd be nice to avoid adding more steps…

@eps1lon
Copy link
Collaborator

eps1lon commented Apr 15, 2024

FYI sizebot failed because the summary is too large: https://app.circleci.com/pipelines/github/facebook/react/52317/workflows/cfa1d5b9-b4cb-40d1-89db-f06f98f94c85/jobs/838157

Summary for this PR can be seen in https://output.circle-artifacts.com/output/job/17d7076d-4cf5-4552-acc0-63e9a29ef9c4/artifacts/0/sizebot-message.md

In #28845, we'll fallback to a link to CI with the full report.

@acdlite
Copy link
Collaborator Author

acdlite commented Apr 16, 2024

@kassens #28827 (comment)

Alternatively, do we even need the renaming? Wouldn't that typically happen anyway as a minification step in product bundling (in various build systems?)

That is indeed what I want to do, this first PR is meant to demonstrate that Closure + a later mangling step (via Terser in this case, since that's what much of the OSS community uses) is equivalent to Closure with mangling enabled.

@acdlite
Copy link
Collaborator Author

acdlite commented Apr 16, 2024

Regarding this, though:

Why don't we let Closure generate the source maps and just conditionally enable the renaming there?

That's how it works in main already, but the problem is that the source maps map to a pre-Closure "source", which means it doesn't have as much inlining and dead code elimination applied to it. If we are going to ship source maps (which again I'd prefer not to) then it should map to something like the Meta production builds — identical program structure, just without mangled names.

In facebook#26446 we started publishing non-minified versions of our production
build artifacts, along with source maps, for easier debugging of React
when running in production mode.

The way it's currently set up is that these builds are generated
*before* Closure compiler has run. Which means it's missing many of
the optimizations that are in the final build, like dead
code elimination.

This PR changes the build process to run Closure on the non-minified
production builds, too, by moving the sourcemap generation to later in
the pipeline.

The non-minified builds will still preserve the original symbol names,
and we'll use Prettier to add back whitespace. This is the exact same
approach we've been using for years to generate production builds
for Meta.

The idea is that the only difference between the minified and non-
minified builds is whitespace and symbol mangling. The semantic
structure of the program should be identical.

To implement this, I disabled symbol mangling when running Closure
compiler. Then, in a later step, the symbols are mangled by Terser.
This is when the source maps are generated.
@acdlite acdlite force-pushed the run-closure-on-non-minified-too branch from cd1f695 to 44ca36d Compare April 19, 2024 17:57
@react-sizebot
Copy link

The size diff is too large to display in a single comment. The CircleCI job contains an artifact called 'sizebot-message.md' with the full message.

Generated by 🚫 dangerJS against 44ca36d

@acdlite acdlite merged commit 0e0b693 into facebook:main Apr 19, 2024
38 checks passed
github-actions bot pushed a commit that referenced this pull request Apr 19, 2024
In #26446 we started publishing non-minified versions of our production
build artifacts, along with source maps, for easier debugging of React
when running in production mode.

The way it's currently set up is that these builds are generated
*before* Closure compiler has run. Which means it's missing many of the
optimizations that are in the final build, like dead code elimination.

This PR changes the build process to run Closure on the non-minified
production builds, too, by moving the sourcemap generation to later in
the pipeline.

The non-minified builds will still preserve the original symbol names,
and we'll use Prettier to add back whitespace. This is the exact same
approach we've been using for years to generate production builds for
Meta.

The idea is that the only difference between the minified and non-
minified builds is whitespace and symbol mangling. The semantic
structure of the program should be identical.

To implement this, I disabled symbol mangling when running Closure
compiler. Then, in a later step, the symbols are mangled by Terser. This
is when the source maps are generated.

DiffTrain build for commit 0e0b693.
github-actions bot pushed a commit that referenced this pull request Apr 19, 2024
In #26446 we started publishing non-minified versions of our production
build artifacts, along with source maps, for easier debugging of React
when running in production mode.

The way it's currently set up is that these builds are generated
*before* Closure compiler has run. Which means it's missing many of the
optimizations that are in the final build, like dead code elimination.

This PR changes the build process to run Closure on the non-minified
production builds, too, by moving the sourcemap generation to later in
the pipeline.

The non-minified builds will still preserve the original symbol names,
and we'll use Prettier to add back whitespace. This is the exact same
approach we've been using for years to generate production builds for
Meta.

The idea is that the only difference between the minified and non-
minified builds is whitespace and symbol mangling. The semantic
structure of the program should be identical.

To implement this, I disabled symbol mangling when running Closure
compiler. Then, in a later step, the symbols are mangled by Terser. This
is when the source maps are generated.

DiffTrain build for [0e0b693](0e0b693)
acdlite added a commit to acdlite/react that referenced this pull request Apr 19, 2024
This disables symbol renaming in production builds. The original
variable and function names are preserved. All other forms of
compression applied by Closure (dead code elimination, inlining, etc)
are unchanged — the final program is identical to what we were
producing before, just in a more readable form.

The motivation is to make it easier to debug React issues that only
occur in production — the same reason we decided to start shipping
sourcemaps in facebook#28827 and facebook#28827.

However, because most apps run their own minification step on their
npm dependencies, it's not necessary for us to minify the symbols
before publishing — it'll be handled the app, if desired.

This is the same strategy Meta has used to ship React for years. The
React build itself has unminified symbols, but they get minified as part
of Meta's regular build pipeline.

Even if an app does not minify their npm dependencies, gzip covers
most of the cost of symbol renaming anyway.

This saves us from having to ship sourcemaps, which means even apps that
don't have sourcemaps configured will be able to debug the React build
as easily as they would any other npm dependency.
acdlite added a commit to acdlite/react that referenced this pull request Apr 19, 2024
This disables symbol renaming in production builds. The original
variable and function names are preserved. All other forms of
compression applied by Closure (dead code elimination, inlining, etc)
are unchanged — the final program is identical to what we were
producing before, just in a more readable form.

The motivation is to make it easier to debug React issues that only
occur in production — the same reason we decided to start shipping
sourcemaps in facebook#28827 and facebook#28827.

However, because most apps run their own minification step on their
npm dependencies, it's not necessary for us to minify the symbols
before publishing — it'll be handled the app, if desired.

This is the same strategy Meta has used to ship React for years. The
React build itself has unminified symbols, but they get minified as part
of Meta's regular build pipeline.

Even if an app does not minify their npm dependencies, gzip covers
most of the cost of symbol renaming anyway.

This saves us from having to ship sourcemaps, which means even apps that
don't have sourcemaps configured will be able to debug the React build
as easily as they would any other npm dependency.
acdlite added a commit to acdlite/react that referenced this pull request Apr 19, 2024
This disables symbol renaming in production builds. The original
variable and function names are preserved. All other forms of
compression applied by Closure (dead code elimination, inlining, etc)
are unchanged — the final program is identical to what we were
producing before, just in a more readable form.

The motivation is to make it easier to debug React issues that only
occur in production — the same reason we decided to start shipping
sourcemaps in facebook#28827 and facebook#28827.

However, because most apps run their own minification step on their
npm dependencies, it's not necessary for us to minify the symbols
before publishing — it'll be handled the app, if desired.

This is the same strategy Meta has used to ship React for years. The
React build itself has unminified symbols, but they get minified as part
of Meta's regular build pipeline.

Even if an app does not minify their npm dependencies, gzip covers
most of the cost of symbol renaming anyway.

This saves us from having to ship sourcemaps, which means even apps that
don't have sourcemaps configured will be able to debug the React build
as easily as they would any other npm dependency.
acdlite added a commit to acdlite/react that referenced this pull request Apr 19, 2024
This disables symbol renaming in production builds. The original
variable and function names are preserved. All other forms of
compression applied by Closure (dead code elimination, inlining, etc)
are unchanged — the final program is identical to what we were
producing before, just in a more readable form.

The motivation is to make it easier to debug React issues that only
occur in production — the same reason we decided to start shipping
sourcemaps in facebook#28827 and facebook#28827.

However, because most apps run their own minification step on their
npm dependencies, it's not necessary for us to minify the symbols
before publishing — it'll be handled the app, if desired.

This is the same strategy Meta has used to ship React for years. The
React build itself has unminified symbols, but they get minified as part
of Meta's regular build pipeline.

Even if an app does not minify their npm dependencies, gzip covers
most of the cost of symbol renaming anyway.

This saves us from having to ship sourcemaps, which means even apps that
don't have sourcemaps configured will be able to debug the React build
as easily as they would any other npm dependency.
acdlite added a commit to acdlite/react that referenced this pull request Apr 19, 2024
This disables symbol renaming in production builds. The original
variable and function names are preserved. All other forms of
compression applied by Closure (dead code elimination, inlining, etc)
are unchanged — the final program is identical to what we were
producing before, just in a more readable form.

The motivation is to make it easier to debug React issues that only
occur in production — the same reason we decided to start shipping
sourcemaps in facebook#28827 and facebook#28827.

However, because most apps run their own minification step on their
npm dependencies, it's not necessary for us to minify the symbols
before publishing — it'll be handled the app, if desired.

This is the same strategy Meta has used to ship React for years. The
React build itself has unminified symbols, but they get minified as part
of Meta's regular build pipeline.

Even if an app does not minify their npm dependencies, gzip covers
most of the cost of symbol renaming anyway.

This saves us from having to ship sourcemaps, which means even apps that
don't have sourcemaps configured will be able to debug the React build
as easily as they would any other npm dependency.
acdlite added a commit that referenced this pull request Apr 20, 2024
This disables symbol renaming in production builds. The original
variable and function names are preserved. All other forms of
compression applied by Closure (dead code elimination, inlining, etc)
are unchanged — the final program is identical to what we were producing
before, just in a more readable form.

The motivation is to make it easier to debug React issues that only
occur in production — the same reason we decided to start shipping
sourcemaps in #28827 and #28827.

However, because most apps run their own minification step on their npm
dependencies, it's not necessary for us to minify the symbols before
publishing — it'll be handled the app, if desired.

This is the same strategy Meta has used to ship React for years. The
React build itself has unminified symbols, but they get minified as part
of Meta's regular build pipeline.

Even if an app does not minify their npm dependencies, gzip covers most
of the cost of symbol renaming anyway.

This saves us from having to ship sourcemaps, which means even apps that
don't have sourcemaps configured will be able to debug the React build
as easily as they would any other npm dependency.
github-actions bot pushed a commit that referenced this pull request Apr 20, 2024
This disables symbol renaming in production builds. The original
variable and function names are preserved. All other forms of
compression applied by Closure (dead code elimination, inlining, etc)
are unchanged — the final program is identical to what we were producing
before, just in a more readable form.

The motivation is to make it easier to debug React issues that only
occur in production — the same reason we decided to start shipping
sourcemaps in #28827 and #28827.

However, because most apps run their own minification step on their npm
dependencies, it's not necessary for us to minify the symbols before
publishing — it'll be handled the app, if desired.

This is the same strategy Meta has used to ship React for years. The
React build itself has unminified symbols, but they get minified as part
of Meta's regular build pipeline.

Even if an app does not minify their npm dependencies, gzip covers most
of the cost of symbol renaming anyway.

This saves us from having to ship sourcemaps, which means even apps that
don't have sourcemaps configured will be able to debug the React build
as easily as they would any other npm dependency.

DiffTrain build for [857ee8c](857ee8c)
bigfootjon pushed a commit that referenced this pull request Apr 25, 2024
In #26446 we started publishing non-minified versions of our production
build artifacts, along with source maps, for easier debugging of React
when running in production mode.

The way it's currently set up is that these builds are generated
*before* Closure compiler has run. Which means it's missing many of the
optimizations that are in the final build, like dead code elimination.

This PR changes the build process to run Closure on the non-minified
production builds, too, by moving the sourcemap generation to later in
the pipeline.

The non-minified builds will still preserve the original symbol names,
and we'll use Prettier to add back whitespace. This is the exact same
approach we've been using for years to generate production builds for
Meta.

The idea is that the only difference between the minified and non-
minified builds is whitespace and symbol mangling. The semantic
structure of the program should be identical.

To implement this, I disabled symbol mangling when running Closure
compiler. Then, in a later step, the symbols are mangled by Terser. This
is when the source maps are generated.

DiffTrain build for commit 0e0b693.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed React Core Team Opened by a member of the React Core Team
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants