webpack打包bundle原理分析

自己写一个webpack

- 读取到配置入口
  - 入口模块的路径
  - 模块分析
    - 模块的依赖(依赖的路径)
      - 可以用递归的方式处理依赖模块
    - 内容处理
    - 依赖图谱对象(处理后的内容代码)
  - webpackBootstrap函数
- 读取到配置出口
  - 生成文件
    - 文件存放的位置
    - 文件的名称

webpaci.config.js

const path = require("path");
module.exports = {
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "./dist"),
    filename: "main.js",
  },
  mode: "development",
};

bundle.js (node bundle.js )

const webpack = require("./lib/webpack.js")

const options = require("./webpack.config.js")

new webpack(options).run()

webpack.js


const fs = require("fs")
const path = require("path")
const babelParser = require("@babel/parser")
const traverse = require("@babel/traverse").default
const { transformFromAst } = require("@babel/core");


module.exports = class webpack {
  constructor(options) {
    // console.log(options);
    const { entry, output } = options
    this.entry = entry
    this.output = output
    this.module = []
  }
  run() {
    const info = this.parse(this.entry)
    // console.log('🚀 ~ file: webpack.js ~ line 18 ~ webpack ~ run ~ info', info)
    this.module.push(info)
    for (let index = 0; index < this.module.length; index++) {
      console.log('🚀 ~ file: webpack.js ~ line 22 ~ webpack ~ run ~ this.module', this.module)
      const element = this.module[index];
      const { yilai } = element
      if (yilai) {
        for (const key in yilai) {
        // console.log('🚀 ~ file: webpack.js ~ line 26 ~ webpack ~ run ~ yilai', yilai)
          if (Object.hasOwnProperty.call(yilai, key)) {
            this.module.push(this.parse(yilai[key]))
            // console.log(key, this.module);
          }
        }
      }
    }
    // 数组转对象
    const obj = {};
    
    this.module.forEach(item => {
      obj[item.entryFile] = {
        yilai: item.yilai,
        code: item.code
      }
    })
    // console.log('🚀 ~ file: webpack.js ~ line 37 ~ webpack ~ run ~ obj', obj)
    this.file(obj)
  }

  parse(entryFile) {
    // console.log(entryFile);
    const content = fs.readFileSync(entryFile, "utf-8")
    // console.log(content);

    const ast = babelParser.parse(content, { sourceType: "module"})
    // console.log('🚀 ~ file: webpack.js ~ line 21 ~ webpack ~ parse ~ ast', ast)
    // console.log(ast.program.body);

    const yilai = {}
    traverse(ast, {
      ImportDeclaration({node}){
        // console.log('🚀 ~ file:', node.source.value)
        const pathName =
          "./" + path.join(path.dirname(entryFile), node.source.value);  // ./a.js ./b.js
        yilai[node.source.value] = pathName
      }
    })

    const { code } = transformFromAst(ast, null, {
      presets: ["@babel/preset-env"],
    });
    // console.log('🚀 ~ file: webpack.js ~ line 39 ~ webpack ~ parse ~ code', code)

    // console.log(yilai);

    return {
      entryFile,
      yilai,
      code
    }
  }
  file(code) {
    const filename = path.join(this.output.path, this.output.filename)

    const newCode = JSON.stringify(code);
    const bundle = `(function(graph){
      function require(module){
        function PathRequire(relativePath){
          return require(graph[module].yilai[relativePath])
        }
        const exports = {};
        (function(require,exports,code){
          eval(code) 
        })(PathRequire,exports,graph[module].code)
        return exports;
      }
      require('${this.entry}')
    })(${newCode})`;

    fs.writeFileSync(filename, bundle, 'utf-8')


    console.log(filename);
  }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

eadela

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值