banner
Madinah

Madinah

github
twitter
telegram
email
bilibili

NodeJSローダー

ローダーの読み込み方法#

まず、node --loaderパラメータを紹介します。このパラメータを使用すると、ESM モジュールの読み込みルールをカスタマイズすることができます。
node --loader ./my-loader.mjs index.mjsを実行します。index.mjs を読み込む際に、まず my-loader.mjs の内容が実行されます。my-loader.js を書いた場合はどうなるでしょうか。node には 2 つのフックが組み込まれています。それぞれresolveloadと呼ばれ、import の際に実行されます(注:これらのフックは ESM モジュールにのみ有効であり、CJS には無効です)。次に、これら 2 つのフックの使用方法を紹介します。

resolve#

resolve 関数は、ファイル名とファイルのフォーマット情報を取得することができます。渡されたモジュールの情報を変更して返すことができます。返された情報は、load フックに渡されて実行されます。

export async function resolve(specifier, context, nextResolve) {
  const { parentURL = null } = context;
  if (Math.random() > 0.5) {
    return {
      shortCircuit: true,
      url: parentURL ?
        new URL(specifier, parentURL).href :
        new URL(specifier).href,
    };
  }
  if (Math.random() < 0.5) { .
    return nextResolve(specifier, {
      ...context,
      conditions: [...context.conditions, 'another-condition'],
    });
  }
  return nextResolve(specifier);
}

specifier は実行するファイルのパスです。context には parentURL とインポートできる条件のルールが記録されています。nextResolve は resolve 関数を書くための関数です。指定されていない場合はデフォルトの関数になります。返される構造は次のようになります。

{
    format: 'commonjs' | 'module' | 'wasm',
    shortCircuit: boolean, // デフォルトはfalseで、resolveフックを終了するかどうかを示します
    url: string; // ファイルのURLで、ファイルの元のURLを処理することができます。
}

load#

このフックは、ファイルの URL がどのように検索および解析されるかを決定します。

export async function load(url, context, defaultLoad) {
  const load = defaultLoad(url, context, defaultLoad)
  const source = load.source

  return {
    format: "module",
    source: `${source} console.log("i am injected from loader.mjs")`,
  }
}
console.log("2")

node --loader ./loader.mjs index.mjsを実行すると、2 i am injected from loader.mjsと表示されます。これにより、実行時に必要なコードを注入することができます。

CJS のローダー#

上記ではいくつかの ESM のフックについて説明しました。次に、CJS で上記の load の機能を実装する方法について説明します。

// モジュールの読み込み
Module.prototype.load = function (filename) {
  var extension = path.extname(filename) || ".js"
  if (!Module._extensions[extension]) extension = ".js"
  Module._extensions[extension](this, filename)
  this.loaded = true
}

// 異なる拡張子の解析メソッドを呼び出す
Module._extensions[".js"] = function (module, filename) {
  var content = fs.readFileSync(filename, "utf8")
  module._compile(stripBOM(content), filename)
}

Module._extensions[".json"] = function (module, filename) {
  var content = fs.readFileSync(filename, "utf8")
  try {
    module.exports = JSON.parse(stripBOM(content))
  } catch (err) {
    err.message = filename + ": " + err.message
    throw err
  }
}

// 最後に_compileメソッドを呼び出してモジュールをコンパイルします。
Module.prototype._compile = function (content, filename) {
  var self = this
  var args = [self.exports, require, self, filename, dirname]
  return compiledWrapper.apply(self.exports, args)
}

同様に、CJS のローダーを注入することもできます。

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。