为会么要用webpack
?
- 首先是编译
loader
:针对jsx
,ts
等的js
通过babel
编译。针对less
,sass
等的css
编译. - 文件打包:一般通过打包压缩
ugliyJS
- 模块化:依赖,网络请示
webpack
是一个前端资源动态加载/打包工具,会分析模块的依赖,并将模块根据指定规则生成静态资源,同一个文件的代码会打包成一个Bundle
文件。
模块打包运行原理
- 读取
webpack
的配置参数 - 启动
webpack
,创建compiler
对象并开始解析项目 - 从入口文件
entry
开始解析,并找到对应导入的依赖模块,递归分析,形成依赖关系树 - 对不同文件类型的依赖模块文件使用对应的
loader
进行编译,最终转为js
文件 - 整个过程中
webpack
会通过发布订阅模式,向外抛出一些hooks
,而webpack
的插件会通过监听这些关键的事件节点,执行插件任务达到干预输出结果的目的。
其中文件解析与构建是一个比较复杂的过程,在webpack
源码中主要依赖于compiler
和compilation
2个核心对象实现。compiler
对象是一个全局单例,它负责把控整个webpack
打包的构建流程,compilation
对象是每一次构建的上下文对象,它包含了当次构建所需要的所有信息,每次热更新和重新构建compiler
都会重新生成一个新的compilation
对象,负责此次更新的构建过程。
而每个模块间的依赖关系,则依赖于AST
语法树,每个模块文件在loader
解析完后,会通过acorn
库生成模块代码的AST
语法树,通过语法树就可以分析这个模块是否还有依赖的模块,进而继续循环执行下一个模块的编译解析。
最终webpack
打包出来的bundle
文件是一个立即执行函数。
webpack
配置,webpack.config.js
首先webpack
是js
代码,js
是需要在运行环境下才能运行的,那我们的webpack
就是在nodejs
(后端服务器)中运行的。
配置开头的require
,用的就是node
的内置模块,require
是运行webpack
时调用.
为什么不用import
是因为,import
是编译时调用,是解构过程,它也是es6
,需要转换成es5
再执行,import
会转码成require
.webpack
的配置文件内容是不经过编译的。
loader
loader
是用来编译处理源文件的,比如es6
,ts
,less
等都要通过loader
编译成浏览器识别的语言。
loader
的执行顺序:从下往上,从右往左。use:['style-loader','css-loader']
;loader
可以链式调用,链中的每个loader
都会对资源进行转换,第一个loader
会将结果(被转换后的资源)传递给下一个loader
的入参,最后的loader
返回js
;loader
的其它配置:
plugin
plugin
主要是对webpack
功能的扩展。
插件可以携带参数/选项,所以要在webpack
配置中,向Plugin
传入new
实例。
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
plugins: [
new HtmlWebpackPlugin({ title: '管理输出'}),//生成新的html文件,并把打包好的js文件引入
new CleanWebpackPlugin(),//清理dist文件夹
]
plugin
的机制基于事件流框架tapable
,这个小型library
是webpack
的一个核心工具,也用于以提供类似的插件接口,webpack
中许多对象扩展自tapable
类,这个类暴露tap
、tapAsync
和tapPromise
方法,使用这些方法,注入自定义的构建步骤,这些步骤将在整个编译过程中不同时机触发。(可以理解成一个生命周期,通过它在编译时期来执行方法);
如compile
、run
、compilation
等都是变异的不同周期,不同的周期内部,又提供更加细分的hooks
.compiler
和compilation
暴露的事件钩子总数超过30
个,在特定的阶段钩入想要添加的自定义功能。
根据官方文档说明,一个自定义的plugin
需要包含:
- 一个
js
命名函数 - 插件函数的
prototype
上要有一个apply
方法 - 指定一个绑定到
webpack
自身的事件钩子 - 注册一个回调函数来处理
webpack
实例中的指定数据 - 处理完后调用
webpack
提供的回调
SplitChunksPlugin
分离包 小即是快
总结
打包过程:
- 从一个文件入口,基于代码文件中所有的
import
、export
、require
构建依赖树 - 编译
JS/CSS
等模块 - 使用算法排序、重写、连接代码
- 优化。
开发环境的webpack
:
- 打包所有的代码
- 启动
webpack-dev-server
托管打包好的代码 - 启动
websocket
处理热更新HMR
应用规模越大,启动和热更新代码越慢。即时启动了热更新,每次代码变更也要重新生产Bundle
文件,再走一遍
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。