为什么要使用构建工具?
- 转换ES6语法(浏览器的兼容)
- 转换JSX
- css前缀补全/预处理器
- 压缩混淆
- 图片压缩
webpack的脚本
const path = require('path')
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
}
grunt、gulp、webpack的区别
-
grunt(task runner 任务运行工具)
run(‘sass’) **/.sass – sass – **/.css – .tmp/
run(‘autoprefixer’) **/.css – auto-prefixer – **/.css – dest -
gulp(流式的task runner) 未处理完的文件放在内存,不放在本地磁盘,没有.tmp/。处理完的文件放dest
-
webpack(模块打包器)
entry 打包入口 查询依赖树模块列表
webpack可以识别模块列表
loaders(test:/.js$/)(‘babel-loader’ options)
plugins(webpack的拓展)
将不需要首屏出现的文件分割出来
前端资源加载 根据模块的依赖关系进行静态分析,然后将这些模块安装指定的规则生成静态文件 https://webpack.js.org/
webpack的流程
流程:1) 初始化参数:合并配置文件和shell命令,得出最终参数
2)加载模块:将上一步得到的参数处理comfiler对象,加载所有配置的插件,执行对象中的run方法,开始执行编译
3)确定入口:找到entry的所有入口文件
4)模块编译:调用所有配置的loader(模块转换器),加载并转换模块
5)完成模块编译:根据依赖关系,形成模块依赖树
6)输出资源:根据入口与模块的关系,组装成一个个包含多个模块的chunk,将chunk打包成单独的文件,并加入输出列表。这是webpack最后一次允许修改输出内容的步骤。
7)输出完成:确定输出文件的路径、文件名,将输出文本写入文件系统。
整个过程中,webpack可以发送特定的广播事件,可以通过plugin实行监听,可以调用webpack的内置api来改变webpack的运行结果。
webpack内置的stats
输出打包信息:
package.json
'script': {
'build:stats': 'webpack --env production --json > stats.json'
}
node的API也可以使用,但是颗粒度比较低
速度分析
speed-measure-webpack-plugin 分析哪个步骤比较耗时
体积分析
webpack-bundle-analyze (构建完端口是8888)
如果包太大,可以通过cdn引入。
构建速度优化
- 使用webpack4
- 多线程构建 happypack(每次webpack解析一个模块,HappyPack会将它及它的依赖分配给worker线程
) 、thread loader、parraller-webpack–并行解析加载 uglyjs-webpack-plugin的parralle参数 --并行压缩 12s-5s - 分包 5.5s -5.0s
1)设置externals html-webpack-externals-plugin(使react、react-dom基础包通过cdn引入,不打入bundle中)
2)预编译资源模块(dll) 调用dllPlugin分包,通过 dllReferencePlugin对mainfest.json引用(使react、react-dom、redux、react-redux基础包和业务基础包,打成一个包) 减少请求数量 - 缓存 : 提升二次构建速度
HardSourceWebpackPlugin或者cache loader - 缩小构建目标:尽可能少构建模块 5.03s–4.63s
babel-loader 不打包 node_modules 发布npm包的时候,都是将es6语法编译成es5语法。
moudle.exports = {
rules:{
test:/.js$/,
loader:‘happypack/loader’,
exclude: ‘node_modules’
}
}
构建体积优化
- Scope Hositing (顺序加载依赖 将多个bundle放在一个闭包里,加快代码运行速度)
new Webpack.optimize.ModuleConcatenationPlugin() -> optimization.concatenateModules
每个模块都需要包裹umd的头,模块多,体积就越大,存在大量的重复闭包代码。
Scope Hositing解决的就是这个问题,将模块按照引用顺序去存放在一个函数作用域里,然后重命名一些变量防止变量冲突。
scope hositing可以减少函数的声明。
2. Tree Shaking (只打包使用到的方法,没使用到的shaking掉, 没用到的在uglify擦除掉) .babelrc modules:false 必须使用esm 静态方法
3. 公共资源分离 (项目级别,抽离公共资源。避免每个页面都打入同一资源) SpitChunksPlugin CommonsChunkPlugin
4. 图片压缩 (图片自动化压缩,图片比较占体积)基于node库的imagemin或者tinypng的API
image-webpack-loader 500k - 200k
5. 动态polyfill (es6很多语法都不支持,babel只是做了一些事情,es6里面很多语法(map、set),babel转不了,要借助polyfill去做。polyfill的包比较大;就需要动态。)polyfill service 使用官方的服务 自己搭建服务
webpack4.0跟3.0的区别
1、mode属性 development 、 production
webpack --mode development
开发:
浏览器调试工具
注释、开发阶段的详细错误日志和提示
快速和优化的增量构建机制
生产:
开启所有优化代码
更小的bundle
去掉只在开发阶段运行的代码
Scope hosting Tree shaking
2、插件和优化
删除了CommonsChunkPlugin
内置了optimization.splitChunks和optimization.runtimeChunk
NoEmitOnErrorsPlugin -> optimization.noEmitOnErrors
ModuleConcatenationPlugin(体积优化策略) -> optimization.concatenateModules
NamedModulesPlugin -> optimization.namedModules
uglifyjs-webpack-plugin(加密,丑化代码) 升级1.0
3、开箱即用WebAssembly(汇编 wasm)
(java代码,java虚拟机执行的二进制文件,文件在java虚拟机编译的二进制)
在web执行二进制语法,性能的补充。
新机制将代码编译成二进制文件,在网络浏览器上运行
js在浏览器运行效率比较低,出现了wasm,性能的补充
4、支持五种模式
说说 AMD CMD ESModule(ESM)
AMD 依赖前置(把模块的依赖可能产生的变化没有放在第三个模块去写)
define([‘a’, ‘b’], function(a, b) {})
CMD 依赖就近 耦合性强一点 模块有点耦合
require(a)
前两者,运行时机制,动态引入,运行时打包
if(true){
const path = require('path')
}else{
const path = require('fs')
}
esm 静态引入,不能放在代码里面,代码的预分析,项目的依赖结构(依赖树)
if(true){
import a from './a'
}else{
import b from './b'
} //不可以
5、OCJS(0 config js)
默认入口 ‘./src’
默认出口 ‘./dist’
6、新的插件系统
提供了针对插件和钩子的新API
开发插件 选择sync/callback/promise插件类型
this.hooks = {myHook: new SyncHook(…)} 注册hook
webpack4 node.js的版本>=8.9.4
wbepack使用很多js新的语法,在新版本v8里经过了优化
为什么要学node?
vue、react不能在浏览器跑,要借助webpack,做代码编译转换。webpack
要借助node的实现。前端的工程化,webpack打包工具。