Skip to content

Instantly share code, notes, and snippets.

@peguerosdc
Last active July 2, 2020 04:31
Show Gist options
  • Save peguerosdc/c495961678cefc01ddf87f5e32f97695 to your computer and use it in GitHub Desktop.
Save peguerosdc/c495961678cefc01ddf87f5e32f97695 to your computer and use it in GitHub Desktop.
CRA + RSuite + webpack-multiple-themes-compile

This is an example on how to make webpack-multiple-themes-compile work with create-react-app.

I'd consider this really a hack as some things have to be changed in the default webpack configuration, so there are a few issues:

  1. When adding the new entry points for the themes (i.e. for theme-custom.css), the original entry points have to be re-shaped and as a result (at least in my build) the first run of the application results in a blank page, but after the reloading everything works as expected.
  2. The number of themes that can be added is limited as the compiler runs out of memory very soon. I think this may be because of how CRA manages the entry points under the hood and we are messing with it with this hack.

Apart from these, I haven't found any issues neither in my dev nor production environments.

const { override, addLessLoader } = require('customize-cra');

- module.exports = override(
-   addLessLoader({
-     javascriptEnabled: true,
-     modifyVars: {}
-   })
- )

+ const path = require('path')
+ const themes = require('./themes.config')
+ 
+ const merge = require('webpack-merge')
+ const multipleThemesCompile = require('webpack-multiple-themes-compile')
+ const multipleEntry = require('react-app-rewire-multiple-entry')
+ 
+ module.exports = {
+   webpack: function(config, env) {
+     // This is to re-format CRA's entries to make them compatible with multipleThemesCompile()
+     const appEntries = multipleEntry([{entry : 'src/index.js'}])
+     appEntries.addMultiEntry(config)
+     // Add theming
+     let multiTheme = multipleThemesCompile({
+        themesConfig: themes,
+        styleLoaders: [
+           { loader: 'css-loader' },
+           {
+             loader: 'less-loader',
+             options: {
+               lessOptions: {
+                 javascriptEnabled: true
+               }
+             }
+           }
+         ],
+         cwd: path.resolve('./')
+      })
+ 
+     /* Store the rule to load less/css files to put it where CRA stores these kind of rules
+      * (otherwise, duplicate rules with existing and the compiler will complain) */
+     var lessRule = multiTheme["module"]["rules"][0]
+     delete multiTheme["module"]["rules"]+ 
+      
+     // Change the location of css files to import them by name without knowing the id
+     multiTheme["plugins"][0]["options"]["chunkFilename"] = "css/[name].css"
+
+     // Merge default CRA config with themes' config. Now, we just need to fix the lessRule.
+     var newConfig = merge(config, multiTheme)+ 
+
+     // Add themes' rule to the beginning of existing 'oneOf' to make it the first to be applied
+     newConfig["module"]["rules"][2]["oneOf"].unshift(lessRule)+ 
+
+     return newConfig
+   }
+ }
+ function LoadCssFile(href, theme) {
+     const link = document.createElement('link')
+     link.rel = 'stylesheet'
+     link.href = href
+     link.dataset.theme = theme
+     document.head.appendChild(link)
+     return link
+ }
+ 
+ LoadCssFile('./css/dark.css');

ReactDOM.render(/*your app*/)
{
    /* your packages */
    "react": "^16.8.6",
    "less": "^3.9.0",
    "react-app-rewired": "^2.1.3",
    "rsuite": "4.7.2",
    /* new dependencies */
-   "less-loader": "^5.0.0",
+   "less-loader": "6.1.2",
+   "react-app-rewire-multiple-entry": "^2.2.0",
+   "webpack-merge": "^4.2.2",
+   "webpack-multiple-themes-compile": "^2.0.0"
}
module.exports = {
default: {'base-color': '#fff'},
dark: {'base-color': '#000'},
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment