webpack-Bundler源码编写(模块分析)
Posted 金钩梨
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了webpack-Bundler源码编写(模块分析)相关的知识,希望对你有一定的参考价值。
为了简单理解webpack原理。
新建项目:webpack_bundler
// 目录 src index.js message.js word.js bundler.js
word.js:
export const word=‘hello‘;
message.js:
import {word} from ‘./word.js‘; const message=`say ${word}`; export default message;
index.js:
import message from ‘./message.js‘; console.log(message);
bundler.js:
const fs=require(‘fs‘); const moduleAnalyser=(filename)=>{ const content=fs.readFileSync(filename,‘utf-8‘); console.log(content); } moduleAnalyser(‘./src/index.js‘);
在命令行中执行:node bundler.js,会输出index.js的内容:
import message from ‘./message.js‘; console.log(message);
const fs=require(‘fs‘); const parser=require(‘@babel/parser‘); const moduleAnalyser=(filename)=>{ const content=fs.readFileSync(filename,‘utf-8‘); console.log(parser.parse(content,{ sourceType:‘module‘ // 当我们使用ES module语法时需要加上 })); } moduleAnalyser(‘./src/index.js‘);
命令行就会输出一个抽象语法树:
Node { type: ‘File‘, start: 0, end: 58, loc: SourceLocation { start: Position { line: 1, column: 0 }, end: Position { line: 3, column: 21 } }, errors: [], program: // 表示当前运行的程序 Node { type: ‘Program‘, start: 0, end: 58, loc: SourceLocation { start: [Position], end: [Position] }, sourceType: ‘module‘, interpreter: null, body: [ [Node], [Node] ], directives: [] }, comments: [] }
接下来我们看一下program下面的body:
const ast=parser.parse(content,{ sourceType:‘module‘ }); console.log(ast.program.body);
输出:
[ Node { type: ‘ImportDeclaration‘, // 引入的声明--import message from ‘./message.js‘; start: 0, end: 35, loc: SourceLocation { start: [Position], end: [Position] }, specifiers: [ [Node] ], source: Node { type: ‘StringLiteral‘, start: 20, end: 34, loc: [SourceLocation], extra: [Object], value: ‘./message.js‘ } }, Node { type: ‘ExpressionStatement‘, // 表达式语句--console.log(message); start: 37, end: 58, loc: SourceLocation { start: [Position], end: [Position] }, expression: Node { type: ‘CallExpression‘, start: 37, end: 57, loc: [SourceLocation], callee: [Node], arguments: [Array] } } ]
这样我们就可以拿到所有引入的声明来分析依赖关系,babel还给我们提供了一个模块来帮我们快速找到import节点:
const fs=require(‘fs‘); const parser=require(‘@babel/parser‘); const traverse=require(‘@babel/traverse‘).default; const moduleAnalyser=(filename)=>{ const content=fs.readFileSync(filename,‘utf-8‘); const ast=parser.parse(content,{ sourceType:‘module‘ }); traverse(ast,{ ImportDeclaration({node}){ console.log(node); } }); } moduleAnalyser(‘./src/index.js‘);
重新运行node bundler.js输出:
Node { type: ‘ImportDeclaration‘, start: 0, end: 35, loc: SourceLocation { start: Position { line: 1, column: 0 }, end: Position { line: 1, column: 35 } }, specifiers: [ Node { type: ‘ImportDefaultSpecifier‘, start: 7, end: 14, loc: [SourceLocation], local: [Node] } ], source: Node { type: ‘StringLiteral‘, start: 20, end: 34, loc: SourceLocation { start: [Position], end: [Position] }, extra: { rawValue: ‘./message.js‘, raw: ‘‘./message.js‘‘ }, value: ‘./message.js‘ } }
let dependencies=[];
traverse(ast,{
ImportDeclaration({node}){
dependencies.push(node.source.value);
}
});
console.log(dependencies);
const fs=require(‘fs‘); const path=require(‘path‘); const parser=require(‘@babel/parser‘); const traverse=require(‘@babel/traverse‘).default; const moduleAnalyser=(filename)=>{ const content=fs.readFileSync(filename,‘utf-8‘); const ast=parser.parse(content,{ sourceType:‘module‘ }); let dependencies=[]; traverse(ast,{ ImportDeclaration({node}){ const dirname=path.dirname(filename); // ./src const newFile=‘./‘+path.join(dirname,node.source.value); dependencies.push(newFile); } }); console.log(dependencies); } moduleAnalyser(‘./src/index.js‘);
let dependencies={}; traverse(ast,{ ImportDeclaration({node}){ const dirname=path.dirname(filename); const newFile=path.join(dirname,node.source.value); dependencies[node.source.value]=newFile; } }); console.log(dependencies);
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‘ }); let 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‘] }); console.log(code); // 浏览器可以运行的代码 return { filename,dependencies,code } } moduleAnalyser(‘./src/index.js‘);
命令行输出:
"use strict"; var _message = _interopRequireDefault(require("./message.js")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } console.log(_message["default"]);
这就转换成浏览器可以运行的代码了。
以上是关于webpack-Bundler源码编写(模块分析)的主要内容,如果未能解决你的问题,请参考以下文章