改进webpack(4)css构建性能

时间:2018-04-13 09:14:37

标签: javascript node.js webpack

我正在从gulp迁移到webpack设置。我想要webpack处理我的js和css资产并将它们打包成捆绑包。我已经设置了2个webpack配置文件:一个用于js,另一个用于css。

我项目中css和js资产的总大小相似:每个部分70个文件(缩小400kb)。

与js相比,我的问题与处理css资产时的webpack性能不佳有关。

比较:

  • JS build(首次运行):15-30秒
  • JS build(带缓存):2秒

  • CSS构建(首次运行):15秒

  • CSS构建(带缓存):10秒

    显然,CSS构建器不像CSS部分那样有效地使用缓存。说实话,我认为它根本不使用缓存(node_modules / .cache没有任何相关的东西),第二次运行更快的唯一原因是文件系统预热。

    手表模式下的问题更大。我做了一个测试,我在监视模式下运行webpack并修改一个小文件(只有几行),它必须包含在一个更大的包中:

  • JS更新:150毫秒

  • CSS更新:1200-2000ms

CSS构建器在这里表现不佳。此外,捆绑包越大,更新它们所需的时间就越长,即使在应该立即编译的小文件中进行更改也是如此。

此外,似乎增加入口点的数量也会对更新时间产生负面影响。更多条目=更新速度较慢,即使更新仅影响一个小文件。

我尝试过使用cache-loader并在提取插件之前和之后放置它。老实说,它没有多大帮助。当缓存加载器放在提取插件前面时,在监视模式下不会发出css(只有js文件)。在提取器之后放置缓存加载器会稍微改善生产构建,但会减慢监视模式更新。

我目前的猜测是sass加载器不使用缓存,并且在每个模块更新时,整个bundle必须从头开始编译并通过sass> postcss> css>再次提取管道。我想知道是否将导入管理委派给postcss-import并在postcss之后运行sass会做得更好。我曾尝试为postcss-import编写兼容sass的导入解析程序。它似乎在一个小的测试环境中工作得更快,但在我们的真实项目中使用它会导致webpack崩溃:(没有足够的时间来找出原因发生的原因。

如何改善当前设置的CSS构建时间?

我的JS和CSS配置如下。

JS:

const path  = require('path');
const merge = require('webpack-merge');
const EntryPlugin = require('webpack-watched-glob-entries-plugin');
const dir = require('./node/dirconfig');

// use NODE_ENV var to switch between production and development
const devel = (process.env.NODE_ENV == 'development');

// base config for both prod and devel modes
let config = 
{
    name: 'scripts',

    // webpack preset
    // this should take care of production optimizations automatically
    mode: devel ? 'development' : 'production',

    // use all js files inside bundle dir as entries
    entry: EntryPlugin.getEntries(
        dir.assets + '/js/bundle/*.js'
    ),

    output: {
        path: dir.static + '/js',
        filename: "[name].js"
    },

    externals: {
        jquery: 'jQuery'
    },

    resolve: {
        modules: [dir.assets + '/js', 'node_modules']
    },

    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        cacheDirectory: true,
                    },
                },
            },
        ]
    },

    plugins: [
        new EntryPlugin(),
    ],
};


// additional config for development mode
const development = 
{
    // add eslint loader
    module: {
        rules: [
            {
                enforce: "pre", // make sure this rule gets executed first
                test: /\.js$/,
                exclude: /(node_modules)/,
                use: {
                    loader: 'eslint-loader',
                    options: {
                        cache: true,
                    },
                },
            },
        ]
    }
};

module.exports = merge(config, devel ? development : {});

CSS:

const path = require('path');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const EntryPlugin = require('webpack-watched-glob-entries-plugin');
const dir = require('./node/dirconfig');

// use NODE_ENV var to switch between production and development
const devel = (process.env.NODE_ENV == 'development');

// base config for both prod and devel modes
let config = 
{
    name: 'styles',

    // webpack preset
    mode: devel ? 'development' : 'production',

    // use all .scss files which don't start with _ as entries
    entry: EntryPlugin.getEntries(
        dir.assets + '/sass/**/!(_*).scss'
    ),

    output: {
        path: dir.static + '/css',
        filename: "[name].js"
    },

    // enable sourcemaps in devel mode
    devtool: devel ? 'inline-source-map' : false,

    module: {
        rules: [
            {
                test: /\.scss$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    // 'cache-loader',
                    {
                        loader: 'css-loader',
                        options: {
                            sourceMap: devel,
                        }
                    },
                    {
                        loader: 'postcss-loader',
                        options: {
                            sourceMap: devel,
                        },
                    },
                    {
                        loader: 'sass-loader',
                        options: {
                            sourceMap: devel,
                        }
                    },
                ]
            },
        ]
    },

    plugins: [
        new MiniCssExtractPlugin({
            filename: "[name].css", // relative to path setting in the output section
        }),
        new EntryPlugin()
    ],
};

module.exports = config;

1 个答案:

答案 0 :(得分:0)

  1. 将线程加载器添加到处理加载器的js中。
  2. 用fast-css-loader替换css-loader,并用fast-sass-loader替换sass-loader。
  3. 将cache-loader放置为js文件的第一个加载器,并将其放置在css加载器中的extract插件之后。