Mini-css-extract-plugin: Extract CSS from SCSS and deferred lazy load into app

Created on 21 Apr 2018  路  12Comments  路  Source: webpack-contrib/mini-css-extract-plugin

I have a few SCSS theme files I want to extract to CSS files and later load them into the page. I want to be able to use contenthash for long term caching.

Since I'm using Webpack 4, I am using mini-css-extract-plugin. I started down the path of creating a splitChunks in my webpack config.

// webpack.config.js
module.exports = {
  plugins: [
      new MiniCssExtractPlugin({
      // Options similar to the same options in webpackOptions.output
      // both options are optional
      filename: "[name].[contenthash].css",
      chunkFilename: "[id].[contenthash].css"
    })
  ],
  optimization: {
    splitChunks: {
      cacheGroups: {
        'theme-a': {
            test: /theme-a.\scss/,
        },
        'theme-b': {
            test: /theme-b.\scss/,
        },
        // more themes
      }
    }
  }
  module: {
    rules: [
      {
        test: /\.scss$/,
        use: [
          MiniCssExtractPlugin.loader,
          "css-loader",
          "sass-loader"
        ]
      }
    ]
  }
}

I've then tried dynamically importing the css in my app:

// app.js
class App extends React.Component {
  // constructor

  login(themeName) {
    import(/* webpackChunkName: "`${themeName}`" */ `./path/to/${themeName}.scss`).then(theme => {
      // do something with `theme`
    }
  }

  // other stuff
}

I need to be able to load that css file dynamically in login() and I'm just not sure how to reference it when it has a generated [contenthash]. Is there a good way to reference the split css chunks in my app when using mini-css-extract-plugin?

Most helpful comment

@danburzo I鈥檓 working until 6pm EST but I鈥檒l follow up. Gotta find the branch too :p

All 12 comments

Related issue: #94

@johnelliott how this issue related to your problem? use [contenthash] for long term caching, also writing your problems in other issues without actual/expected/minimum reproducible test repo will not help in solving your problem

@fillippeyton sorry i can't help your here, please create new issue with minimum reproducible test repo and what you have and what you expected and description. Why do I ask to do this? Because we have hundreds of requests (issues and PR褘) and it takes a lot of time, the more accurately you can formulate the problem and demonstrate it using a small configuration, the sooner your problem will be solved or you can start investigating problem yourself and send us PR

@johnelliott The solution I've come up with is using extract-text-webpack-plugin and creating a "theme manifest" injected into my HtmlWebpackPlugin template. I then reference that on login() and inject a "theme" link into the <head> like <link href="theme-a.css" />. Here's my related SO post: https://stackoverflow.com/a/49993381/401393

I would love to dynamically import these via a named import or some way that feels less hacky.

@fillippeyton can we close issue?

@fillippeyton my solution was to use the extract-loader and file-loader after the css-loader. From there I would conditionally emit the file on the client or server webpack config and have the output file name be the content hash. This would allow me to import the file name on disk in both server and client.

Then in the client when the webpack mode is development I would use the style-loader instead of the extract-loader and file-loader chain.

I realize it鈥檚 a bit difficult to describe some of these configurations without some code to look at. :/

Appreciate the effort looking into this @johnelliott ! I'll take a swing at that solution when I have some time.

@johnelliott thank you for the idea! Would you be able to share your setup? I'm looking into doing something similar, and would greatly appreciate it.

@danburzo I鈥檓 working until 6pm EST but I鈥檒l follow up. Gotta find the branch too :p

Thank you @johnelliott for the idea! I was able to adapt it to suit our needs, like below. (It actually ended up not using mini-css-extract-plugin).

__webpack.config.js__

module: {
  rules: {
    // Font stylesheets
    {
        test: /\.css$/,
        use: [
            {
                loader: 'file-loader',
                options: {
                    name: config.local ? 'css/[name].[ext]' : 'css/[hash].[ext]'
                }
            },
            'extract-loader',
            'css-loader',
            'postcss-loader'
        ],
        include: [/fonts/]
    },

    // Font files
    {
        test: /\.(woff|woff2|ttf|otf)$/,
        loader: 'file-loader',
        include: [/fonts/],

        // awkward path config to make everything work
        // See: https://github.com/webpack-contrib/file-loader/issues/261
        options: {
            name: config.local ? '[name].[ext]' : '[hash].[ext]',
            outputPath: 'css/',
            publicPath: '../css/'
        }
    },
  }
}

With this setup:

postcss-loader > css-loader > extract-loader > file-loader

I am able to have individual, content-hashed CSS files whose URLs I can obtain in the JS code with require('fonts/somefont/style.css'), and the files themselves are plain CSS.

Good to hear Dan :)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

skrobek picture skrobek  路  4Comments

TheHolyWaffle picture TheHolyWaffle  路  4Comments

weoil picture weoil  路  3Comments

IdeaHunter picture IdeaHunter  路  3Comments

Legends picture Legends  路  4Comments