【问题标题】:Improve webpack (4) css build performance提升webpack(四)css构建性能
【发布时间】:2018-09-23 14:23:05
【问题描述】:

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

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

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

比较:

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

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

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

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

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

  • JS 更新:150 毫秒

  • CSS 更新时间:1200-2000 毫秒

CSS builder 在这里表现不佳。此外,捆绑包越大,更新它们所需的时间就越长,即使更改是在一个应该立即编译的小文件中完成的。

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

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

我目前的猜测是 sass 加载器不使用缓存,并且在每次模块更新时,整个包都必须从头开始编译并再次通过 sass > postcss > css > extract 管道。我想知道将导入管理委托给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;

【问题讨论】:

    标签: javascript node.js webpack


    【解决方案1】:
    1. 将线程加载器添加到 js 处理加载器。
    2. 将 css-loader 替换为 fast-css-loader,将 sass-loader 替换为 fast-sass-loader。
    3. 将 cache-loader 作为 js 文件的第一个加载器,在 css 加载器中提取插件之后。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-02-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-09
      • 2018-01-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多