持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第7天,点击查看活动详情
前言
身为一个前端小菜鸟,总是有一个飞高飞远的梦想,因此,每点小成长,我都想要让它变得更有意义,为了自己,也为了更多值得的人
开开心心学技术大法~~
来了来了,他真的来了~
正文
之前用了六十行代码阐述webpack-core的思想,今天我们就在webapck-core的基础上再实现下webpack-loader。
明确webpack-loader的本质
想必一些小伙伴已经有自己实现webpack-loader的经验,所以应该知道webpack-loader其实就是一个抛出来的function,类似于下面这种。
module.exports = function(content,map,meat){
// ...loader操作
return newContent;
}
回顾webpack-core
因为接下来要实现的loader需要跟webpack-core结合,所以先简单回顾一下webapck-core中的关键方法。
- 通过
fs模块加载入口资源,拿到文件的utf-8编码的内容 - 通过babel的
parser和traverse拿到入口文件import的资源路径,也就是依赖模块的路径 - 通过拿到的依赖模块的路径信息做递归操作,将所有被引入模块的依赖关系做成一个依赖图
- 统一导入导出方法
- 将所有被依赖的文件资源build输出到一个指定文件
在以上流程中,我们大概总结了这几个关键方法
getModuleInfo方法来获取单个模块文件信息getGraphInfo方法来获得最终的依赖图build方法来生成最终的dist/built.js文件
思考loader应该被怎样实现
那首先思考下loader一般是用来处理什么?
实现在哪里
没错,loader就是为了处理文件资源的,将webapck不认识的资源转变成webpack认识的js资源。
再进一步,其实loader就是处理文件的。而我们在webpack-core中已经有了明确的getMouldeInfo方法,所以loader只需要被实现在getModuleInfo中。
怎样实现
因为上面我们已经知道了loader用来处理文件,且会return一个utf-8编码的资源内容,那我们只需要在getModuleInfo中拿到文件源代码source,然后将source传入到loader中,并且将返回结果重新赋值给source即可。
const selfLoader = require('./loader.js');
const JSONLoader = require('./json-loader.js');
const webpackConfig = {
module: {
rules: [
{
test: /\.json$/i,
loader: JSONLoader,
},
{
test: /\.js$/i,
use: [selfLoader],
},
],
},
plugins: [new OutputPlugin()]
}
getModuleInfo(filepath){
let source = fs.readSync(filepath)
// 因为loader会有this,this指向的就是loader的上下文,所以我们定义一个loaderContext
const webpackLoaderContext = {
data: 'loader-data',
addDependency(dependency) {
console.log('添加到了依赖', dependency);
}
}
// 如果有loader的话,在这里加上loader的处理,因为loader基本都是对文件进行操作的,所以会在加载依赖图的时候进行loader的注册和触发
webpackConfig.module.rules.map(item => {
if (item.test.test(filepath)) {
// 如果是单个loader
if (item.loader) {
// 将loader处理过的源代码替换掉原来的source
// source = item.loader(source)
// 因为webpack-loader中会有loader上下文,所以绑定this到loader山下文
source = item.loader.call(webpackLoaderContext, source)
} else if (item.use) {
// 如果是多个loader
// 因为loader是从后向前执行的,所以reverse一下
item.use.reverse().map(singleLoader => {
// 将loader处理过的源代码替换掉原来的source
source = singleLoader.call(webpackLoaderContext, source)
})
}
}
})
// ...其他的module操作
}
其中webpackConfig可以通过外部定义一个webpack.config.js来引入,我们这里静态模拟一个用户的配置。
其中两个loaderselfLoader和json-loader是我自己实现的,用来验证loader功能是否ok
其中selfLoader的功能是在console.log前添加====我是zzz===!!!的字符串前缀
module.exports = function (content) {
// 尝试访问loader的this
this.addDependency('我是依赖的dependency')
return content.replace(/console\.log\('/g,'console\.log\(\'====我是zzz===!!!')
}
json-loader实现了对json文件的支持,具体实现也很简单
// json-loader.js
module.exports = function (content) {
return `module.exports = ${JSON.stringify(content)}`
}
以上,就实现了webpack-core中实现loader的功能
结语
往期好文推荐「我不推荐下,大家可能就错过了史上最牛逼vscode插件集合啦!!!(嘎嘎嘎~)😄」