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

Dependency Extraction: output asset.php files for shared chunks too #41002

Merged
merged 3 commits into from
Jul 1, 2022

Conversation

jsnajdr
Copy link
Member

@jsnajdr jsnajdr commented May 11, 2022

When there is a webpack project where an entrypoint has multiple chunks, then assumptions that the deps extraction plugin kind of break down.

The plugin assumes that when there is an entrypoint called main, it has exactly one JS file called main.js and that's all we need to load. A main.asset.php file is produced, and we can use it to enqueue a WordPress script:

wp_enqueue_script( 'main', 'main.js', $asset['dependencies'], $asset['version' );

But an entrypoint can have multiple chunks, for example:

  • entry-main.js is the primary script file for main entrypoint, and can have arbitrary name
  • runtime.js is a shared webpack runtime created with the runtime: 'single' option
  • shared.js is a chunk shared with another entrypoint in the same project, with common code
  • vendor-lib.js is a separate chunk with stable library code, created using the optimization.splitChunks.cacheGroups option

Currently there is no asset.php info indicating that these chunks exist and need to be loaded. There will be main.asset.php file that doesn't even point correctly to the entry-main.js file.

This PR is a step towards solving this. For the example above, it will produce four asset files, entry-main.asset.php, runtime.asset.php, shared.asset.php and vendor-lib.asset.php. Each of them will specify dependencies used by that particular chunk, and a content hash of that one specific .js file in the version field.

For the common case it doesn't change anything. You can see that from the unit test snapshot updates, where the only modification is for the runtime-single case, where there is a runtime chunk that newly gets a runtime.asset.php file.

The PR rewrites the loop that traverses the entrypoints and chunks from:

for ( entrypoint of entrypoints ) {
  compute_hash( entrypoint.getFiles() );
  write_file( entrypoint.name + '.asset.php' );
}

to

for ( chunk of entrypointChunks ) {
  compute_hash( chunk.getJSFile() );
  write_file( chunk.name + '.asset.php' );
}

For the runtime-single example, the structure of entrypoints and chunks would be like:

entrypoints: {
  a: {
    chunks: [
      a: { files: [ 'a.js', 'a.css' ] },
      runtime: { files: [ 'runtime.js' },
    ]
  },
  b: {
    chunks: [
      b: { files: [ 'b.js', 'a.css' ] },
      runtime: { files: [ 'runtime.js' },
    ]
  },
}

In the old code, each content hash would be calculated from three files: a.js, a.css and runtime.js, and files a.asset.php and b.asset.php would be written.

In the new code, we first construct a set of entrypoint chunks. There are three, one of them shared. And for each of these chunks we'll compute hash for just the .js file, and write files a.asset.php, b.asset.php, and runtime.asset.php.

@jsnajdr jsnajdr added the [Package] Dependency Extraction Webpack Plugin /packages/dependency-extraction-webpack-plugin label May 11, 2022
@jsnajdr jsnajdr self-assigned this May 11, 2022
@jsnajdr jsnajdr requested a review from gziolo as a code owner May 11, 2022 14:19
@jsnajdr
Copy link
Member Author

jsnajdr commented May 11, 2022

After this PR, we have asset files for all JS assets, but we still don't know what we need to load the a entrypoint. That's maybe a task for another file, like a.manifest.php, which would have content:

<?php return array( 'a', 'runtime' )

Or can we co-opt the existing assets.php file (produced with the combineAssets option) that would contain this information?

Also, we're not handling CSS assets. Gutenberg packages usually have just one style.css file that's not produced by webpack. If we started using CSS modules, or started extracting CSS from CSS-in-JS to static .css files, then we'll need an equivalent of asset.php for them, too, with data for wp_enqueue_style.

@github-actions
Copy link

github-actions bot commented May 11, 2022

Size Change: 0 B

Total Size: 1.25 MB

ℹ️ View Unchanged
Filename Size
build/a11y/index.min.js 982 B
build/annotations/index.min.js 2.76 kB
build/api-fetch/index.min.js 2.26 kB
build/autop/index.min.js 2.14 kB
build/blob/index.min.js 475 B
build/block-directory/index.min.js 6.58 kB
build/block-directory/style-rtl.css 990 B
build/block-directory/style.css 991 B
build/block-editor/default-editor-styles-rtl.css 378 B
build/block-editor/default-editor-styles.css 378 B
build/block-editor/index.min.js 152 kB
build/block-editor/style-rtl.css 14.5 kB
build/block-editor/style.css 14.5 kB
build/block-library/blocks/archives/editor-rtl.css 61 B
build/block-library/blocks/archives/editor.css 60 B
build/block-library/blocks/archives/style-rtl.css 65 B
build/block-library/blocks/archives/style.css 65 B
build/block-library/blocks/audio/editor-rtl.css 150 B
build/block-library/blocks/audio/editor.css 150 B
build/block-library/blocks/audio/style-rtl.css 103 B
build/block-library/blocks/audio/style.css 103 B
build/block-library/blocks/audio/theme-rtl.css 110 B
build/block-library/blocks/audio/theme.css 110 B
build/block-library/blocks/avatar/editor-rtl.css 116 B
build/block-library/blocks/avatar/editor.css 116 B
build/block-library/blocks/avatar/style-rtl.css 59 B
build/block-library/blocks/avatar/style.css 59 B
build/block-library/blocks/block/editor-rtl.css 161 B
build/block-library/blocks/block/editor.css 161 B
build/block-library/blocks/button/editor-rtl.css 441 B
build/block-library/blocks/button/editor.css 441 B
build/block-library/blocks/button/style-rtl.css 543 B
build/block-library/blocks/button/style.css 543 B
build/block-library/blocks/buttons/editor-rtl.css 292 B
build/block-library/blocks/buttons/editor.css 292 B
build/block-library/blocks/buttons/style-rtl.css 275 B
build/block-library/blocks/buttons/style.css 275 B
build/block-library/blocks/calendar/style-rtl.css 207 B
build/block-library/blocks/calendar/style.css 207 B
build/block-library/blocks/categories/editor-rtl.css 84 B
build/block-library/blocks/categories/editor.css 83 B
build/block-library/blocks/categories/style-rtl.css 79 B
build/block-library/blocks/categories/style.css 79 B
build/block-library/blocks/code/style-rtl.css 103 B
build/block-library/blocks/code/style.css 103 B
build/block-library/blocks/code/theme-rtl.css 124 B
build/block-library/blocks/code/theme.css 124 B
build/block-library/blocks/columns/editor-rtl.css 108 B
build/block-library/blocks/columns/editor.css 108 B
build/block-library/blocks/columns/style-rtl.css 406 B
build/block-library/blocks/columns/style.css 406 B
build/block-library/blocks/comment-author-avatar/editor-rtl.css 125 B
build/block-library/blocks/comment-author-avatar/editor.css 125 B
build/block-library/blocks/comment-content/style-rtl.css 92 B
build/block-library/blocks/comment-content/style.css 92 B
build/block-library/blocks/comment-template/style-rtl.css 187 B
build/block-library/blocks/comment-template/style.css 185 B
build/block-library/blocks/comments-pagination-numbers/editor-rtl.css 123 B
build/block-library/blocks/comments-pagination-numbers/editor.css 121 B
build/block-library/blocks/comments-pagination/editor-rtl.css 222 B
build/block-library/blocks/comments-pagination/editor.css 209 B
build/block-library/blocks/comments-pagination/style-rtl.css 235 B
build/block-library/blocks/comments-pagination/style.css 231 B
build/block-library/blocks/comments-title/editor-rtl.css 75 B
build/block-library/blocks/comments-title/editor.css 75 B
build/block-library/blocks/comments/editor-rtl.css 95 B
build/block-library/blocks/comments/editor.css 95 B
build/block-library/blocks/cover/editor-rtl.css 615 B
build/block-library/blocks/cover/editor.css 616 B
build/block-library/blocks/cover/style-rtl.css 1.55 kB
build/block-library/blocks/cover/style.css 1.55 kB
build/block-library/blocks/embed/editor-rtl.css 293 B
build/block-library/blocks/embed/editor.css 293 B
build/block-library/blocks/embed/style-rtl.css 410 B
build/block-library/blocks/embed/style.css 410 B
build/block-library/blocks/embed/theme-rtl.css 110 B
build/block-library/blocks/embed/theme.css 110 B
build/block-library/blocks/file/editor-rtl.css 300 B
build/block-library/blocks/file/editor.css 300 B
build/block-library/blocks/file/style-rtl.css 253 B
build/block-library/blocks/file/style.css 254 B
build/block-library/blocks/file/view.min.js 346 B
build/block-library/blocks/freeform/editor-rtl.css 2.44 kB
build/block-library/blocks/freeform/editor.css 2.44 kB
build/block-library/blocks/gallery/editor-rtl.css 948 B
build/block-library/blocks/gallery/editor.css 950 B
build/block-library/blocks/gallery/style-rtl.css 1.5 kB
build/block-library/blocks/gallery/style.css 1.49 kB
build/block-library/blocks/gallery/theme-rtl.css 108 B
build/block-library/blocks/gallery/theme.css 108 B
build/block-library/blocks/group/editor-rtl.css 333 B
build/block-library/blocks/group/editor.css 333 B
build/block-library/blocks/group/style-rtl.css 57 B
build/block-library/blocks/group/style.css 57 B
build/block-library/blocks/group/theme-rtl.css 78 B
build/block-library/blocks/group/theme.css 78 B
build/block-library/blocks/heading/style-rtl.css 76 B
build/block-library/blocks/heading/style.css 76 B
build/block-library/blocks/html/editor-rtl.css 327 B
build/block-library/blocks/html/editor.css 329 B
build/block-library/blocks/image/editor-rtl.css 738 B
build/block-library/blocks/image/editor.css 737 B
build/block-library/blocks/image/style-rtl.css 524 B
build/block-library/blocks/image/style.css 530 B
build/block-library/blocks/image/theme-rtl.css 110 B
build/block-library/blocks/image/theme.css 110 B
build/block-library/blocks/latest-comments/style-rtl.css 284 B
build/block-library/blocks/latest-comments/style.css 284 B
build/block-library/blocks/latest-posts/editor-rtl.css 199 B
build/block-library/blocks/latest-posts/editor.css 198 B
build/block-library/blocks/latest-posts/style-rtl.css 463 B
build/block-library/blocks/latest-posts/style.css 462 B
build/block-library/blocks/list/style-rtl.css 88 B
build/block-library/blocks/list/style.css 88 B
build/block-library/blocks/media-text/editor-rtl.css 266 B
build/block-library/blocks/media-text/editor.css 263 B
build/block-library/blocks/media-text/style-rtl.css 493 B
build/block-library/blocks/media-text/style.css 490 B
build/block-library/blocks/more/editor-rtl.css 431 B
build/block-library/blocks/more/editor.css 431 B
build/block-library/blocks/navigation-link/editor-rtl.css 705 B
build/block-library/blocks/navigation-link/editor.css 703 B
build/block-library/blocks/navigation-link/style-rtl.css 115 B
build/block-library/blocks/navigation-link/style.css 115 B
build/block-library/blocks/navigation-submenu/editor-rtl.css 296 B
build/block-library/blocks/navigation-submenu/editor.css 295 B
build/block-library/blocks/navigation-submenu/view.min.js 402 B
build/block-library/blocks/navigation/editor-rtl.css 2.03 kB
build/block-library/blocks/navigation/editor.css 2.04 kB
build/block-library/blocks/navigation/style-rtl.css 1.96 kB
build/block-library/blocks/navigation/style.css 1.95 kB
build/block-library/blocks/navigation/view-modal.min.js 2.78 kB
build/block-library/blocks/navigation/view.min.js 423 B
build/block-library/blocks/nextpage/editor-rtl.css 395 B
build/block-library/blocks/nextpage/editor.css 395 B
build/block-library/blocks/page-list/editor-rtl.css 363 B
build/block-library/blocks/page-list/editor.css 363 B
build/block-library/blocks/page-list/style-rtl.css 175 B
build/block-library/blocks/page-list/style.css 175 B
build/block-library/blocks/paragraph/editor-rtl.css 157 B
build/block-library/blocks/paragraph/editor.css 157 B
build/block-library/blocks/paragraph/style-rtl.css 260 B
build/block-library/blocks/paragraph/style.css 260 B
build/block-library/blocks/post-author/style-rtl.css 175 B
build/block-library/blocks/post-author/style.css 176 B
build/block-library/blocks/post-comments-form/editor-rtl.css 96 B
build/block-library/blocks/post-comments-form/editor.css 96 B
build/block-library/blocks/post-comments-form/style-rtl.css 495 B
build/block-library/blocks/post-comments-form/style.css 495 B
build/block-library/blocks/post-comments/editor-rtl.css 77 B
build/block-library/blocks/post-comments/editor.css 77 B
build/block-library/blocks/post-comments/style-rtl.css 632 B
build/block-library/blocks/post-comments/style.css 630 B
build/block-library/blocks/post-excerpt/editor-rtl.css 73 B
build/block-library/blocks/post-excerpt/editor.css 73 B
build/block-library/blocks/post-excerpt/style-rtl.css 69 B
build/block-library/blocks/post-excerpt/style.css 69 B
build/block-library/blocks/post-featured-image/editor-rtl.css 605 B
build/block-library/blocks/post-featured-image/editor.css 605 B
build/block-library/blocks/post-featured-image/style-rtl.css 153 B
build/block-library/blocks/post-featured-image/style.css 153 B
build/block-library/blocks/post-template/editor-rtl.css 99 B
build/block-library/blocks/post-template/editor.css 98 B
build/block-library/blocks/post-template/style-rtl.css 282 B
build/block-library/blocks/post-template/style.css 282 B
build/block-library/blocks/post-terms/style-rtl.css 73 B
build/block-library/blocks/post-terms/style.css 73 B
build/block-library/blocks/post-title/style-rtl.css 80 B
build/block-library/blocks/post-title/style.css 80 B
build/block-library/blocks/preformatted/style-rtl.css 103 B
build/block-library/blocks/preformatted/style.css 103 B
build/block-library/blocks/pullquote/editor-rtl.css 198 B
build/block-library/blocks/pullquote/editor.css 198 B
build/block-library/blocks/pullquote/style-rtl.css 370 B
build/block-library/blocks/pullquote/style.css 370 B
build/block-library/blocks/pullquote/theme-rtl.css 167 B
build/block-library/blocks/pullquote/theme.css 167 B
build/block-library/blocks/query-pagination-numbers/editor-rtl.css 122 B
build/block-library/blocks/query-pagination-numbers/editor.css 121 B
build/block-library/blocks/query-pagination/editor-rtl.css 221 B
build/block-library/blocks/query-pagination/editor.css 211 B
build/block-library/blocks/query-pagination/style-rtl.css 234 B
build/block-library/blocks/query-pagination/style.css 231 B
build/block-library/blocks/query/editor-rtl.css 369 B
build/block-library/blocks/query/editor.css 369 B
build/block-library/blocks/quote/style-rtl.css 213 B
build/block-library/blocks/quote/style.css 213 B
build/block-library/blocks/quote/theme-rtl.css 223 B
build/block-library/blocks/quote/theme.css 226 B
build/block-library/blocks/read-more/style-rtl.css 132 B
build/block-library/blocks/read-more/style.css 132 B
build/block-library/blocks/rss/editor-rtl.css 202 B
build/block-library/blocks/rss/editor.css 204 B
build/block-library/blocks/rss/style-rtl.css 289 B
build/block-library/blocks/rss/style.css 288 B
build/block-library/blocks/search/editor-rtl.css 165 B
build/block-library/blocks/search/editor.css 165 B
build/block-library/blocks/search/style-rtl.css 385 B
build/block-library/blocks/search/style.css 386 B
build/block-library/blocks/search/theme-rtl.css 64 B
build/block-library/blocks/search/theme.css 64 B
build/block-library/blocks/separator/editor-rtl.css 146 B
build/block-library/blocks/separator/editor.css 146 B
build/block-library/blocks/separator/style-rtl.css 233 B
build/block-library/blocks/separator/style.css 233 B
build/block-library/blocks/separator/theme-rtl.css 194 B
build/block-library/blocks/separator/theme.css 194 B
build/block-library/blocks/shortcode/editor-rtl.css 464 B
build/block-library/blocks/shortcode/editor.css 464 B
build/block-library/blocks/site-logo/editor-rtl.css 708 B
build/block-library/blocks/site-logo/editor.css 708 B
build/block-library/blocks/site-logo/style-rtl.css 192 B
build/block-library/blocks/site-logo/style.css 192 B
build/block-library/blocks/site-tagline/editor-rtl.css 86 B
build/block-library/blocks/site-tagline/editor.css 86 B
build/block-library/blocks/site-title/editor-rtl.css 84 B
build/block-library/blocks/site-title/editor.css 84 B
build/block-library/blocks/social-link/editor-rtl.css 177 B
build/block-library/blocks/social-link/editor.css 177 B
build/block-library/blocks/social-links/editor-rtl.css 674 B
build/block-library/blocks/social-links/editor.css 673 B
build/block-library/blocks/social-links/style-rtl.css 1.37 kB
build/block-library/blocks/social-links/style.css 1.36 kB
build/block-library/blocks/spacer/editor-rtl.css 322 B
build/block-library/blocks/spacer/editor.css 322 B
build/block-library/blocks/spacer/style-rtl.css 48 B
build/block-library/blocks/spacer/style.css 48 B
build/block-library/blocks/table/editor-rtl.css 494 B
build/block-library/blocks/table/editor.css 494 B
build/block-library/blocks/table/style-rtl.css 611 B
build/block-library/blocks/table/style.css 609 B
build/block-library/blocks/table/theme-rtl.css 175 B
build/block-library/blocks/table/theme.css 175 B
build/block-library/blocks/tag-cloud/style-rtl.css 226 B
build/block-library/blocks/tag-cloud/style.css 227 B
build/block-library/blocks/template-part/editor-rtl.css 149 B
build/block-library/blocks/template-part/editor.css 149 B
build/block-library/blocks/template-part/theme-rtl.css 101 B
build/block-library/blocks/template-part/theme.css 101 B
build/block-library/blocks/text-columns/editor-rtl.css 95 B
build/block-library/blocks/text-columns/editor.css 95 B
build/block-library/blocks/text-columns/style-rtl.css 166 B
build/block-library/blocks/text-columns/style.css 166 B
build/block-library/blocks/verse/style-rtl.css 87 B
build/block-library/blocks/verse/style.css 87 B
build/block-library/blocks/video/editor-rtl.css 561 B
build/block-library/blocks/video/editor.css 563 B
build/block-library/blocks/video/style-rtl.css 159 B
build/block-library/blocks/video/style.css 159 B
build/block-library/blocks/video/theme-rtl.css 110 B
build/block-library/blocks/video/theme.css 110 B
build/block-library/common-rtl.css 987 B
build/block-library/common.css 984 B
build/block-library/editor-rtl.css 10.2 kB
build/block-library/editor.css 10.2 kB
build/block-library/index.min.js 183 kB
build/block-library/reset-rtl.css 478 B
build/block-library/reset.css 478 B
build/block-library/style-rtl.css 11.5 kB
build/block-library/style.css 11.5 kB
build/block-library/theme-rtl.css 677 B
build/block-library/theme.css 682 B
build/block-serialization-default-parser/index.min.js 1.11 kB
build/block-serialization-spec-parser/index.min.js 2.83 kB
build/blocks/index.min.js 47 kB
build/components/index.min.js 230 kB
build/components/style-rtl.css 14 kB
build/components/style.css 14 kB
build/compose/index.min.js 11.7 kB
build/core-data/index.min.js 14.7 kB
build/customize-widgets/index.min.js 11.2 kB
build/customize-widgets/style-rtl.css 1.4 kB
build/customize-widgets/style.css 1.4 kB
build/data-controls/index.min.js 653 B
build/data/index.min.js 7.95 kB
build/date/index.min.js 32 kB
build/deprecated/index.min.js 507 B
build/dom-ready/index.min.js 324 B
build/dom/index.min.js 4.65 kB
build/edit-navigation/index.min.js 16 kB
build/edit-navigation/style-rtl.css 4.03 kB
build/edit-navigation/style.css 4.04 kB
build/edit-post/classic-rtl.css 546 B
build/edit-post/classic.css 547 B
build/edit-post/index.min.js 30.3 kB
build/edit-post/style-rtl.css 7.04 kB
build/edit-post/style.css 7.04 kB
build/edit-site/index.min.js 51 kB
build/edit-site/style-rtl.css 8.28 kB
build/edit-site/style.css 8.26 kB
build/edit-widgets/index.min.js 16.4 kB
build/edit-widgets/style-rtl.css 4.36 kB
build/edit-widgets/style.css 4.36 kB
build/editor/index.min.js 39.2 kB
build/editor/style-rtl.css 3.67 kB
build/editor/style.css 3.67 kB
build/element/index.min.js 4.27 kB
build/escape-html/index.min.js 537 B
build/format-library/index.min.js 6.75 kB
build/format-library/style-rtl.css 571 B
build/format-library/style.css 571 B
build/hooks/index.min.js 1.64 kB
build/html-entities/index.min.js 448 B
build/i18n/index.min.js 3.77 kB
build/is-shallow-equal/index.min.js 527 B
build/keyboard-shortcuts/index.min.js 1.78 kB
build/keycodes/index.min.js 1.38 kB
build/list-reusable-blocks/index.min.js 1.74 kB
build/list-reusable-blocks/style-rtl.css 835 B
build/list-reusable-blocks/style.css 835 B
build/media-utils/index.min.js 2.9 kB
build/notices/index.min.js 953 B
build/nux/index.min.js 2.05 kB
build/nux/style-rtl.css 732 B
build/nux/style.css 728 B
build/plugins/index.min.js 1.94 kB
build/preferences-persistence/index.min.js 2.22 kB
build/preferences/index.min.js 1.3 kB
build/primitives/index.min.js 933 B
build/priority-queue/index.min.js 612 B
build/react-i18n/index.min.js 696 B
build/react-refresh-entry/index.min.js 8.44 kB
build/react-refresh-runtime/index.min.js 7.31 kB
build/redux-routine/index.min.js 2.69 kB
build/reusable-blocks/index.min.js 2.22 kB
build/reusable-blocks/style-rtl.css 256 B
build/reusable-blocks/style.css 256 B
build/rich-text/index.min.js 11.1 kB
build/server-side-render/index.min.js 1.61 kB
build/shortcode/index.min.js 1.53 kB
build/token-list/index.min.js 644 B
build/url/index.min.js 3.61 kB
build/vendors/react-dom.min.js 38.5 kB
build/vendors/react.min.js 4.34 kB
build/viewport/index.min.js 1.08 kB
build/warning/index.min.js 268 B
build/widgets/index.min.js 7.19 kB
build/widgets/style-rtl.css 1.16 kB
build/widgets/style.css 1.16 kB
build/wordcount/index.min.js 1.06 kB

compressed-size-action

@gziolo
Copy link
Member

gziolo commented May 11, 2022

Thank you so much for attacking this complex problem ❤️

I’ll try to take a deeper dive into proposed implementation later this week.

@gziolo gziolo added the [Type] Enhancement A suggestion for improvement. label May 11, 2022
@jsnajdr
Copy link
Member Author

jsnajdr commented May 19, 2022

One idea how to avoid calculating the contenthash ourselves: for assets produced by Gutenberg and block builds, the filename template should be:

[name].js?ver=[contenthash]

instead of just [name].js. Because in practice, wp_enqueue_script with a version parameter will produce a URL just like that, with a ?ver= query param.

When writing files to disk, webpack will remove the ?ver part, of course, and what we're left with is assetInfo that's guaranteed to have a .contenthash field, because it was used in the filename.

fyi @anomiex

@anomiex
Copy link
Contributor

anomiex commented May 19, 2022

Keep in mind that this package is released for third parties to use too, who may not share your constraints.

Also, we're not handling CSS assets. Gutenberg packages usually have just one style.css file that's not produced by webpack. If we started using CSS modules, or started extracting CSS from CSS-in-JS to static .css files, then we'll need an equivalent of asset.php for them, too, with data for wp_enqueue_style.

In Jetpack we're already using mini-css-extract-plugin to extract CSS from our bundles. We're currently using the version from asset.php for loading those too. We'd be fine with doing it differently, although I hope we don't wind up with double the number of asset.php files littering the filesystem.

One idea how to avoid calculating the contenthash ourselves: for assets produced by Gutenberg and block builds, the filename template should be

If you go with that, your code should gracefully fail if someone tries to use the plugin without having the configuration set in that manner.

@jsnajdr
Copy link
Member Author

jsnajdr commented May 20, 2022

In Jetpack we're already using mini-css-extract-plugin to extract CSS from our bundles. We're currently using the version from asset.php for loading those too.

Well this means that we don't really want the version to be the contenthash as webpack understands it. Because the webpack contenthash is always just the hash of the content of one particular file, equivalent to what e.g. openssl dgst -md4 < script.js would output.

But here we calculate, and want to calculate, the combined hash of all the chunk's assets, both .js and .css. If we used just the .js contenthash, changes in CSS would go undetected as the style.css?ver=hash URL doesn't change.

The relevant assets are foo.js, foo.css and foo.rtl.css for each chunk.

Thanks for clarifying the requirements.

@gziolo
Copy link
Member

gziolo commented May 28, 2022

For the common case it doesn't change anything. You can see that from the unit test snapshot updates, where the only modification is for the runtime-single case, where there is a runtime chunk that newly gets a runtime.asset.php file.

I can confirm it works as expected.

After this PR, we have asset files for all JS assets, but we still don't know what we need to load the a entrypoint. That's maybe a task for another file, like a.manifest.php, which would have content:

<?php return array( 'a', 'runtime' );

Or can we co-opt the existing assets.php file (produced with the combineAssets option) that would contain this information?

I noticed that we cover every possible case for JavaScript files but dynamic imports. It still works correctly as all dependencies get collected in the entry point's asset file, but sometimes it might be suboptimal. It's an edge case and I expect it would be hard to handle correctly anyway so we can live with this limitation.

Regarding the information about the existing shared dependencies created by webpack, it's also the tricky part that we can address separately. One idea I can think of, would be referencing the path to the asset file next to all other usual dependencies.

In Jetpack we're already using mini-css-extract-plugin to extract CSS from our bundles. We're currently using the version from asset.php for loading those too.
Well this means that we don't really want the version to be the contenthash as webpack understands it. Because the webpack contenthash is always just the hash of the content of one particular file, equivalent to what e.g. openssl dgst -md4 < script.js would output.

I'm noting that with the changes proposed in this PR the version calculated for JS file that imports CSS files, it doesn't depend on CSS anymore. I tested it by updating CSS file in the test fixture for the style-imports test case.

@jsnajdr
Copy link
Member Author

jsnajdr commented May 30, 2022

I noticed that we cover every possible case for JavaScript files but dynamic imports.

Chunks that are dynamically imported don't need to be externally visible -- their file names are webpack's internal implementation detail. It's the webpack runtime that knows how to load them.

The external world only needs to know how to load an entrypoint. Then the webpack runtime takes over and handles everything else.

In that sense, we only need to generate manifests for entrypoints.

I'm noting that with the changes proposed in this PR the version calculated for JS file that imports CSS files, it doesn't depend on CSS anymore.

That's true, and it's a blocker that prevents merging this PR as is. It would break Jetpack.

@gziolo
Copy link
Member

gziolo commented May 31, 2022

Chunks that are dynamically imported don't need to be externally visible -- their file names are webpack's internal implementation detail. It's the webpack runtime that knows how to load them.

The external world only needs to know how to load an entrypoint. Then the webpack runtime takes over and handles everything else.

It was quite some time when I was working with dynamic imports. In the block editor, we don't use lazy loading so I wasn't sure about that part. Thank you for clarifying that.

That's true, and it's a blocker that prevents merging this PR as is. It would break Jetpack.

Let's address that point and land the rest of changes 💯

@jsnajdr jsnajdr force-pushed the update/dep-extr-asset-files-for-shared-chunks branch 2 times, most recently from 82f6103 to 316b936 Compare June 3, 2022 14:58
@jsnajdr
Copy link
Member Author

jsnajdr commented Jun 4, 2022

Let's address that point and land the rest of changes

I changed the content hash calculation algorithm to include all assets in the chunk, both CSS and JS. As the previous code did.

As the unit tests show, all the hashes remained the same as they were before this PR. The only change is that we're outputting a new .asset.php file for the runtime chunk.

I believe we're ready to 🚢 here.

@anomiex
Copy link
Contributor

anomiex commented Jun 6, 2022

[deleted: never mind, I didn't have the latest copy checked out thanks to the force-push]

Copy link
Contributor

@anomiex anomiex left a comment

Choose a reason for hiding this comment

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

Seems to work for Jetpack's build. None of the hashes even changed.

Left some comments inline for consideration.


const chunkJSFile = chunkFiles.find( ( f ) => /\.js$/i.test( f ) );
if ( ! chunkJSFile ) {
// There's no JS file in this chunk, no work for us. Typically a `style.css` from cache group.
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this hold true for third parties who might be using this and processing CSS in different ways? Or might they still want the asset file?

Copy link
Member

Choose a reason for hiding this comment

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

If that is the case then it would be accidental. I think it's fine to proceed as is and revisit this approach if we hear back about the exact use cases projects could have.

Copy link
Member

Choose a reason for hiding this comment

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

I was using the generated asset.php files for standalone CSS files output from Webpack to provide a version number, e.g.:

$componentAndHookStylesMetadata =
	require MY_DIR . '/build/component-and-hook-styles.asset.php';

wp_enqueue_style(
	'my-plugin-component-and-hook-styles',
	plugin_dir_url(__DIR__) . 'build/component-and-hook-styles.css',
	[],
	$componentAndHookStylesMetadata['version']
);

It seems the changes in this PR have broken this, resulting in fatal errors when my plugin tries to load the asset.php file that is no longer created.

I've worked around this by changing the code to:

$lastModifiedTimestamp =
	filemtime(plugin_dir_path(__DIR__) . 'build/component-and-hook-styles.css');

// (DT::now() is just a custom util to get a DateTimeImmutable for the current moment.)
if ($lastModifiedTimestamp === false) $lastModifiedTimestamp = DT::now()->getTimestamp();

wp_enqueue_style(
	'my-plugin-component-and-hook-styles',
	plugin_dir_url(__DIR__) . 'build/component-and-hook-styles.css',
	[],
	(string) $lastModifiedTimestamp,
);

Maybe this is how I should've been handling it from the start, but I figured I mention that this did indeed affect at least one person.

Copy link
Member

Choose a reason for hiding this comment

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

@ZebulanStanphill, how would you get the asset file generated for the CSS file? Was it set explicitly as an entry point?

It's also possible to use the version field in the block.json file, so it gets automatically used with CSS files:
https://github.com/WordPress/gutenberg/blob/trunk/docs/reference-guides/block-api/block-metadata.md#version

The solution you have works great but only in case when your block is always loaded from the same server.

Copy link
Member

Choose a reason for hiding this comment

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

@gziolo Yeah, I had an SCSS file as one of my Webpack entry points, and I used mini-css-extract-plugin to put the styles in a CSS file, and webpack-remove-empty-scripts to remove the empty .js file generated from the entry point.

Thanks for the advice on using a version field on the block.json. The project I'm working on is internal and only used on a single site and server anyway, though, so I suppose it's fine to continue using filemtime in my case. (And also, I'd probably forget to update the version field on the blocks if I was using that, haha.)

Copy link
Member

Choose a reason for hiding this comment

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

I would expect that updating version is easy to miss, so maybe we should figure out how to generate asset files also for all CSS files after all. It definitely didn't produce asset files for CSS files extracted when importing them from JS. We never explored that because in CSS, unlike in JavaScript, we don't need to sort out their dependent styles.

@gziolo gziolo force-pushed the update/dep-extr-asset-files-for-shared-chunks branch from fa78e1c to 3a44214 Compare July 1, 2022 10:46
Copy link
Member

@gziolo gziolo left a comment

Choose a reason for hiding this comment

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

I rebase this PR with the latest changes from trunk. I also included an entry in the CHANGELOG file.

Everything tests well. We should look into better integration between the newly generated asset files for shared chunks with the regular chunks as the next step.

@gziolo gziolo merged commit 0ee78b1 into trunk Jul 1, 2022
@gziolo gziolo deleted the update/dep-extr-asset-files-for-shared-chunks branch July 1, 2022 11:14
@github-actions github-actions bot added this to the Gutenberg 13.7 milestone Jul 1, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Package] Dependency Extraction Webpack Plugin /packages/dependency-extraction-webpack-plugin [Type] Enhancement A suggestion for improvement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants