Webpack打包构建太慢了?试试几个方法

Webpack是个很流行的打包工具,但其打包速度却一直被吐槽着

如果不用上一些打包的优化建议,单单打包两三个文件就能花上好几秒,放上几十个入口文件依赖几百上千个包的话,几分钟十几分钟妥妥的

本文整理了常见的一些方法,部分使用之后就看到了很大改善,部分没什么明显的变化,也可能是项目规模还不够大,先记录一下方法也好

一、使用监听模式或热更新热替换

webpack支持监听模式,此时需要重新编译时就可以进行增量构建,增量构建是很快的,基本不到一秒或几秒之内就能重新编译好

注意区分一下开发环境和线上环境,开发环境启用热更新替换

// 开发环境设置本地服务器,实现热更新
    devServer: {
        contentBase: path.resolve(__dirname, ‘static‘),
        // 提供给外部访问
        host: ‘0.0.0.0‘,
        port: 8388,
        // 允许开发服务器访问本地服务器的包JSON文件,防止跨域
        headers: {
            ‘Access-Control-Allow-Origin‘: ‘*‘
        },
        // 设置热替换
        hot: true,
        // 设置页面引入
        inline: true
    },

    // 文件输出配置
    output: {
        // 设置路径,防止访问本地服务器相关资源时,被开发服务器认为是相对其的路径
        publicPath: ‘http://localhost:8188/dist/js/‘,
    },

// 插件配置
    plugins: [
        // 热更新替换
        new webpack.HotModuleReplacementPlugin()
    ]

线上环境的编译,加个 --watch 参数就可以了

二、开发环境不做无意义的操作

很多配置,在开发阶段是不需要去做的,我们可以区分出开发和线上的两套配置,这样在需要上线的时候再全量编译即可

比如说 代码压缩、目录内容清理、计算文件hash、提取CSS文件等

三、选择一个合适的devtool属性值

配置devtool可以支持使用sourceMap,但有些是耗时严重的,这个得多试试

四、代码压缩用ParallelUglifyPlugin代替自带的 UglifyJsPlugin插件

自带的JS压缩插件是单线程执行的,而webpack-parallel-uglify-plugin可以并行的执行,在我的小demo中使用后,速度直接从25s变成了14s

      new webpack.optimize.UglifyJsPlugin({
            sourceMap: true,
            compress: {
                warnings: false
            }
        }),

ParallelUglifyPlugin = require(‘webpack-parallel-uglify-plugin‘)

new ParallelUglifyPlugin({
           cacheDir: ‘.cache/‘,
           uglifyJS:{
             output: {
               comments: false
             },
             compress: {
               warnings: false
             }
           }
         }),

五、css-loader使用0.15.0以下的版本

听闻这个版本以上的速度会慢许多,不过在我的小demo中还没看到明显变化

六、使用fast-sass-loader代替sass-loader

fast-sass-loader可以并行地处理sass,在提交构建之前会先组织好代码,速度也会快一些

七、babel-loader开启缓存

babel-loader在执行的时候,可能会产生一些运行期间重复的公共文件,造成代码体积大冗余,同时也会减慢编译效率

可以加上cacheDirectory参数或使用 transform-runtime 插件试试

