I am currently developing an application which uses different frontend-themes. These themes are simply CSS-Files which can be selected by the user.
Technically these themes are .scss-files which are compiled by webpack and loaded via standard link-tag in angular:
<link rel="stylesheet", ng-href="themes/{{theme}}.css">
My stripped webpack config looks like this:
theme1CssExtractor = new ExtractTextPlugin('themes/theme-1.css'),
theme2CssExtractor = new ExtractTextPlugin('themes/theme-2.css'),
module.exports = new WebpackConfig().merge({
entry: {
app: [
'./app/main.ts',
'./assets/sass/themes/theme-1.scss',
'./assets/sass/themes/theme-2.scss'
],
},
output: {
path: "build/",
filename: "[name].bundle.js",
publicPath: "/build/"
},
plugins: [
theme1CssExtractor,
theme2CssExtractor,
],
module: {
loaders: [
{
test: /\.ts$/,
loaders: ['awesome-typescript-loader']
},
[
{
test: /theme-1\.scss$/,
include: path.resolve(__dirname, "assets/sass/themes"),
loader: theme1CssExtractor.extract(
"style",
"css!sass?includePaths[]=" + path.resolve(__dirname, './node_modules/compass-mixins/lib')
)
},
{
test: /theme-2\.scss$/,
include: path.resolve(__dirname, "assets/sass/themes"),
loader: theme2CssExtractor.extract(
"style",
"css!sass?includePaths[]=" + path.resolve(__dirname, './node_modules/compass-mixins/lib')
)
}
]
]
}
This works completly fine until I want to use the webpack-dev-server with hot module replacement (HMR) feature enabled, because extractTextPlugin does not support HMR. When I simply disable extractTextPlugin (options.disable) or remove them, all themes are compiled into main module and this - of cource - breaks the themes because all are applied together.
How can I generate these CSS-Files directly with webpack without using the extractTextPlugin? I tried various attempts with different enntries/chunks, file-loaders, ... but nothing really works.
It should be simple: Generate static CSS-Files from SCSS-Files without transforming them into JS-Files without using ExtractTextPlugin.
It would be great, if someone could point me in the right direction.
One approach could be to organize your Webpack config in the way that it respects different modes:
You may take a look at how it's done in este.
Regarding the problem that you have without ExtractTextPlugin (one file that contains all themes): it happens because your configuration contains both theme-1.scss
and theme-2.scss
as entry points in 'app' chunk, so Webpack puts them together (one chunk). You can try to go another way: exclude them from the list of entry points, and add in your source code something like:
require('../assets/sass/themes/' + theme + '.scss');
In this case in development mode you'll get only one module (theme) loaded depending on the value of variable "theme". And in production mode Webpack will go through all files in 'assets/sass/themes/' (specific Webpack behavior when 'require' contains expression), including them as modules, and then ExtractTextPlugin will handle their extraction (so you don't have to do anything here).
There is some tricky part about how then in production the particular theme is loaded (because "require" that you have in the code will do nothing, ExtractTextPlugin will leave the corresponding modules empty), so you have to put some code that adds <link>
to the <head>
of your HTML. And at the same time this code shouldn't be invoked in the development mode. One dirty hack that could help achieving it:
if (!__DEV__) {
// do adding <link> to the <head>
}
(see also in the este example how DefinePlugin could be used to define __DEV__
variable).
I'm really curious how it could be solved in a better way...
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