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

Support Hot Module Replacement (HMR) for CSS #64444

Draft
wants to merge 3 commits into
base: trunk
Choose a base branch
from
Draft

Conversation

kevin940726
Copy link
Member

@kevin940726 kevin940726 commented Aug 12, 2024

What?

Part of #36142.

Add Hot Module Replacement for CSS. This is an experimental development-only feature.

Why?

HMR for JavaScript is a little bit more complicated and supporting CSS also helps pave the way too.

Hot Module Replacement (or hot reload) is a bundler (webpack) feature that replaces the module upon saving the files without reloading the page. This PR adds support for CSS HMR so that updating CSS files locally automatically updates the stylesheets on the page in development mode. This helps developers iterate more quickly with faster visual feedback.

How?

Due to how Gutenberg works, this is a bit complicated but I'll try my best explaining it 😅.

To understand how HMR works, we must understand the current way of building CSS in Gutenberg. When running npm run dev, there are multiple steps to complete to update the CSS on the page:

flowchart LR
    A(packages/*/src/style.scss) -->|SASS compiler / postCSS| B(packages/*/build-style/style.css)
    B -->|webpack| C(build/*/style.css)
Loading
  1. build-worker builds the SASS source files to CSS files to each package's build-style folder. These files will be published to the npm registry.
  2. webpack then copies those build files to the root build directory for the page to consume.

We don't change the first step in this PR to simplify and minimize the scope (but we could for future optimizations).

Now, let's move on to how HMR works in webpack. The official doc has a great overview of the technical background. The difference between the recommended setup and our setup are:

  1. We don't import styles in our JavaScript code.
  2. The styles are not registered by webpack, but instead managed by the PHP backend.

The first difference is relatively easy to fix if we just unshift the style entries for each JavaScript entry.

module.exports = {
  entry: {
    'edit-post': {
-      import: './packages/edit-post',
+      import: [ './packages/edit-post/build-style/style.css', './packages/edit-post' ],
    }
  },
};

This tells webpack to load the styles in each JavaScript entry so that they can be processed by webpack and inject the HMR runtime. We want to keep the JavaScript file at the end so that they'll be exported to the window.wp property.

The second difference is important because we don't want to change the order of the styles to prevent breakage. This means we can't use style-loader, which is the most popular way to inject and hot reload CSS files at the time.

Instead, we create a separate custom loader for CSS files that includes the HMR code to replace injected styles on the fly. I first tried out restyle-loader which mostly did what we want but it lacks maintenance and doesn't work for iframed styles. css-hmr-loader is refactor that largely based on restyle-loader and mini-css-extract-plugin that suits our needs. The code uses the HMR runtime API to listen and react to code changes.

The next step is to start a dev server that listens to the HMR event on the client. webpack-dev-server provides everything we need, we just need to provide a manual entry for the HMR runtime because we have multiple entry points. The dev server will listen on port 8887 which matches the port used in blocks development.

Setting the dev server up also means we no longer treat the file system as the source of truth, but rather the hot-enabled in-memory dev server. Any request to the original URL (http://localhost:8888/wp-content/plugins/gutenberg/build/*) will need to be redirected to the dev server (http://localhost:8887/build/*) for HMR to work. We achieve this by changing the implementation of gutenberg_url in client-assets.php. I'm not sure if that's enough, if not then we could also go a bit further and inject a custom .htaccess file.

As a bonus, but also pretty essential, is that we also want to continue to support running e2e tests in development mode. Since there's no difference from the PHP backend perspective to know whether it's loading a production build or a hot-enabled development mode, the most reliable way is to check whether a hot.js entry point is created in the build folder. If it exists then we assume it's running a development build, redirecting from localhost:8888 to localhost:8887.

I believe this covers most of the implementation in this PR. Feel free to ask any further questions or if you spot any bugs!

The same implementation could and should be able to be used for JavaScript HMR too. But I think that's better left to another PR to minimize the scope 😅.

Testing Instructions

  1. Run npm run dev (run rm -rf build beforehand if you want to test it from scratch.)
  2. Visit any editor and notice the WDS message in the console.
  3. Edit some .css files and see if they reflect themselves on the page without a reload.
  4. Try different setups and builds like the testing environment localhost:8889 and production builds npm run build. Expect they still work correctly.

Screenshots or screencast

Kapture.2024-08-13.at.11.30.56.mp4

@kevin940726 kevin940726 added [Type] Build Tooling Issues or PRs related to build tooling Developer Experience Ideas about improving block and theme developer experience labels Aug 12, 2024
@kevin940726 kevin940726 self-assigned this Aug 12, 2024
Copy link

github-actions bot commented Aug 12, 2024

Size Change: +8.89 kB (+0.5%)

Total Size: 1.79 MB

Filename Size Change
build/a11y/index.min.js 844 B -107 B (-11.25%) 👏
build/annotations/index.min.js 2.25 kB -10 B (-0.44%)
build/api-fetch/index.min.js 2.33 kB +13 B (+0.56%)
build/autop/index.min.js 2.02 kB -94 B (-4.44%)
build/blob/index.min.js 493 B -86 B (-14.85%) 👏
build/block-directory/index.min.js 7.59 kB +475 B (+6.68%) 🔍
build/block-editor/index.min.js 256 kB -979 B (-0.38%)
build/block-library/index.min.js 219 kB +786 B (+0.36%)
build/block-serialization-default-parser/index.min.js 1.02 kB -96 B (-8.59%)
build/block-serialization-spec-parser/index.min.js 2.86 kB -7 B (-0.24%)
build/blocks/index.min.js 52.7 kB +329 B (+0.63%)
build/components/index.min.js 227 kB +2.9 kB (+1.3%)
build/compose/index.min.js 12.9 kB +335 B (+2.66%)
build/core-commands/index.min.js 2.94 kB +118 B (+4.18%)
build/core-data/index.min.js 73.6 kB +379 B (+0.52%)
build/customize-widgets/index.min.js 11.2 kB +201 B (+1.83%)
build/data-controls/index.min.js 547 B -94 B (-14.66%) 👏
build/data/index.min.js 9.02 kB +42 B (+0.47%)
build/date/index.min.js 17.6 kB -347 B (-1.93%)
build/deprecated/index.min.js 457 B -1 B (-0.22%)
build/dom-ready/index.min.js 301 B -24 B (-7.38%)
build/dom/index.min.js 4.58 kB -80 B (-1.72%)
build/edit-post/index.min.js 12.9 kB +210 B (+1.65%)
build/edit-site/index.min.js 219 kB +2.24 kB (+1.03%)
build/edit-widgets/index.min.js 18.4 kB +739 B (+4.18%)
build/editor/index.min.js 103 kB +1.21 kB (+1.19%)
build/element/index.min.js 5.01 kB +177 B (+3.66%)
build/escape-html/index.min.js 447 B -90 B (-16.76%) 👏
build/format-library/index.min.js 8.33 kB +218 B (+2.69%)
build/hooks/index.min.js 1.46 kB -85 B (-5.51%)
build/html-entities/index.min.js 361 B -84 B (-18.88%) 👏
build/i18n/index.min.js 3.5 kB -81 B (-2.26%)
build/is-shallow-equal/index.min.js 451 B -75 B (-14.26%) 👏
build/keyboard-shortcuts/index.min.js 1.28 kB -27 B (-2.07%)
build/keycodes/index.min.js 1.4 kB -62 B (-4.24%)
build/list-reusable-blocks/index.min.js 2.44 kB +257 B (+11.78%) ⚠️
build/media-utils/index.min.js 3.15 kB -46 B (-1.44%)
build/notices/index.min.js 881 B -65 B (-6.87%)
build/nux/index.min.js 1.61 kB +2 B (+0.12%)
build/patterns/index.min.js 7.48 kB +132 B (+1.8%)
build/plugins/index.min.js 1.8 kB -7 B (-0.39%)
build/preferences-persistence/index.min.js 1.96 kB -96 B (-4.67%)
build/preferences/index.min.js 2.96 kB +62 B (+2.14%)
build/primitives/index.min.js 808 B -21 B (-2.53%)
build/priority-queue/index.min.js 1.37 kB -168 B (-10.94%) 👏
build/private-apis/index.min.js 926 B -83 B (-8.23%)
build/react-i18n/index.min.js 581 B -49 B (-7.78%)
build/redux-routine/index.min.js 2.69 kB +3 B (+0.11%)
build/reusable-blocks/index.min.js 2.61 kB +60 B (+2.35%)
build/rich-text/index.min.js 10.1 kB +4 B (+0.04%)
build/router/index.min.js 2 kB +38 B (+1.94%)
build/server-side-render/index.min.js 1.94 kB -1 B (-0.05%)
build/style-engine/index.min.js 2.26 kB +219 B (+10.73%) ⚠️
build/token-list/index.min.js 555 B -26 B (-4.48%)
build/url/index.min.js 3.74 kB -166 B (-4.25%)
build/viewport/index.min.js 917 B -48 B (-4.97%)
build/warning/index.min.js 219 B -31 B (-12.4%) 👏
build/widgets/index.min.js 7.27 kB +69 B (+0.96%)
build/wordcount/index.min.js 929 B -101 B (-9.81%) 👏
build/runtime.min.js 1.01 kB +1.01 kB (new file) 🆕
ℹ️ View Unchanged
Filename Size
build/block-directory/style-rtl.css 1.01 kB
build/block-directory/style.css 1.01 kB
build/block-editor/content-rtl.css 4.65 kB
build/block-editor/content.css 4.64 kB
build/block-editor/default-editor-styles-rtl.css 394 B
build/block-editor/default-editor-styles.css 394 B
build/block-editor/style-rtl.css 16.2 kB
build/block-editor/style.css 16.2 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 90 B
build/block-library/blocks/archives/style.css 90 B
build/block-library/blocks/audio/editor-rtl.css 149 B
build/block-library/blocks/audio/editor.css 151 B
build/block-library/blocks/audio/style-rtl.css 132 B
build/block-library/blocks/audio/style.css 132 B
build/block-library/blocks/audio/theme-rtl.css 134 B
build/block-library/blocks/audio/theme.css 134 B
build/block-library/blocks/avatar/editor-rtl.css 115 B
build/block-library/blocks/avatar/editor.css 115 B
build/block-library/blocks/avatar/style-rtl.css 104 B
build/block-library/blocks/avatar/style.css 104 B
build/block-library/blocks/button/editor-rtl.css 265 B
build/block-library/blocks/button/editor.css 265 B
build/block-library/blocks/button/style-rtl.css 538 B
build/block-library/blocks/button/style.css 538 B
build/block-library/blocks/buttons/editor-rtl.css 291 B
build/block-library/blocks/buttons/editor.css 291 B
build/block-library/blocks/buttons/style-rtl.css 328 B
build/block-library/blocks/buttons/style.css 328 B
build/block-library/blocks/calendar/style-rtl.css 240 B
build/block-library/blocks/calendar/style.css 240 B
build/block-library/blocks/categories/editor-rtl.css 132 B
build/block-library/blocks/categories/editor.css 131 B
build/block-library/blocks/categories/style-rtl.css 152 B
build/block-library/blocks/categories/style.css 152 B
build/block-library/blocks/code/editor-rtl.css 53 B
build/block-library/blocks/code/editor.css 53 B
build/block-library/blocks/code/style-rtl.css 121 B
build/block-library/blocks/code/style.css 121 B
build/block-library/blocks/code/theme-rtl.css 122 B
build/block-library/blocks/code/theme.css 122 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 420 B
build/block-library/blocks/columns/style.css 420 B
build/block-library/blocks/comment-author-avatar/editor-rtl.css 124 B
build/block-library/blocks/comment-author-avatar/editor.css 124 B
build/block-library/blocks/comment-author-name/style-rtl.css 72 B
build/block-library/blocks/comment-author-name/style.css 72 B
build/block-library/blocks/comment-content/style-rtl.css 120 B
build/block-library/blocks/comment-content/style.css 120 B
build/block-library/blocks/comment-date/style-rtl.css 65 B
build/block-library/blocks/comment-date/style.css 65 B
build/block-library/blocks/comment-edit-link/style-rtl.css 70 B
build/block-library/blocks/comment-edit-link/style.css 70 B
build/block-library/blocks/comment-reply-link/style-rtl.css 71 B
build/block-library/blocks/comment-reply-link/style.css 71 B
build/block-library/blocks/comment-template/style-rtl.css 200 B
build/block-library/blocks/comment-template/style.css 199 B
build/block-library/blocks/comments-pagination-numbers/editor-rtl.css 122 B
build/block-library/blocks/comments-pagination-numbers/editor.css 121 B
build/block-library/blocks/comments-pagination/editor-rtl.css 228 B
build/block-library/blocks/comments-pagination/editor.css 217 B
build/block-library/blocks/comments-pagination/style-rtl.css 234 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 832 B
build/block-library/blocks/comments/editor.css 832 B
build/block-library/blocks/comments/style-rtl.css 632 B
build/block-library/blocks/comments/style.css 631 B
build/block-library/blocks/cover/editor-rtl.css 641 B
build/block-library/blocks/cover/editor.css 642 B
build/block-library/blocks/cover/style-rtl.css 1.62 kB
build/block-library/blocks/cover/style.css 1.6 kB
build/block-library/blocks/details/editor-rtl.css 65 B
build/block-library/blocks/details/editor.css 65 B
build/block-library/blocks/details/style-rtl.css 86 B
build/block-library/blocks/details/style.css 86 B
build/block-library/blocks/embed/editor-rtl.css 331 B
build/block-library/blocks/embed/editor.css 331 B
build/block-library/blocks/embed/style-rtl.css 419 B
build/block-library/blocks/embed/style.css 419 B
build/block-library/blocks/embed/theme-rtl.css 133 B
build/block-library/blocks/embed/theme.css 133 B
build/block-library/blocks/file/editor-rtl.css 326 B
build/block-library/blocks/file/editor.css 326 B
build/block-library/blocks/file/style-rtl.css 278 B
build/block-library/blocks/file/style.css 279 B
build/block-library/blocks/file/view.min.js 324 B
build/block-library/blocks/footnotes/style-rtl.css 198 B
build/block-library/blocks/footnotes/style.css 197 B
build/block-library/blocks/form-input/editor-rtl.css 229 B
build/block-library/blocks/form-input/editor.css 229 B
build/block-library/blocks/form-input/style-rtl.css 342 B
build/block-library/blocks/form-input/style.css 342 B
build/block-library/blocks/form-submission-notification/editor-rtl.css 344 B
build/block-library/blocks/form-submission-notification/editor.css 341 B
build/block-library/blocks/form-submit-button/style-rtl.css 69 B
build/block-library/blocks/form-submit-button/style.css 69 B
build/block-library/blocks/form/view.min.js 470 B
build/block-library/blocks/freeform/editor-rtl.css 2.6 kB
build/block-library/blocks/freeform/editor.css 2.6 kB
build/block-library/blocks/gallery/editor-rtl.css 955 B
build/block-library/blocks/gallery/editor.css 958 B
build/block-library/blocks/gallery/style-rtl.css 1.83 kB
build/block-library/blocks/gallery/style.css 1.82 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 103 B
build/block-library/blocks/group/style.css 103 B
build/block-library/blocks/group/theme-rtl.css 79 B
build/block-library/blocks/group/theme.css 79 B
build/block-library/blocks/heading/style-rtl.css 188 B
build/block-library/blocks/heading/style.css 188 B
build/block-library/blocks/html/editor-rtl.css 346 B
build/block-library/blocks/html/editor.css 347 B
build/block-library/blocks/image/editor-rtl.css 891 B
build/block-library/blocks/image/editor.css 890 B
build/block-library/blocks/image/style-rtl.css 1.59 kB
build/block-library/blocks/image/style.css 1.59 kB
build/block-library/blocks/image/theme-rtl.css 137 B
build/block-library/blocks/image/theme.css 137 B
build/block-library/blocks/image/view.min.js 1.65 kB
build/block-library/blocks/latest-comments/style-rtl.css 355 B
build/block-library/blocks/latest-comments/style.css 354 B
build/block-library/blocks/latest-posts/editor-rtl.css 179 B
build/block-library/blocks/latest-posts/editor.css 179 B
build/block-library/blocks/latest-posts/style-rtl.css 509 B
build/block-library/blocks/latest-posts/style.css 510 B
build/block-library/blocks/list/style-rtl.css 107 B
build/block-library/blocks/list/style.css 107 B
build/block-library/blocks/loginout/style-rtl.css 61 B
build/block-library/blocks/loginout/style.css 61 B
build/block-library/blocks/media-text/editor-rtl.css 321 B
build/block-library/blocks/media-text/editor.css 320 B
build/block-library/blocks/media-text/style-rtl.css 558 B
build/block-library/blocks/media-text/style.css 556 B
build/block-library/blocks/more/editor-rtl.css 427 B
build/block-library/blocks/more/editor.css 427 B
build/block-library/blocks/navigation-link/editor-rtl.css 644 B
build/block-library/blocks/navigation-link/editor.css 645 B
build/block-library/blocks/navigation-link/style-rtl.css 192 B
build/block-library/blocks/navigation-link/style.css 191 B
build/block-library/blocks/navigation-submenu/editor-rtl.css 295 B
build/block-library/blocks/navigation-submenu/editor.css 294 B
build/block-library/blocks/navigation/editor-rtl.css 2.19 kB
build/block-library/blocks/navigation/editor.css 2.19 kB
build/block-library/blocks/navigation/style-rtl.css 2.25 kB
build/block-library/blocks/navigation/style.css 2.23 kB
build/block-library/blocks/navigation/view.min.js 1.03 kB
build/block-library/blocks/nextpage/editor-rtl.css 392 B
build/block-library/blocks/nextpage/editor.css 392 B
build/block-library/blocks/page-list/editor-rtl.css 378 B
build/block-library/blocks/page-list/editor.css 378 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 236 B
build/block-library/blocks/paragraph/editor.css 236 B
build/block-library/blocks/paragraph/style-rtl.css 341 B
build/block-library/blocks/paragraph/style.css 340 B
build/block-library/blocks/post-author-biography/style-rtl.css 74 B
build/block-library/blocks/post-author-biography/style.css 74 B
build/block-library/blocks/post-author-name/style-rtl.css 69 B
build/block-library/blocks/post-author-name/style.css 69 B
build/block-library/blocks/post-author/editor-rtl.css 107 B
build/block-library/blocks/post-author/editor.css 107 B
build/block-library/blocks/post-author/style-rtl.css 188 B
build/block-library/blocks/post-author/style.css 189 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 527 B
build/block-library/blocks/post-comments-form/style.css 528 B
build/block-library/blocks/post-content/editor-rtl.css 74 B
build/block-library/blocks/post-content/editor.css 74 B
build/block-library/blocks/post-content/style-rtl.css 79 B
build/block-library/blocks/post-content/style.css 79 B
build/block-library/blocks/post-date/style-rtl.css 62 B
build/block-library/blocks/post-date/style.css 62 B
build/block-library/blocks/post-excerpt/editor-rtl.css 71 B
build/block-library/blocks/post-excerpt/editor.css 71 B
build/block-library/blocks/post-excerpt/style-rtl.css 155 B
build/block-library/blocks/post-excerpt/style.css 155 B
build/block-library/blocks/post-featured-image/editor-rtl.css 729 B
build/block-library/blocks/post-featured-image/editor.css 726 B
build/block-library/blocks/post-featured-image/style-rtl.css 347 B
build/block-library/blocks/post-featured-image/style.css 347 B
build/block-library/blocks/post-navigation-link/style-rtl.css 215 B
build/block-library/blocks/post-navigation-link/style.css 214 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 399 B
build/block-library/blocks/post-template/style.css 398 B
build/block-library/blocks/post-terms/style-rtl.css 96 B
build/block-library/blocks/post-terms/style.css 96 B
build/block-library/blocks/post-time-to-read/style-rtl.css 70 B
build/block-library/blocks/post-time-to-read/style.css 70 B
build/block-library/blocks/post-title/style-rtl.css 226 B
build/block-library/blocks/post-title/style.css 226 B
build/block-library/blocks/preformatted/style-rtl.css 125 B
build/block-library/blocks/preformatted/style.css 125 B
build/block-library/blocks/pullquote/editor-rtl.css 134 B
build/block-library/blocks/pullquote/editor.css 134 B
build/block-library/blocks/pullquote/style-rtl.css 342 B
build/block-library/blocks/pullquote/style.css 342 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 121 B
build/block-library/blocks/query-pagination-numbers/editor.css 118 B
build/block-library/blocks/query-pagination/editor-rtl.css 154 B
build/block-library/blocks/query-pagination/editor.css 154 B
build/block-library/blocks/query-pagination/style-rtl.css 237 B
build/block-library/blocks/query-pagination/style.css 237 B
build/block-library/blocks/query-title/style-rtl.css 64 B
build/block-library/blocks/query-title/style.css 64 B
build/block-library/blocks/query/editor-rtl.css 452 B
build/block-library/blocks/query/editor.css 451 B
build/block-library/blocks/query/view.min.js 958 B
build/block-library/blocks/quote/style-rtl.css 238 B
build/block-library/blocks/quote/style.css 238 B
build/block-library/blocks/quote/theme-rtl.css 233 B
build/block-library/blocks/quote/theme.css 236 B
build/block-library/blocks/read-more/style-rtl.css 138 B
build/block-library/blocks/read-more/style.css 138 B
build/block-library/blocks/rss/editor-rtl.css 101 B
build/block-library/blocks/rss/editor.css 101 B
build/block-library/blocks/rss/style-rtl.css 288 B
build/block-library/blocks/rss/style.css 287 B
build/block-library/blocks/search/editor-rtl.css 199 B
build/block-library/blocks/search/editor.css 199 B
build/block-library/blocks/search/style-rtl.css 672 B
build/block-library/blocks/search/style.css 671 B
build/block-library/blocks/search/theme-rtl.css 113 B
build/block-library/blocks/search/theme.css 113 B
build/block-library/blocks/search/view.min.js 475 B
build/block-library/blocks/separator/editor-rtl.css 100 B
build/block-library/blocks/separator/editor.css 100 B
build/block-library/blocks/separator/style-rtl.css 248 B
build/block-library/blocks/separator/style.css 248 B
build/block-library/blocks/separator/theme-rtl.css 195 B
build/block-library/blocks/separator/theme.css 195 B
build/block-library/blocks/shortcode/editor-rtl.css 286 B
build/block-library/blocks/shortcode/editor.css 286 B
build/block-library/blocks/site-logo/editor-rtl.css 806 B
build/block-library/blocks/site-logo/editor.css 803 B
build/block-library/blocks/site-logo/style-rtl.css 218 B
build/block-library/blocks/site-logo/style.css 218 B
build/block-library/blocks/site-tagline/editor-rtl.css 87 B
build/block-library/blocks/site-tagline/editor.css 87 B
build/block-library/blocks/site-tagline/style-rtl.css 65 B
build/block-library/blocks/site-tagline/style.css 65 B
build/block-library/blocks/site-title/editor-rtl.css 85 B
build/block-library/blocks/site-title/editor.css 85 B
build/block-library/blocks/site-title/style-rtl.css 206 B
build/block-library/blocks/site-title/style.css 206 B
build/block-library/blocks/social-link/editor-rtl.css 338 B
build/block-library/blocks/social-link/editor.css 338 B
build/block-library/blocks/social-links/editor-rtl.css 757 B
build/block-library/blocks/social-links/editor.css 756 B
build/block-library/blocks/social-links/style-rtl.css 1.51 kB
build/block-library/blocks/social-links/style.css 1.5 kB
build/block-library/blocks/spacer/editor-rtl.css 346 B
build/block-library/blocks/spacer/editor.css 346 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-of-contents/style-rtl.css 83 B
build/block-library/blocks/table-of-contents/style.css 83 B
build/block-library/blocks/table/editor-rtl.css 394 B
build/block-library/blocks/table/editor.css 394 B
build/block-library/blocks/table/style-rtl.css 640 B
build/block-library/blocks/table/style.css 639 B
build/block-library/blocks/table/theme-rtl.css 152 B
build/block-library/blocks/table/theme.css 152 B
build/block-library/blocks/tag-cloud/editor-rtl.css 144 B
build/block-library/blocks/tag-cloud/editor.css 144 B
build/block-library/blocks/tag-cloud/style-rtl.css 266 B
build/block-library/blocks/tag-cloud/style.css 265 B
build/block-library/blocks/template-part/editor-rtl.css 368 B
build/block-library/blocks/template-part/editor.css 368 B
build/block-library/blocks/template-part/theme-rtl.css 113 B
build/block-library/blocks/template-part/theme.css 113 B
build/block-library/blocks/term-description/style-rtl.css 126 B
build/block-library/blocks/term-description/style.css 126 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 165 B
build/block-library/blocks/text-columns/style.css 165 B
build/block-library/blocks/verse/style-rtl.css 98 B
build/block-library/blocks/verse/style.css 98 B
build/block-library/blocks/video/editor-rtl.css 396 B
build/block-library/blocks/video/editor.css 397 B
build/block-library/blocks/video/style-rtl.css 192 B
build/block-library/blocks/video/style.css 192 B
build/block-library/blocks/video/theme-rtl.css 134 B
build/block-library/blocks/video/theme.css 134 B
build/block-library/classic-rtl.css 179 B
build/block-library/classic.css 179 B
build/block-library/common-rtl.css 1.1 kB
build/block-library/common.css 1.1 kB
build/block-library/editor-elements-rtl.css 75 B
build/block-library/editor-elements.css 75 B
build/block-library/editor-rtl.css 11.8 kB
build/block-library/editor.css 11.8 kB
build/block-library/elements-rtl.css 54 B
build/block-library/elements.css 54 B
build/block-library/reset-rtl.css 472 B
build/block-library/reset.css 472 B
build/block-library/style-rtl.css 15 kB
build/block-library/style.css 15 kB
build/block-library/theme-rtl.css 708 B
build/block-library/theme.css 712 B
build/commands/index.min.js 16.1 kB
build/commands/style-rtl.css 955 B
build/commands/style.css 952 B
build/components/style-rtl.css 12.1 kB
build/components/style.css 12.1 kB
build/customize-widgets/style-rtl.css 1.35 kB
build/customize-widgets/style.css 1.35 kB
build/edit-post/classic-rtl.css 578 B
build/edit-post/classic.css 580 B
build/edit-post/style-rtl.css 2.31 kB
build/edit-post/style.css 2.31 kB
build/edit-site/posts-rtl.css 7.31 kB
build/edit-site/posts.css 7.31 kB
build/edit-site/style-rtl.css 12.6 kB
build/edit-site/style.css 12.6 kB
build/edit-widgets/style-rtl.css 4.2 kB
build/edit-widgets/style.css 4.2 kB
build/editor/style-rtl.css 9.28 kB
build/editor/style.css 9.29 kB
build/format-library/style-rtl.css 476 B
build/format-library/style.css 476 B
build/interactivity/debug.min.js 16.4 kB
build/interactivity/file.min.js 447 B
build/interactivity/image.min.js 1.78 kB
build/interactivity/index.min.js 13.2 kB
build/interactivity/navigation.min.js 1.16 kB
build/interactivity/query.min.js 742 B
build/interactivity/router.min.js 2.8 kB
build/interactivity/search.min.js 615 B
build/list-reusable-blocks/style-rtl.css 846 B
build/list-reusable-blocks/style.css 846 B
build/modules/importmap-polyfill.min.js 12.3 kB
build/nux/style-rtl.css 749 B
build/nux/style.css 745 B
build/patterns/style-rtl.css 687 B
build/patterns/style.css 685 B
build/preferences/style-rtl.css 554 B
build/preferences/style.css 554 B
build/react-refresh-entry/index.min.js 9.47 kB
build/react-refresh-runtime/index.min.js 6.76 kB
build/reusable-blocks/style-rtl.css 256 B
build/reusable-blocks/style.css 256 B
build/shortcode/index.min.js 1.4 kB
build/vendors/react-dom.min.js 41.7 kB
build/vendors/react-jsx-runtime.min.js 560 B
build/vendors/react.min.js 4.02 kB
build/widgets/style-rtl.css 1.16 kB
build/widgets/style.css 1.16 kB

compressed-size-action

@kevin940726 kevin940726 changed the title Add HMR for CSS Support Hot Module Replacement (HMR) for CSS Aug 13, 2024
lib/client-assets.php Outdated Show resolved Hide resolved
Copy link

Flaky tests detected in a51dfd4.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/10423728271
📝 Reported issues:

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.

Nice one. There are a few small tweaks we could land today to the current configuration. It would be a huge win to be able to st CSS styles updated on the fly for WP packages. I'm wondering if it will fully work for the styles that get also included in the iframed editor, as they might require another layer that automatically syncs changes to the editor's iframe. Edit: I realized that there is a glue layer that iterates over all frames to update CSS files 👍🏻

// Register the runtime script.
gutenberg_override_script(
$scripts,
'wp-runtime',
Copy link
Member

Choose a reason for hiding this comment

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

Do you think it should be included in the WordPress core, too? Otherwise, it could be a regular script registration and the script handle should be more gutenberg-packages-runtime.

Copy link
Member Author

Choose a reason for hiding this comment

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

What do you mean by a regular script registration? I'm not that familiar with PHP script registration and loading 😅.

Copy link
Member

Choose a reason for hiding this comment

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

If it isn’t included in WP core, there is no value in the overhead of gutenberg_override_script which unregisters core scripts first.

Copy link
Member Author

Choose a reason for hiding this comment

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

I see. I think this is worth getting into core too. I need to get familiar with core's webpack config first though 😅.

@@ -275,7 +277,7 @@
"build:plugin-zip": "bash ./bin/build-plugin-zip.sh",
"clean:package-types": "tsc --build --clean && rimraf \"./packages/*/build-types\"",
"clean:packages": "rimraf \"./packages/*/@(build|build-module|build-style)\"",
"dev": "cross-env NODE_ENV=development npm run build:packages && concurrently \"wp-scripts start\" \"npm run dev:packages\"",
"dev": "cross-env NODE_ENV=development npm run build:packages && concurrently \"wp-scripts serve\" \"npm run dev:packages\"",
Copy link
Member

Choose a reason for hiding this comment

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

What are the limitation of wp-scripts start --hot that force introducing a new script? I would be more in favor of always using the dev server for start by default even when not using hot module replacement.

Copy link
Member Author

Choose a reason for hiding this comment

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

We want to use our own manual HMR setup so we don't want to pass --hot to webpack. wp-scripts start --hot seems to always pass that to webpack which then override the hot: false in the config.

I agree using start will be ideal but serve seems reasonable too, given that the official webpack command uses serve to start a dev server too.

Copy link
Member

Choose a reason for hiding this comment

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

Sure, webpack serve is a thing which is reflected in wp-scripts start implementation. The same applies to webpack watch but it doesn’t need to be exposed to the devs.

},
liveReload: false,
devMiddleware: {
writeToDisk( filePath ) {
Copy link
Member

Choose a reason for hiding this comment

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

That's something we could reuse in the default config shipped with @wordpress/scripts as we don't need to save these files on disk that are specific for hot module replacement.

devServer: isProduction
? undefined
: {
devMiddleware: {
writeToDisk: true,
},
allowedHosts: 'auto',
host: 'localhost',
port: 8887,
proxy: {
'/build': {
pathRewrite: {
'^/build': '',
},
},
},
},

Copy link
Member Author

Choose a reason for hiding this comment

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

In fact, we don't actually need to write anything to the disk 😆. The only reason we do now is because the PHP backend uses glob to search for the built files on the disk, which I think is probably an anti-pattern we can avoid? Practically we want to avoid the calls for IO since it's often the most costly operations, I guess we can replace that with a generated manifest JSON and/or something like a API call in development mode. I try to keep everything the same in this PR as much as possible to prevent any accidental breakage though 😅.

Copy link
Member

Choose a reason for hiding this comment

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

There are also asset files produced (in core it’s a single file, maybe in Gutenberg, too) which work like a manifest. Anyway, if you see some room for improvement you probably should look at optimizing WP core, too.

@@ -143,29 +152,103 @@ module.exports = {
performance: {
hints: false, // disable warnings about package sizes
},
optimization: {
...baseConfig.optimization,
runtimeChunk: {
Copy link
Member

Choose a reason for hiding this comment

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

Does it make sense to enable the runtime chunk also on production? I was wondering whether it's something that we should also add to the @wordpress/scripts if there is more than a single chunk to ensure it works correctly with React Fast Refresh. However, my initial thinking was it only is useful in the dev mode when using hot module reloading.

Copy link
Member Author

Choose a reason for hiding this comment

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

Generally, we want to use a single runtime chunk when we have multiple entries in webpack. The size of the runtime is minimal in production though, and it doesn't seem to impact the overall bundle sizes that much (see #64444 (comment)). Extracting the runtime makes it easier to integrate with webpack features like HMR and code splitting though. I think it makes sense to do it in both development and production mode.

@kevin940726 kevin940726 force-pushed the add/css-hmr branch 2 times, most recently from 92f9db5 to b25200b Compare September 6, 2024 14:36
@kevin940726
Copy link
Member Author

Do we still need a backport PR if this is intended to use in gutenberg plugin only?

IIUC, core only uses the npm published packages, so this won't affect them. However, I think it's beneficial to also explore the same setup in core, in other PRs of course.

@ramonjd
Copy link
Member

ramonjd commented Nov 15, 2024

Is this PR still relevant? If so, is there someone that would care to take it over?

@ramonjd ramonjd added the No Core Sync Required Indicates that any changes do not need to be synced to WordPress Core label Nov 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Developer Experience Ideas about improving block and theme developer experience No Core Sync Required Indicates that any changes do not need to be synced to WordPress Core [Type] Build Tooling Issues or PRs related to build tooling
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants