实现代码
实现一个类似webpack的打包工具,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| 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, { sourceType: 'module' }) const dependencies = {} traverse(ast, { ImportDeclaration({ node }) { const dirname = path.dirname(filename) const newFile = './' + path.posix.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 makeDependencoesGraph = (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 }
const generateCode = (entry) => { const graph = JSON.stringify(makeDependencoesGraph(entry)) return ` (function(graph) { function require(module) { function localRequire(relativePath) { return require(graph[module].dependencies[relativePath]) } var exports = {}; (funcrion(require, exports, code) { eval(code); })(localRequire, exports, graph[module].code); return exports; }; require('${entry}') })(${graph}); `; }
|
代码解读
moduleAnalyser
要对入口文件进行打包,我们应该对入口文件进行分析:
- 拿到入口文件的源代码。借助fs模块实现
- 找到入口文件的依赖。借助@babel/parser,把源代码转换成AST,再用@babel/traverse找到源代码中的声明的语句而找到依赖的路径。创建一个对象来保存这些依赖即可
- ES6转ES5。@babel/core,@babel/preset-env
makeDependencoesGraph
模块的依赖里又会引用其他依赖,想完全分析好必须弄清所有依赖的关系,创建依赖图谱
generateCode
生成最终打包完成的代码。return的应该是打包生成的代码(字符串),同时这些代码应该是一个闭包,避免污染全局环境