深入理解webpack打包机制(四)
栏目: JavaScript · 发布时间: 6年前
内容简介:有了webpack的模版 并且有了各个模块之间的依赖关系,接下来我们就可以实现打包。接下来就开始实现Compiler.js中的最终打包(即emit)方法:写emit()方法之前,首先要安装一下ejs模块,我们需要用ejs模版引擎来解析刚才手写的webpck模版。
有了webpack的模版 并且有了各个模块之间的依赖关系,接下来我们就可以实现打包。
接下来就开始实现Compiler.js中的最终打包(即emit)方法:
写emit()方法之前,首先要安装一下ejs模块,我们需要用ejs模版引擎来解析刚才手写的webpck模版。
进入到my-pick目录, 运行命令:npm i ejs -D
Compiler.js:
let path = require('path');
let fs = require('fs');
let babylon = require('babylon');
let traverse = require('@babel/traverse').default;
let t = require('@babel/types');
let generator = require('@babel/generator').default;
let ejs = require('ejs');
class Compiler{
constructor(config){
this.config = config;
this.entry = config.entry;
this.entryId = '';
this.modules = {};
this.rootPath = process.cwd();
}
run(){
this.buildModule(path.resolve(this.rootPath,this.entry),true);
this.emit();
}
buildModule(modulePath, isEntry){
let source = this.getSource(modulePath);
let moduleName = './'+path.relative(this.rootPath,modulePath);
if(isEntry){ this.entryId = moduleName };
let { sourceCode, dependencies } = this.parse(source, path.dirname(moduleName));
this.modules[moduleName] = sourceCode;
dependencies.forEach((depend)=>{
this.buildModule(path.join(this.rootPath,depend),false);
});
}
parse(source, parentPath){
let dependencies = [];
let ast = babylon.parse(source);
traverse(ast, {
CallExpression(p){
if(p.node.callee.name === 'require'){
p.node.callee.name = '__webpack_require__';
let moduleName = p.node.arguments[0].value;
moduleName = moduleName + (path.extname(moduleName)?'':'.js');
moduleName = './'+path.join(parentPath,moduleName);
dependencies.push(moduleName);
p.node.arguments = [t.stringLiteral(moduleName)];
}
}
});
let sourceCode = generator(ast).code;
return { sourceCode, dependencies };
}
getSource(sourcePath){
return fs.readFileSync(sourcePath,'utf8');
}
emit(){
let main = path.join(this.config.output.path,this.config.output.filename);
let templateStr = this.getSource(path.resolve(__dirname, 'template.ejs'));
let code = ejs.render(templateStr,{
entryId:this.entryId,modules:this.modules
});
this.assets = {};
this.assets[main] = code;
fs.writeFileSync(main,this.assets[main]);
}
}
module.exports = Compiler;
emit()方法就是最终我们实现webpack的打包方法。最后的bundle.js就是由该方法生成。
首先,通过path.join()方法和config中的output 获取到最终的打包文件的路径。
第二行又获取到之前写好的模版文件:template.ejs。最终通过ejs模块解析 并且传入主入口entryId和依赖关系对象modules生成最终的打包文件。
生成了最终的打包文件后就很简单了,首先把最终的文件放到this.assets对象中,最后又通过fs.readFileSync()写入bundle.js文件到输出路径。
最后,回到webpack的目录:运行自己的pick命令:npx my-pack. 即可看到dist目录中多了一个bundle.js的文件
bundle.js:
(function(modules) {
var installedModules = {};
function __webpack_require__(moduleId) {
if(installedModules[moduleId]) {
return installedModules[moduleId].exports;
}
var module = installedModules[moduleId] = {
i: moduleId,
l: false,
exports: {}
};
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
module.l = true;
return module.exports;
}
return __webpack_require__(__webpack_require__.s = "./src/index.js");
})
/* 自执行函数 传入参数 */
({
"./src/index.js":
(function(module, exports, __webpack_require__) {
eval(`console.log('index.js');
__webpack_require__("./src/a.js");`);
}),
"./src/a.js":
(function(module, exports, __webpack_require__) {
eval(`let b = __webpack_require__("./src/b.js");
console.log('a.js');
console.log(b);`);
}),
"./src/b.js":
(function(module, exports, __webpack_require__) {
eval(`module.exports = 'b.js';`);
}),
});
可以看到 ,所以的依赖关系都被传递到了webpack的自执行函数的参数中。通过右键run,或者浏览器中打开。发现打印了我们写的代码:
index.js a.js b.js
到此为止,我们已经手动实现了webpack的打包功能。当然这只是webpack中的冰山一角,我们只是简单实现了解析模块的依赖关系,打包了js文件。像webpack的钩子,loader,plugins,css文件..等等都没有进行处理。
可能会在以后的文章中会较为深入的解析webpack的loader和plugins是如何实现的。谢谢观看~喜欢点个:+1:
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 深入理解webpack打包机制(二)
- 深入理解webpack打包机制(三)
- 深入 webpack 打包后的 js 世界
- 带你深入浅出理解深度学习(附资源打包下载)
- 深入 Spring Boot(十四):jar/war 打包解决方案
- 【前端打包部署】谈一谈我在SPA项目打包=>部署的处理
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Programming Python
Mark Lutz / O'Reilly Media / 2006-8-30 / USD 59.99
Already the industry standard for Python users, "Programming Python" from O'Reilly just got even better. This third edition has been updated to reflect current best practices and the abundance of chan......一起来看看 《Programming Python》 这本书的介绍吧!