进击webpack4 (优化篇)
进击webpack 4 (基础篇一)
进击webpack4 (基础篇二:配置 一)
进击webpack4 (基础篇三:配置 二)
不解析不依赖第三方模块的模块
noParse
有一些第三方模块,它本身不依赖于其他模块,比如jquery,lodash,不去编译这些库,会使得webpack打包更加快速
noParse是个正则或者包含正则的数组 RegExp | [RegExp]
module:{ noParse:/jquery/, //不去解析jquery rules:[ //... ] }, ---------------------
忽略某些库内的第三方模块
ignorePlugin
以moment这个时间库为例, 导入moment的同时, moment会引入自身依赖的语言包,这些语言包其中有部分是我们不需要用到的,moment内部代码
plugins: [ new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/) ],
2个参数代表的意思是:
当匹配到moment这个库的时候 引入moment并且忽略moment里面匹配到locale的库
这个时候我们如果想要自己需要的locale 需在main.js手动引入
import 'moment/locale/zh-cn'
动态链接库
另起一个webpack.config.dll.js 专门用来生成动态链接库
//webpack.config.dll.js const path=require('path'); const webpack=require('webpack'); module.exports={ mode:'development', entry: { react:['react','react-dom'], jquery:['jquery'] },// 把 React 相关模块的放到一个单独的动态链接库 output: { path: path.resolve(__dirname,'dist'),// 输出的文件都放到 dist 目录下 filename: '[name].dll.js',//输出的动态链接库的文件名称,[name] 代表当前动态链接库的名称 library: '_dll_[name]',//存放动态链接库的全局变量名称,例如对应 react 来说就是 _dll_react }, plugins: [ new webpack.DllPlugin({ // 动态链接库的全局变量名称,需要和 output.library 中保持一致 // 该字段的值也就是输出的 mainfest.json 文件 中 name 字段的值 // 例如 react.manifest.json 中就有 "name": "_dll_react" name: '_dll_[name]', // 描述动态链接库的 manifest.json 文件输出时的文件名称 path: path.join(__dirname, 'dist', '[name].mainfest.json') }) ] }
//打包 npx webpack --config webpack.config.dll.js
这样会在dist生成
然后在webpack.config.js里
const webpack= require('webpack') plugins: [ new webpack.DllReferencePlugin({ manifest:require('./dist/react.mainfest.json') }), new webpack.DllReferencePlugin({ manifest:require('./dist/jquery.mainfest.json') }) ]
这里它会从mainfest.json寻找name 然后根据它的标识找到相应内容, dll.js就是打包出来后的动态链接库
然后在html模板文件里引入
<script src="./jquery.dll.js"></script> <script src="./react.dll.js"></script>
如果你在main.jsimport React from 'react'
,他会首先找动态链接库, 找不到才会执行打包
注:使用react需要配置好rule
{ test:/\.js/, use:{ loader:'babel-loader', options:{ presets:[ '@babel/preset-env', '@babel/preset-react' ] } } },
开启多进程打包
npm i happypack -D
如果一个项目代码密集,读写操作频繁,happypack 就能让Webpack把任务分解给多个子进程去并发的执行,子进程处理完后再把结果发送给主进程。
const HappyPack = require('happypack'); rules: [ { test: /\.js$/, // 把对 .js 文件的处理转交给 id 为 babel 的 HappyPack 实例 use: ['happypack/loader?id=babel'], exclude: path.resolve(__dirname, 'node_modules'), }, { test: /\.css$/, // 把对 .css 文件的处理转交给 id 为 css 的 HappyPack 实例 use: ['happypack/loader?id=css'] } ] new Happypack({ //ID是标识符的意思,ID用来代理当前的happypack是用来处理一类特定的文件的 id: 'js', use: [{ loader: 'babel-loader', //options=query都是向插件传递参数的 options: { presets: [["@babel/preset-env", { modules: false }], "@babel/preset-react"], plugins: [ ["@babel/plugin-proposal-decorators", { "legacy": true }], ["@babel/plugin-proposal-class-properties", { "loose": true }], ] } }] }), new Happypack({ //ID是标识符的意思,ID用来代理当前的happypack是用来处理一类特定的文件的 id: 'css', use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader'], threads: 4,//你要开启多少个子进程去处理这一类型的文件 verbose: true//是否要输出详细的日志 verbose })
注意:开启进程也需要时间, 如果一个项目并不是很复杂, 斟酌使用
不打包第三方库 使用cdn引入
module.exports = { //... externals: { jquery: 'jQuery' } };
main.js 引入jquery 将不会打包 import jquery from 'jQuery'
html模板内引入jquery的cdn地址即可
尽量使用es6的模块导入
webpack的tree-shaking自己可以分析出哪些没有使用到的代码可以剔除,前提是es6模块语法
scope-hosting可以提升作用域 比如 var a = 1; var b = a ; console.log(b) 会编译成var b = 1; console.log(b)
提取公共代码
做这种操作首先得是多页面
entry:{ home:['./src/index.js'], login:['./src/login.js'] }, // 入口文件
//home.js import React from 'react' import {render }from 'react-dom' render(<h1>动态链接库</h1>,window.root) //login.js import React from 'react' import {render }from 'react-dom' render(<h1>动态链接库</h1>,window.root)
//webpack.config.js optimization:{ // 优化 splitChunks:{ //分割代码 cacheGroups:{ // 缓存组 common:{ // 公共的代码 一般是自己写的公共代码 chunks:'initial', minSize:0, minChunks: 2, //最少被引用2次的模块 name: "common" }, vendor:{ // 一般是第三方公共模块 priority:1, // 因为执行是从上往下, 所以设置优先级比上面高 不然上面抽离的话第三方模块也被抽离了 test:/node_modules/ , //匹配node_modules下的公共代码, chunks:'initial', minSize:0, minChunks: 2, //最少被引用2次的模块 name: "vendor" } } } }
懒加载
这里拿vue举例
const Login = () => import(/* webpackChunkName: "login" */,"./login"); new VueRouter({ routes: [{ path: "/login", component: Login }] })
webpackChunkName虽然是注释, 但是webpack能识别, 编译后这个组件生产的名字就是login
可能会需要@babel/plugin-syntax-dynamic-import 才能识别
yarn add @babel/plugin-syntax-dynamic-import -D
具体配置看此文
热更新
devServer:{ // 告诉 DevServer 要开启模块热替换模式 hot: true, }
在vue中只要这样配置就可以了, vue自己帮我们做了配置
其他库中:
import React from 'react' import {render} from 'react-dom' render(<App/>, document.getElementById('root')); if (module.hot) { // accept 函数的第一个参数指出当前文件接受哪些子模块的替换,这里表示只接受 ./AppComponent 这个子模块 // 第2个参数用于在新的子模块加载完毕后需要执行的逻辑 module.hot.accept(['./App'], () => { // 新的 AppComponent 加载成功后重新执行下组建渲染逻辑 let App=require('./App').default; render(<App/>, document.getElementById('root')); }); }