webpack-contrib / mini-css-extract-plugin

Lightweight CSS extraction plugin
MIT License
4.65k stars 390 forks source link

CSS with [contenthash] not refreshing with HMR, webpack-dev-middleware #1089

Open YellowSaleTag opened 4 months ago

YellowSaleTag commented 4 months ago

Bug report

CSS with [contenthash] not refreshing with HMR, webpack-dev-middleware

1. We see our stylesheet loaded in the document with the expected CSS.

Screenshot 2024-03-17 at 2 24 45 AM

2. We make an update to our CSS. We change the padding from 50 to 75 px.

Screenshot 2024-03-17 at 2 27 24 AM

3. We see a request in the network tab for the CSS update. However, the contents is stale. It has the old value of 50 px.

Screenshot 2024-03-17 at 2 31 01 AM

4. We refresh the page using the refresh button and see the updated value of 75 px.

Screenshot 2024-03-17 at 2 34 53 AM

Package Versions

"express": "4.18.2",
"webpack": "5.90.3",
"webpack-dev-middleware": "7.0.0",
"webpack-hot-middleware": "2.26.1",
"webpack-manifest-plugin": "5.0.0"

Webpack Config (relevant parts)

{
  name: '<build-name>',
  mode: 'development',
  devtool,
  context: __dirname,
  entry: [`webpack-hot-middleware/client?name=<build-name>&path=${publicPath}__webpack_hmr`],
  output: {
    chunkFilename: '[name].[contenthash].js',
    filename: '[name].[contenthash].js',
    path: path.resolve(__dirname, 'dist', 'browser'),
    publicPath
  },
  optimization: {
    splitChunks: {
      chunks: 'all'
    }
  },
  module: {
    rules: [
      {
        test: /\.(css)$/,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1, // https://webpack.js.org/loaders/css-loader/#importloaders
              modules: {
                localIdentName: '[hash:8]'
              }
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new HtmlWebpackPlugin({
      filename: 'index.html',
      inject: false,
      template: path.resolve(__dirname, 'src', 'targets', 'browser', 'index-browser.html')
    }),
    new MiniCssExtractPlugin({
      chunkFilename: '[name].[contenthash].css',
      filename: '[name].[contenthash].css'
    })
  ]
}

Middleware Config

webpackDevMiddleware(compiler, { serverSideRender: true })
webpackHotMiddleware(compiler, { path: `/dist/__webpack_hmr` })

Actual Behavior

  1. We see our stylesheet loaded in the document with the expected CSS.
  2. We make an update to our CSS. We change the padding from 50 to 75 px.
  3. We see a request in the network tab for the CSS update. However, the contents is stale. It has the old value of 50 px.
  4. We refresh the page using the refresh button and see the updated value of 75 px.

Expected Behavior

  1. The requested CSS via hot reload update should render the new CSS values and the page should update.

How Do We Reproduce?

Minimal configuration provided above for now...

Please paste the results of npx webpack-cli info here, and mention other relevant information

  System:
    OS: macOS 14.3.1
    CPU: (10) arm64 Apple M1 Pro
    Memory: 1.03 GB / 32.00 GB
  Binaries:
    Node: 18.19.0 - ~/.nvm/versions/node/v18.19.0/bin/node
    Yarn: 1.22.18 - /opt/homebrew/bin/yarn
    npm: 10.2.3 - ~/.nvm/versions/node/v18.19.0/bin/npm
  Browsers:
    Edge: 122.0.2365.92
    Safari: 17.3.1
  Packages:
    babel-loader: 9.1.3 => 9.1.3 
    copy-webpack-plugin: 12.0.2 => 12.0.2 
    css-loader: 6.8.1 => 6.8.1 
    html-webpack-plugin: 5.5.4 => 5.5.4 
    style-loader: 3.3.3 => 3.3.3 
    webpack: 5.90.3 => 5.90.3 
    webpack-cli: 5.1.4 => 5.1.4 
    webpack-hot-middleware: 2.26.1 => 2.26.1 
    webpack-manifest-plugin: 5.0.0 => 5.0.0 
  Global Packages:
    webpack: 5.90.3
alexander-akait commented 4 months ago

Please create a github repo with the reproducible example of the problem, thank you

YellowSaleTag commented 4 months ago

Thank you so much for taking the time to respond. I created a minimal example here.

YellowSaleTag commented 4 months ago

I found the root cause.

It breaks when:

new MiniCssExtractPlugin({
  chunkFilename: '[name].[contenthash].id-[id].css',
  filename: '[name].[contenthash].css'
}),

It works when:

new MiniCssExtractPlugin({
  chunkFilename: '[name].[contenthash].id-[id].css',
  filename: '[name].css'
})

It seems [contenthash] with hot module reloading does not work. I use content hash to avoid caching of the CSS file.

Is there another way I can avoid caching of the css file?

I updated the minimal PoC to reflect this. Here too.

Attached is a screenshot of the PoC with [contenthash] and a stale CSS payload in hot reload network request.

Screenshot 2024-03-17 at 4 30 54 PM
alexander-akait commented 4 months ago

Weird, I can't reproduce, even more, we have test cases for this...

alexander-akait commented 4 months ago

Can you provide full steps using your repo above - https://github.com/YellowSaleTag/hmr-stale-css-payload/?

YellowSaleTag commented 4 months ago

Hmm interesting, sure see the following.

  1. npm i
  2. npm run build
  3. npm run start
  4. browse localhost:3000
  5. inspect the network logs to see the main.css request and payload. confirm the html rule has padding of 200px
  6. change the padding value in ./app/components/App/app.css to 50 px
  7. confirm the hot update network request - main.css update request should have a payload with an html padding value of 50px
  8. kill the app
  9. modify ./webpack.config.js both lines 89 and 128. At these lines change [name].css to [name].[contenthash].css.
  10. run npm run build
  11. run npm run start
  12. follow steps 4, 5 (confirm 50px), 6 (update to 200px).
  13. follow step 7. except when you confirm the hot update request for main.[contenthash].css you'll find padding: 50px even though you changed it to 200px