# 简易版本webpack

# 前置条件

  • npm init 生成package.json
  • 添加依赖 后 npm install
{
  "name": "easy-webpack",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {},
  "keywords": [],
  "author": "",
  "license": "MIT",
  "dependencies": {
    "@babel/core": "^7.7.7",
    "@babel/parser": "^7.7.7",
    "@babel/preset-env": "^7.7.7",
    "@babel/traverse": "^7.7.4"
  }
}

# webpack.config.js

// 这里是传入 compiler的option哦
const path = require("path");
module.exports = {
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "./dist"),
    filename: "main.js"
  }
};

# index.js

  • 执行 node index.js 会打包出 dist文件夹
const Complier = require("./lib/Compiler");
const options = require("./webpack.config");
new Complier(options).run();

# Parser

  • @babel/parser 解析入口,获取语法树ast
  • @babel/traverse 遍历维护ast树状态,找出依赖
  • @babel/core and @babel/preset-envast转为浏览器可执行的代码
const fs = require("fs");
const path = require("path");
const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const { transformFromAst } = require("@babel/core");
const Parser = {
  getAst: path => {
    const content = fs.readFileSync(path, "utf-8");// 入口文件
    return parser.parse(content, {
      sourceType: "module"
    });
  },
  getDependecies: (ast, filename) => {
    const dependecies = {};//依赖
    traverse(ast, {
      ImportDeclaration({ node }) {
        const dirname = path.dirname(filename);
        // 保存依赖路径
        const filepath = "./" + path.join(dirname, node.source.value);
        dependecies[node.source.value] = filepath;
      }
    });
    return dependecies;
  },
  getCode: ast => {
    const { code } = transformFromAst(ast, null, {
      presets: ["@babel/preset-env"]
    });
    return code;
  }
};

module.exports = Parser;

# Complier

const fs = require("fs");
const path = require("path");
const Parser = require("./Parser");
class Compiler {
  constructor(options) { // 读取配置
    const { entry, output } = options;
    this.entry = entry;
    this.output = output;
    this.modules = [];
  }
   build(filename) {
    const { getAst, getDependecies, getCode } = Parser;
    const ast = getAst(filename);
    const dependecies = getDependecies(ast, filename);
    const code = getCode(ast);
    return {
      filename,
      dependecies,
      code
    };
  }
  // 构建启动
  run() {
    const info = this.build(this.entry);
    this.modules.push(info);
    this.modules.forEach(({ dependecies }) => { //遍历所有依赖
      if (dependecies) {
        for (const dependency in dependecies) {
          this.modules.push(this.build(dependecies[dependency]));
        }
      }
    });
    // 依赖图
    const dependencyGraph = this.modules.reduce(
      (graph, item) => ({
        ...graph,
        [item.filename]: { //唯一标识符
          dependecies: item.dependecies,
          code: item.code
        }
      }),
      {}
    );
    this.generate(dependencyGraph);
  }
 
 // 重写require函数,输出bundle
  generate(code) {
    const filePath = path.join(this.output.path, this.output.filename);
    const bundle = `(function(graph){
      function require(moduleId){ 
        function localRequire(relativePath){
          return require(graph[moduleId].dependecies[relativePath])
        }
        var exports = {};
        (function(require,exports,code){
          eval(code)
        })(localRequire,exports,graph[moduleId].code);
        return exports;
      }
      require('${this.entry}')
    })(${JSON.stringify(code)})`;
    // 写入文件系统
    fs.writeFileSync(filePath, bundle, "utf-8");
  }
}

module.exports = Compiler;

# bundle实现

  • 这是node index.js后你生成在dist下的js文件
(function (graph) { // 立即执行函数
  function require(moduleId) { //重写require
    function localRequire(relativePath) { // 依赖
      return require(graph[moduleId].dependecies[relativePath])
    }
    //出口对象
    var exports = {};
    (function (require, exports, code) {
      eval(code)
    })(localRequire, exports, graph[moduleId].code);
    return exports; //暴露
  }
  require('./src/index.js') // 从入口文件开始执行
})({
  "./src/index.js": {
    "dependecies":
      { "./hello.js": "./src/hello.js" },
    "code": "\"use strict\";\n\nvar _hello = require(\"./hello.js\");\n\ndocument.write((0, _hello.say)(\"webpack\"));"
  },
  "./src/hello.js": {
    "dependecies": {},
    "code": "\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n  value: true\n});\nexports.say = say;\n\nfunction say(name) {\n  return \"yiki \".concat(name);\n}"
  }
})
Last Updated: 2021/9/26 下午12:23:31