简单实现
要实现一个简单的webpack,我们首先要理解其中的原理,目前还没看过源码,现在的理解是通过对入口文件分析,转成抽象语法树,进而可以深度遍历到所有依赖的文件,然后将文件转码成我们想要的文件,
我们先来写一下我们想打包的文件
// index.js
import util from './util/util.js';
console.log(util.add(1, 2));
// util.js
function add(a, b) {
return a + b;
}
export default {
add,
};
首先我们先从分析入口文件开始,了解一下文件是怎样被分析转成抽象语法树的,编译过程前端为词法分析,语法分析,生成抽象语法树,我们来读取字符串来匹配还是很麻烦的,babel给我们提供了现成的方法,我们先来安装我们需要的几个babel的包@babel/parser @babel/traverse @babel/core @babel/preset-env
,我们使用parser来解析代码生成抽象语法树,traverse遍历取出抽象语法树中我们想要的信息,另外两个包我们使用过,帮我们来生成低版本浏览器可以使用的代码
const fs = require('fs');
const path = require('path');
const parser = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const babel = require('@babel/core');
function analysisEntry(filename) {
let content = fs.readFileSync(filename, 'utf-8');
const ast = parser.parse(content, {
sourceType: 'module',
});
const dependencies = {};
traverse(ast, {
ImportDeclaration({ node }) {
const dirname = path.dirname(filename);
dependencies[node.source.value] = './' + path.join(dirname, node.source.value);
},
});
const code = babel.transformFromAst(ast, null, {
presets: ['@babel/preset-env'],
}).code;
return {
filename,
dependencies,
code,
};
}
通过上边的方法我们可以对入口文件分析,剩下的就是,对所有依赖文件进行分析然后生成代码了,我们通过深度遍历,把每一个依赖的文件加入到一个对象中,最后定义一个require方法来加载我们的code
function dependenciesGraph(entry) {
const root = analysisEntry(entry);
const graphArray = [root];
let i = 0;
const graph = {};
while (i < graphArray.length) {
let item = graphArray[i];
for (const key in item.dependencies) {
const element = item.dependencies[key];
graphArray.push(analysisEntry(element));
}
i++;
}
graphArray.forEach(i => {
graph[i.filename] = i;
});
return graph;
}
function generateCode(entry) {
const graph = JSON.stringify(dependenciesGraph(entry))
return `(function(graph){
function require(module){
function localRequire(path) {
return require(graph[module].dependencies[path])
}
var exports = {};
(function(require, exports, code){
eval(code)
})(localRequire, exports, graph[module].code)
return exports;
}
require('${entry}')
})(${graph})`
}
console.log(generateCode('./src/index.js'))
网友评论