[TOC] [整个章节的参考链接](https://kaiwu.lagou.com/course/courseInfo.htm?courseId=416#/detail/pc?id=4425) >[success] # 编译阶段提速 ~~~ 1.编译模块阶段的效率提升,下面的行为操作都是在webpack编译阶段去做的 ~~~ >[warning] ### IgnorePlugin -- 忽略第三方包指定目录 ~~~ 1.webpack 的内置插件,作用是忽略第三方包指定目录。 2.有的依赖包,除了项目所需的模块内容外,还会附带一些多余的模块,例如'moment' 会将所有 本地化内容和核心功能一起打包 3.下面案例通过配置的'webpack-bundle-analyzer'来看使用 'IgnorePlugin'后对'moment'的影响 ~~~ * 配置代码 ~~~ const webpack = require('webpack') //webpack.config.js module.exports = {     //...     plugins: [         //忽略 moment 下的 ./locale 目录         new webpack.IgnorePlugin({ resourceRegExp: /^\.\/locale$/, contextRegExp: /moment$/, }),     ] } ~~~ * 配置前 ![](https://img.kancloud.cn/10/91/109140ff5c8b146d4984f3b38263fa4d_1373x675.png) * 配置后 ![](https://img.kancloud.cn/15/77/1577bde59f19de3e43a0686d14b4c4da_990x467.png) >[danger] ##### 疑问这些包并不想全排除部分还是想引用要怎么做 ~~~ 1.可以配合'ContextReplacementPlugin' ,关于这部分可以参考= 'https://iamakulov.com/notes/webpack-contextreplacementplugin/' ~~~ >[warning] ### 按需引入 ~~~ 1.以'lodash' 为例通常项目中只使用很少的lodash方法,但是构建时却发现构建时引入了整个依赖包 所以需要按需引入这些内容 如果之前你的项目是这样使用loash: import _ from 'lodash' console.log(_.slice([])) 现在按需你需要这么写: import slice from 'lodash/slice' console.log(slice([])) ~~~ * 配置前 ![](https://img.kancloud.cn/93/5b/935b90af1008f6a201ef918f1c63d969_1068x465.png) * 配置后 ![](https://img.kancloud.cn/1d/b6/1db6146f02f9af618e940eca32f44ebe_1369x673.png) >[danger] ##### lodash 如果已经在项目初期没有做按需引入如何补救 ~~~ 1.使用'babel-plugin-lodash' 和'lodash-webpack-plugin' 插件参考文章'https://www.jianshu.com/p/3dd1948cf5a2' 2.使用'babel-plugin-import '参考'https://www.ctolib.com/mip/shenshanyoumu-babel-plugin-import-annotations.html' 'https://xiaozhuanlan.com/topic/2984105637' 上面两个来实现动态删除无效代码 ~~~ >[warning] ### 预编译资源模块 ~~~ 1.提前对一些业务包,一类打包后然后使用 ~~~ >[danger] ##### 创建一个webpack.dll.js ~~~ 1.创建一个webpack.dll.js 用来专门处理这些需要预处理的文件 2.使用 DLLPlugin 进行分包,DllReferencePlugin对 manifest.json 引用 ~~~ ~~~ const path = require('path'); const webpack = require('webpack'); module.exports = { entry: { // 要处理的文件,这个library不是固定的可以自己个根据需要起适合自己的 library: [ 'react', 'react-dom' ] }, output: { filename: '[name]_[chunkhash].dll.js', // library.dll.js中暴露出的全局变量名是entry里面key path: path.join(__dirname, 'build/library'),// 打包后文件输出的位置 library: '[name]_[hash]' // 库暴露出来的名字 可以参考打包组件和基础库 }, plugins: [ new webpack.DllPlugin({ name: '[name]_[hash]',// 生成一个文件映射json名字 path: path.join(__dirname, 'build/library/[name].json') // 保存的位置 }) ] }; ~~~ >[danger] ##### 在webpack 打包指令位置配置 ~~~ 1.上面是一个单独的指令,专门用来打包提取包的不是对项目打包,将提取包的内容通过 'DllReferencePlugin' 引入之后,在执行打包 plugins: [ new webpack.DllReferencePlugin({ context: __dirname, manifest: require('./build/library/') }) ], ~~~ >[danger] ##### 可以参考 [参考链接](https://www.cnblogs.com/lusongshu/p/8473318.html) >[warning] ### 使用Externals ~~~ 1.希望 webpack 不会对其进行打包,此时就可以配置 externals ~~~ >[danger] ##### 使用 ~~~ 1.这样jq在编译阶段就不会被,打入项目中可以通过cdn的形式引入 module.exports = {     //...     externals: {         //jquery通过script引入之后,全局中即有了 jQuery 变量         'jquery': 'jQuery'     } } // 通过手动cdn形式引入 <!DOCTYPE html> <html lang="en"> <head>     <meta charset="UTF-8">     <meta name="viewport" content="width=device-width, initial-scale=1.0">     <meta http-equiv="X-UA-Compatible" content="ie=edge">     <title>Document</title> </head> <body>     <div id="root">root</div>     <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script> </body> </html> ~~~ >[danger] ##### Externals 和 DLLPlugin 区别 ~~~ 1.在 Webpack 的配置方面,externals 更简单,而 DllPlugin 需要独立的配置文件。 2.DllPlugin 包含了依赖包的独立构建流程,而 externals 配置中不包含依赖框架的生成方式,通常 使用已传入 CDN 的依赖包。 3.externals 配置的依赖包需要单独指定依赖模块的加载方式:全局对象、CommonJS、AMD 等。 4.在引用依赖包的子模块时,DllPlugin 无须更改,而 externals 则会将子模块打入项目包中。 ~~~ >[danger] ##### 如何自动引入cdn * 说明 页面提取资源使用vue 做的一个案例,[关于webpack中如何使用vue参考配置](https://vue-loader.vuejs.org/) ~~~ 1.当做项目的时候对一些基础第三方包我们可以采用cdn的形式,将类第三方包抽离 2.配置cnd的'plugins' 用到的是'html-webpack-externals-plugin' -- 'npm install --save-dev html-webpack-externals-plugin' 3.使用的时候需要配合'HtmlWebpackPlugin' 一起使用 ~~~ [html-webpack-externals-plugin 具体使用地址](https://www.npmjs.com/package/html-webpack-externals-plugin) >[danger] ##### 以vue 举个例子 ~~~ 1.注意事项,下面案例'entry' 是直接可以跟cdn地址的,为什么vue这个却没有想react那种简写呢?因为 仔细看我用的vue的cdn地址结尾是没有类型,如果是没有具体类型的cdn地址,注意一定要加type字段 2.注意"global: 'Vue'" 这个vue 是大写的,为什么是大写因为我在后续文件引入写法是 " import Vue from 'vue' ",我用的参数是大写,这里也是一个坑,具体可以看文档对global解释 ~~~ ~~~ const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin') moudles.export = { plugins: [ new HtmlWebpackExternalsPlugin({ externals: [{ module: 'vue', entry: { path: 'https://cdn.jsdelivr.net/npm/vue@2.6.11', type: 'js' }, global: 'Vue' }], files:['template.html'] // 也可以指定页面加入对应cdn 看文档都有 }) } // entry 简写版本 // moudles.export = { // plugins: [ // new HtmlWebpackExternalsPlugin({ // externals: [{ // module: 'react', // entry: '//11.url.cn/now/lib/16.2.0/react.min.js', // global: 'React' // }, // { // module: 'react-dom', // entry: '//11.url.cn/now/lib/16.2.0/react-dom.min.js', // global: 'ReactDom' // } // ] // }) // ] // } ~~~ >[warning] ### include/exclude ~~~ 1.webpack 中所有的loader 都可以拥有include和exclude属性。 exclude:排除不满足条件的文件夹(这样可以排除webpack查找不必要的文件) include:需要被loader 处理的文件或文件夹 2.exclude 的优先级高于 include 3.作用不需要再用loader处理而已,打包还是会打包的,比如jQuery,不需要再被babel处理,因为jQuery已经是es5, 浏览器直接可以识别。这个时候,你不设置exclude,jQuery就会被处理,这样就增加了打包时间。所以,设置好 exclude和include可以优化打包时间 { test: /\.js$/, exclude: /node_modules/, // include: [path.resolve(__dirname, 'src')] use: ['babel-loader?cacheDirectory=true'] } ~~~ >[warning] ### noParse [链接](https://blog.csdn.net/qq_17175013/article/details/86842321) >[warning] ### Source Map ~~~ 1.参考'Source Map' 章节 ~~~ >[warning] ### TypeScript 编译优化 ~~~ 1.Webpack 中编译 TS 有两种方式:使用 ts-loader 或使用 babel-loader 1.1.在使用 ts-loader 时,由于 ts-loader 默认在编译前进行类型检查,因此编译时间往往比较慢, 通过加上配置项 transpileOnly: true可以在编译时忽略类型检查,提高编译速度,但往往关闭后需要 在配合'ForkTsCheckerWebpackPlugin' 1.2. babel-loader 则需要单独安装 @babel/preset-typescript 来支持编译 TS(Babel 7 之前的版本则还是需要 使用 ts-loader) 我这简单试过几次如果'ts-loader' +'ForkTsCheckerWebpackPlugin' 感觉比'@babel/preset-typescript ' 慢, ~~~ >[danger] ##### 使用 ~~~ 1.注释部分是'ts-loader' +'ForkTsCheckerWebpackPlugin' 用法,没注释的地方是'babel-loader ' 用法,当然还需要 配置预设'@babel/preset-typescript ' 这里不做详细说明了 ~~~ ~~~ var TSCheckerPlugin = require('fork-ts-checker-webpack-plugin') module: { rules: [ { test: /\.ts$/, // use: { // loader: 'ts-loader', // options: { // transpileOnly: true, // }, // }, use: ['babel-loader'], // 使用babel-loader 情况下 }, ], }, plugins: [ // new TSCheckerPlugin({ // typescript: { // diagnosticOptions: { // semantic: true, // syntactic: true, // }, // }, // }), ], } ~~~ >[danger] ##### 文章说明 [对比说明](https://segmentfault.com/q/1010000019545436) >[warning] ### resolve ~~~ 1.这个后续再看优化 resolve.modules 配置(减少模块搜索层级) ~~~ >[warning] ### 多进程打包处理 loader资源并行解析 ~~~ 1.webpack需要处理的文件是非常多的,构建过程是一个涉及大量文件读写的过程。项目复杂起来了, 文件数量变多之后,webpack构建就会特别满,而且运行在nodeJS上的webpack是单线程模型的, 也就是说Webpack一个时刻只能处理一个任务,不能同时处理多个任务。 文件读写和计算操作是无法避免的,那能不能让Webpack在同一时刻处理多个任务发挥多核CPU电脑的功能, 以提升 2.webpack 4.x 使用'thread-loader',小于4.0 可以使用'HappyPack'可以将原有的 webpack 对 loader 的执行过程, 从单一进程的形式扩展为多进程的模式,从而加速代码构建 3.这里要注意如果你是小项目,这里多进程打包反而速度会慢 ~~~ [https://segmentfault.com/a/1190000022414110](https://segmentfault.com/a/1190000022414110) [thread-loader使用](https://www.webpackjs.com/loaders/thread-loader/) ~~~ const threadLoader = require('thread-loader'); const jsWorkerPool = { // options // 产生的 worker 的数量,默认是 (cpu 核心数 - 1) // 当 require('os').cpus() 是 undefined 时,则为 1 workers: 2, // 闲置时定时删除 worker 进程 // 默认为 500ms // 可以设置为无穷大, 这样在监视模式(--watch)下可以保持 worker 持续存在 poolTimeout: 2000 }; const cssWorkerPool = { // 一个 worker 进程中并行执行工作的数量 // 默认为 20 workerParallelJobs: 2, poolTimeout: 2000 }; threadLoader.warmup(jsWorkerPool, ['babel-loader']); threadLoader.warmup(cssWorkerPool, ['css-loader', 'postcss-loader']); module.exports = { // ... module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: [ { loader: 'thread-loader', options: jsWorkerPool }, 'babel-loader' ] }, { test: /\.s?css$/, exclude: /node_modules/, use: [ 'style-loader', { loader: 'thread-loader', options: cssWorkerPool }, { loader: 'css-loader', options: { modules: true, localIdentName: '[name]__[local]--[hash:base64:5]', importLoaders: 1 } }, 'postcss-loader' ] } // ... ] // ... } // ... } ~~~ * 或者 ~~~ module: { rules: [{ test: /\.js$/, exclude: /node_modules/, use: [{ loader: 'thread-loader', options: { // 产生的 worker 的数量,默认是 cpu 的核心数 workers: 3, // 一个 worker 进程中并行执行工作的数量 // 默认为 20 workerParallelJobs: 50, // 额外的 node.js 参数 // workerNodeArgs: ['--max-old-space-size', '1024'], // 闲置时定时删除 worker 进程 // 默认为 500ms // 可以设置为无穷大, 这样在监视模式(--watch)下可以保持 worker 持续存在 poolTimeout: 500, // 池(pool)分配给 worker 的工作数量 // 默认为 200 // 降低这个数值会降低总体的效率,但是会提升工作分布更均一 poolParallelJobs: 200, // 池(pool)的名称 // 可以修改名称来创建其余选项都一样的池(pool) // name: "my-pool" } }, 'babel-loader' ] } } ~~~