Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Long Module Build Chains #176

Closed
adjavaherian opened this issue Oct 21, 2015 · 5 comments
Closed

Long Module Build Chains #176

adjavaherian opened this issue Oct 21, 2015 · 5 comments

Comments

@adjavaherian
Copy link

The webpack analyzer identifies most of my .scss requires as long module build chains in the hints sections. But even when I pre-fetch the modules nearest to the scss require, I still see the warning and a difference of about 10s between the start time and end time of the scss partial build. I suspect that this is because I'm using the ExtractTextPlugin like so:

    module: {
        loaders: [
            {
                test: /\.scss$/,
                loader: ExtractTextPlugin.extract('style-loader', 'css!sass')
            }
        ]
    },

    plugins: [
        new ExtractTextPlugin('style.[name].[chunkhash].css', {
            disable: false,
            allChunks: true //extract all css from async chunks as well
        }),

And the process does not begin until the chunks are being emitted near the end of the compilation. How does this jive with your experience and what would speed up the build time? Can the sass-loader be configured to pre-fetch all scss and compile them async with node-sass while the rest of the compilation is working?

@jhnns
Copy link
Member

jhnns commented Oct 25, 2015

The build time heavily depends on how your styles are structured. I've described three different ways how to structure your styles.

I suspect that this is because I'm using the ExtractTextPlugin

I don't think so. The ExtractTextPlugin just "extracts" the CSS from the bundle (which is stored in a JS string). I don't see why that should take so much time.

Can the sass-loader be configured to pre-fetch all scss and compile them async with node-sass while the rest of the compilation is working

The sass-loader is async, it does not block webpack. However, the sass-loader does not know your scss files until webpack encounters a require() and invokes the sass-loader.

You could modify the sass-loader in your project to track when the sass-loader is actually invoked and how much time it spends on waiting for node-sass to compile. Then you could compare these figures against "vanilla" node-sass compilations. If they're almost identical, it's node-sass which takes so much time...

@Phoenixmatrix
Copy link

First, make sure to upgrade to node-sass 3.4. The 3.X line had a major performance regression that was fixed. The actual time spent in node-sass will pretty much be cut by 80% by using node-sass 3.4, which was released recently.

Second, if you're using css-loader and not using CSS modules, -downgrade- to css-loader 0.14.5, which is about 4x faster. The introduction of css modules and postcss and whatsnot slowed css-loader like crazy. 0.14.5 works fine and is the version right before the regression. If you do not need url resolution (common in development), pass css-loader the url=false argument. That speeds things up too.

If you do not need url and do not use CSS sourcemaps (you can use node-sass' sourceComments flag instead during development), you'll get another huge boost by using the raw-loader instead of css-loader.

Finally, since the ExtractTextPlugin needs to find your CSS in the huge amount of javascript to extract it, you can gain a 5-15% performance boost by making the file smaller: if you're simply requiring your CSS from your javascript entry point (and no requiring CSS from all over your JS modules), create a second webpack configuration (webpack.config can be an array of configs), with the CSS as entry points, so extracting the CSS will be super quick as there won't be any JS. I think the css loader gets invoked in a different way with ExtractTextPlugin which makes things worse, too. The latest webpack seems to handle this better, so upgrade that too.

Doing all of the above (especially the node-sass 3.4 upgrade, webpack 1.12.2, and not using css-loader > 0.14.5, brought our CSS compile time from 10-20s to <2s!!!.

Note that for SASS, incremental compile only makes a difference if you have a lot of chunks (unlike JS, where it can incrementally compile a single file inside a chunk), so if you have 1 big sass file with @import, you gain almost nothing with incremental.

@jhnns
Copy link
Member

jhnns commented Oct 29, 2015

Thx @Phoenixmatrix for your insights 👍

If the new css-loader is so much slower, it should probably be addressed as issue. Though CSS modules are a nice feature, it should not degrade the performance of those who don't want to use it.

If you do not need url resolution (common in development)

I don't get that... For me, url resolution is one of the reasons I would like to compile my styles via Webpack. And why would you like to have url resolution in production when you don't use it in development?

@Phoenixmatrix
Copy link

Yes, it should be fixed IMO. See webpack-contrib/css-loader#124

I also feel it breaks the philosophy behind webpack loaders. You should chain very task specific loaders...having a huge feature like CSS module be part of a basic loader like css-loader seems wrong. There should be a css-module-loader or something. css-loader should be about url resolution, sourcemaps, and thats about it.

For url resolution, maybe its because we migrated from rails and then gulp, but all our file paths work without url resolution for images, and for css files, we just use includePaths.

We use url resolution for hashed filenames for cache busting, rewriting to point to our CDN, as well as inlining small files as base64 urls. None of that matters anywhere except in production. Your millage may vary :) Webpack's sourcemaps support is fantastic ("It just works"), but our devs prefered seeing the compiled output with sourceComments, so we just ended up using raw-loader in dev, and css-loader for prod.

@jhnns
Copy link
Member

jhnns commented Mar 22, 2017

Closing this in favor of #296
I also did some profiling: #296 (comment)

@jhnns jhnns closed this as completed Mar 22, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants