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

Assets: Fix the order of the chunk files (2nd try) #96100

Merged
merged 9 commits into from
Feb 3, 2025

Conversation

arthur791004
Copy link
Contributor

Related to #95748

Proposed Changes

Why are these changes being made?

Testing Instructions

Pre-merge Checklist

  • Has the general commit checklist been followed? (PCYsg-hS-p2)
  • Have you written new tests for your changes?
  • Have you tested the feature in Simple (P9HQHe-k8-p2), Atomic (P9HQHe-jW-p2), and self-hosted Jetpack sites (PCYsg-g6b-p2)?
  • Have you checked for TypeScript, React or other console errors?
  • Have you used memoizing on expensive computations? More info in Memoizing with create-selector and Using memoizing selectors and Our Approach to Data
  • Have we added the "[Status] String Freeze" label as soon as any new strings were ready for translation (p4TIVU-5Jq-p2)?
  • For changes affecting Jetpack: Have we added the "[Status] Needs Privacy Updates" label if this pull request changes what data or activity we track or use (p4TIVU-aUh-p2)?

@arthur791004 arthur791004 self-assigned this Nov 6, 2024
@arthur791004
Copy link
Contributor Author

I'll come back to this when I have time.

@jsnajdr jsnajdr force-pushed the fix/webpack-chunk-files-order branch from 05fe9bb to 21b5627 Compare January 19, 2025 13:11
@matticbot
Copy link
Contributor

matticbot commented Jan 19, 2025

This PR modifies the release build for the following Calypso Apps:

For info about this notification, see here: PCYsg-OT6-p2

  • notifications

To test WordPress.com changes, run install-plugin.sh $pluginSlug fix/webpack-chunk-files-order on your sandbox.

@matticbot
Copy link
Contributor

This PR does not affect the size of JS and CSS bundles shipped to the user's browser.

Generated by performance advisor bot at iscalypsofastyet.com.

@jsnajdr
Copy link
Member

jsnajdr commented Jan 23, 2025

Hi @arthur791004 👋 I'd like to merge this patch again. To do that responsibly, I'd like to know some details why exactly it failed the first time, on Nov 6 2024. In this comment you say that production chunks were empty. Do you remember anything beyond that? I tried to find some Slack thread about it, but didn't find anything.

I'd like to avoid discovering exactly the same problem again and reverting again, without learning anything new. The second try should be in some sense better, more informed than the first one.

@arthur791004
Copy link
Contributor Author

Do you remember anything beyond that? I tried to find some Slack thread about it, but didn't find anything.

I checked the response html after the deployment and found that the chunk files were not listed. It didn't break anything, but it caused the preload not to work.

@jsnajdr
Copy link
Member

jsnajdr commented Jan 23, 2025

I checked the response html after the deployment and found that the chunk files were not listed.

Thanks, this is already useful info. I understand it as:

  • it's not that the chunk files would be empty, i.e., the HTTP responses, but the <script> tags were not included in the HTML document
  • the <script> tags for the entrypoint were there, so the app booted up and worked. It's only the preloads for the initial section (e.g., the reader chunk for the /read route) that were missing.

Is that right?

@arthur791004
Copy link
Contributor Author

Yes, exactly!

@jsnajdr jsnajdr force-pushed the fix/webpack-chunk-files-order branch from 21b5627 to f279841 Compare January 23, 2025 12:51
@jsnajdr
Copy link
Member

jsnajdr commented Jan 23, 2025

I can reproduce this on calypso.live. The preloads for the section JS chunks are missing. Locally, in dev mode on calypso.localhost they are there.

