简介

webpack 简易实现学习笔记。

webpack 配置文件

'use strict';
const path = require('path');

module.exports = {
  entry: path.join(__dirname, './src/index.js'),
  output: {
    path: path.join(__dirname, './dist'),
    filename: 'main.js'
  }
};

webpack 编译入口

const Compiler = require('./compiler');
const options = require('../simplepack.config');

const compiler = new Compiler(options);
compiler.run();

babel 解析工具

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

module.exports = {
  /** 将 js 文件解析成 AST【@babel/parser】 */
  getAST: (path) => {
    const content = fs.readFileSync(path, 'utf-8');
    return parser.parse(content, {
      sourceType: 'module',
      plugins: [
        'jsx',
        'flow',
      ]
    });
  },

  /** 遍历AST: 分析依赖【@babel/traverse】 */
  getDependencis: (ast) => {
    const dependencies = [];
    traverse(ast, {
      ImportDeclaration: ({ node }) => {
        dependencies.push(node.source.value);
      }
    });
    return dependencies;
  },

  /** 将 ast 转换成 js 代码【@babel/core】 */
  transform: (ast) => {
    const { code } = transformFromAst(ast, null, {
      presets: ['@babel/preset-env']
    });
    return code;
  }
};

webpack 编译函数


const fs = require('fs');
const path = require('path');
const { getAST, getDependencis, transform } = require('./parser');

module.exports = class Compiler {
  constructor(options) {
    const { entry, output } = options;
    this.entry = entry;
    this.output = output;
    this.modules = [];
  }

  run() {
    /** 一、解析入口文件,收集依赖 */
    const entryModule = this.buildModule(this.entry, true);
    /** 二、解析入口文件的所有依赖 */
    this.modules.push(entryModule);
    this.modules.map((_module) => {
      _module.dependencies.map((dependency) => {
        this.modules.push(this.buildModule(dependency));
      });
    });
    console.log(11111, this.modules);
    /** 三、根据 output 生成文件 */
    this.emitFiles();
  }

  /** 根据入口文件收集到文件依赖、转换为 es5 */
  buildModule(filename, isEntry) {
    let ast;
    if (isEntry) {
      /** 绝对路径 */
      ast = getAST(filename);
    } else {
      /** 相对路径 */
      let absolutePath = path.join(process.cwd(), './src', filename);
      ast = getAST(absolutePath);
    }

    return {
      filename,
      dependencies: getDependencis(ast),
      transformCode: transform(ast)
    };
  }

  /** 输出文件 */
  emitFiles() { 
    const outputPath = path.join(this.output.path, this.output.filename);
    let modules = '';
    /** 1、生成 文件名:文件内容生成函数 的键值对 */
    this.modules.map((_module) => {
      modules += `'${_module.filename}': function(require, module, exports) { 
        ${_module.transformCode}
      },`
    });

    /** 2、自定义实现 require 方法和 module.exports 方法 */
    const bundle = `
      (function(modules) {
        function require(fileName) {
          /** 获取 modules 对象的 fileName */
          const fn = modules[fileName];

          /** module 变量初始化, 会将依赖模块中的方法挂载到这里 */
          const module = { exports : {} };

          /** 执行 modules 对象的 fileName 函数 */
          fn(require, module, module.exports);

          /** 返回 module.exports, 即返回依赖模块中的方法 */
          /** 因为 babel 解析之后会将模块的方法挂载到 module.exports 中 */
          return module.exports;
        }

        /** 传入入口文件开始执行 */
        require('${this.entry}');
      })({${modules}})
    `;

    fs.writeFileSync(outputPath, bundle, 'utf-8');
  }
};

最终输出文件

(function (modules) {
  function require(fileName) {
    /** 获取 modules 对象的 fileName */
    const fn = modules[fileName];

    /** module 变量初始化, 会将依赖模块中的方法挂载到这里 */
    const module = { exports: {} };

    /** 执行 modules 对象的 fileName 函数 */
    fn(require, module, module.exports);

    /** 返回 module.exports, 即返回依赖模块中的方法 */
    /** 因为 babel 解析之后会将模块的方法挂载到 module.exports 中 */
    return module.exports;
  }

  /** 传入入口文件开始执行 */
  require("/Users/yunaichun/GitHub/webpack-study/webpack-simple/src/index.js");
})({
  "/Users/yunaichun/GitHub/webpack-study/webpack-simple/src/index.js":
    function (require, module, exports) {
      "use strict";

      var _greeting = require("./greeting.js");

      document.write((0, _greeting.greeting)("Jane"));
    },
  "./greeting.js": function (require, module, exports) {
    "use strict";

    Object.defineProperty(exports, "__esModule", {
      value: true,
    });
    exports.greeting = greeting;

    function greeting(name) {
      return "hello " + name;
    }
  },
});

项目地址

地址: https://github.com/yunaichun/webpack-study/tree/master/webpack-simple

参考资料

powered by Gitbook该文件修订时间: 2023-05-16 18:08:03

results matching ""

    No results matching ""