webpack在打包中体积和速度上的一点优化

    xiaoxiao2022-07-03  127

    一、配置 resolve.modules

    1,优化原理

    (1)webpack 的 resolve.modules 是用来配置模块库(即 node_modules)所在的位置。当 js 里出现 import 'vue' 这样不是相对、也不是绝对路径的写法时,它便会到 node_modules 目录下去找。

    (2)在默认配置下,webpack 会采用向上递归搜索的方式去寻找。但通常项目目录里只有一个 node_modules,且是在项目根目录。为了减少搜索范围,可我们以直接写明 node_modules 的全路径。

     

    2,操作步骤

    (1)打开 build/webpack.base.conf.js 文件,添加如下高亮配置:

    module.exports = { resolve: { extensions: ['.js', '.vue', '.json'], modules: [ resolve('src'), resolve('node_modules') ], alias: { 'vue$': 'vue/dist/vue.esm.js', '@': resolve('src'), } },

    二、配置装载机的 include & exclude

    1,优化原理

     Webpack 的装载机(loaders),允许每个子项都可以有以下属性:

    test:必须满足的条件(正则表达式,不要加引号,匹配要处理的文件)exclude:不能满足的条件(排除不处理的目录)include:导入的文件将由加载程序转换的路径或文件数组(把要处理的目录包括进来)loader:一串“!”分隔的装载机(2.0版本以上,”-loader”不可以省略)loaders:作为字符串的装载器阵列

    对于include,更精确指定要处理的目录,这可以减少不必要的遍历,从而减少性能损失。同样,对于已经明确知道的,不需要处理的目录,则应该予以排除,从而进一步提升性能。假设你有一个第三方组件的引用,它肯定位于node_modules,通常它将有一个 src 和一个 dist 目录。如果配置 Webpack 来排除 node_modules,那么它将从 dist 已经编译的目录中获取文件。否则会再次编译它们。故而,合理的设置 include & exclude,将会极大地提升 Webpack 打包优化速度

     

    2,操作步骤

    (1)打开 build/webpack.base.conf.js 文件,添加如下高亮配置:

    module: { rules: [ { test: /\.vue$/, loader: 'vue-loader', options: vueLoaderConfig, include: [resolve('src')], exclude: /node_modules\/(?!(autotrack|dom-utils))|vendor\.dll\.js/ }, { test: /\.js$/, loader: 'babel-loader', include: [resolve('src')], exclude: /node_modules/ },

    三、使用 webpack-parallel-uglify-plugin 插件来压缩代码

    1,优化原理

    (1)默认情况下 webpack 使用 UglifyJS 插件进行代码压缩,但由于其采用单线程压缩,速度很慢。

    (2)我们可以改用 webpack-parallel-uglify-plugin 插件,它可以并行运行 UglifyJS 插件,从而更加充分、合理的使用 CPU 资源,从而大大减少构建时间。

     

    2,操作步骤

    (1)执行如下命令安装 webpack-parallel-uglify-plugin

    npm i webpack-parallel-uglify-plugin

     

    (2)打开 build/webpack.prod.conf.js 文件,并作如下修改:

    const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin'); //.... // 删掉webpack提供的UglifyJS插件 //new UglifyJsPlugin({ // uglifyOptions: { // compress: { // warnings: false // } // }, // sourceMap: config.build.productionSourceMap, // parallel: true //}), // 增加 webpack-parallel-uglify-plugin来替换 new ParallelUglifyPlugin({ cacheDir: '.cache/', uglifyJS:{ output: { comments: false }, compress: { warnings: false } } }),

    四、使用 HappyPack 来加速代码构建

    1,优化原理

    你知道,Webpack 中为了方便各种资源和类型的加载,设计了以 loader 加载器的形式读取资源,但是受限于 nodejs 的编程模型影响,所有的 loader 虽然以 async 的形式来并发调用,但是还是运行在单个 node 的进程,以及在同一个事件循环中,这就直接导致了些问题:当同时读取多个loader文件资源时,比如`babel-loader`需要 transform 各种jsx,es6的资源文件。在这种同步计算同时需要大量耗费 cpu 运算的过程中,node的单进程模型就无优势了,而 Happypack 就是针对解决此类问题而生的存在。

    Happypack 的处理思路是:将原有的 webpack 对 loader 的执行过程,从单一进程的形式扩展多进程模式,从而加速代码构建;原本的流程保持不变,这样可以在不修改原有配置的基础上,来完成对编译过程的优化。

    通过在 loader 中配置直接指向 happypack 提供的 loader,对于文件实际匹配的处理 loader,则是通过配置在 plugin 属性来传递说明,这里 happypack 提供的 loader 与 plugin 的衔接匹配,则是通过id=happybabel来完成。

    Happypack 在编译过程中,除了利用多进程的模式加速编译,还同时开启了 cache 计算,能充分利用缓存读取构建文件,对构建的速度提升也是非常明显的;更多关于 happyoack 个中原理,可参见 @淘宝前端团队(FED) 的这篇:happypack 原理解析。如果你使用的 Vue.js 框架来开发,也可参考 vue-webpack-happypack 相关配置。

     

    2,操作步骤

    (1)执行如下命令安装 happypack:

    npm i happypack

    (2)打开 build/webpack.base.conf.js 文件,并作如下修改:

    const HappyPack = require('happypack'); const os = require('os'); const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length }); module.exports = { module: { rules: [ { test: /\.js$/, //把对.js 的文件处理交给id为happyBabel 的HappyPack 的实例执行 loader: 'happypack/loader?id=happyBabel', include: [resolve('src')], //排除node_modules 目录下的文件 exclude: /node_modules/ }, ] }, plugins: [ new HappyPack({ //用id来标识 happypack处理那里类文件 id: 'happyBabel', //如何处理 用法和loader 的配置一样 loaders: [{ loader: 'babel-loader?cacheDirectory=true', }], //共享进程池 threadPool: happyThreadPool, //允许 HappyPack 输出日志 verbose: true, }) ] }

    五、利用 DllPlugin 和 DllReferencePlugin 预编译资源模块

    1,优化原理

    (1)我们的项目依赖中通常会引用大量的 npm 包,而这些包在正常的开发过程中并不会进行修改,但是在每一次构建过程中却需要反复的将其解析,而下面介绍的两个插件就是用来规避此类损耗的:

    DllPlugin 插件:作用是预先编译一些模块。DllReferencePlugin 插件:它的所用则是把这些预先编译好的模块引用起来。

    (2)注意:DllPlugin 必须要在 DllReferencePlugin 执行前先执行一次,dll 这个概念应该也是借鉴了 windows 程序开发中的 dll 文件的设计理念。

     

    2,操作步骤

    (1)在 build 文件夹中新建 webpack.dll.conf.js 文件,内容如下(主要是配置下需要提前编译打包的库):

    const path = require('path'); const webpack = require('webpack'); module.exports = { entry: { vue: ['vue/dist/vue.esm.js', 'vuex', 'vue-router'], //也可以只生成一个dll文件 vendor: ['lodash', 'axios'], common: ['element-ui'], antv1: ['@antv/g2'], antv2: ['@antv/data-set'] }, output: { path: path.join(__dirname, '../static/js'), filename: '[name].dll.js', library: '[name]_library' // vendor.dll.js中暴露出的全局变量名 }, plugins: [ new webpack.DllPlugin({ path: path.join(__dirname, '.', '[name]-manifest.json'), name: '[name]_library' }), new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }) ] };

     

    (2)编辑 package.json 文件,添加一条编译命令:

    "dll": "webpack --config build/webpack.dll.conf.js"

    (3)接着执行 npm run dll 命令来生成对应的 dll.js。

    注意:如果之后这些需要预编译的库又有变动,则需再次执行 npm run build:dll 命令来重新生成 dll.js

    (4)index.html 这边将 dll.js 引入进来。

    <body> <div id="app"></div> <script src="./static/js/vue.dll.js"></script> ··· // 你生成了几个dll都加进来 <script src="./static/js/vendor.dll.js"></script> </body>

    (5)打开 build/webpack.base.conf.js 文件,编辑添加如下高亮配置,作用是通过 DLLReferencePlugin 来使用 DllPlugin 生成的 DLL Bundle。

    const webpack = require('webpack'); module.exports = { context: path.resolve(__dirname, '../'), entry: { app: './src/main.js' }, //..... plugins: [ // 添加DllReferencePlugin插件 new webpack.DllReferencePlugin({ // 前面添加了几个这里就添加几个 context: path.resolve(__dirname, '..'), manifest: require('./vue-manifest.json') }), new webpack.DllReferencePlugin({ context: path.resolve(__dirname, '..'), manifest: require('./common-manifest.json') }), new webpack.DllReferencePlugin({ context: path.resolve(__dirname, '..'), manifest: require('./vendor-manifest.json') }), new webpack.DllReferencePlugin({ context: path.resolve(__dirname, '..'), manifest: require('./antv1-manifest.json') }), new webpack.DllReferencePlugin({ context: path.resolve(__dirname, '..'), manifest: require('./antv2-manifest.json') }) ] }
    最新回复(0)