@@ -82,10 +82,8 @@ Object.assign( AssetsWriter.prototype, {

statsToOutput.chunks = stats.chunks.map( ( chunk ) =>
Object.assign( {}, chunk, {
chunks: stats.namedChunkGroups[ chunk.id ]?.chunks,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line causes the problem with missing chunks in production. The chunk.id is a chunk ID, but stats.namedChunkGroups uses chunk names as keys. In development they are both identical (we use chunkIds: 'named') but in production the chunk IDs are numbers.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I fixed this by a radical refactoring of the assets.json file format 🙂 It turns out that everything the app needs to serve the right assets is in the stats.namedChunkGroups object and in the assets field of this object's entries. For each chunk group, assets is a combined array of all assets from all chunks that comprise a chunk group. We don't need to look at chunks of the chunk group and then find all individual chunks one by one and read their assets. It's all already prepared by webpack at one place.

In the server code that reads the assets.json file, I also unified the two functions getFilesForEntrypoint and getFilesForChunk. Because entrypoint is just a special type of a chunk group. We only need one function, getFilesForChunkGroup.

@jsnajdr jsnajdr force-pushed the fix/webpack-chunk-files-order branch from ba58ad8 to f561b74 Compare January 24, 2025 12:14
}

return asset.info.hotModuleReplacement || asset.info.development;
}
Copy link
Member

@jsnajdr jsnajdr Jan 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fixes one of possible causes of the "window.AppBoot is not a function" error. In development mode, we were writing the *.hot-update.* assets to the assets.json file, and the dev server was probably serving them as one of the scripts in the initial HTML page. That's wrong, hot updates are supposed to be sent only to a live page without reload. Once you reload, you'll load the updated asset.

See how html-webpack-plugin does exactly the same filtering of assets that will be included on the HTML page: https://github.com/jantimon/html-webpack-plugin/blob/7299866767d7256c65e1d11daaed83426b6d74aa/index.js#L558-L564

I discovered this by accident when having the assets.json file open in the editor and suddenly noticing suspicious entries there:

Screenshot 2025-01-24 at 15 28 11

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice find 👍

@jsnajdr jsnajdr requested a review from tyxla January 24, 2025 15:47
@matticbot matticbot added the [Status] Needs Review The PR is ready for review. This also triggers e2e canary tests and wp-desktop tests automatically. label Jan 24, 2025
@jsnajdr
Copy link
Member

jsnajdr commented Jan 24, 2025

@tyxla @arthur791004 I believe this PR is now fixed and ready. The assets.json file now contains only the information that is needed and nothing else. In the manifests field, there are inline scripts that are supposed to be inline in the HTML page. And the assets field contains list of asset names for each chunk group: either an entrypoint, or an async import.

The asset writer code has been incrementally patched for years, since webpack 1 all the way to webpack 5, and accumulated some noise. Now it's cleaned up again.

How to test:
Load /read or /home on calypso.live and verify that:

  • the entry-main scripts are loaded at the bottom of the <body>
  • the reader or home scripts are preloaded in the <head>
  • all the CSS for both entry-main and reader is loaded fully in <head>, because the initial HTML can in theory contain server-rendered Reader markup that needs the Reader styles from the very beginning

Copy link
Member

@tyxla tyxla left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests as expected 👍

I think we should try it out.

Also left a few minor questions, nothing blocking though.

Let's make sure to test thoroughly once on production.

#!/usr/bin/env node
const path = require( 'path' );
const stats = require( path.join( __dirname, '..', 'build', 'assets.json' ) );
const gzipSize = require( 'gzip-size' );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, we can actually remove the gzip-size dependency now 👍

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Someone here has a well trained detector of removable code 👍 Pushed a commit that removes gzip-size from the NPM dependencies.

@@ -1,80 +0,0 @@
#!/usr/bin/env node
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this script completely unused? Was it ever used for anything beyond debugging during major webpack upgrades?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we discussed this in the try-1 version of this PR: #95748 (comment)

The script has been completely replaced by ICFY.

return false;
}

return asset.info.hotModuleReplacement || asset.info.development;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wasn't able to see a single asset where development is true. Is this intended to be for source maps? If we're not sure, should we keep the pre-existing *.map check?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, development: true is a flag that source maps have. It's reliable, html-webpack-plugin also uses it, for the same job as we do here: figure out which compilation assets and how to embed into the app's HTML document.

Here is a webpack source reference where the source maps plugin adds the flag: https://github.com/webpack/webpack/blob/3919c844eca394d73ca930e4fc5506fb86e2b094/lib/SourceMapDevToolPlugin.js#L547-L550

'entry-domains-landing': assetsList.map( ( asset ) =>
asset.replace( 'entry-main', 'entry-domains-landing' )
),
'entry-gutenboarding': assetsList.map( ( asset ) =>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh my, this is long gone 😅 let's remove it.

}

return asset.info.hotModuleReplacement || asset.info.development;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice find 👍

@jsnajdr jsnajdr force-pushed the fix/webpack-chunk-files-order branch from 5187f8a to c0de2a3 Compare February 1, 2025 13:23
@jsnajdr jsnajdr merged commit c0cb77b into trunk Feb 3, 2025
13 checks passed
@jsnajdr jsnajdr deleted the fix/webpack-chunk-files-order branch February 3, 2025 07:25
@github-actions github-actions bot removed the [Status] Needs Review The PR is ready for review. This also triggers e2e canary tests and wp-desktop tests automatically. label Feb 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants