Webpack 的构建流程主要有哪些环节?如果可以请尽可能详尽的描述 Webpack 打包的整个过程
在项目中一般都会散落着各种资源文件,webpack会根据配置文件找到其中的一个文件作为打包入口,一般情况为js文件,在js文件中,根据代码中出现的import,require之类的语句,解析推断出来所依赖的资源模块,然后分别解析每个资源模块对应的依赖,最后形成整个个项目中所有用到文件之间的依赖关系的依赖树,用依赖树去递归这个依赖树,找到每个节点所对应的资源文件,最后根据配置文件中的rules属性找到这个模块所对应的加载器,交给对应的加载器去加载这个模块,最后将加载完成的结果放到bundle.js(打包结果当中),从而实现整个项目的打包
loader机制是webpack的核心,没有loader就无法实现各种资源模块的加载,变成只能打包合并js的工具
打包原理
- 打包之后是一个自执行函数
- 参数为一个对象,键为各个模块的路径,值为各个-模块的代码
Loader 和 Plugin 有哪些不同?请描述一下开发 Loader 和 Plugin 的思路
loader负责资源文件从输入到输出的转换,对于同一个资源可以同时使用多个loader
每个webpack的loader都需要去导出一个函数,这个函数就是对加载资源的处理过程,输入为加载到的文件的内容,输出为此次加工后的结果,可以用参数接收输入,返回输出,因为loader类似一个工作管道,所以要返回一段标准JavaScript的代码,也可以继续下一个loader接收返回值处理
const marked = require('marked')
module.exports = source => {
const html = marked(source)
// return `module.exports = "${html}"`
// return `export default ${JSON.stringify(html)}`
// 返回 html 字符串交给下一个 loader 处理
return html
}
loader只是在加载模块的环节去工作,而plugin几乎可以触及到webpack的每一个环节
plugin通过钩子机制实现,类似于web当中的事件,在webpack工作当中会有很多的环节,为了便于插件的扩展,webpack给每个环节都埋下了一个钩子,这样我们在开发插件的手时候往这些节点上,去挂载不同的任务,可以轻松扩展webpack的能力
plugin插件要求必须是一个函数或者是一个包含apply方法的对象,是通过在生命周期的钩子中挂载函数实现扩展
class MyPlugin {
apply (compiler) {
console.log('MyPlugin 启动')
compiler.hooks.emit.tap('MyPlugin', compilation => {
// compilation => 可以理解为此次打包的上下文
for (const name in compilation.assets) {
// console.log(name)
// console.log(compilation.assets[name].source())
if (name.endsWith('.js')) {
// 打包文件名
// compilation.assets[name]
// 文件内容
const contents = compilation.assets[name].source()
const withoutComments = contents.replace(/\/\*\*+\*\//g, '')
// 重新
compilation.assets[name] = {
source: () => withoutComments,
size: () => withoutComments.length
}
}
}
})
}
}