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 also 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: {
        'vendor': {
            // custom commons chunk for js
        },
        '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].
mini-css-extract-plugin.Edit: Created a mini-css-extract-plugin issue here.
Your code seems to be alright as post React 16.8 you can use css and scss modules without configuring webpack. I would suggest you check your version of React first. If you are using a version of React < 16.8 then you would have to eject and configure your webpack in order to use css and scss modules.
Browser-level lazy-loading does not apply to CSS background images, so you need to consider other methods if you have background images to lazy-load.
Using React Suspense ( React 16.6+ )From React 16.6+, react added React Suspense which performs lazy loading.
My solution ended up using extract-text-webpack-plugin. My config now looks like this:
// webpack.config.js
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const ExtractThemeA = new ExtractTextPlugin({ filename: 'themeA.[hash].css', allChunks: true});
module.exports = {
  plugins: [
      ExtractThemeA,
      // more plugins for other css files
  ],
  optimization: {
    splitChunks: {
      cacheGroups: {
        // Note: No changes to splitChunks
        'vendor': {
            // custom commons chunk for js
        }
    }
  }
  module: {
    rules: [
      {
        test: /theme-a\.scss$/,
        use: ExtractThemeA.extract([ 'css-loader', 'sass-loader' ])
      },
      // more module rules for each css file needed
    ]
  }
}
Then, these chunks are available by file name in my HtmlWebpackPlugin:
<!-- HtmlWebpackPlugin Template -->
<script>
// provides me with an array of file name strings
var themesManifest = <%= htmlWebpackPlugin.files.css %>
</script>
                        Sorry for my miss understanding,
You could probably just make two different scss-files and import them as needed. theme.scss admin.scss or like so
This is how I am doing scss in React right now
In App.js
import styles from '../../stylesheet/main.scss'
// could be as well
import styles1 from '../../stylesheet/theme.scss' // some file
import styles2 from '../../stylesheet/admin.scss' // some other file
const App = () => {
  <div className={styles.action_feed} >{ content }</div>
} 
In main.scss
.action_feed {
  position: fixed;
  width: 350px;
  height: auto;
  max-height: 100%;
  max-width: 100%;
  top: 0;
  left: 0;
  z-index: 9999;
}
I think you could just as well do it like so
const themeName = 'main'
import(`./stylesheet/${themeName}.scss`, (css) => {
  // meaby set this to state? not quite sure how should properly handle
  // dynamically imported css
  this.setState({ css: css.action_feed })
  // or possible this way. I have done some non-React dom manipulation
  // this way before
  document.querySelector('body').classList.add(css.action_feed)
})
<div className={this.state.css}>{ content }</div>
You should probably check out React's new Refs API as well. It might give you some nice flexibility for giving className-attr to required element.
Having set to splitChunks.chunks to all works though i think in this case anyway
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With