webpack
2020-06-05 14:16:48 0 举报
AI智能生成
前端面试
作者其他创作
大纲/内容
3.webpack核心概念
Loader
loader是什么?
它是一个打包方案,webpack只知道如何打包js文件,不知道如何打包非.js文件,loader可以告诉webpack如何打包这些文件
常用loader
vue-loader
打包.vue文件
file-loader
打包图片、.txt等
打包图片时,单独生成一个图片文件
url-loader
与file-loader的区别
file-loader 单独生产一个图片文件<br>url-loader 把图片转换成一个base64的字符串,然后直接把这个base64的字符串放到bundle.js里,而不是单独生成一个图片文件
利弊<br>
好处是,可以少发一次http请求,适合图片比较小的情况
坏处是,如果图片过大,bundle.js会变得很大,请求时间过长,页面很久才能展示出来
改进
{<br> loader: 'file-loader',<br> options: {<br> limit:2048<br> }<br>}
图片大于2048字节(2KB)时使用file-loader<br>图片小于2048字节时,使用url-loader,把图片变成base64放到bundle.js里
使用loader打包静态资源
图片
{<br> loader: '<font color="#c41230">file-loader</font>',<br> options: {<br> name: '[path][name]_[hash].[ext]'<br> }<br>}
[ext] 资源扩展名
[name] 资源的基本名称
[path] 资源相对于 context的路径
[hash] 内容的哈希值
字体
iconfont
阿里矢量图标库
下载图标,把iconfont.css里的样式粘贴到本地样式文件里,修改字体src
<font color="#c41230">file-loader</font>
它告诉webpack去打包后缀为.eot .ttf .svg的字体
样式
module: {<br> rules: [<br> {<br> test: /\.css$/,<br> <font color="#c41230"> use: [ 'style-loader', 'css-loader','sass-loader','postcss-loader' ]</font><br> }<br> ]<br> }
style-css
在得到css生成的内容以后,把这段内容挂在到页面的<head>里
css-loader
分析几个css文件之间的关系,把几个css文件合并成一段css
css-loader扩展项
{<br> loader: 'css-loader',<br> options: {<br> importLoaders: 2 <br> modules:true<br> }<br> },
importLoaders: 2
用于配置「css-loader 作用于 @import 的资源之前」有多少个 loader<br>对scss文件里@import的scss文件如何进行打包
<font color="#c41230">modules:true</font>
对css进行模块化打包,可以防止样式冲突
sass-loader
把.scss文件翻译成css
postcss-loader
自动添加厂商前缀
postcss.config.js
autoprefixer插件
plugins
使打包更加便捷
plugin可以在webpack运行到某一个时刻时帮你做一些事情,比如html-webpack-plugin会在打包结束这一个时刻自动生成html文件
常用插件
html-webpack-plugin
plugins: [<br> new HtmlWebpackPlugin(), // Generates default index.html<br> ]
在打包结束后,自动生成一个html文件,并把打包生成的js自动引入到这个html文件中
plugins: [<br> new HtmlWebpackPlugin({ // Also generate a test.html<br> filename: 'test.html',<br> template: 'src/assets/test.html'<br> })<br> ]
以template指定的文件为模板生成html文件
clean-webpack-plugin
plugins: [<br> new CleanWebpackPlugin(['dist']), <br>]
在打包之前,先删除dist目录
hot-module-replacement-plugin
热更新
<font color="#c41230">Entry与Output</font>
多个入口起点
{<br> entry: {<br> app: './src/app.js',<br> search: './src/search.js'<br> },<br> output: {<br> filename: '[name].js',<br> path: __dirname + '/dist'<br> }<br>}
filename是输出的js的文件名
[name]里的name就是entry里的key值
打包多个入口文件
静态资源放在CDN时
output: {<br> publicPath: 'http://cdn/...'<br> }
打包后的html引入的js文件中会加上 publicPath前缀
<font color="#c41230">SouceMap</font>
<font color="#c41230">它是一个映射关系,它会建立打包后的文件和源文件之间的映射关系,告诉你源文件的什么位置出错</font>
打包会变慢,因为它要构建映射关系
devtool配置选项
devtool: "source-map"
打包后生成 .js.map文件<br>该文件对源代码和打包后的代码进行映射<br>
devtool: "inline-source-map"
打包后不会生成.js.map<br>映射关系以base64的形式被引入打包后的js文件中的souceMappingURL中
devtool: "cheap-inline-source-map"
只提示哪一行出错不提示列,只针对业务代码不针对loader生成sourcemap,可以提升打包性能
devtool: "eval"
最快,但是业务复杂时提示不全面
devtool: "cheap-module-source-map"
module 针对loader生成sourcemap
<font color="#c41230">production环境选用这个较好</font>
devtool: "cheap-module-eval-source-map"
<font color="#c41230">development环境选这个较好,性能快,信息全</font>
<font color="#c41230">WebpackDevServer</font>
webpack --watch
可以监听变动并自动打包
它不能起服务器,每次打包后需要手动刷新浏览器
webpack-dev-server
功能
<font color="#c41230">监听变动并自动打包</font>
<font color="#c41230">自动打开、刷新浏览器</font>
<font color="#c41230">模拟服务器特性</font>
开启一个web服务器,localhost:8080,启动完服务器打包代码到dist目录下
以http的方式打开浏览器,可以发ajax请求<br>而以file
基础配置
devServer: {<br> contentBase: path.join(__dirname, 'public'),<br> open: true,<br> proxy: ,<br> port: ,<br> }
contentBase:WebpackDevServer 服务器要启动在哪一个文件夹下
open: true, 启动时自动打开浏览器
proxy 接口代理
port 端口号
<font color="#c41230">Hot Module Replacement(HMR)</font>
devServer: {<br> hot: true,<br> hotonly:true<br> }<br>并引入<font color="#c41230">hot-module-replacement-plugin</font>插件
module.hot.accept('file',()=>{ })
当file文件的内容改变时,执行后边的回调函数进行热更新
样式文件 vue react不需要手写这段HMR代码,是因为css-loader vue-loader内置了这个功能
<font color="#c41230">Bable</font>
<font color="#c41230">把ES6代码转换成浏览器可以识别的ES5代码</font>
安装
npm install babel-loader @babel/core --save-dev<br>npm install @babel/preset-env --save-dev<br>npm install @babel/polyfill --save<br>
<font color="#c41230">@babel/core</font>
是babel的核心库,<br>它能让babel去识别js代码里的内容,然后把js代码转成AST抽象语法树,然后再把抽象语法树编译转成新的语法
<font color="#c41230">babel-loader </font>
负责打通跟webpack的关联,并没有转换
<font color="#c41230">@babel/preset-env</font>
负责转换新的JavaScript句法(syntax)而不转换新的API
<font color="#c41230">@babel/polyfill</font>
弥补ES5缺失的变量或者函数,设置useBuiltIns为'usage'可以只打包已经用到的API语法,按需引入减少文件体积
配置
打包业务代码<br>
presets:[["@babel/preset-env",{<br> targets:{<br> chrome:'67'<br> },<br> useBuiltIns:"usage"<br> }]]
打包业务代码,只需要设置@babel/preset-env
在chrome大于67以上的版本进行语法转换,如果浏览器本身支持ES6语法,则不进行转换
@babel/pollyfill会污染全局环境
打包内库代码<br>
plugins:[["@babel/plugin-transform-runtime",{<br> "corejs":2,<br> "helpers":true,<br> "regenerator":true,<br> "useESModules":false<br> }]]<br>
生成一些第三方模块或者UI组件时,打包这些库时不希望污染全局变量,<br>@babel/plugin-transform-runtime会以闭包的方式注入对应的内容,当可以防止污染全局变量<br>
"corejs":2,
"corejs":要设置为2,当页面不存在map promise方法时,才会把代码打包进来
需要额外安装@babel/runtime-corejs2
babel配置也可以单配在.babelrc文件里,将.babelrc放到项目的根目录下
哪些文件转换?<br>哪些不转换?
<font color="#c41230">include</font>: [<br> path.resolve(__dirname, "app/src"),<br> path.resolve(__dirname, "app/test")<br> ],<br><font color="#c41230"> exclude</font>: /node_modules/
<font color="#c41230">include: 表示目录中的哪些 .js 文件需要进行转换<br>exclude: babel-loader做语法解析时忽略node_modules这些第三方模块</font>
4.webpack进阶
<font color="#c41230">Tree Shaking</font>
<font color="#c41230">当引入一个模块时,不引入该模块所有的代码,只引入需要的代码,剔除掉无用代码</font>
<font color="#c41230">只支持ES Module,因为它的底层是静态引入<br>不支持CommonJS,因为它的底层是动态引入</font>
配置
webpack.config.js
生产环境
<font color="#c41230"> mode: 'production',</font><br>
<font color="#c41230">自动进行treeShaking</font><br>不需要写<br>optimization: {<br> usedExports: true,<br> }, <br>
开发环境
<font color="#c41230"> mode: 'development',</font><br> optimization: {<br> usedExports: true,<br> }, <br>
<font color="#c41230">usedExports: true<br>表示,哪些模块用export导出了就打包,如果模块没有export打包时就忽略掉</font>
在development环境下打包时,即使用了treeShaking,也不会把代码直接从打包后的js文件里剔除掉,但是会提示exports used<br>因为开发环境需要做一些调试,如果直接剔除可能会导致soucemap对应的行数出错
package.json
<font color="#c41230">"sideEffects": [] </font>
把<font color="#c41230">不需要进行treeShaking的文件</font>写到[],比如css文件['*.css']<br>
<font color="#c41230">"sideEffects":false</font>
如果对<font color="#c41230">所有文件都进行treeShaking</font>,设为"sideEffects":false
<font color="#c41230">webpack和code splitting</font>
<font color="#c41230">为什么要分割?</font>
比如引入lodash,仅使用其中一两个方法,仍会把所有的lodash打包进来,造成打包文件过大,加载时间长
分割方法
手动代码分割
新建一个lodash.js<br>import _ from 'lodash'<br>window._ = _ ;
entry:{<br> lodash:'./src/lodash.js'<br>}
使用webpack配置进行代码分割
两种情形下的分割配置
同步引入模块代码
webpack.common.js<br>optimization:{<br> splitChunks:{<br> chunks: 'all'<br> }<br>}
异步引入模块代码<br>import('loadash').then。。。<br>
无需配置optimization<br>动态引入语法需安装 npm install babel-plugin-dynamic-import-webpack --save-dev<br>.bebelrc 添加配置:"plugins": ["dynamic-import-webpack"]
代码分割与webpack无关<br>
<font color="#c41230">代码分割的三种方法</font>
<ul><li>Entry Points:入口文件设置的时候可以配置</li><li>CommonsChunkPlugin</li><li>Dynamic Imports:动态导入</li></ul>
splitChunksPlugin参数详解
splitChunks: {<br> chunks: "async",<br> minSize: 30000,<br> minChunks: 1,<br> maxAsyncRequests: 5,<br> maxInitialRequests: 3,<br> automaticNameDelimiter: '~',<br> name: true,<br> cacheGroups: {<br> vendors: {<br> test: /[\\/]node_modules[\\/]/,<br> priority: -10<br> },<br> default: {<br> minChunks: 2,<br> priority: -20,<br> reuseExistingChunk: true<br> }<br> }<br>}<br>
<font color="#c41230">Lazy Loading</font>
其实懒加载就是通过import来异步的加载一个模块。什么时候执行import语法时,它对应的模块才会被载入。<br>好处是借助Import这种语法,我们可以让页面加载的更快。
minChunks: 2<br>假设我们打包以后会有很多个文件,如果有两个以上文件里面需要引用lodash 那我们就需要对lodash进行代码分割。
打包分析 Preloding Prefeching
打包分析
生成打包过程的描述文件: <br>webpack --profile --json > stats.json
打包分析工具<br>bundle 分析<br>
https://github.com/webpack/<font color="#c41230">analyse</font>/
<font color="#c41230">webpack-chart</font>
<font color="#c41230">webpack-bundle-analyzer</font>
预加载
使用场景
异步加载交互代码时:例如当点击的时候再加载异步代码,虽然提高了页面初始化速度,但是对用用户点击的体验不好,速度太慢;<br>为了解决懒加载带来的问题:使用prefetch preload<br><br>使用预加载,比如打开一个网站,首页加载完,在首页加载完成后利用空闲时间,预先加载登陆模态框,等用户登陆时模态框可以很快的加载出来
使用方法
使用魔术注释<br>import(/* webpackPrefetch: true */ 'LoginModal');
区别
<font color="#c41230">prefetch</font> 会等主流程都加载完成,等待空闲再加载;(最优)<br><font color="#c41230">preload </font> 和主线程一起加载<br>
优化
代码使用率
打开控制台 :ctrl+shift+p 输入coverage 查看js代码使用率
缓存能带来的性能提升是非常有限的,应该重点考虑提升代码的使用率,<br>有些交互之后才能用到的代码,可以放到单独的异步模块里 提高加载速度及页面利用率
CSS文件的代码分割
css代码分割插件<br><font color="#c41230">mini-css-extract-plugin</font>
解决什么问题
css in js<br>默认会把css打包进js中<br>
作用
<font color="#c41230">css代码分割,可以将css单独打包</font>
缺点
暂时<font color="#c41230">不支持HMR</font>,因此<font color="#c41230">只能在线上使用</font>
安装使用
1、安装插件<br>
npm install --save-dev mini-css-extract-plugin
2、配置webpack.prod.js<br>
const MiniCssExtractPlugin = require('mini-css-extract-plugin');<br><br>module.exports = {<br> plugins: [new MiniCssExtractPlugin()],<br> module: {<br> rules: [<br> {<br> test: /\.css$/i,<br> use: [<font color="#c41230">MiniCssExtractPlugin.loader</font>, 'css-loader'],<br> },<br> ],<br> },<br>};
引入插件, require...
plugins中使用插件
new MiniCssExtractPlugin({...})
更改loader,开发环境和线上环境分开配置loader,配置loader为MiniCssExtractPlugin.loader
3、经过1和2,还不能把css拆分出来,原因在于<br>对css文件进行了tree shaking
webpack.prod.js
optimization:{<br> usedExports:true <br>}
package.json
sideEffects:[<br> '*.css'<br>]<br>
css文件不进行tree shaking
4、css压缩
<font color="#c41230">对抽离出来的css文件进行代码的合并压缩</font><br>
<font color="#c41230">optimize-css-webpack-plugin</font>
扩展用法
<font color="#c41230">Extracting CSS based on entry</font>
<font color="#c41230">根据入口分割css</font>
将不同入口文件中加载的所有模块的css样式打包到一个文件里<br>比如有两个入口文件index.js index1.js,将index.js index1.js中加载的所有模块的样式<font color="#c41230">分别进行打包</font>
配置
配置 cacheGroups<br>optimization:{<br> splitChunks:{<br> cacheGroups:{ 。。。 }<br> }<br>}
<font color="#c41230">Extracting all CSS in a single file</font>
<font color="#c41230">当有多个入口文件时,将所有入口文件里引入的css文件全部打包到一个css文件里</font>
配置
optimization: {<br> splitChunks: {<br> cacheGroups: {<br> styles: {<br> name: 'styles',<br> test: /\.css$/,<br> chunks: 'all',<br> enforce: true,<br> },<br> },<br> },
将所有 .css文件打包到一个名为styles的文件里
webpack与浏览器缓(caching)<br>
缓存
浏览器缓存<br>存在什么问题
代码打包,将dist目录下的文件上传到服务器<br>用户第一次打开页面,浏览器加载打包后的文件,<br>用户再次刷新,则浏览器从缓存中拿文件<br><br>修改源代码,重新打包,将dist目录下的文件上传到服务器<br>用户再次刷新,浏览器请求文件时发现本地有缓存(因为文件的名字没有改变),则从缓存中拿文件,就不会加载新上传的文件<br>
怎么解决
在<font color="#c41230">每次修改源文件后,打包时使用contenthash改变文件的名字</font>,可以解决上述问题
contenthash
作用
<font color="#c41230">contenthash,是根据content产生的一个hash字符串,content不变hash字符串就不会变<br>如果源代码没有改变,那么打包生成文件的contenthash永远都不会变</font>
配置
output: {<br> filename: '[name].<font color="#c41230">[contenthash]</font>.js',<br> chunkFilename: '[name].<font color="#c41230">[contenthash]</font>.js'<br>}
修改源文件,重新打包,将dist目录下的文件(main.js、vendor.js、index.html)放到服务器上去<br>当用户再次访问线上的页面时,流程如下:<br>打开index.html,浏览器加载index.html中<script>引入的js文件,<br>加载vendor.js时,发现vendors.***.js里的contenthash值没变,则使用本地缓存<br>加载main.js时,main.******.js里的contenthash值变了,则去服务器上加载最新的main.js文件<br>
shimming的作用
作用
解决webpack打包时存在的兼容性问题,修改webpack的默认行为,实现webpack自身无法实现的一些效果
使用场景
eg: 自动引入第三方库<br>如果使用了一些版本比较老的第三方模块,它里边用到了jquery或者lodash等第三方库,而这些模块并没有使用ES6 moudle的 import引入这些第三方库,<br>这时候打包会出错,使用providePlugin,可以在模块中自动引入依赖的第三方库
用途
自动引入第三方库
new webpack.providePlugin({<br> $: 'jquery'<br>})<br>
当发现一个模块中使用了$,就会在模块里自动引入jquery这个模块,然后把$作为模块的名字<br>即,在底层完成了 import $ from 'jquery'
改变this的指向
安装 imports-loader<br>修改配置 loader: 'imports-loader?this=>window'
this默认指向它所在的模块<br>改变this的指向,让它指向window
5.webpack实战配置案例
Library打包(库打包)
引子
当自己实现一个库时,打包后的文件给别人使用,用户可能会使用各种引入方式,比如 ES6 module 、CommonJS 、AMD、 <script>。。。<br>你要如何配置才能支持用户的各种引入方式?
配置
ouput:{<br> <font color="#c41230"> library</font>:'root',<br> <font color="#c41230">libraryTarget</font>:'umd' <br>},<br>
<script>标签引入
library:'root',
生成一个全局变量root,用户可以在<srcipt src='root.js'></script>中引入
模块化引入
libraryTarget:' umd'
表示用户可以用任意的模块引入方式引入这个这个模块
libraryTarget:' this'
变量root会注入到this对象中
libraryTarget:' window'
变量root会注入到window对象中
防止重复引入
<font color="#c41230">externals</font>:['lodash']
externals的值为数组或对象
<font color="#c41230">表示打包过程中要忽略打包的库,防止使用时用户重复引入库</font>
发布npm包
npm adduser 用户 密码 邮箱 <br><font color="#c41230">npm publish 把项目发布到npm的仓库里</font><br>
TypeScript的打包配置
typescript
它是javascript的一个超集
规范了js语法,提升代码的可维护性
安装配置
安装
npm install ts-loader typescript -D
创建tsconfig.js文件,并配置
配置webpack.config.js
多页面打包配置
<font color="#c41230">多页面应用的本质就是创建多个HtmlWebpackPlugin</font>
增加入口
创建htmlWebpackPlugin
chunks的作用
让index.html中只引入index.js,list.html中只引入list.js<br>如果不配置chunks,.html中会引入所有的.js文件
6.webpack底层原理及脚手架分析
如何编写一个loader
<font color="#c41230">loader本质</font>
它是一个<font color="#c41230">函数</font>
写一个loader<br>并使用
使用自己写的loader
配置webpack
<font color="#c41230">写一个loader</font>
编写一个loader
<font color="#c41230">不能写成箭头函数</font>,要<font color="#c41230">写成声明式函数</font>,<br>因为这个函数里需要用this,webpack在调loader时,会把this做一下变更,变更之后才能使用this里的一些方法
<font color="#c41230">source</font>是引入文件的内容,即<font color="#c41230">源代码</font>,<font color="#c41230">loader可以针对该源代码进行一些加工,返回你想要的内容</font>
常见使用场景
捕获业务代码异常
可以对业务代码进行异常捕获,当检测到function时,把它放入try{function(){}}catch(e){}中
实现整个网站的国际化
伪代码
在业务代码中,使用{{title}}占位符,loader会根据不同的语言环境,把网站打包成不同的语言版本
如何编写一个plugin
<font color="#c41230">插件本质</font>
它<font color="#c41230">是一个类</font>
编写&使用插件
<font color="#c41230">定义一个插件</font>
一个插件的基本格式
使用插件
在webpack.config.js中配置plugins
<font color="#c41230">以new 一个类实例的形式来使用</font>
插件的参数
传递参数
webpack配置文件
用name给插件传递参数
接受参数
在插件中,options接受参数
webpack性能优化
提高打包速度
1. <font color="#c41230">跟上技术的迭代(Node,Npm,Yarn)</font><br>
新版本的webpack node等性能更好,打包更快
2. <font color="#c41230">在尽可能少的模块上应用Loader</font>
<font color="#c41230">合理的使用include和exclude,减少loader的作用范围,减少一些无用的分析可以加快打包速度</font>
3. <font color="#c41230">Plugin尽可能精简并确保可靠</font>
尽量少的使用插件,并确保每一个插件的可靠性和性能(尽量使用官方插件,性能有保证)<br>在开发环境下,不要使用代码压缩插件,节约代码压缩这部分的打包时间
4<font color="#c41230">.resolve参数合理配置</font>
<font color="#c41230">extensions: ['.js','.jsx']</font>
这个作用是引入文件的时候省略后缀名
要合理配置,如果配置过多,需要查找很多次有没有这些后缀的文件,会有性能损耗<br>因此,建议只把.js .jsx .vue 配置到extensions里,资源类的引入时直接带着后缀引入<br>
<font color="#c41230">alias</font>:{<br> child: path.resolve(__dirname,'../src/child')<br>}
指定一个路径的别名,当引入child时,其实是引入的'../src/child'
5.<font color="#c41230">使用DllPlugin提高打包速度</font>
问题
引入很多第三方库,每次打包时,都要从node-modules中取出这些库,然后把这些库打包到源代码中<br>每次打包时重复打包这些第三方库,导致打包时间很长
解决思路
而<font color="#c41230">这些第三方库几乎不怎么变化,第一次打包时把这些第三方库打包成一个文件存起来,<br>之后再打包时,直接用第一次打包存起来的代码</font><br>
目标:
1.第三方模块打包一次
2.引入第三方模块的时候,使用.dll文件引入
6.控制包文件大小
没用的包去除掉,或者不要引入
把大文件拆分成小文件<br>
7.<font color="#c41230">thread-loader , parallel-webpack , happypack 多进程打包</font>
webpack默认是通过nodejs来运行的,所以它是单进程的打包<br>可以借助node的多进程提升打包速度
thread-loader , happypack
多进程打包
parallel-webpack
多页应用打包时,通过parallel-webpack对多个页面一起进行打包
8<font color="#c41230">.合理使用sourceMap</font>
打包时生成sourcemap,内容越详细,打包越慢,根据情况合理使用
9.结合stats分析打包结果
10.开发环境内存编译
在开发环境使用devServer,它在做打包时不会生成dist目录,它会把编译生成的文件放到内存里,内存的读取比硬盘快
11.开发环境无用插件剔除
比如在开发环境,不需要进行代码压缩,所以不要使用压缩代码的插件
这些文章太旧了,<br>很多插件已经弃用了<br>白整理了啊 ~ ~ ~
面试题1
几个常见的loader
<ul><li><font color="#c41230">babel-loader</font>:把 ES6 转换成 ES5</li></ul>
<ul><li><font color="#c41230">file-loader</font>:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件</li><li><font color="#c41230">url-loader</font>:和 file-loader 类似,但是能在文件很小的情况下以 base64 的方式把文件内容注入到代码中去</li></ul>
<ul><li><font color="#c41230">style-loader</font>:把 CSS 代码注入到 JavaScript 中,通过 DOM 操作去加载 CSS。</li><li><font color="#c41230">css-loader</font>:加载 CSS,支持模块化、压缩、文件导入等特性</li><li><font color="#c41230">sass-loader</font>: Loads a SASS/SCSS file and compiles it to CSS.</li></ul>
<ul><li><font color="#c41230">source-map-loader</font>:加载额外的 Source Map 文件,以方便断点调试</li></ul>
<ul><li>ts-loader</li></ul>
webpack v5中的
几个常见的plugin
<ul><li><font color="#c41230">html-webpack-plugin</font>: 为html文件中引入的外部资源,可以生成创建html入口文件</li></ul>
<ul><li>DllPlugin</li></ul>
这个插件是在一个额外的独立的 webpack 设置中创建一个只有 dll 的 bundle(dll-only-bundle)。<br>这个插件会生成一个名为 manifest.json 的文件,这个文件是用来让 DLLReferencePlugin 映射到相关的依赖上去的。
<ul><li><font color="#c41230">SplitChunksPlugin</font></li></ul>
Since version 4 the CommonsChunkPlugin was removed in favor of <br>optimization.splitChunks and optimization.runtimeChunk options.
<ul><li><font color="#c41230">HotModuleReplacementPlugin</font></li></ul>
永远不要在生产环境(production)下启用 HMR
<ul><li><font color="#c41230">DefinePlugin</font></li></ul>
DefinePlugin 允许创建一个在编译时可以配置的全局常量。<br>这可能会对开发模式和发布模式的构建允许不同的行为非常有用
<ul><li><font color="#c41230">uglifyjs-webpack-plugin</font>:通过UglifyES压缩ES6代码</li></ul>
clean-webpack-plugin:删除打包文件<br>
webpack有哪些优点
1、专注于处理模块化的项目,能做到开箱即用,一步到位<br>2、可通过plugin扩展,完整好用又不失灵活<br>3、使用场景不局限于web开发<br>4、社区庞大活跃,经常引入紧跟时代发展的新特性,能为大多数场景找到已有的开源扩展<br>5、良好的开发体验
分别介绍bundle,chunk,module是什么
<font color="#c41230">bundle</font>:是由webpack打包出来的文件,<br><font color="#c41230">chunk</font>:代码块,一个chunk由多个模块组合而成,用于代码的合并和分割。<br><font color="#c41230">module</font>:是开发中的单个模块,在webpack的世界,一切皆模块,一个模块对应一个文件,webpack会从配置的entry中递归开始找出所有依赖的模块。
面试题2
5.Loader和Plugin的不同?
不同的作用
<font color="#c41230">Loader直译为"加载器"</font>。Webpack将一切文件视为模块,但是<font color="#c41230">webpack原生是只能解析js文件</font>,如果想将其他文件也打包的话,就会用到loader。 所以<font color="#c41230">Loader的作用是让webpack拥有了加载和解析非JavaScript文件的能力</font>。<br><ul><li>Plugin直译为"插件"。<font color="#c41230">Plugin可以扩展webpack的功能,让webpack具有更多的灵活性</font>。 <font color="#c41230">在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果</font>。</li></ul>
不同的用法
<font color="#c41230">Loader在module.rules中配置</font>,也就是说他作为模块的解析规则而存在。 类型为数组,每一项都是一个Object,里面描述了对于什么类型的文件(test),使用什么加载(loader)和使用的参数(options)<br><font color="#c41230">Plugin在plugins中单独配置</font>。 <font color="#c41230">类型为数组,每一项是一个plugin的实例</font>,参数都通过构造函数传入。
6.webpack的构建流程是什么?<br>从读取配置到输出文件这个过程尽量说全
Webpack 的运行流程是一个串行的过程,从启动到结束会依次执行以下流程:<br><br>1、<font color="#c41230">初始化参数</font>:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数;<br>2、<font color="#c41230">开始编译</font>:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译;<br>3、<font color="#c41230">确定入口</font>:根据配置中的 entry 找出所有的入口文件;<br>4、<font color="#c41230">编译模块</font>:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理;<br>5、<font color="#c41230">完成模块编译</font>:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系;<br>6、<font color="#c41230">输出资源</font>:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会;<br>7、<font color="#c41230">输出完成</font>:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。<br>在以上过程中,Webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用 Webpack 提供的 API 改变 Webpack 的运行结果。<br><br>在以上过程中,Webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用 Webpack 提供的 API 改变 Webpack 的运行结果。<br>
7.是否写过Loader和Plugin?<br>描述一下编写loader或plugin的思路?
Loader像一个"翻译官"把读到的源文件内容转义成新的文件内容,并且每个Loader通过链式操作,将源文件一步步翻译成想要的样子。<br><br>编写<font color="#c41230">Loader时要遵循单一原则,每个Loader只做一种"转义"工作</font>。 每个Loader的拿到的是源文件内容(source),可以通过返回值的方式将处理后的内容输出,也可以调用t<font color="#c41230">his.callback()</font>方法,将内容返回给webpack。 还可以通过 <font color="#c41230">this.async()</font>生成一个callback函数,再用这个callback将处理后的内容输出出去。 此外webpack还为开发者准备了开发loader的工具函数集——<font color="#c41230">loader-utils</font>。<br><br>相对于Loader而言,Plugin的编写就灵活了许多。 <font color="#c41230">webpack在运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。</font>
9.如何利用webpack来<font color="#c41230">优化前端性能</font>?(提高性能和体验)
用webpack优化前端性能是指优化webpack的输出结果,让打包的最终结果在浏览器运行快速高效。<br><br>1、<font color="#c41230">压缩代码</font>。删除多余的代码、注释、简化代码的写法等等方式。可以利用webpack的UglifyJsPlugin和ParallelUglifyPlugin来压缩JS文件, 利用cssnano(css-loader?minimize)来压缩css<br>2、<font color="#c41230">利用CDN加速</font>。在构建过程中,将引用的静态资源路径修改为CDN上对应的路径。可以利用webpack对于output参数和各loader的publicPath参数来修改资源路径<br>3、<font color="#c41230">删除死代码(Tree Shaking)</font>。将代码中永远不会走到的片段删除掉。可以通过在启动webpack时追加参数--optimize-minimize来实现<br>4、<font color="#c41230">提取公共代码</font>。
10.如何提高webpack的构建速度?
<strike>1、多入口情况下,使用CommonsChunkPlugin来提取公共代码(CommonsChunkPlugin被弃用了)</strike><br>2、通过externals配置来提取常用库<br>3、利用DllPlugin和DllReferencePlugin预编译资源模块 通过DllPlugin来对那些我们引用但是绝对不会修改的npm包来进行预编译,再通过DllReferencePlugin将预编译的模块加载进来。<br><strike>4、使用Happypack 实现多线程加速编译(效果不好)</strike><br>5、使用<strike>webpack-uglify-paralle(官网查不到)l</strike>来提升uglifyPlugin的压缩速度。 原理上<strike>webpack-uglify-parallel</strike>采用了多核并行压缩来提升压缩速度<br>6、使用Tree-shaking和Scope Hoisting来剔除多余代码
11.怎么配置单页应用?怎么配置多页应用?
单页应用可以理解为webpack的标准模式,直接<font color="#c41230">在entry中指定单页应用的入口</font>即可,这里不再赘述<br><br>多页应用的话,可以使用webpack的<strike> AutoWebPlugin(查不到)</strike>来完成简单自动化的构建,但是前提是项目的目录结构必须遵守他预设的规范。 多页应用中要注意的是:<br><br>1、每个页面都有公共的代码,可以将这些代码抽离出来,避免重复的加载。比如,每个页面都引用了同一套css样式表<br>2、随着业务的不断扩展,页面可能会不断的追加,所以一定要让入口的配置足够灵活,避免每次添加新页面还需要修改构建配置
面试题3
一、优化构建速度
缩小文件的搜索范围
使用DllPlugin减少基础模块编译次数
<strike style="">使用HappyPack开启多进程Loader转换</strike><strike>(happypack 效果不好)</strike>
使用<strike>ParallelUglifyPlugin(查不到)</strike>开启多进程压缩JS文件
二、优化开发体验
使用自动刷新
Webpack监听文件
1. 启动时 webpack --watch
2. 在配置文件中设置watch:true
DevServer刷新浏览器
开启模块热替换HMR
开启方式
1、webpack-dev-server --hot<br>2、使用HotModuleReplacementPlugin,比较麻烦
开启后如果修改子模块就可以<font color="#c41230">实现局部刷新</font>
三、<font color="#c41230">优化输出质量-压缩文件体积</font>
区分环境--减小生产环境代码体积
DefinePlugin
压缩代码-JS、ES、CSS
压缩JS:Webpack内置<strike>UglifyJS插件、ParallelUglifyPlugin(官网都查不到)</strike>
压缩ES6
<font color="#c41230">uglify-webpack-plugin(v5中的)</font>提供了压缩ES6代码的功能
另外<font color="#c41230">要防止babel-loader转换ES6代码</font>,要在<font color="#c41230">.babelrc</font>中去掉babel-preset-env,<br>因为正是<font color="#c41230">babel-preset-env负责把ES6转换为ES5</font>
压缩CSS:
<strike>css-loader?minimize(查不到minimize)</strike>
css-loader内置了cssnano,只需要使用 css-loader?minimize 就可以开启cssnano压缩
cssnano基于PostCSS,不仅是删掉空格,还能理解代码含义
<strike>PurifyCSSPlugin(查不到)</strike>
需要配合 extract-text-webpack-plugin (v5 中的)使用,它主要的作用是可以去除没有用到的CSS代码,类似JS的Tree Shaking
使用Tree Shaking剔除JS死代码
它正常工作的前提是代码<font color="#c41230">必须采用ES6的模块化语法</font>,<br>因为ES6模块化语法是静态的(<font color="#c41230">在导入、导出语句中的路径必须是静态字符串,且不能放入其他代码块中</font>)
启用Tree Shaking
1、修改.babelrc以保留ES6模块化语句
2、启动webpack时带上 --display-used-exports可以在shell打印出关于代码剔除的提示<br>3、使用<strike>UglifyJSPlugin(v3 中的)</strike>,或者启动时使用--optimize-minimize<br>4、在使用第三方库时,需要配置 resolve.mainFields: ['jsnext:main', 'main'] 以指明解析第三方库代码时,采用ES6模块化的代码入口
四、<font color="#c41230">优化输出质量--加速网络请求</font>
<font color="#c41230">使用CDN加速静态资源加载</font>
1、<font color="#c41230">HTML文件:放在自己的服务器上且关闭缓存,不接入CDN<br>2、静态的JS、CSS、图片等资源:开启CDN和缓存,同时文件名带上由内容计算出的Hash值</font>,<br>这样只要内容变化hash就会变化,文件名就会变化,就会被重新下载而不论缓存时间多长
<font color="#c41230">多页面应用提取页面间公共代码,以利用缓存</font>
原理
<font color="#c41230">大型网站通常由多个页面组成,每个页面都是一个独立的单页应用,多个页面间肯定会依赖同样的样式文件</font>、技术栈等。<br>如果不把这些公共文件提取出来,那么每个单页打包出来的chunk中都会包含公共代码,相当于要传输n份重复代码。<br>如果把公共文件提取出一个文件,那么当用户访问了一个网页,加载了这个公共文件,再访问其他依赖公共文件的网页时,就直接使用文件在浏览器的缓存,这样公共文件就只用被传输一次。
相比于webpack3,4.0版本用<font color="#c41230">optimization.splitChunks</font>配置替换了3.0版本的CommonsChunkPlugin插件
<font color="#c41230">分割代码以按需加载</font>
原理
单页应用的一个问题在于使用一个页面承载复杂的功能,要加载的文件体积很大,不进行优化的话会导致首屏加载时间过长,影响用户体验。做按需加载可以解决这个问题
具体方法如下
1、将网站功能按照相关程度划分成几类<br>2、每一类合并成一个Chunk,按需加载对应的Chunk<br>3、例如,只把首屏相关的功能放入执行入口所在的Chunk,这样首次加载少量的代码,其他代码要用到的时候再去加载。最好提前预估用户接下来的操作,提前加载对应代码,让用户感知不到网络加载
做法
一个最简单的例子:网页首次只加载main.js,网页展示一个按钮,点击按钮时加载分割出去的show.js,加载成功后执行show.js里的函数
import(/* webpackChunkName:show */ './show').then() 是实现按需加载的关键,<br>Webpack内置对import( *)语句的支持,<font color="#c41230">Webpack会以./show.js为入口重新生成一个Chunk</font>。<br>代码在浏览器上运行时只有点击了按钮才会开始加载show.js,且import语句会返回一个Promise,加载成功后可以在then方法中获取加载的内容。<br>这要求浏览器支持Promise API,对于不支持的浏览器,需要注入Promise polyfill。<br>/* webpackChunkName:show */ 是定义动态生成的Chunk的名称,默认名称是[id].js,定义名称方便调试代码。
五、优化输出质量--提升代码运行时的效率
<strike>使用Prepack提前求值</strike>
<strike>prepack-webpack-plugin</strike>
现在Prepack还<font color="#c41230">不够成熟</font>,<font color="#c41230">用于线上环境还为时过早</font>
使用Scope Hoisting
作用域提升
需要分析模块间的依赖关系,所以源码必须是采用了ES6模块化的
六、使用输出分析工具
启动Webpack时带上这两个参数可以生成一个json文件,输出分析工具大多依赖该文件进行分析
1、官方工具Webpack Analyse
2、webpack-bundle-analyzer
可视化分析工具,比Webapck Analyse更直观
七、其他Tips
1、配置babel-loader时,<font color="#c41230">use: [‘babel-loader?cacheDirectory’] cacheDirectory用于缓存babel的编译结果</font>,<font color="#c41230">加快重新编译的速度</font>。另外注意排除node_modules文件夹,因为文件都使用了ES5的语法,没必要再使用Babel转换。<br>2、配置<font color="#c41230">externals,排除因为已使用<script>标签引入而不用打包的代码</font>,noParse是排除没使用模块化语句的代码。<br>3、配置performance参数可以输出文件的性能检查配置。<br>4、配置profile:true,是否捕捉Webpack构建的性能信息,用于分析是什么原因导致构建性能不佳。<br>5、配置<font color="#c41230">cache:true</font>,是否启用缓存来提升构建速度。<br>6、可以使用<font color="#c41230">url-loader把小图片转换成base64嵌入到JS或CSS中,减少加载次数</font>。<br>7、<strike>通过imagemin-webpack-plugin压缩图片(查不到imagemin-webpack-plugin)</strike><br>8、<font color="#c41230">开发环境下将devtool设置为cheap-module-eval-source-map</font>,因为生成这种source map的速度最快,能加速构建。<br> 在生产环境下将devtool设置为hidden-source-map
博客总结
优质资料
带你深度解锁Webpack系列(基础篇)
带你深度解锁Webpack系列(进阶篇)
带你深度解锁Webpack系列(优化篇)
一步步从零开始用 webpack 搭建一个大型项目
几个常见的loader
<ul><li><font color="#c41230">babel-loader</font>:把 ES6 转换成 ES5</li></ul>
图片/字体文件处理
<ul><li><font color="#c41230">file-loader</font></li></ul>
把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件
<ul><li><font color="#c41230">url-loader</font></li></ul>
和 file-loader 类似,但是能在文件很小的情况下以 base64 的方式把文件内容注入到代码中去
将资源转换为 base64 可以减少网络请求次数,<br>但是 base64 数据较大,如果太多的资源是 base64,会导致加载变慢,<br>因此设置 limit 值时,需要二者兼顾
<ul><li><font color="#c41230">source-map-loader</font></li></ul>
加载额外的 Source Map 文件,以方便断点调试
<font color="#c41230">处理样式文件</font>
<ul><li><font color="#c41230">style-loader</font></li></ul>
Adds CSS to the DOM by injecting a <style> tag<br>
<ul><li><font color="#c41230">css-loader</font></li></ul>
The css-loader interprets @import and url() like import/require() and will resolve them
<ul><li><font color="#c41230">postcss-loader</font></li></ul>
处理兼容性问题,自动生成浏览器前缀
<ul><li><font color="#c41230">sass-loader</font></li></ul>
Loads a SASS/SCSS file and compiles it to CSS.
<ul><li><font color="#c41230">less-loader</font></li></ul>
Compiles Less to CSS.
几个常见的plugin
<ul><li><font color="#c41230">html-webpack-plugin</font></li></ul>
按照模板生成一个html文件
<ul><li>DllPlugin</li></ul>
这个插件是在一个额外的独立的 webpack 设置中创建一个只有 dll 的 bundle(dll-only-bundle)。<br>这个插件会生成一个名为 manifest.json 的文件,这个文件是用来让 DLLReferencePlugin 映射到相关的依赖上去的。
<ul><li>DLLReferencePlugin</li></ul>
<ul><li><font color="#c41230">SplitChunksPlugin</font></li></ul>
Since version 4 the CommonsChunkPlugin was removed in favor of <br>optimization.splitChunks and optimization.runtimeChunk options.
<ul><li><font color="#c41230">HotModuleReplacementPlugin</font></li></ul>
永远不要在生产环境(production)下启用 HMR
<ul><li><font color="#c41230">DefinePlugin</font></li></ul>
DefinePlugin 允许创建一个在编译时可以配置的全局常量。<br>这可能会对开发模式和发布模式的构建允许不同的行为非常有用
<ul><li><font color="#c41230">clean-webpack-plugin</font></li></ul>
删除打包文件,每次打包前清空dist目录
处理CSS
<ul><li><font color="#c41230"> mini-css-extract-plugin</font></li></ul>
<font color="#c41230">抽离CSS,</font>即将CSS文件单独打包,<br>这可能是因为打包成一个JS文件太大,影响加载速度,也有可能是为了缓存(例如,只有JS部分有改动)
<ul><li><font color="#c41230">optimize-css-assets-webpack-plugin</font></li></ul>
<font color="#c41230">将抽离出来的css文件进行压缩</font>
一些弃用的或者项目中无须使用的
<strike>uglifyjs-webpack-plugin</strike>
通过UglifyES压缩ES6代码
进阶
<b><font color="#ffffff">按需加载</font></b>
<font color="#c41230">import()</font>
很多时候我们不需要一次性加载所有的JS文件,而应该在不同阶段去加载所需要的代码。<br>webpack内置了强大的分割代码的功能可以实现按需加载。
import() 语法,需要 @babel/plugin-syntax-dynamic-import 的插件支持,<br>但是因为当前 <font color="#c41230">@babel/preset-env </font>预设中已经包含了 @babel/plugin-syntax-dynamic-import,因此我们<font color="#c41230">不需要再单独安装和配置</font>。<br>
构建结果
webpack 遇到 import(****) 这样的语法的时候,会这样处理:<br>
<ul><li>以**** 为入口新生成一个 Chunk</li><li>当代码执行到 import 所在的语句时,才会加载该 Chunk 所对应的文件(如这里的1.bundle.8bf4dc.js)</li></ul>
<font color="#ffffff">热更新</font>
<ol><li>首先配置 devServer 的 hot 为 true</li></ol>
2. 并且在 plugins 中增加<br> new webpack.HotModuleReplacementPlugin()
3. 在入口文件中新增
此时,再修改代码,不会造成整个页面的刷新
多页应用打包
配置
目录
配置chunks 参数,指定html引入的js文件
查看 index.html 和 login.html 会发现,都同时引入了 index.f7d21a.js 和 login.f7d21a.js,通常这不是我们想要的,<br>我们希望,index.html 中只引入 index.f7d21a.js,login.html 只引入 login.f7d21a.js<br><br>HtmlWebpackPlugin 提供了一个 <font color="#c41230">chunks 的参数</font>,可以接受一个数组,配置此参数仅<font color="#c41230">会将数组中指定的js引入到html文件中</font>,<br>此外,如果你需要引入多个JS文件,仅有少数不想引入,还可以指定<font color="#c41230"> excludeChunks </font>参数,它接受一个数组<br>
resolve 配置
resolve 配置 webpack <font color="#c41230">如何寻找模块所对应的文件</font>。<br>webpack 内置 JavaScript 模块化语法解析功能,默认会采用模块化标准里约定好的规则去寻找,<br>但你可以根据自己的需要修改默认的规则。
配置项
modules
resolve.modules 配置 webpack <font color="#c41230">去哪些目录下寻找第三方模块</font>,<font color="#c41230">默认</font>情况下,只会去<font color="#c41230"> node_modules 下寻找</font>,<br>如果你我们项目中某个文件夹下的模块经常被导入,不希望写很长的路径,那么就可以通过配置 resolve.modules 来简化<br>
这样配置之后,我们 import Dialog from 'dialog',会去寻找 ./src/components/dialog,不再需要使用相对路径导入。<br>如果在 ./src/components 下找不到的话,就会到 node_modules 下寻找<br>
alias
resolve.alias 配置项通过别名把原导入路径映射成一个新的导入路径
extensions
用途
适配多端的项目
缺省文件后缀
在导入语句没带文件后缀时,会自动带上extensions 中配置的后缀后,去尝试访问文件是否存在,<br>因此要将高频的后缀放在前面,并且数组不要太长,减少尝试次数。<br>如果没有配置 extensions,默认只会找对对应的js文件
enforceExtension
如果配置了 resolve.enforceExtension 为 true,那么导入语句不能缺省文件后缀。
mainFields
有一些第三方模块会提供多份代码,<br>引入模块时,去找哪个文件以及查找的顺序
区分不同的环境
<ul><li>webpack.base.js 定义公共的配置</li><li>webpack.dev.js:定义开发环境的配置</li><li>webpack.prod.js:定义生产环境的配置</li></ul>
<font color="#c41230">webpack-merge</font> 专为 webpack 设计,提供了一个<font color="#c41230"> merge 函数</font>,用于连接数组,合并对象
定义环境变量
使用 webpack 内置插件<font color="#c41230"> DefinePlugin</font> 来定义环境变量
配置
使用
利用webpack解决跨域问题
假设前端在3000端口,服务端在4000端口,我们通过 webpack 配置的方式去实现跨域
配置代理
优化
量化
speed-measure-webpack-plugin
speed-measure-webpack-plugin 插件可以测量各个插件和loader所花费的时间
1. <font color="#c41230">exclude/include</font>
确保<font color="#c41230">转译尽可能少的文件</font>。<br>顾名思义,exclude 指定要排除的文件,include 指定要包含的文件
2. <font color="#c41230">cache-loader</font>
在一些性能开销较大的 loader 之前添加 cache-loader,将结果缓存中磁盘中
只打算给 babel-loader 配置 cache 的话,<br>也可以不使用 cache-loader,<br><font color="#c41230">给 babel-loader 增加选项 cacheDirectory</font>
cacheDirectory:默认值为 false。<br>当有设置时,指定的目录将用来缓存 loader 的执行结果。<br><font color="#c41230">之后的 Webpack 构建,将会尝试读取缓存,来避免在每次执行时,可能产生的、高性能消耗的 Babel 重新编译过程</font>。<br>设置空值或者 true 的话,使用默认缓存目录:node_modules/.cache/babel-loader<br>
3. happypack
把任务分解给多个子进程去并发的执行,子进程处理完后再把结果发送给主进程
当你的项目不是很复杂时,不需要配置 happypack,<br>因为进程的分配和管理也需要时间,并不能有效提升构建速度,甚至会变慢
4.thread-loader
除了使用 Happypack 外,我们也可以使用 thread-loader ,<br>把 thread-loader 放置在其它 loader 之前
thread-loader 和 Happypack 我对比了一下,构建时间基本没什么差别。<br>不过 thread-loader 配置起来为简单
5<font color="#c41230">.开启 JS 多进程压缩</font>
虽然很多 webpack 优化的文章上会提及多进程压缩的优化,<br>不管是 webpack-parallel-uglify-plugin 或者是 uglifyjs-webpack-plugin 配置 parallel。<br>不过这里我要说一句,<font color="#c41230">没必要单独安装这些插件,它们并不会让你的 Webpack 构建速度提升</font><br>
当前 Webpack 默认使用的是 <font color="#c41230">TerserWebpackPlugin</font>,<font color="#c41230">默认就开启了多进程和缓存</font>
6. <font color="#c41230">HardSourceWebpackPlugin</font>
<font color="#c41230">HardSourceWebpackPlugin 为模块提供中间缓存</font>,<br>缓存默认的存放路径是: node_modules/.cache/hard-source
首次构建时间变化不大,第二次开始,构建时间降低效果很明显
7. noParse
如果一些第三方模块没有AMD/CommonJS规范版本,可以使用 noParse 来标识这个模块,<br>这样 Webpack 会引入这些模块,但是不进行转化和解析,<br>从而提升 Webpack 的构建性能 ,例如:jquery 、lodash
如果你<font color="#c41230">使用到了不需要解析的第三方依赖</font>,<br>那么配置 noParse 很显然是一定<font color="#c41230">会起到优化作用</font>的
8. resolve
resolve 配置 webpack 如何寻找模块所对应的文件
resolve.moudles
resolve.extensions 配置,默认是 ['.js', '.json']
将频率最高的后缀放在第一位,<br>并且控制列表的长度,以减少尝试次数
项目较小时,优化效果不明显
9. IgnorePlugin
webpack 的内置插件,作用是忽略第三方包指定目录
减小包体积
10. <font color="#c41230">externals</font>
可以将一些JS<font color="#c41230">文件存储在 CDN 上</font>(减少 Webpack打包出来的 js 体积),<br>在 index.html 中通过 <script> 标签引入
希望在使用时,仍然可以通过 import 的方式去引用(如 import $ from 'jquery'),<br>并且希望 webpack <font color="#c41230">不会对其进行打包</font>,此时就可以配置 externals
11. <font color="#c41230">DllPlugin</font>
有些时候,如果<font color="#c41230">所有的JS文件都打成一个JS文件,会导致最终生成的JS文件很大</font>,<br>这个时候,我们就要考虑<font color="#c41230">拆分 bundles</font>
DllPlugin 和 DLLReferencePlugin 可以<font color="#c41230">实现拆分 bundles</font>,<br>并且可以<font color="#c41230">大大提升构建速度</font>,<br>DllPlugin 和 DLLReferencePlugin 都是 webpack 的内置模块
使用 DllPlugin 将不会频繁更新的库进行编译,<br><font color="#c41230">当这些依赖的版本没有变化时,就不需要重新编译</font>
配置
在一个新建的配置文件中,<br>把第三方库单独打包成一个动态链接库
打包后,生成动态链接库
dist<br>└── dll<br> ├── manifest.json<br> └── react.dll.9dcd9d.js
manifest.json 用于让 DLLReferencePlugin 映射到相关依赖上
在主配置文件中
在html文件中引入dll文件
<script src="/dll/react.dll.9dcd9d.js"></script>
效果
构建速度
构建时间缩短,<br>尤其是modules with no loaders,这项构建时间缩短较为明显
体积
打包后的bundle.js体积减少
12. <font color="#c41230">optimization.splitChunks</font><br><font color="#c41230"> 抽离公共代码</font>
抽离公共代码是<font color="#c41230">对于多页应用来说的</font>,<br>如果多个页面引入了一些公共模块,那么可以<font color="#c41230">把</font>这些<font color="#c41230">公共的模块抽离出来,单独打包</font>。<br><font color="#c41230">公共代码</font>只需要<font color="#c41230">下载一次就缓存</font>起来了,<font color="#c41230">避免了重复下载</font>
抽离公共代码对于单页应用和多页应该在配置上没有什么区别,<br>都是<font color="#c41230">配置在 optimization.splitChunks 中</font>
即使是<font color="#c41230">单页应用</font>,<font color="#c41230">同样可以使用这个配置</font>,<br>例如,打包出来的 bundle.js 体积过大,<br>我们可以将一些依赖打包成动态链接库,然后将剩下的第三方依赖拆出来。<br>这样可以有效减小 bundle.js 的体积大小<br>当然,你还可以继续提取业务代码的公共模块<br>
效果
配置DllPlugin 和 SplitChunks 后,General output time有所减少(不包含dll打包时间)
runtimeChunk
runtimeChunk 的作用是将包含 chunk 映射关系的列表从 main.js 中抽离出来,<br>在配置了 splitChunk 时,记得配置 runtimeChunk.
optimization: {<br> runtimeChunk: {<br> name: 'manifest'<br> }<br> }
终构建出来的文件中会生成一个 manifest.js
借助 <font color="#c41230">webpack-bundle-analyzer</font> 进一步优化
在做 webpack 构建优化的时候,vendor 打出来超过了1M,react 和 react-dom 已经打包成了DLL。<br><br>因此需要借助 webpack-bundle-analyzer 查看一下是哪些包的体积较大
配置
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;<br>。。。<br>plugins: [<br> //...<br> new BundleAnalyzerPlugin(),<br> ]<br>
npm run build 构建,<br>会默认打开: http://127.0.0.1:8888/,<br>可以看到各个包的体积
打包后的 vendor 太大了
使用 splitChunks 进行拆分
13.webpack自身的优化
<font color="#c41230">tree-shaking</font>
如果使用ES6的import 语法,<br>那么在<font color="#c41230">生产环境</font>下,会<font color="#c41230">自动移除没有使用到的代码</font>
<font color="#c41230">scope hosting 作用域提升</font>
变量提升,可以<font color="#c41230">减少一些变量声明</font>。<br>在<font color="#c41230">生产环境</font>下,<font color="#c41230">默认开启</font>
babel 配置的优化
0 条评论
下一页