-->

How to ensure that hot CSS loads before JS in webp

2020-08-26 03:17发布

问题:

I'm using webpack-dev-server to hot load all of my assets including CSS. Currently though, my CSS loads after the JavaScript which causes my application issues in some places that depend on layout existing.

How can I ensure that the CSS loads before the JavaScript executes?

I'm thinking there must be a way to do this from module, perhaps a a callback I could hook in to? Or maybe by configuring the style-loader to have priority?

This is my index.js:

import './styles/main.scss';
import './scripts/main.js';

if (module.hot) {
  module.hot.accept();
}

and this is my styles loader:

{
        test: /\.(scss)$/,
        loader: 'style!css?&sourceMap!postcss!resolve-url!sass?sourceMap'
},

A similar question has been asked at this style-loader Github Issue: https://github.com/webpack/style-loader/issues/121

回答1:

I was having the exacly same issue, in production the css are extracted so it always work, however in development because of the style-loader "sometimes executing after the main bundle" i had issues where the main bundle would calculate the size of some nodes in the DOM which was set by the css... so it could result to wrong sizes as the main css still havent loaded... i fixed this issue by having the option singleton:true.

example:

{
    test: /\.s?css$/,
    loader: ExtractTextPlugin.extract({
            fallback: [
                {
                    loader: 'style-loader',
                    options: { singleton: true }
                }
            ],
            use: [
                {
                    loader: 'css-loader',
                    options: {
                        importLoaders: 1,
                        minimize: !isProduction,
                        sourceMap: !isProduction
                    }
                },
                { loader: 'postcss-loader', options: { sourceMap: !isProduction, ...postcss } },
                { loader: 'resolve-url-loader', options: { sourceMap: !isProduction } },
                { loader: 'sass-loader', options: { sourceMap: true } }
            ]
        }
    )
}


回答2:

Looks like there's no event, callback or any way to detect that the style has been loaded. After long hours of searching in vain, I had to do something really dirty:

function checkCSS() {
  const repeat = requestAnimationFrame(checkCSS);
  // CSS loaded?
  if(getComputedStyle(document.body).boxSizing === 'border-box') {
    routes.loadEvents() // Init JS
    cancelAnimationFrame(repeat) // Cancel next frame
  }
}
if (process.env.NODE_ENV !== 'production') {
  checkCSS()
} else {
  $(document).ready(() => {
    routes.loadEvents()
  })
}

Because I have * { box-sizing: border-box; } in my styles and that I'm pretty sure native CSS styles won't never look like this, I can be ~99% sure that my own CSS is loaded.

I died a little writing this. Hopefully we'll find a better way!