[webpack]手写一个mvp版本的webpack

Posted piaobodewu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[webpack]手写一个mvp版本的webpack相关的知识,希望对你有一定的参考价值。

let fs = require(‘fs‘);
let path = require(‘path‘);

let babylon = require(‘babylon‘); // Babylon 把源码转换为AST
let t = require(‘@babel/types‘); // @babel-types 替换节点
let traverse = require(‘@babel/traverse‘).default; // @babel-traverse 遍历节点
let generator = require(‘@babel/generator‘).default; // @babel/generator 生成

let ejs = require(‘ejs‘); // js模版

class Compiler 
    // 构造函数
    constructor(config) 
        // entry out
        this.config = config;
        // 1、保存入口文件的路径
        this.entryId;
        // 2、博阿村所有的模块依赖
        this.modules = ;
        // 入口路径
        this.entry = config.entry;
        // 工作路径
        this.root = process.cwd();
    
    // 获取文件源码
    getSource(modulePath)
        let content = fs.readFileSync(modulePath,‘utf8‘);
        return content;
    
    // 解析源码
    parse(source,parentPath)
        // AST解析语法树
        let ast = babylon.parse(source);
        let dependencies = [];
        traverse(ast,
            CallExpression(p)
                let node = p.node; // 对应的节点
                if(node.callee.name === ‘require‘)
                    node.callee.name = ‘__webpack_require__‘;
                    let moduleName = node.arguments[0].value; // 取到的就是模块的引用名字
                    moduleName = moduleName + (path.extname(moduleName)?‘‘:‘.js‘);
                    moduleName = ‘./‘+path.join(parentPath,moduleName);
                    dependencies.push(moduleName);
                    node.arguments = [t.stringLiteral(moduleName)];
                
            
        );
        let sourceCode = generator(ast).code;
        return  sourceCode, dependencies 
    
    // 建立模块
    buildModule(modulePath,isEntry)
        // 拿到模块的内容
        let source = this.getSource(modulePath);
        // 模块id modulePath modulePath-this.root  =  src/index.js
        let moduleName = ‘./‘+path.relative(this.root,modulePath);
        if(isEntry)
             // 保存入口的名字
            this.entryId = moduleName;
        
        // 解析需要把source源码进行改造,返回一个依赖列表
        let sourceCode,dependencies = this.parse(source,path.dirname(moduleName));
        this.modules[moduleName] = sourceCode;
        dependencies.forEach(
            // 父模块的加载,递归加载
            (dep)=>
                this.buildModule(path.join(this.root,dep),false)
            
        );
    
    emitFile()
        // 发射文件
        // 用数据渲染
        // 输出路径
        let main = path.join(this.config.output.path,this.config.output.filename);
        // 模板的路径
        let tempateStr = this.getSource(path.join(__dirname,‘main.ejs‘));
        let code = ejs.render(tempateStr,
            entryId:this.entryId,
            modules: this.modules
        );

        // this.assets = ;
        // // 路径对应的代码
        // this.assets[main] = code;
        // fs.writeFileSync(main,this.assets[main]);

        fs.writeFileSync(main,code);
    
    run() 
        // 执行并创建模块依赖关系
        this.buildModule(path.resolve(this.root, this.entry),true);
        // 发射一个打包后的文件
        this.emitFile();
    


module.exports = Compiler;

  

以上是关于[webpack]手写一个mvp版本的webpack的主要内容,如果未能解决你的问题,请参考以下文章

webpack 安装卸载

如何手写一个 webpack 插件:实现 vuecli3 打包时生成一个 git 分支版本信息的文件?

$(...).tooltip 不是一个函数 rails 6 webpack

搭建vue-cli项目和打包项目

webpack +vue开发

webpack用法总结