0打包优化战略收拾小结_javascript技艺_脚本之家

作者: 澳门金莎娱乐网站  发布:2019-11-28

简介

本文介绍了webpack4.0打包优化策略整理小结,分享给大家,具体如下:

读了《深入浅出webpack》总结一下常用的webpack的构建优化策略,可通过以下手段来提升项目构建时的速度

webapck4 新特性介绍-参考资料

更精准的loader规则

1.优化loader配置

将loader规则写清楚

1.1 缩小文件匹配范围

仅让需要处理的文件,进入loader处理环节,如下

通过排除node_modules下的文件 从而缩小了loader加载搜索范围 高概率命中文件

 rules: [{ // 正则尽量准确 test: /.js$/, // 使用缓存,缓存后在文件未改变时编译会更快 use: ['babel-loader?cacheDirectory'], // 指定需要处理的目录 include: path.resolve // 理论上只有include就够了,但是某些情况需要排除文件的时候可以用这个,排除不需要处理文件 // exclude: [] }]
 module: { rules: [ { test: /.js$/, use: 'babel-loader', exclude: /node_modules/, // 排除不处理的目录 include: path.resolve // 精确指定要处理的目录 } ] }

更精准的查找目录

1.2 缓存loader的执行结果

理论上我们项目的第三方依赖均应在自己的工程的node_modules下,所以我们可以设置查找目录,减少node的默认查找

cacheDirectory是loader的一个特定的选项,默认值是false。指定的目录(use: 'babel-loader?cacheDirectory=cacheLoader')将用来缓存loader的执行结果,减少webpack构建时Babel重新编译过程。如果设置一个空值(use: 'babel-loader?cacheDirectory') 或true(use: 'babel-loader?cacheDirectory=true') 将使用默认的缓存目录(node_modules/.cache/babel-loader),如果在任何根目录下都没有找到 node_modules 目录,将会降级回退到操作系统默认的临时文件目录。

module.exports = { resolve: { // 指定当前目录下的node_modules目录 modules: [path.resolve(__dirname, 'node_modules')] }}
module: { rules: [ { test: /.js$/, use: 'babel-loader?cacheDirectory', // 缓存loader执行结果 发现打包速度已经明显提升了 exclude: /node_modules/, include: path.resolve } ]}

更精准的扩展名

2.resolve优化配置

数量更多类型的文件尽量放在前面

2.1 优化模块查找路径 resolve.modules

平时写代码,我们都习惯直接写文件名,而不去写扩展名,那么解析则按照下面属性进行解析

Webpack的resolve.modules配置模块库所在的位置,在 js 里出现 import 'vue' 这样不是相对、也不是绝对路径的写法时,会去 node_modules 目录下找。但是默认的配置,会采用向上递归搜索的方式去寻找,但通常项目目录里只有一个 node_modules,且是在项目根目录,为了减少搜索范围,可以直接写明 node_modules 的全路径;同样,对于别名的配置,亦当如此:

module.exports = { extensions: ['.js', '.jsx', '.ts', '.tsx'],}

extensions: [".js", ".json"]
const path = require;function resolve { // 转换为绝对路径 return path.join;}resolve: { modules: [ // 优化模块查找路径 path.resolve, path.resolve // 指定node_modules所在位置 当你import 第三方模块时 直接从这个路径下搜索寻找 ]}

使用动态链接库预编译大模块

配置好src目录所在位置后,由于util目录是在src里面 所以可以用下面方式引入util中的工具函数

使用动态链接库,提前编译大模块

// main.jsimport dep1 from 'util/dep1';import add from 'util/add';

新建一个文件webpack_dll.config.js,内容如下

2.2 resolve.alias 配置路径别名

const path = require;const webpack = require;// 复用的大模块放在这里,这样每次都不需要重新编译了const vendors = [ 'react', 'react-dom', 'lodash'];module.exports = { mode: 'development', output: { path: path.resolve, filename: '[name].js', library: '[name]', }, entry: { vendors, }, plugins: [ new webpack.DllPlugin({ path: path.resolve(__dirname, './dist/manifest.json'), name: '[name]', }), ],};

创建 import 或 require 的路径别名,来确保模块引入变得更简单。配置项通过别名来把原导入路径映射成一个新的导入路径 此优化方法会影响使用Tree-Shaking去除无效代码

执行webpack --config webpack_dll.config.js进行首次编译

例如,一些位于 src/ 文件夹下的常用模块:

然后在你的webpack配置文件中引入manifest.json

alias: { Utilities: path.resolve(__dirname, 'src/utilities/'), Templates: path.resolve(__dirname, 'src/templates/')}
 plugins: [ new webpack.DllReferencePlugin({ manifest: require('./dist/manifest.json') }) ],

现在,替换「在导入时使用相对路径」这种方式,就像这样:

多进程处理文件

import Utility from '../../utilities/utility';

import Utility from 'Utilities/utility';

resolve: { alias: { // 别名配置 通过别名配置 可以让我们引用变的简单 'vue$': 'vue/dist/vue.common.js', // $表示精确匹配 src: resolve // 当你在任何需要导入src下面的文件时可以 import moduleA from 'src/moduleA' src会被替换为resolve 返回的绝对路径 而不需要相对路径形式导入 }}

使用HappyPack同时处理多个loader编译任务

也可以在给定对象的键后的末尾添加 $,以表示精准匹配:

为了发挥多核CPU电脑的功能,利用HappyPack将任务分发给多个子进程并发执行

alias: { util$: resolve}

import Test1 from 'util'; // 精确匹配,所以 src/util/add.js 被解析和导入import Test2 from 'util/dep1.js'; // 精确匹配,触发普通解析 util/dep1.js
const path = require;const HappyPack = require;// 共享5个进程池const happyThreadPool = HappyPack.ThreadPool;module.exports = { entry: './src/index.js', output: { filename: 'bundle.js', path: path.resolve, }, module: { // noParse: [/react.production.min.js$/], rules: [{ test: /.js$/, // 和下面插件id一直,happypack才可以找到 use: ['happypack/loader?id=babel'], include: path.resolve }] }, plugins: [ // 插件可以实例化多个 new HappyPack({ // 与上面对应 id: 'babel', // 实际要使用的loader loaders: ['babel-loader?cacheDirectory'], // 默认开启进程数 threads: 3, // 是否允许happyPack打印日志 verbose: true, // 共享进程数,如果你使用超过一个happyplugin,官方建议共享进程池 threadPool: happyThreadPool }) ],};

2.3resolve.extensions

多进程压缩文件

当引入模块时不带文件后缀 webpack会根据此配置自动解析确定的文件后缀

使用ParallelUglifyPlugin多进程同时压缩文件

后缀列表尽可能小 频率最高的往前放 导出语句尽可能带上后缀

ParallelUglifyPlugin是在UglifyJS基础上,增加了多进出处理的能力,加快了压缩速度

resolve: { extensions: ['.js', '.vue']}
import ParallelUglifyPlugin from 'webpack-parallel-uglify-plugin'; module.exports = { plugins: [ new ParallelUglifyPlugin({ test, include, exclude, cacheDir, workerCount, sourceMap, uglifyJS: { }, uglifyES: { } }), ],};

3.module.noParse

减少监听文件

用了noParse的模块将不会被loaders解析,所以当我们使用的库如果太大,并且其中不包含import require、define的调用,我们就可以使用这项配置来提升性能, 让 Webpack 忽略对部分没采用模块化的文件的递归解析处理。

减少监听文件

// 忽略对jquery lodash的进行递归解析module: { // noParse: /jquery|lodash/ // 从 webpack 3.0.0 开始 noParse: function { return /jquery|lodash/.test }}

当我们使用webpack的watch功能进行文件监听时,更好的方式是控制监听目录,如下,排除node_modules减少对该目录监听,减少编译所需要循环的文件,提高检查速度

4.HappyPack

module.export = { watchOptions: { ignored: /node_modules/ }}

HappyPack是让webpack对loader的执行过程,从单一进程形式扩展为多进程模式,也就是将任务分解给多个子进程去并发的执行,子进程处理完后再把结果发送给主进程。从而加速代码构建 与 DLL动态链接库结合来使用更佳。

其他没那么重要的优化

npm i happypack@next -D

更精准的mainFields

webpack.config.js

默认的这个值查找方式见官网点击此处

const HappyPack = require;const os = require; // node 提供的系统操作模块 // 根据我的系统的内核数量 指定线程池个数 也可以其他数量const happyThreadPool = HappyPack.ThreadPool.lenght})module: { rules: [ { test: /.js$/, use: 'happypack/loader?id=babel', exclude: /node_modules/, include: path.resolve } ]},plugins: [ new HappyPack({ // 基础参数设置 id: 'babel', // 上面loader?后面指定的id loaders: ['babel-loader?cacheDirectory'], // 实际匹配处理的loader threadPool: happyThreadPool, // cache: true // 已被弃用 verbose: true });]

看了下react和lodash,只有一个main,目前来看使用es6看来还不普遍,所以这个值目前可能不太重要

happypack提供的loader,是对文件实际匹配的处理loader。这里happypack提供的loader与plugin的衔接匹配,则是通过id=happypack来完成。

module.exports = { resolve: { mainFields: ['main'] }}
npm run dev

为什么这个不重要,我发现react直接导出的index.js则是根据环境判断使用哪份代码,目测来看并不需要进行循环依赖的处理

5.DLL动态链接库

通过依赖,则可以直接使用打包后代码,而不需webpack去循环依赖

在一个动态链接库中可以包含其他模块调用的函数和数据,动态链接库只需被编译一次,在之后的构建过程中被动态链接库包含的模块将不会被重新编译,而是直接使用动态链接库中的代码。

 resolve: { mainFields: ["main"], alias: { 'react': path.resolve(__dirname, './node_modules/react/cjs/react.production.min.js') } }

将web应用依赖的基础模块抽离出来,打包到单独的动态链接库中。一个链接库可以包含多个模块。 当需要导入的模块存在于动态链接库,模块不会再次打包,而是去动态链接库中去获取。 页面依赖的所有动态链接库都需要被加载。

不使用inline模式的devServer

5.1 定义DLL配置

默认情况下,应用程序启用内联模式。这意味着一段处理实时重载的脚本被插入到你的包中,并且构建消息将会出现在浏览器控制台。

依赖的两个内置插件:DllPlugin 和 DllReferencePlugin

当使用inline模式时,devServer会向每个Chunk中注入一段重载的脚本代码,但是其实一个页面只需要一次,所以当Chunk过多时,可以将inline设置为false

5.1.1 创建一个DLL配置文件webpack_dll.config.js

module.export = { devServer: { inline: false }}
module.exports = { entry: { react: ['react', 'react-dom'] }, output: { filename: '[name].dll.js', // 动态链接库输出的文件名称 path: path.join, // 动态链接库输出路径 libraryTarget: 'var', // 链接库输出方式 默认'var'形式赋给变量 b library: '_dll_[name]_[hash]' // 全局变量名称 导出库将被以var的形式赋给这个全局变量 通过这个变量获取到里面模块 }, plugins: [ new webpack.DllPlugin({ // path 指定manifest文件的输出路径 path: path.join(__dirname, 'dist', '[name].manifest.json'), name: '_dll_[name]_[hash]', // 和library 一致,输出的manifest.json中的name值 }) ]}

本文由金沙澳门官网发布于澳门金莎娱乐网站,转载请注明出处:0打包优化战略收拾小结_javascript技艺_脚本之家

关键词: 金沙澳门官网