webpack-底层原理(Loader编写Plugin编写 Bundler编写)
Posted 火腿肠烧烤大赛冠军
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了webpack-底层原理(Loader编写Plugin编写 Bundler编写)相关的知识,希望对你有一定的参考价值。
Loader编写
- 编写replaceLoader.js
//不可以写箭头函数
module.exports = function(source) {
//this.query种存放参数(可以用loader-util帮助分析)
return source.replace('lee', 'world');
//异步方法
const callback = this.async();
setTimeout(() => {
const result = source.replace('dell', options.name);
callback(null, result);
}, 1000);
}
- 路径写法
可在 自定义loader中查看
注意:loader的使用顺序时从下到上从右到左
在引入loader时做一些事情
resolveLoader: {
modules: ['node_modules', './loaders']
},
这样就可以直接这样写路径了
rules: [{
test: /\\.js/,
use: [
{
loader: 'replaceLoader',
},
{
loader: 'replaceLoaderAsync',
options: {
name: 'lee'
}
},
]
}]
Plugin编写
class CopyrightWebpackPlugin {
constructor(a){
// a为接受的参数
}
//自动执行compiler可以理解为webpack实例compilation为当次打包实例
apply(compiler) {
//同步时刻
compiler.hooks.compile.tap('CopyrightWebpackPlugin', (compilation) => {
console.log('compiler');
})
//emit为钩子异步时刻
compiler.hooks.emit.tapAsync('CopyrightWebpackPlugin', (compilation, cb) => {
//打断点 然后查看compilation内的参数
debugger;
//新增文件
compilation.assets['copyright.txt']= {
//内容
source: function() {
return 'copyright by dell lee'
},
//大小
size: function() {
return 21;
}
};
cb();
})
}
}
module.exports = CopyrightWebpackPlugin;
文档:compiler 钩子举例文档
创建plugin对象:copyright-webpack-plugin
之后使用即可
debugger
Bundler编写(模块分析部分)
//获取文件信息
const fs = require('fs');
const path = require('path');
//分析语法(抽象语法树)
const parser = require('@babel/parser');
//解析抽象语法树
const traverse = require('@babel/traverse').default;
//代码转换
const babel = require('@babel/core');
//接收入口文件内容
const moduleAnalyser = (filename) => {
//读文件
const content = fs.readFileSync(filename, 'utf-8');
const ast = parser.parse(content, {
//ES6解析方式
sourceType: 'module'
});
const dependencies = {};
traverse(ast, {
ImportDeclaration({ node }) {
//获取绝对路径
const dirname = path.dirname(filename);
//相对路径转化为相对于根目录绝对路径
const newFile = './' + path.join(dirname, node.source.value);
// 同时存入相对路径和绝对路径
dependencies[node.source.value] = newFile;
}
});
//翻译成浏览器可执行文件
const { code } = babel.transformFromAst(ast, null, {
presets: ["@babel/preset-env"]
});
return {
filename,
dependencies,
code
}
}
const moduleInfo = moduleAnalyser('./src/index.js');
console.log(moduleInfo);
高亮显示代码
Bundler编写(Dependencies Graph)
//依赖图谱
const makeDependenciesGraph = (entry) => {
const entryModule = moduleAnalyser(entry);
const graphArray = [ entryModule ];
//数组递归
for(let i = 0; i < graphArray.length; i++) {
const item = graphArray[i];
const { dependencies } = item;
if(dependencies) {
for(let j in dependencies) {
graphArray.push(
moduleAnalyser(dependencies[j])
);
}
}
}
const graph = {};
graphArray.forEach(item => {
graph[item.filename] = {
dependencies: item.dependencies,
code: item.code
}
});
return graph;
}
Bundler编写(生成可运行代码)
const generateCode = (entry) => {
//将字符串转化为对象
const graph = JSON.stringify(makeDependenciesGraph(entry));
return `
(function(graph){
function require(module) {
//相对路径转化函数
function localRequire(relativePath) {
return require(graph[module].dependencies[relativePath]);
}
var exports = {};
//引入当前模块文件
(function(require, exports, code){
//执行代码
eval(code)
})(localRequire, exports, graph[module].code);
return exports;
};
require('${entry}')
})(${graph});
`;
}
okk~
以上是关于webpack-底层原理(Loader编写Plugin编写 Bundler编写)的主要内容,如果未能解决你的问题,请参考以下文章