
Webpack はフロントエンドの「包囲ライオン」として非常によく知られており、すべてのリソース (JS、TS、JSX、画像、フォント、CSS など) をパッケージ化し、依存関係に配置できます。 . 依存関係を参照して、ニーズに応じてリソースを使用できるようになります。 Webpack は、フロントエンドで複数のファイル リソースを変換し、複雑なモジュールの依存関係を分析するという優れた機能を備えています。また、ローダーをカスタマイズして独自のリソースを自由にロードすることもできます。今日はぜひ見に来てください。
1. require とは何ですか?
require に関して最初に思い浮かぶのは、import です。import は es6 の標準構文です。
つまり
、require は理論的にはコード内のどこでも使用できます。
Webpackを
使用してコンパイルする場合、CommonJS にはグローバル メソッド require() があり、これはモジュールをロードするために使用されます。 . AMD と CMD も参照に require メソッドを使用します。
例:
var add = require('./a.js');
簡単に言えば、 add(1,2)
は実際には関数であり、参照される./a.jsは関数の単なるパラメーターです。
2. 輸出とは何ですか?
ここでは、エクスポートをオブジェクトとして考えることができます。MDN エクスポートの具体的な使用方法がわかります。
まず、パッケージ化後のコード構造を見てみましょう。パッケージ化の後に、require とexport が表示されることがわかります。
すべてのブラウザが require エクスポートを実行できるわけではありません。コードが正常に動作するようにするには、自分で require およびエクスポートを実装する必要があります。パッケージ化されたコードは自己実行関数であり、パラメーターには依存関係情報が含まれており、実行される関数本体は eval を通じてコードを実行します。

全体の設計図は以下の通りです。

ステップ 1: 構成ファイルを作成します。
構成ファイルは、後続の生成ファイルを準備するために、パッケージ化されたエントリとパッケージ化された終了出力を構成します。
const パス = require("パス");
module.exports = {
エントリ: "./src/index.js",
出力: {
path: path.resolve(__dirname, "./dist"),//パッケージ化後に出力されるファイルアドレスは絶対パスが必要なのでパスは必須
ファイル名:「main.js」
}、
モード: "開発"ステップ 2: モジュール分析の全体的な考え方
:要約すると、fs ファイルを使用してエントリ ファイルを読み取り、依存ファイルがまだ存在する場合は AST を通じてインポート依存ファイルのパスを取得します。依存関係がある場合は、依存関係の分析が明確になるまで再帰を続け、マップ内で維持されます。
詳細な内訳: AST はこの関数で誕生したため、なぜ AST が使用されるのか疑問に思う人もいるかもしれません。もちろん、ファイルは通常のマッチングを使用することもできます。素晴らしい正規表現はファイルの依存関係のパスを取得するのに役立ちますが、十分にエレガントではありません。
。index.js ファイル
import { str } from "./a.js";
console.log(`${str} Webpack`) a.js ファイル
インポート { b} from "./b.js"
import const str = "hello" b.js file
export const b="bbb"
モジュール分析を作成する: AST の @babel/parser を使用してファイルから読み取った文字列を AST ツリーに変換し、@babel/traverse を使用して構文 ImportDeclaration を分析して使用し、インポートをフィルターで除外し、ファイルの依存関係を見つけます。
const content = fs.readFileSync(entryFile, "utf-8");
const ast = parser.parse(content, {sourceType: "モジュール" });
const dirname = path.dirname(entryFile);
const 依存関係 = {};
トラバース(ast, {
ImportDeclaration({ ノード }) {
//インポートをフィルターで除外する
const newPathName = "./" + path.join(dirname, node.source.value);
依存関係[node.source.value] = 新しいパス名;
}
})
const { コード } =transformFromAst(ast, null, {
プリセット: ["@babel/preset-env"]
})
戻る {
エントリファイル、
扶養家族、
コード
結果は次のとおりです。

依存関係を分析するには、再帰またはループを使用してファイルを 1 つずつインポートします。ここで、ループですべての依存関係を分析できるのは、 dependency.modules .push があると、モジュールの長さが変化するためです。新しい依存関係では、 modules.length が変更されます。
for (let i = 0; i < this.modules.length; i++) {
const item = this.modules[i];
const { 依存関係 } = アイテム;
if (依存関係) {
for (j を従属変数に入れる) {
this.modules.push(this.parse(dependents[j]));
}
}
ステップ3
: WebpackBootstrap 関数を作成し、出力ファイルを生成します。
WebpackBootstrap関数を作成します。ここで最初に行う必要があるのは、コンパイル後、ソース コードのインポートがブラウザに解析されることです。結局のところ、require はメソッドであるため、変数の汚染を防ぐためにスコープの分離にも注意する必要があります。また、コードの実行時にエクスポートがすでに存在することを確認するために、コード内でエクスポートを宣言する必要があります。
出力ファイルを生成する: 生成されたファイルのアドレスは構成ファイルにすでに書き込まれており、fs.writeFileSync を使用してそれを出力フォルダーに書き込みます。
ファイル(コード) {
const filePath = path.join(this.output.path, this.output.filename)
const newCode = JSON.stringify(code);
// バンドル ファイルの内容を生成する const Bundle = `(function(modules){
関数 require(モジュール){
関数 pathRequire(relativePath){
return require(モジュール[モジュール].dependents[相対パス])
}
const エクスポート={};
(関数(require,exports,code){
eval(コード)
})(pathRequire,exports,modules[モジュール].code);
輸出を返す
}
require('${this.entry}')
})(${newCode})`;
// WebpackBoostrap
// ファイルを生成します。 dist ディレクトリに置きます。 fs.writeFileSync(filePath,bundle,'utf-8')
} 
ステップ 4: 実行シーケンスを分析する

パッケージ化された結果をブラウザ コンソールで実行できます。正常に動作すると、hello Webpack が出力されるはずです。

上記の分析を通じて、AST を使用してコードを解析することは、Webpack の実際の実装には独自の AST 解析メソッドがあるわけではなく、Webpack の一般的なプロセスについて基本的に理解できるはずです。 Webpack エコシステムは非常に完全です。興味のある子供たちは次の 3 つの質問を検討できます。