Skip to content

实现须知

实现步骤

js
const fs = require('fs');
const parser = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const babel = require('@babel/core');
const path = require('path');

const entry = './src/index.js';
const output = './dist/bundle.js';

// 分析依赖
function parseModule(file) {
  const entry = getMoudleInfo(file);

  const temp = [entry]; // 使用数组,是因为可能有其他模块

  const depsGraph = {};

  getDeps(temp, entry);

  // 生成依赖图 
  temp.forEach(moduleInfo => {
    depsGraph[moduleInfo.file] = {
      deps: moduleInfo.deps,
      code: moduleInfo.code
    }
  })

  return depsGraph;
}

function getDeps(temp, { deps }) {
  Object.keys(deps).forEach(key => {
    const child = getMoudleInfo(deps[key]);
    temp.push(child);
    getDeps(temp, child);
  })
}

// 获取模块信息
function getMoudleInfo(file) {
  // 读取文件
  const body = fs.readFileSync(file, 'utf-8');
  // 转化为ast
  const ast = parser.parse(body, { sourceType: 'module' });

  const deps = {};

  traverse(ast, {
    // 获取import导入的模块
    ImportDeclaration({ node }) {
      const dirname = path.dirname(file);

      // 获取标准路径
      const absPath = './' + path.join(dirname, node.source.value);
      deps[node.source.value] = absPath;
    },
  });

  const { code } = babel.(ast, null {
    presets: ["@babel/preset-env"]
  });

  const moduleInfo = { file, deps, code};

  return moduleInfo;
}

// 实现bundle
function bundle(file) {
  const depsGraph = JSON.stringify(parseModule(file));

  // todo
  return `;
  (function(graph) {
    function require(file) {
      function absRequire(realPath) {
        return require(graph[file]).deps[realPath];
      }

      var exports = {};

      (function(require, exports, code) {
        eval(code);
      })(absRequire, exports, graph[file].code)
      return exports;
    }

    return require('${file}');
  })(${depsGraph});`
}

const content = bundle(entry);
fs.writeFileSync(output, content, 'utf-8');

参考

实现一个webpack