// webpack.config.js
use: [{
                loader: ‘babel-loader‘,
                options: {
                    cacheDirectory: true
                }]

// .bablerc
{
    "presets": [
        "env",
        "react"
    ],
    "plugins": ["transform-runtime"]
}

八、不需要打包编译的插件库换成全局<script>标签引入的方式

比如jQuery插件,react, react-dom等,代码量是很多的,打包起来可能会很耗时

可以直接用标签引入,然后在webpack配置里使用 expose-loader  或 externals 或 ProvidePlugin  提供给模块内部使用相应的变量

// @1
use: [{
                loader: ‘expose-loader‘,
                options: ‘$‘
            }, {
                loader: ‘expose-loader‘,
                options: ‘jQuery‘
            }]

// @2
externals: {
        jquery: ‘jQuery‘
    },

// @3
        new webpack.ProvidePlugin({
            $: ‘jquery‘,
            jQuery: ‘jquery‘,
            ‘window.jQuery‘: ‘jquery‘
        }),

九、使用 DllPlugin 和 DllReferencePlugin

这种方式其实和externals是类似的,主要用于有些模块没有可以在<script>标签中引入的资源(纯npm包)

Dll是动态链接库的意思,实际上就是将这些npm打包生成一个JSON文件,这个文件里包含了npm包的路径对应信息

这两个插件要一起用

首先,新建一个dll.config.js配置文件,先用webpack来打包这个文件

const webpack = require(‘webpack‘);
const path = require(‘path‘);

module.exports = {
    output: {
        // 将会生成./ddl/lib.js文件
        path: path.resolve(__dirname, ‘ddl‘),
        filename: ‘[name].js‘,
        library: ‘[name]‘,
    },
    entry: {
        "lib": [
            ‘react‘,
            ‘react-dom‘,
            ‘jquery‘
            // ...其它库
        ],
    },
    plugins: [
        new webpack.DllPlugin({
            // 生成的映射关系文件
            path: ‘manifest.json‘,
            name: ‘[name]‘,
            context: __dirname,
        }),
    ],
};

在manifest.json文件中就是相应的包对应的信息

然后在我们的项目配置文件中配置DllReferencePlugin 使用这个清单文件

    // 插件配置
    plugins: [
        new webpack.DllReferencePlugin({
            context: __dirname,
            manifest: require(‘./manifest.json‘)
        }),

十、提取公共代码

使用CommonsChunkPlugin提取公共的模块,可以减少文件体积,也有助于浏览器层的文件缓存,还是比较推荐的

 // 提取公共模块文件
        new webpack.optimize.CommonsChunkPlugin({
            chunks: [‘home‘, ‘detail‘],
            // 开发环境下需要使用热更新替换,而此时common用chunkhash会出错,可以直接不用hash
            filename: ‘[name].js‘ + (isProduction ? ‘?[chunkhash:8]‘ : ‘‘),
            name: ‘common‘
        }),

// 切合公共模块的提取规则,有时后你需要明确指定默认放到公共文件的模块
// 文件入口配置
    entry: {
        home: ‘./src/js/home‘,
        detail: ‘./src/js/detail‘,
        // 提取jquery入公共文件
        common: [‘jquery‘, ‘react‘, ‘react-dom‘]
    },

十一、使用HappyPack来加速构建

HappyPack会采用多进程去打包构建,使用方式还是蛮简单的,但并不是支持所有的loader

首先引入,定义一下这个插件所开启的线程,推荐是四个,其实也可以直接使用默认的就行了

HappyPack = require(‘happypack‘),
    os = require(‘os‘),
    happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });

然后在module的规则里改动一下,引入它,其中 id是一个标识符

{
            test: /\.jsx?$/,
            // 编译js或jsx文件,使用babel-loader转换es6为es5
            exclude: /node_modules/,
            loader: ‘HappyPack/loader?id=js‘
            // use: [{
            //     loader: ‘babel-loader‘,
            //     options: {

            //     }
            // }]
        }

然后我们调用插件,设置匹配的id,然后相关的配置可以直接把use:的规则部分套在loaders上

new HappyPack({
            id: ‘js‘,
            loaders: [{
                loader: ‘babel-loader‘,
                options: {
                    // cacheDirectory: true
                }
            }]
        }),

要注意的第一点是,它对file-loader和url-loader支持不好,所以这两个loader就不需要换成happypack了,其他loader可以类似地换一下

要注意的第二点是,使用ExtractTextWebpackPlugin提取css文件也不是完全就能转换过来,所以需要小小的改动一下,比如

