Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generate static CSS files with webpack

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.

like image 234
Cornelius Schmale Avatar asked Oct 28 '15 13:10

Cornelius Schmale


1 Answers

One approach could be to organize your Webpack config in the way that it respects different modes:

  • development: don't use ExtractTextPlugin (see later about the problem with one file that includes everything)
  • production: use ExtractTextPlugin as you do right now

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...

like image 183
Ivan Kornienko Avatar answered Oct 18 '22 22:10

Ivan Kornienko