No way to have multiple themes when working with Webpack.
andrewplummer opened this issue · 5 comments
Hi... first off thanks for the awesome library. The concept is fanstaic. However some of the implementation such as reversing the imports for the config (ie. importing theme.config
from the "inside out" -- from inside the node module into your source directory) make it very brittle to use with webpack it would seem. First off, is the only approach really to use webpack's resolve.alias
? Aside from feeling hacky, it leads to situations like where I want to compile multiple entry points and it doesn't seem possible... for example:
resolve: {
alias: {
'../../theme.config$': path.resolve('./src/app1/theme.config'),
'../../theme.config$': path.resolve('./src/app2/theme.config')
}
},
What is the official way to resolve the conflict with the above 2 lines? Yes of course I could split the webpack entry points out to different webpack configs but then I would lose the benefit of chunking as well as a lot of other hassles to deal with.
Thanks for the question. Have the same problem here... How build many themes using Webpack in order to use theme with a Theme selector in a React app ?
@andrewplummer Were you ever able to find a solution for this?
@aautem not really.. I find overriding the theming cumbersome anyway so I've been manually importing the specific styles I need for "functional styles" (like hiding/showing modals) and writing everything else from scratch
There is a way to build multiple themes in one project using less-loader:
This is the minimum configuration required for webpack:
{
resolve: {
alias: {
'../../theme.config$': path.join(paths.appSrc, '/semantic-ui/theme.config')
}
},
module: {
rules: [
{
test: /\.less$/,
use: [
{
loader: "less-loader",
options: {
additionalData: (content, loaderContext) => {
const { resourceQuery } = loaderContext;
const theme = /[?&]theme=([^?&]+)/.exec(resourceQuery);
if (theme) {
console.log("building custom theme: " + theme[1]);
return "@custom_theme: " + theme[1] + ";" + content;
}
return content;
},
},
},
],
},
],
},
}
or use craco config:
const CracoLessPlugin = require("craco-less");
module.exports = {
plugins: [{
plugin: CracoLessPlugin,
options: {
lessLoaderOptions: {
additionalData: (content, loaderContext) => {
const { resourceQuery } = loaderContext;
const theme = /[?&]theme=([^?&]+)/.exec(resourceQuery);
if (theme) {
console.log("building custom theme: " + theme[1]);
return "@custom_theme: " + theme[1] + ";" + content;
}
return content;
}
}
}
}]
};
In your theme.config you can now use multiple site directories or do other customizations based on the loaded theme:
/* Path to site override folder */
@siteFolder : '../../src/semantic-ui/@{custom_theme}/site';
Now you are able to lazy load your theme at runtime by adding a JS module for each theme like this one (./src/semantic-ui/dark.js
):
import 'semantic-ui-less/semantic.less?theme=dark';
To load the theme based on a query string for example you could do this in your main module:
const urlParams = new URLSearchParams(window.location.search);
const theme = urlParams.get('theme');
if (theme === 'dark') {
import('./semantic-ui/dark.js').then(render).catch(console.error);
} else {
import('./semantic-ui/light.js').then(render).catch(console.error);
}
const render = () => {
// theme is now loaded. render your app...
}