1. 程式人生 > 實用技巧 >webpack原理-實現webpack打包js

webpack原理-實現webpack打包js

// 這裡匯入webpack配置,我用物件的形式表示,當然entry屬性上定義的檔案要有
// const config = require("./webpack.config");
const config = { entry: './src/index.js' };

const { join, dirname } = require("path");
const { readFileSync, writeFileSync } = require("fs");
const reg = /(?<=from\s+['"])[\.\/\w]+(?=['"])/g;

class Complier {
  constructor({ entry }) {
    this.entry = entry;
  }
  run() {
    writeFileSync('generateFile.js', generateCode(this.entry));
  }
}

const parser = (entry, prePath = '.') => {
    let temp = null;
    const filePath = `./${join(prePath, entry)}`;
    const code = Buffer.from(readFileSync(filePath)).toString();
    const dependencies = {};
    // 通過正則將當前檔案es匯入的模組識別並存到dependencies裡,註釋也會存起來,請不要寫註釋
    while ((temp = reg.exec(code)) !== null) {
      temp.forEach(filePath => {
        dependencies[filePath] = `./${join(prePath, dirname(entry), filePath)}`;
      })
    }
    
    return {
      filePath,
      dependencies,
      code,
    };
  }

const makeDependenciesGraph = (entry) => {
  const entryModule = parser(entry);
  const graphArray = [entryModule];
  // 利用廣度遍歷的思想遍歷一遍
  for (let i = 0; i < graphArray.length; i++) {
    const { dependencies } = graphArray[i];
    if (dependencies) {
      for (let path in dependencies) {
        graphArray.push(parser(path, dirname(entry)));
      }
    }
  }
  const graph = {};
  graphArray.forEach(({ filePath, dependencies, code }) => {
    graph[filePath] = {
      dependencies,
      code
    };
  });
  return graph;
};

const generateCode = (entry) => {
  const graph = JSON.stringify(makeDependenciesGraph(entry));
  return `
  (function (graph) {
  function require(module) {
    function localRequire(relativePath) {
      return require(graph[module].dependencies[relativePath]);
    }
    var exports = {};
    (function (require, exports, code) {
      eval(code);
    })(localRequire, exports, graph[module].code);
    return exports;
  }
  require("${`./${join('.', entry).replace(/\\/g, '\\\\')}`}");
})(${graph});
 `;
};

new Complier(config).run();