blog

Webpack 再学習シリーズ - Webpack を 0 から 1 に実装する

ミニマリストパッケージを実装する次のステップは、babelの助けを借りてそれを変換することです。...

Nov 10, 2020 · 5 min. read
シェア

webpackをより明確に実装するために、この記事ではwebpackキーワードの代わりにfastpackを使用します。

Fasterpackの実装

#!/usr/bin/env node
const path = require("path");
const fs = require("fs");
const config = require(path.resolve("./fasterpack.config.js"));
class Fasterpack {
 constructor(config) {
 //キャッシュの設定
 this.config = config;
 //エントリーを保存する
 this.entry = config.entry;
 //ルートディレクトリを取得する
 this.root = process.cwd();
 //モジュールを作成する
 this.modules = {};
 }
 /**
 *
 * @param {*} code  
 * @param {*} parent 親ディレクトリ
 */
 pares(code, parent) {
 // console.log("parent", parent);
 const deps = [];
 const r = /require\(['"](.*)['"]\)/g;
 const r1 = /[
]/g;
 //requireを置き換える
 code = code.replace(r, function (match, arg) {
 const retPath = path.join(parent, arg.replace(/'|"/g, ""));
 // 依存パスを追加する
 deps.push(retPath);
 return `__fasterpack_require__("./${retPath}")`;
 });
 //改行を置き換える
 code = code.replace(r1, function (match, arg) {
 return "\
";
 });
 code = code.replace(/"/g, '"');
 code = `"${code}"`;
 return { code, deps };
 }
 /**
 *
 * @param {*} modulePath モジュールの物理パス
 * @param {*} name プロジェクトユニークパスキー
 */
 createModule(modulePath, name) {
 const modulePathKeys = Object.keys(this.modules);
 const fileContent = fs.readFileSync(modulePath, "utf-8");
 //プロジェクトが登録されているかどうかを再帰的に判断する
 if (!modulePathKeys.includes(name)) {
 //解析されたソースコードとその依存関係を返す。
 const { code, deps } = this.pares(fileContent, path.dirname(name));
 this.modules[name] = `function(module,exports,__fasterpack_require__){
 eval(${code})
 }`;
 // モジュールの再帰的作成
 deps.forEach((dep) => {
 this.createModule(path.join(this.root, dep), `./${dep}`);
 });
 }
 }
 generateModuleStr() {
 let fnTemp = "";
 Object.keys(this.modules).forEach((name) => {
 fnTemp += `"${name}":${this.modules[name]},`;
 });
 return `{${fnTemp}}`;
 }
 generateFile() {
 //パラメータ・インジェクション・テンプレート
 this.tempalate = getTempalate(this.generateModuleStr(), this.entry);
 fs.writeFileSync(`./dist/main.js`, this.tempalate);
 console.log("書き直す");
 }
 start() {
 console.log("解析開始");
 const entryPath = path.resolve(this.root, this.entry);
 //キャッシュモジュールを作成する
 this.createModule(entryPath, this.entry);
 //ファイルを生成する
 this.generateFile();
 }
}
const getTempalate = (__modules_content__, __entry__) => {
 return `(function (modules) {
 const installModules = {};
 function __faster_require__(moduleId) {
 //キャッシュするかどうか
 if (installModules[moduleId]) {
 console.log(installModules, moduleId, installModules[moduleId].exports);
 return installModules[moduleId].exports;
 }
 var module = (installModules[moduleId] = {
 exports: {},
 });
 modules[moduleId].call(
 module.exports,
 module,
 module.exports,
 __faster_require__
 );
 return module.exports;
 }
 // 
 return __faster_require__("${__entry__}");
})(${__modules_content__});`;
};
const fasterpack = new Fasterpack(config);
fasterpack.start();

次のステップは、バベルの助けを借りてそれを変換することです。

知る必要があります。

  • 1
  • 2
  • 3
#!/usr/bin/env node
const path = require("path");
const fs = require("fs");
// ソースコードをastツリーに変換する
const parser = require("@babel/parser");
// ast構文集を解析する
const traverse = require("@babel/traverse").default;
// ソースコードの解析と変換
const { transformFromAst } = require("@babel/core");
const config = require(path.resolve("./fasterpack.config.js"));
class Fasterpack {
 constructor(config) {
 //キャッシュの設定
 this.config = config;
 //エントリーを保存する
 this.entry = config.entry;
 //ルートディレクトリを取得する
 this.root = process.cwd();
 //モジュールを作成する
 this.modules = {};
 }
 pares(fileContent, parentDirname) {
 const deps = [];
 const ast = parser.parse(fileContent, {
 sourceType: "module",
 });
 traverse(ast, {
 ImportDeclaration({ node }) {
 deps.push(path.join(parentDirname, node.source.value));
 },
 });
 let { code } = transformFromAst(ast, null, {
 //変換の標準
 presets: ["@babel/preset-env"],
 });
 const r = /require\(['"](.*)['"]\)/g;
 code = code.replace(r, function (match, arg) {
 const retPath = path.join(parentDirname, arg.replace(/'|"/g, ""));
 // 依存パスを追加する
 return `__fasterpack_require__("./${retPath}")`;
 });
 return { code, deps };
 }
 /**
 *
 * @param {*} modulePath モジュールの物理パス
 * @param {*} name プロジェクトユニークパスキー
 */
 createModule(modulePath, name) {
 const modulePathKeys = Object.keys(this.modules);
 const fileContent = fs.readFileSync(modulePath, "utf-8");
 //プロジェクトが登録されているかどうかを再帰的に判断する
 if (!modulePathKeys.includes(name)) {
 //解析されたソースコードとその依存関係を返す。
 const { code, deps } = this.pares(fileContent, path.dirname(name));
 this.modules[name] = `function(module,exports,__fasterpack_require__){
 eval(${JSON.stringify(code)})
 }`;
 // モジュールの再帰的作成
 deps.forEach((dep) => {
 this.createModule(path.join(this.root, dep), `./${dep}`);
 });
 }
 }
 generateModuleStr() {
 let fnTemp = "";
 Object.keys(this.modules).forEach((name) => {
 fnTemp += `"${name}":${this.modules[name]},`;
 });
 return `{${fnTemp}}`;
 }
 generateFile() {
 //パラメータ・インジェクション・テンプレート
 this.tempalate = getTempalate(this.generateModuleStr(), this.entry);
 fs.writeFileSync(`./dist/main.js`, this.tempalate);
 console.log("上書きする ", this.m);
 }
 start() {
 console.log("解析開始");
 const entryPath = path.resolve(this.root, this.entry);
 //キャッシュモジュールを作成する
 this.createModule(entryPath, this.entry);
 //ファイルを生成する
 this.generateFile();
 }
}
const getTempalate = (__modules_content__, __entry__) => {
 return `(function (modules) {
 const installModules = {};
 function __faster_require__(moduleId) {
 //キャッシュするかどうか
 if (installModules[moduleId]) {
 console.log(installModules, moduleId, installModules[moduleId].exports);
 return installModules[moduleId].exports;
 }
 var module = (installModules[moduleId] = {
 exports: {},
 });
 modules[moduleId].call(
 module.exports,
 module,
 module.exports,
 __faster_require__
 );
 return module.exports;
 }
 // 
 return __faster_require__("${__entry__}");
})(${__modules_content__});`;
};
const fasterpack = new Fasterpack(config);
fasterpack.start();
Read next

TCPプロトコルの解釈

TCP接続では、2つの当事者だけが互いに通信します。ブロードキャストやマルチキャストはTCPでは使用できません。 注:TCPは、データが相手によって受信されることを保証するものではありません。したがって、TCPは正確には1...

Nov 10, 2020 · 3 min read