-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
Generate minified .min.js and unminified .js files for GB js entry points when building #31732
Generate minified .min.js and unminified .js files for GB js entry points when building #31732
Conversation
The downside of this approach is that the build task runs webpack twice (through wp-scripts): one time to generate the minified min.js script (and its asset PHP file) and another pass to generate the unminfied version. |
lib/client-assets.php
Outdated
$script_path = gutenberg_dir_path() . 'build/' . substr( $handle, 3 ) . '/index.js'; | ||
$indexFilename = ( defined( 'SCRIPT_DEBUG') && SCRIPT_DEBUG ) ? 'index.js' : 'index.min.js'; | ||
|
||
$script_path = gutenberg_dir_path() . 'build/' . substr( $handle, 3 ) . "/$indexFilename"; |
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'm not really sure if we should change the filename to index.min.js
here 🤔 (since this function seems related to translations). Could someone shed some light? Is it okay to leave it as is?
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'm not really sure if we should change the filename to
index.min.js
here
Are there places where the exact filename matters? For example, the Gutenberg plugin overrides the Gutenberg assets that are present in Core with the newer ones in the plugin. Does the exact filename play any role there? Or does it involve only symbolic ids of the scripts?
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 know. I'll have a look, but I'd love to get insights from @grzim, @ockham or @youknowriad about that.
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 tests well for me! Thanks for working on this 🥳
Run npm run build and verify that for each of the generated packages, there's a /index.js that is NOT minified and /index.min.js that is minified (if it's a block, check that the same applies for the frontend.[min].js script).
✅ Verified: index.min.js
files are minified & index.js
aren't.
Verify that the Gutenberg plugin is working correctly and that these changes do not break it in some unexpected way. The minified files should load by default.
✅ Verified: I've built the plugin and uploaded it to my site. Minified files load by default and the plugin seems to be working as usual.
Verify that index.min.js loads when the SCRIPT_DEBUG PHP constant is not set or set and false, or index.js loads when SCRIPT_DEBUG is set and true (the const is set to true by default in wp-config.php).
✅ Verified: SCRIPT_DEBUG
constant determines correctly which files should be requested.
@gziolo @youknowriad how does it look to you? Is there anything that you'd consider a blocker here?
Do we know why the original attempt from @sirreal has been reverted? How can we check that i18n string discovery still works properly with this PR? (I think GlotPress uses some |
The original attempt renamed the single generated JavaScript file extensions from
|
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 two webpack compilations generate two index.asset.php
and index.min.asset.php
files that are identical. We need only one. Does the filename need the .min.
infix?
We should disable the DependencyExtractionWebpackPlugin
for the non-minified compilation. And if we don't want to include .min.
in the PHP filename, patch the part of the plugin that does:
assetFilename = buildFilename.replace( /\.js$/, '.asset.php' );
and replace the entire .min.js
suffix (with a /(\.min)?\.js$/
regexp).
If we want to avoid the double compilation and output both .js
and .min.js
assets at the same time, it should be possible with a simple webpack plugin. One that hooks to a place right before the Terser minification, outputs a .js
asset, and then lets Terser minify the source into a .min.js
asset. Let me know if you want me to push a commit with that 🙂
webpack.config.js
Outdated
@@ -113,6 +114,7 @@ module.exports = { | |||
mode === 'production' && ! process.env.WP_BUNDLE_ANALYZER, | |||
minimizer: [ | |||
new TerserPlugin( { | |||
test: /\.min\.js$/, |
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 this mean that we are setting up the minimizer even if MINIMIZE
is false, and just setting it up to ignore the input files?
You could simply set the optimization.minimize = MINIMIZE
boolean option.
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 this mean that we are setting up the minimizer even if MINIMIZE is false, and just setting it up to ignore the input files?
Yes, it will run but will ignore due to the match.
You could simply set the optimization.minimize = MINIMIZE boolean option.
TIL, Thanks!
Oh, good catch!
Thanks for pointing this out, I wasn't aware of this part.
@jsnajdr That would be great! ❤️ 🙇🏻 |
Actually, I think it'd be fun to poke with WebPack plugins. I'll take it for a spin today and see if I can manage to get it working. |
…ar and enqueue .min.js files by default in `client-assets.php`
… var - If set and true, we enqueue the unminified index.js file for the given package; - If not set or set and false, we enqueue the minified (production) index.min.js file.
768e8da
to
31419f8
Compare
31419f8
to
7049cfa
Compare
@jsnajdr I gave it a try but didn't manage to implement what you suggested, yet :(. I pushed what I did so far in the following commit: 7049cfa. After failing to tap into a hook that would allow me to generate the unminized files before the minimizer ran, I tried a more brute-force approach in the plugin I created, but it doesn't work. Well, it does generate the If I could get hold of the unminized source for each asset at this point, then I could leave Terser where it belongs in the
Or maybe I just didn't understand how to tap into the emit hook but before the Terser runs. Even if I do, though, I'd have to somehow make sure the asset entries I add don't get mangled later. I'll continue tomorrow, but if you know how to solve this from the top of your head, feel free to jump in. If you don't have the time, I could use some tips on how to proceed. Thanks in advance! |
@fullofcaffeine I'm playing with something like this: class AddReadableJsAssetsWebpackPlugin {
extractUnminifiedFiles( compilation ) {
const files = compilation.chunks.flatMap( ( chunk ) => chunk.files );
compilation.unminifiedAssets = files.map( ( file ) => {
const asset = compilation.assets[ file ];
const unminifiedFile = file.replace( /\.min\.js$/, '.js' );
return [ unminifiedFile, asset.source() ];
} );
}
async writeUnminifiedFiles( compilation ) {
for ( const [ file, source ] of compilation.unminifiedAssets ) {
await fs.promises.writeFile( file, source );
}
}
apply( compiler ) {
compiler.hooks.compilation.tap(
this.constructor.name,
( compilation ) => {
compilation.hooks.additionalAssets.tap(
this.constructor.name,
() => this.extractUnminifiedFiles( compilation )
);
}
);
compiler.hooks.afterEmit.tapPromise(
this.constructor.name,
( compilation ) => this.writeUnminifiedFiles( compilation )
);
}
} Don't modify anything about That's all I managed to do today. You can continue from this point, I'm coming back tomorrow again. |
@jsnajdr Oh now I understand what you had in mind! To clarify: My idea was to avoid manually getting the file contents and writing to the filesystem myself. I thought it'd be simpler to just hook into the lifecycle to add some unminimized assets to the list before terser runs (or after), and then let the already setup WebPack pipeline run after that, thus spitting all the files for us. As you can see, I did manage to accomplish part of it, I just couldn't find a way to exclude files from being minimized or get unminimized files after the minimizer ran :( Anyway, your approach is sound and I'll try it out today! Thanks a lot for taking the time to work on it! |
Change the plugin version to include a '-prerelease' suffix. Co-authored-by: Greg Ziółkowski <grzegorz@gziolo.pl>
Fix webpack spelling :) Co-authored-by: Greg Ziółkowski <grzegorz@gziolo.pl>
@gziolo Thanks for the review 🙇🏻. This is ready for another look! |
Size Change: -566 B (0%) Total Size: 1.03 MB
ℹ️ View Unchanged
|
Is |
It should be useful for any WordPress plugin that builds and ships minified JS files. This plugin will output unminified versions on the side. It's my understanding that it's common for WordPress plugins to publish also unminified versions. For translations, for reviews by the plugin review team, for the It could be an option for the |
Proposing that this is reverted in #32617, as this seems to stop sourcemaps from working when using |
Quick fix was made here. We'll eventually follow-up with improvements. |
…ints when building (#31732) * Add .min.js suffix to index script depending on the presence of env var and enqueue .min.js files by default in `client-assets.php` * Decide what to enqueue depending on the value of the SCRIPT_DEBUG env var - If set and true, we enqueue the unminified index.js file for the given package; - If not set or set and false, we enqueue the minified (production) index.min.js file. * WIP * Save unminified .js sources before minimizer runs * No need to pass the mode anymore * Add packaged version PoC and tests * Package as internal monorepo npm, remove top-level PoC module * Add test artifacts * Use snake case for var, simplify and DRY the asset name * Hardcode index.min.js for override scripts * Always refer to index.asset.php as the asset loader scripts The WebPack build generates them using the `index.asset.php` name format. * More reliable extension replacement * Fix lint error * Fix php lint errors * Fix another linter error (prefer-alphabetical-devDependencies) * Update packages/readable-js-assets-webpack-plugin/package.json Change the plugin version to include a '-prerelease' suffix. Co-authored-by: Greg Ziółkowski <grzegorz@gziolo.pl> * Update packages/readable-js-assets-webpack-plugin/README.md Fix webpack spelling :) Co-authored-by: Greg Ziółkowski <grzegorz@gziolo.pl> * Add .nmprc and CHANGELOG.md * Restrict the compressed-size-action to *.min.js assets (and *.css) Co-authored-by: Jarda Snajdr <jsnajdr@gmail.com> Co-authored-by: Greg Ziółkowski <grzegorz@gziolo.pl>
Description
Attempts to solve #23960.
Follow-up to: #31729.
TerserPlugin
to only apply to files that match.min.js
;min.js
files by default;SCRIPT_DEBUG
constant. When it'strue
, the unminified version of the script should be loaded, instead.How has this been tested?
npm install
andnpm run build
and verify that for each of the generated packages, there's a<name>.js
that is NOT minified and<name>.min.js
that is minified (if it's a block, check that the same applies for thefrontend.[min].js
script) for each entry-point inbuild/
.index.min.js
loads when theSCRIPT_DEBUG
PHP constant is not set or set and false, orindex.js
loads whenSCRIPT_DEBUG
is set and true (the const is set totrue
by default inwp-config.php
).You can also verify / run the unit test. From the Gutenberg root directory, run:
npm run test-unit packages/readable-js-assets-webpack-plugin/test/build.js
. It should pass 🟢.Types of changes
Checklist:
*.native.js
files for terms that need renaming or removal).