# 18. webpack相关问题
# 1. 介绍下 webpack 热更新原理
- 当修改了一个或多个文件;
- 文件系统接收更改并通知webpack;
- webpack重新编译构建一个或多个模块,并通知HMR服务器进行更新;
- HMR Server 使用webSocket通知HMR runtime 需要更新,HMR运行时通过HTTP请求更新jsonp;
- HMR运行时替换更新中的模块,如果确定这些模块无法更新,则触发整个页面刷新。
# 2. babel 怎么把字符串解析成 AST,是怎么进行词法/语法分析的?
Babel 是将 ES6、ES7等代码转译为 ES5 代码且能安全稳定运行的工具。
1.先对输入代码进行分词,根据最小有效语法单元,对字符串进行切割。 -> 2.AST,然后进行语法分析,会涉及到读取、暂存、回溯、暂存点销毁等操作。 -> 3.然后转换生成新的 AST。-> 4.最后根据新生成的 AST 输出目标代码。
解析
- Babylon是一个解析器,它可以将javascript字符串,转化为更加友好的表现形式,称之为抽象语法树;
- 在解析过程中有两个阶段:词法分析和语法分析,
- 词法分析阶段:字符串形式的代码转换为令牌(tokens)流,令牌类似于AST中的节点;
- 语法分析阶段:把一个令牌流转化为AST的形式,同时这个阶段会把令牌中的信息转化为AST的表述结构
转换
- babel-traverse 模块允许你浏览、分析和修改抽象语法树(AST Abstract Syntax Tree)
- Babel接收解析得到的AST并通过babel-traverse对其进行深度优先遍历,在此过程中对节点进行添加、更新及移除操作。
生成
- babel-generator 模块用来将转换后的抽象语法树(AST Abstract Syntax Tree)转化为Javascript 字符串
- 将经过转换的AST通过babel-generator再转换为js代码,过程及时深度遍历整个AST,然后构建转换后的代码字符串。
# 3. 介绍下 npm 模块安装机制,为什么输入 npm install 就可以自动安装对应的模块?
- 发出npm install命令;
- npm 向 registry 查询模块压缩包的网址;
- 下载压缩包,存放在~/.npm目录;
- 解压压缩包到当前项目的node_modules目录;
# 4. webpack插件开发?
webpack 插件由以下组成:
- 一个 JavaScript 命名函数或 JavaScript 类。
- 在插件函数的 prototype 上定义一个 apply 方法。
- 指定一个绑定到 webpack 自身的事件钩子。
- 处理 webpack 内部实例的特定数据。
- 功能完成后调用 webpack 提供的回调。
Compiler 它扩展自 Tapable 类,设置了一系列事件钩子和各种配置参数,并定义了 webpack 诸如启动编译、观测文件变动、将编译结果文件写入本地等一系列核心方法。
常见事件钩子介绍:
- beforeRun:在编译器开始读取 records 之前执行;
- run:在读取 records 之前;
- thisCompilation:在 compilation 初始化时执行;
- compilation:在 compilation 创建之后执行;
- make:在 complication 完成之前执行;
- afterCompilation:在 compilation 完成后执行;
- emit:在生成文件到 output 目录之前执行;
- afterEmit:在生成文件到 output 目录之后执行;
- done:在 compilation 完成之后执行;
实现方法:
class MyWebpackPlugin {
constructor(doneCallback, emitCallback) {
this.emitCallback = emitCallback
this.doneCallback = doneCallback
}
apply(compiler) {
compiler.hooks.emit.tap('MyWebpackPlugin', () => {
// 在 emit 事件中回调 emitCallback
this.emitCallback();
});
compiler.hooks.done.tap('MyWebpackPlugin', (err) => {
// 在 done 事件中回调 doneCallback
this.doneCallback();
});
compiler.hooks.compilation.tap('MyWebpackPlugin', () => {
// compilation('编译器'对'编译ing'这个事件的监听)
console.log("The compiler is starting a new compilation...")
});
compiler.hooks.compile.tap('MyWebpackPlugin', () => {
// compile('编译器'对'开始编译'这个事件的监听)
console.log("The compiler is starting to compile...")
});
}
}
// 导出插件
module.exports = MyWebpackPlugin;
// 使用插件
module.exports = {
plugins: [
new MyWebpackPlugin(
() => {
// Webpack 模块完成转换成功
console.log('emit 事件发生啦,所有模块的转换和代码块对应的文件已经生成好~')
},
() => {
// Webpack 构建成功,并且文件输出了后会执行到这里,在这里可以做发布文件操作
console.log('done 事件发生啦,成功构建完成~')
}
)
]
}