1.module、chunk、bundle的区别
- module:各个源码文件,webpack中一切建模块。
- chunk:多模块合并成的,代码块。如:entry、 import()、 splitChunk
- bundle:最终输出文件
2.webpack性能优化
可以从两方面来着手考虑:打包构建速度、优化产出代码
打包构建速度:
- 优化babel-loader
①开启缓存:?cacheDirectort
②明确范围:include
、exclude
{
test: /\.js$/,
use: ['babel-loader?cacheDirectort'],//开启缓存
include: path.resolve(__dirname, 'src'),//明确范围
// //排除范围,include 和 exclude 两者选一个即可
// exclude: path.resolve(__dirname, 'node_modules');
}
- IgnorePlugin
避免引入无用模块。
例如:
//避免引入moment 下的 /locale 目录
//plugins配置项中使用webpack中的IgnorePlugin方法(首先得import('webpack'))
plugins: [
// 忽略 moment 下的 /locale 目录
new webpack.IgnorePlugin(/\.\/locale/, /moment/),
]
- noParse
避免重复打包
比如针对react.min.js等已经打包过的文件,不需要重复打包。
跟IgnorePlugin的区别为:IgnorePlugin直接不引入,代码中没有。noParse引入,但不打包。
module.exports = {
module: {
noParse: [/react\.min\.js$/],
}
}
- happyPack
多进程打包
先安装:npm install happypack
。再引入:const happyPack = require('happypack');
modules: {
rules: [
{
text: /\.js$/,
// 把对 .js 文件的处理转交给 id 为 babel 的 HappyPack 实例
use: ['happypack/loader?id=babel'],//跟下面的id对应
incluse: path.join(__dirname, '..', 'src')
}
]
},
plugins: [
// happyPack 开启多进程打包
new HappyPack({
// 用唯一的标识符 id 来代表当前的 HappyPack 是用来处理一类特定的文件
id: 'babel',
// 如何处理 .js 文件,用法和 Loader 配置中一样
loaders: ['babel-loader?cacheDirectory']
}),
]
- ParallelUglifyPlugin
开启多进程压缩js,一般只在生产配置中启用。
备注:1.webpack内置Uglify
巩固压缩JS,但是是单线程的。和happyPack同理。
2.一般只应用于较大项目中使用,按需使用。
配置:
安装:npm install webpack-parallel-uglify-plugin
引入:const ParallelUglifyPlugin = require('npm install webpack-parallel-uglify-plugin');
plugins: [
// 使用 ParallelUglifyPlugin 并行压缩输出的 JS 代码
new ParallelUglifyPlugin({
// 传递给 UglifyJS 的参数
// (还是使用 UglifyJS 压缩,只不过帮助开启了多进程)
uglifyJS: {
output: {
beautify: false, // 最紧凑的输出
comments: false, // 删除所有的注释
},
compress: {
// 删除所有的 `console` 语句,可以兼容ie浏览器
drop_console: true,
// 内嵌定义了但是只用到一次的变量
collapse_vars: true,
// 提取出出现多次但是没有定义成变量去引用的静态值
reduce_vars: true,
}
}
})
]
- 自动刷新
在代码改完保存之后自动打包并刷新页面
实际中使用webpack devServer就自带自动刷新功能 - 热更新(自动刷新的升级版)
自动刷新:整个网页全部刷新,速度较慢,状态会丢失
热更新:新代码生效,网页不刷新,状态不丢失
引入:const HotModuleReplacementPlugin = require('webpack/lib/HotModuleReplacementPlugin');
前提是使用devServer。
涉及entry plugins devServer三个配置项
entry: {
// index: path.join(srcPath, 'index.js'),
index: [
'webpack-dev-server/client?http://localhost:8080/',
'webpack/hot/dev-server',
path.join(srcPath, 'index.js')
]
},
plugins: [
new HotModuleReplacementPlugin()
],
devServer: {
port: 8080,
progress: true, // 显示打包的进度条
contentBase: distPath, // 根目录
open: true, // 自动打开浏览器
compress: true, // 启动 gzip 压缩
hot: true,//开启热更新
// 设置代理
proxy: {
// 将本地 /api/xxx 代理到 localhost:3000/api/xxx
'/api': 'http://localhost:3000',
// 将本地 /api2/xxx 代理到 localhost:3000/xxx
'/api2': {
target: 'http://localhost:3000',
pathRewrite: {
'/api2': ''
}
}
}
},
另外:需要在入口js文件中增加热更新的逻辑代码:
index.js:
//增加,开启热更新之后的代码逻辑
if (module.hot) {
module.hot.accept(['./math'], () => {//数组中接收:哪些文件需要热更新。一旦该文件内容改变,触发热更新,执行该回调函数。
})
}
- DLLPlugin
动态链接库插件
webpack已内置DLLPlugin支持,打包出dll文件,DLLRefrtencePlugin:使用dll文件
优化产出代码:
考虑点:
- 体积更小
- 合理分包,不重复加载
- 速度更快、内存使用更少
方式:
- 小图片base64编码
- bundle加hash
- 懒加载
- 提取公共代码
- IgnorePlugin
- 使用CDN加速:
publicPath
1.可以在output配置项中添加,将修改所有静态文件 url 的前缀(如 cdn 域名)
2.也可以在module rules规则配置中,如图片加载:
{
test: /\.(png|jpg|jpeg|gif)$/,
use: {
loader: 'url-loader',
options: {
// 设置图片的 cdn 地址(也可以统一在外面的 output 中设置,那将作用于所有静态资源)
publicPath: 'http://cdn.abc.com' //cdn地址
}
}
},
- 使用production
在mode中开启production。mode: 'production'
好处:
1.自动开启代码压缩(不需要自己配置了)
2.vue React 等会自动删掉调试代码
3.启动Tree-shaking(会将无用代码删除;必须用ES6 module才能让tree-shaking生效)
备注:ES6 MOdule 和 Commonjs区别:
1.ES6 Module 静态引入,编译时引入
2.Commonjs 动态引入,执行时引入
3.只有ES6 Module才能静态分析,实现Tree-shaking - Scope Hosting
目的:编译过来之后,多个函数合并成一个函数,减少作用域,减少内存cpu的消耗
好处:代码体积更少,代码可读性更好,创建函数作用域更少
使用:
1.引入:const ModuleConcatenationPlugin = require('webpack/lib/optimize/ModuleConcatenationPlugin');
2.开启插件:
plugins: [
resolve: {
//针对 npm中的第三方模块优先采用jsnext:main 中指向的ES6 模块化语法的文件
mainFields: ['jsnext:main', 'browser', 'main']
}
//开启Scope Hosting
new ModuleConcatenationPlugin();
]
3.babel相关
环境搭建&基本配置
- 环境搭建
需要安装一些东西:用package.json配置表示安装哪些:
"devDependencies": {
"@babel/cli": "^7.7.5",
"@babel/core": "^7.7.5",
"@babel/plugin-transform-runtime": "^7.7.5",
"@babel/preset-env": "^7.7.5"
},
"dependencies": {
"@babel/polyfill": "^7.7.0",
"@babel/runtime": "^7.7.5"
}
- .babelrc配置
presets
和plugins
{
"presets": [
[
"@babel/preset-env",//预设看官网,一般就用这个就可以了
{
"useBuiltIns": "usage",
"corejs": 3
}
]
],
"plugins": [//插件 看官网
[
"@babel/plugin-transform-runtime",
{
"absoluteRuntime": false,
"corejs": 3,
"helpers": true,
"regenerator": true,
"useESModules": false
}
]
]
}
运行:npx babel src/index.js
babel-polyfill
-
什么是Polyfill
API补丁 -
core.js 和 regenerator
core.js是所有API补丁的集合,(处理不了generator函数,generator后被aync跟await取代),所以引入了 regenerator库。 -
Babel7.4之后被弃用,推荐直接使用core.js和regenerator语法
Babel只解析语法,但是像Promise、includes等新API不支持解析,需要使用babel-polyfill来解决。并且不处理模块化。所以webpack跟babel需要一起使用
使用:
引入babel-polyfill:import '@babel/polyfill'
备注:babel-polyfill文件很大,可以配置按需引入。不需要import
配置按需引入:
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage",//按需引入
"corejs": 3//版本号
}
]
]
问题:
会污染全局环境,所以要使用babel-runtime
babel-runtime
(功能跟babel-polyfill一样,开发第三方库必须使用babel-runtime)
原理:例如includesAPI,babel-polyfill会执行:Array.prototype.includes = function() { … }。污染全局的includes,而babel-runtime会:Array.prototype._includes = function() { … }。
要安装插件:plugin-transform-runtime、runtime。看pakage.json:
"devDependencies": {
"@babel/cli": "^7.7.5",
"@babel/core": "^7.7.5",
"@babel/plugin-transform-runtime": "^7.7.5",
"@babel/preset-env": "^7.7.5"
},
"dependencies": {
"@babel/polyfill": "^7.7.0",
"@babel/runtime": "^7.7.5"
}
然后在.babelc
中的plugins做配置:
"plugins": [
[
"@babel/plugin-transform-runtime",//使用plugin-transform-runtime
{
"absoluteRuntime": false,
"corejs": 3,//corejs版本
"helpers": true,//帮助提示
"regenerator": true,//是否使用regenerator语法
"useESModules": false//是否使用ESmodule
}
]
]