-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
CSS Modules HMR working again #3031
Conversation
a8df863
to
284204e
Compare
@gauravtiwari can you give me a review, please? |
lib/webpacker/helper.rb
Outdated
@@ -137,7 +137,9 @@ def preload_pack_asset(name, **options) | |||
# <%= stylesheet_pack_tag 'calendar' %> | |||
# <%= stylesheet_pack_tag 'map' %> | |||
def stylesheet_pack_tag(*names, **options) | |||
stylesheet_link_tag(*sources_from_manifest_entrypoints(names, type: :stylesheet), **options) | |||
unless current_webpacker_instance.dev_server.running? |
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 seems risky. Must avoid ever having a path that leads to a port check happening in production. Seems like something that should happen outside the pack call itself.
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.
@dhh, does the refactoring clarify that there cannot be a port check during production?
8e2f3c7
to
8a8a90f
Compare
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.
@dhh Please let me know if I addressed your concerns. I also improved the HMR setup.
lib/install/config/webpacker.yml
Outdated
hmr: false | ||
# Inline should be set to true if using HMR; it inserts a script to take care of live reloading | ||
inline: true | ||
hmr: true |
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 see no reason to have the extra settings in the YML file since they are not used by the Ruby code and they can be customized in a custom Webpack config.
lib/webpacker/dev_server.rb
Outdated
@@ -11,7 +11,7 @@ def initialize(config) | |||
@config = config | |||
end | |||
|
|||
def running? | |||
def configured_and_running? |
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.
By renaming this method, it's clear that there's no cost for checking if the devServer is "configured" on a production environment.
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 know I flagged this, but seeing it in context, it actually looks worse. I think we were better off with just #running?. Which is kinda ironic because I vaguely remember flipflopping on this exact question when we originally made web packer!
@@ -30,6 +30,7 @@ def load_config | |||
@port = dev_server.port | |||
@pretty = dev_server.pretty? | |||
@https = dev_server.https? | |||
@hot = dev_server.hmr? |
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.
Recent docs on using HMR with the webpack-dev-server all suggest using the command line option rather than the plugin.
@@ -8,7 +8,7 @@ class Webpacker::Engine < ::Rails::Engine | |||
config.webpacker = ActiveSupport::OrderedOptions.new | |||
|
|||
initializer "webpacker.proxy" do |app| | |||
insert_middleware = Webpacker.config.dev_server.present? rescue nil |
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.
There is no need to rescue and swallow errors here.
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.
Don't think the local variable explains anything. Should just inline into the conditional.
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.
Agree.
injectClient: devServer.inject_client, | ||
inline: devServer.inline || devServer.hmr, | ||
injectClient: devServer.hmr, | ||
injectHot: devServer.hmr, |
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.
Let's base the default "it just works" settings based on the one hmr
setting.
package/utils/helpers.js
Outdated
@@ -39,6 +39,9 @@ const canProcess = (rule, fn) => { | |||
return null | |||
} | |||
|
|||
const runningWebpackDevServer = process.env.WEBPACK_DEV_SERVER && | |||
process.env.WEBPACK_DEV_SERVER !== 'undefined' |
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.
When running the webpack-dev-server, this ENV value is set.
3f1adf0
to
90e80d5
Compare
Thanks @justin808 for working on getting CSS module HMR working. I understand it's an important feature to projects like react_on_rails and I appreciate your efforts here. I do feel that changing the default to orient toward HMR should be reconsidered. My strong personal preference is that extracting css in development and test should be the default, even if the dev server is running. That means I also prefer that HMR should not be enabled by default. As we saw in last year's May-of-WTFs, Webpacker has not provided a great out-of-the-box experience for many Rails developers. Anything we can do improve the OOB experience would be a win in terms of adoption and getting more folks helping improve the project. Extracting CSS and disabling HMR, even if the dev server is running, is closer to what I expect newcomers would expect and decrease the likelihood of those WTF moments that turn developers off. When To summarize, I'd prefer the view helper logic look something like extract_css = !Webpacker.dev_server.running_and_hmr_enabled? # not necessarily the suggested method name And in
|
The big question is: If you want simplicity and lack of WTFs, why not use Is there another benefit to using the webpack-dev-server without HMR? Is it any faster than watch mode? Maybe we can make the default for development mode to be For tests, static files are the way to go.
I agree with "Anything we can do improve the OOB experience." That's why we should remove extra devServer options in the I agree that having a default of CSS extraction is a big win, as that is the typical scenario of both However, JS devs would expect that HMR is on by default, as that's the default for creating-react-app, gatsby, and next.js. So not having HMR work by default would be a WTF for others. Having finicky things like HMR "it just works" is a big reason to use a library like rails/webpacker. So can we have:
I'm also OK with @rossta's idea of adding the check that HMR is on before disabling the CSS extraction and style tag. At the same time, I don't see the point of using the webpack-dev-server without HMR, when it seems much simpler to just use Any opinions? |
Per my previous comment, there might be a slight performance advantage in using the webpack-dev-server per these docs. So I'm OK with having HMR be off for the default, and if HMR is off, then CSS is extracted. |
I agree with this statement. Having worked mostly with Rails and some Next.js recently, there is a definitive gap between the default webpacker experience and the default experience of the mentioned frameworks. But I also understand the concern that onboarding people coming from the assets pipeline is important. |
be46fe9
to
a219f64
Compare
a219f64
to
8fbc86f
Compare
@@ -137,6 +141,9 @@ def preload_pack_asset(name, **options) | |||
# <%= stylesheet_pack_tag 'calendar' %> | |||
# <%= stylesheet_pack_tag 'map' %> | |||
def stylesheet_pack_tag(*names, **options) | |||
css_inline = Webpacker.dev_server.hmr? && Webpacker.dev_server.configured_and_running? | |||
return "" if css_inline | |||
|
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.
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.
LGTM
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 would pull this up into Webpacker, so it's Webpacker.inlining_css?
.
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.
Done. How's this look?
if (devServer.hmr) { | ||
devConfig = merge(devConfig, { | ||
output: { filename: '[name]-[hash].js' }, | ||
plugins: [new webpack.HotModuleReplacementPlugin()] |
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.
Previously, we always included the HotModuleReplacementPlugin even if HMR was off. So it's no change if the command line option --hot
is always added.
8fbc86f
to
6ca0bc0
Compare
package/utils/helpers.js
Outdated
const runningWebpackDevServer = process.env.WEBPACK_DEV_SERVER && | ||
process.env.WEBPACK_DEV_SERVER !== 'undefined' |
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.
Is this a string? And not the undefined
keywork? 🤔
> process.env.WEBPACK_DEV_SERVER
undefined
> process.env.WEBPACK_DEV_SERVER !== 'undefined'
true
> process.env.WEBPACK_DEV_SERVER !== undefined
false
>
const runningWebpackDevServer = process.env.WEBPACK_DEV_SERVER && | |
process.env.WEBPACK_DEV_SERVER !== 'undefined' | |
// When running the webpack-dev-server, this ENV value is set. | |
const runningWebpackDevServer = process.env.WEBPACK_DEV_SERVER !== undefined |
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.
Updated to check against 'true'.
@guillaumebriday Almost ready. Just got to fix the jest tests. |
1. Use style-loader for CSS modules HMR 2. Don't extract CSS if running the webpack-dev-server
Webpacker.dev_server.running? might appear to be costly, but it first checks that the dev_server value is on the config Hash. Renaming the method makes it clear that the first check is whether it is configured. Since the dev_server would ever be configured on production, there is no cost for calling this method on production.
* HMR default to true for webpacker.yml * inline, injectClient, and injectHot default to the value of hmr * hmr turned on for the webpack dev server if the hmr config is true * using command line option for --hot as the docs recommend that over the plugin.
1. hmr default is false 2. CSS is extracted unless yml file configuredd HMR and running webpack-dev-server
ce8929e
to
9e282f6
Compare
65d4f71
to
0e16135
Compare
0e16135
to
ab5a7a5
Compare
@@ -137,6 +141,9 @@ def preload_pack_asset(name, **options) | |||
# <%= stylesheet_pack_tag 'calendar' %> | |||
# <%= stylesheet_pack_tag 'map' %> | |||
def stylesheet_pack_tag(*names, **options) | |||
css_inline = Webpacker.dev_server.hmr? && Webpacker.dev_server.configured_and_running? | |||
return "" if css_inline | |||
|
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.
Done. How's this look?
module.exports = { | ||
railsEnv: railsEnv && railsEnv.match(regex) ? railsEnv : DEFAULT, | ||
nodeEnv, | ||
isProduction, | ||
isDevelopment | ||
isDevelopment, | ||
runningWebpackDevServer |
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.
runningWebpackDevServer feels like an env value.
@guillaumebriday @dhh this PR now has all the requested changes. |
docs/developing_webpacker.md
Outdated
|
||
## Update the Package Code | ||
1. Make some JS change in WEBPACKER_DIR | ||
2. Run `yalc push` and your changes will to your `TEST_APP_DIR`'s node_modules. |
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 think we missed a verb in this phrase.
... and your changes will be pushed to your...
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.
Fixed! Thanks!
Looks solid to me. Kudos on the helper variables naming! |
responding to #3055 (comment) Followed the instructions to test:
aborted testing here
i tried with |
Hi @tomgilligan, please pul the latest code from shakacode/react_on_rails_demo_ssr_hmr#12 I had updated rails/webpacker, but I forgot to push my test code! @guillaumebriday Can you give it a try? |
Thank you for the update @justin808 . I now get this for both node v14.15.4 and v16.4.0 .
|
@tomgilligan Please pull the latest from my branch. Updating dependencies fixed the issue. |
I made a video showing this working: https://youtu.be/lIkhnLXIH6I |
LGTM! Any idea when this will get merged? |
I was able to run the proposed test on the following platform:
I had to do the following changes:
Thank you for the good job. |
Update to include: rails/webpacker#3031 Check if inlining CSS before doing hot refresh We can only use the ReactRefreshWebpackPlugin if the server is running and doing HMR, which is what the inliningCss does.
Update to include: rails/webpacker#3031 Check if inlining CSS before doing hot refresh We can only use the ReactRefreshWebpackPlugin if the server is running and doing HMR, which is what the inliningCss does.
PR #3031 added a dependency for `style-loader` when CSS is inlined here: https://github.com/rails/webpacker/blob/master/package/utils/get_style_rule.js#L16 The integration instructions for supporting CSS does not include that package for the `yarn add` so no one would know to include it until they try to run the dev server locally and are greeted with a missing package error. ``` ERROR in ./app/packs/entrypoints/application.js 8:0-33 Module not found: Error: Can't resolve 'style-loader' in '/path/to/webapp' resolve 'style-loader' in '/path/to/webapp' ``` Adding the package with `yarn add` fixes the issue. I added `style-loader` to the README under the CSS integration section.
Demo: https://youtu.be/lIkhnLXIH6I
Changes
inliningCss
from JS packagethe plugin.
To Test
Tested on shakacode/react_on_rails_demo_ssr_hmr#12
justin808/change-css-loader
foreman start -f Procfile.dev-hmr