Webpack 问与答
webpack 的作用是什么?¶
-
模块打包。将不同模块的文件打包整合在一起,并且保证它们之间的引用正确,执行有序。
-
编译兼容。通过 webpack 的 Loader 机制,不仅仅可以对代码做
polyfill
,还可以编译转换诸如.less
,.vue
,.jsx
这类在浏览器无法识别的格式文件。 -
能力扩展。 通过 webpack 的 Plugin 机制,可以进一步实现诸如按需加载,代码压缩等一系列功能。
模块打包的运行原理?¶
答案参考 Webpack 核心原理
sourceMap 是什么?¶
- 定义:
sourceMap
是一项将编译、打包、压缩后的代码映射回源代码的技术。 - 作用:
sourceMap
可以帮助我们快速定位到源代码的位置,提高开发效率。 - 使用:
development
开发模式下,每个__webpack_modules__
文件模块的代码最末端,都会加上//# sourceURL=webpack://file-path?
,从而实现对sourceMap
的支持。
编写 loader 的思路?¶
- 意义:Webpack 内部默认只能够处理 JS 模块代码;需要 Loader 机制,先对其进行必要的转换,才能继续执行打包任务。
- 当 Webpack 在转换该文件类型的时候,会按顺序链式调用每一个 loader,前一个 loader 返回的内容会作为下一个 loader 的入参。
- loader 函数中的
this
上下文由 webpack 提供,可以通过 this 对象提供的相关属性,获取当前loader需要的各种信息数据。事实上,this 指向了一个叫loaderContext
的 loader-runner 特有对象。
module.exports = function(source) {
const content = doSomeThing2JsString(source);
// 如果 loader 配置了 options 对象,那么this.query将指向 options
const options = this.query;
// 可以用作解析其他模块路径的上下文
console.log('this.context');
/*
* this.callback 参数:
* error:Error | null,当 loader 出错时向外抛出一个 error
* content:String | Buffer,经过 loader 编译后需要导出的内容
* sourceMap:为方便调试生成的编译后内容的 source map
* ast:本次编译生成的 AST 静态语法树,之后执行的 loader 可以直接使用这个 AST,进而省去重复生成 AST 的过程
*/
this.callback(null, content);
// or return content;
}
编写 plugin 的思路?¶
-
webpack基于发布订阅模式,在运行的生命周期中会广播出许多事件,插件通过监听这些事件,就可以在特定的阶段执行自己的插件任务,从而实现自己想要的功能。
-
其中 compiler 暴露了和 Webpack 整个生命周期相关的钩子(
compiler-hooks
),而 compilation 则暴露了与模块和依赖有关的粒度更小的事件钩子(Compilation Hooks
)。 -
Plugin 的开发需要遵循一些规范和原则:
- 插件必须是一个函数或者是一个包含 apply 方法的对象,这样才能访问 compiler 实例;
- 传给每个插件的 compiler 和 compilation 对象都是同一个引用,若在一个插件中修改了它们身上的属性,会影响后面的插件;
- 异步的事件需要在插件处理完任务时调用回调函数通知 Webpack 进入下一个流程,不然会卡住;
class MyPlugin {
apply (compiler) {
// 找到合适的事件钩子,实现自己的插件功能
compiler.hooks.emit.tap('MyPlugin', compilation => {
// compilation: 当前打包构建流程的上下文
console.log(compilation);
// do something...
})
}
}