module: {
        rules: [{
            test: /\.css$/,
            // loader: ‘HappyPack/loader?id=css‘
            // 提取CSS文件
            use: cssExtractor.extract({
                // 如果配置成不提取,则此类文件使用style-loader插入到<head>标签中
                fallback: ‘style-loader‘,
                use: ‘HappyPack/loader?id=css‘
                // use: [{
                //         loader: ‘css-loader‘,
                //         options: {
                //             // url: false,
                //             minimize: true
                //         }
                //     },
                //     // ‘postcss-loader‘
                // ]
            })
        }, {
            test: /\.scss$/,
            // loader: ‘HappyPack/loader?id=scss‘
            // 编译Sass文件 提取CSS文件
            use: sassExtractor.extract({
                // 如果配置成不提取,则此类文件使用style-loader插入到<head>标签中
                fallback: ‘style-loader‘,
                use: ‘HappyPack/loader?id=scss‘
                // use: [
                //     ‘css-loader‘,
                //     // ‘postcss-loader‘,
                //     {
                //         loader: ‘sass-loader‘,
                //         options: {
                //             sourceMap: true,
                //             outputStyle: ‘compressed‘
                //         }
                //     }
                // ]
            })
        }

因为它是直接函数调用的,我们就放到里层的use规则就行了,然后配置插件即可

plugins: [
        new HappyPack({
            id: ‘css‘,
            loaders: [{
                loader: ‘css-loader‘,
                options: {
                    // url: false,
                    minimize: true
                }
            }]
        }),
        new HappyPack({
            id: ‘scss‘,
            loaders: [{
                ‘loader‘: ‘css-loader‘
            }, {
                loader: ‘fast-sass-loader‘,
                options: {
                    sourceMap: true,
                    outputStyle: ‘compressed‘
                }
            }]
        }),

十二、优化构建时的搜索路径

在webpack打包时,会有各种各样的路径要去查询搜索,我们可以加上一些配置,让它搜索地更快

比如说,方便改成绝对路径的模块路径就改一下,以纯模块名来引入的可以加上一些目录路径

还可以善于用下resolve alias别名 这个字段来配置

还有exclude等的配置,避免多余查找的文件,比如使用babel别忘了剔除不需要遍历的

{
            test: /\.jsx?$/,
            // 编译js或jsx文件,使用babel-loader转换es6为es5
            exclude: /node_modules/,
             use: [{
                 loader: ‘babel-loader‘,
                 options: {

                 }
             }]
        }

十三、(导出编译JSON文件)理一下打包构建涉及的模块,分析看有哪些包是不需要打包的,只打包需要的模块

检查一下代码,看看是不是有不需要引入的模块出现在代码里

webpack编译时加上参数 --json > stat.json 后,可以上传到 webpack-analysewebpack-visualizer等分析站点上,看看打包的模块信息

十四、使用ModuleConcatenationPlugin插件来加快JS执行速度

这是webpack3的新特性(Scope Hoisting),其实是借鉴了Rollup打包工具来的,它将一些有联系的模块,放到一个闭包函数里面去,通过减少闭包函数数量从而加快JS的执行速度

 new webpack.optimize.ModuleConcatenationPlugin({

        })

十五、使用noParse

webpack打包的时候,有时不需要解析某些模块的依赖(这些模块并没有依赖,或者并根本就没有模块化),我们可以直接加上这个参数,直接跳过这种解析

module: {
    noParse: /node_modules\/(jquey\.js)/
  }

十六、使用异步的模块加载

这个算是可以减小模块的体积吧,在一定程度上也是为用户考虑的,使用require.ensure来设置哪些模块需要异步加载,webpack会将它打包到一个独立的chunk中,

在某个时刻(比如用户点击了查看)才异步地加载这个模块来执行

$(‘.bg-input‘).click(() => {
    console.log(‘clicked, loading async.js‘)

    require.ensure([], require => {

        require(‘./components/async2‘).log();
        require(‘./components/async1‘).log();
        console.log(‘loading async.js done‘);
    });
});

十七、以模块化来引入

有些模块是可以以模块化来引入的,就是说可以只引入其中的一部分,比如说lodash

// 原来的引入方式
 import {debounce} from ‘lodash‘;

//按模块化的引入方式
import debounce from ‘lodash/debounce‘;

主要是整理过来的,试用了几个方法,首次编译的速度可以从之前半分多钟减小到十秒左右了,当然,开启了热更新替换后简直美不可言

当然还有很多方法没整理出,这些方法是有使用场景的,并不是每个都需要用,需要在自己的项目中尝试,结合配置它的复杂性和带来的效应来权衡。

时间: 2024-11-05 19:35:55

Webpack打包构建太慢了?试试几个方法的相关文章

Webpack打包进阶

说在前面 由于使用了React直出,页面各项性能指标使人悦目.本篇将深入探讨目前PC部落所采用webpack打包优化策略,以及探讨PC部落并未使用的 webpack Code Splitting 代码分包.异步模块加载特性.看看它们又是如何对PC部落的性能起到进一步的催化作用. 为什么要使用webpack 如果你曾经使用过 Broserify, RequireJS 或类似的打包工具,并注重:代码分包.异步加载.静态资源打包(图片/CSS).那么 webpack 就是帮你构建项目的利器!简单一句话

Webpack 打包太慢? 试试 Dllplugin

webpack在build包的时候,有时候会遇到打包时间很长的问题,这里提供了一个解决方案,让打包如丝般顺滑~ 1. 介绍 在用 Webpack 打包的时候,对于一些不经常更新的第三方库,比如 react,lodash,vue 我们希望能和自己的代码分离开,Webpack 社区有两种方案 CommonsChunkPlugin DLLPlugin 对于 CommonsChunkPlugin,webpack 每次打包实际还是需要去处理这些第三方库,只是打包完之后,能把第三方库和我们自己的代码分开.而

Vue项目模板--和--webpack自动化构建工具的---项目打包压缩使用

[首先安装node.js]: 1. 从node.js官网下载并安装node,安装过程很简单. 2. npm 版本需要大于 3.0,如果低于此版本需要升级它: # 查看版本 npm -v2.3.0 #升级 npm cnpm install npm -g 3.基于node.js,利用淘宝npm镜像安装相关依赖.由于国内使用npm会很慢,这里推荐使用淘宝NPM镜像(http://npm.taobao.org/) npm install -g cnpm --registry=https://regist

实现webpack的实时打包构建

1. 由于每次重新修改代码之后,都需要手动运行webpack打包的命令,比较麻烦,所以使用`webpack-dev-server`来实现代码实时打包编译,当修改代码之后,会自动进行打包构建.2. 运行`cnpm i webpack-dev-server --save-dev`安装到开发依赖3. 安装完成之后,在命令行直接运行`webpack-dev-server`来进行打包,发现报错,此时需要借助于`package.json`文件中的指令,来进行运行`webpack-dev-server`命令,

webpack + vue2 构建vue项目骨架

前端项目打包工具webpack与前端开发框架vue,算是现在前后端分离后非常流行的技术了,今天主要讲的是使用webpack和vue2构建一个前后端分离项目的基本骨架.虽然使用vue-cli脚手架可以帮我们搭建好一个项目骨架,但是了解原理我觉得还是很重要的,所以这篇文章主要就写webpack与vue构建一个基础项目.前提是已经安装了nodejs. 整个项目需要通过npm安装的依赖 css : style-loader.css-loader.sass-loader.node-sass js:babe

webpack打包多页面的方式

一开始接触webpack是因为使用Vue的关系,因为Vue的脚手架就是使用webpack构建的.刚开始的时候觉得webpack就是为了打包单页面而生的,后来想想,这么好的打包方案,只在单页面上使用是否太浪费资源了呢?如果能在传统多页面上使用webpack,开始效率是否会事半功倍呢?好在众多优秀的前端开发者已经写了许多demo和文章供人学习.我也写了一个小项目,希望对大家学习webpack有帮助. webpack-multi-page   项目解决的问题 SPA好复杂,我还是喜欢传统的多页应用怎么

webpack前端构建工具学习总结(四)之自动化生成项目中的html页面

接续上文:webpack前端构建工具学习总结(三)之webpack.config.js配置文件 1.安装html-webpack-plugin插件,输入命令:npm install html-webpack-plugin --save-dev 2.在webpack.config.js文件中,引入html-webpack-plugin插件 3.输入命令:npm run webpack,编译打包 可以看到在dist/js目录下新生成了一个index.html文件,并且引入了新编译生成的两个js,但此

[转]webpack进阶构建项目(一)

阅读目录 1.理解webpack加载器 2.html-webpack-plugin学习 3.压缩js与css 4.理解less-loader加载器的使用 5.理解babel-loader加载器 6.理解 extract-text-webpack-plugin(独立打包样式文件) 7.webpack打包多个资源文件 8.webpack对图片的打包 9.学习web-dev-server 创建服务器及动态监听css及js文件的改变: 10.assets-webpack-plugin插件解决html文件

webpack进阶构建项目(一)

阅读目录 1.理解webpack加载器 2.html-webpack-plugin学习 3.压缩js与css 4.理解less-loader加载器的使用 5.理解babel-loader加载器 6.理解 extract-text-webpack-plugin(独立打包样式文件) 7.webpack打包多个资源文件 8.webpack对图片的打包 9.学习web-dev-server 创建服务器及动态监听css及js文件的改变: 10.assets-webpack-plugin插件解决html文件