jiti-hooks.mjs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. import { dirname, join } from "node:path";
  2. import { fileURLToPath } from "node:url";
  3. import { existsSync } from "node:fs";
  4. import { readFile } from "node:fs/promises";
  5. import { isBuiltin } from "node:module";
  6. import { createJiti } from "./jiti.mjs";
  7. let jiti;
  8. // https://nodejs.org/api/module.html#initialize
  9. export async function initialize() {
  10. jiti = createJiti();
  11. }
  12. // https://nodejs.org/api/module.html#resolvespecifier-context-nextresolve
  13. export async function resolve(specifier, context, nextResolve) {
  14. if (_shouldSkip(specifier)) {
  15. return nextResolve(specifier, context);
  16. }
  17. const resolvedPath = jiti.esmResolve(specifier, {
  18. parentURL: context?.parentURL,
  19. conditions: context?.conditions,
  20. });
  21. return {
  22. url: resolvedPath,
  23. shortCircuit: true,
  24. };
  25. }
  26. // https://nodejs.org/api/module.html#loadurl-context-nextload
  27. export async function load(url, context, nextLoad) {
  28. if (_shouldSkip(url)) {
  29. return nextLoad(url, context);
  30. }
  31. const filename = fileURLToPath(url);
  32. if (url.endsWith(".js")) {
  33. const pkg = await _findClosestPackageJson(dirname(filename));
  34. if (pkg && pkg.type === "module") {
  35. return nextLoad(url, context);
  36. }
  37. }
  38. const rawSource = await readFile(filename, "utf8");
  39. if (url.endsWith(".json")) {
  40. const pkg = await _findClosestPackageJson(dirname(filename));
  41. return pkg && pkg.type === "module"
  42. ? {
  43. source: `export default ${rawSource}`,
  44. format: "module",
  45. shortCircuit: true,
  46. }
  47. : {
  48. source: `module.exports = ${rawSource}`,
  49. format: "commonjs",
  50. shortCircuit: true,
  51. };
  52. }
  53. const transpiledSource = jiti.transform({
  54. source: rawSource,
  55. filename: filename,
  56. ts: url.endsWith("ts"),
  57. retainLines: true,
  58. async: true,
  59. jsx: jiti.options.jsx,
  60. });
  61. if (url.endsWith(".js") && !transpiledSource.includes("jitiImport")) {
  62. return {
  63. source: transpiledSource,
  64. format: "commonjs",
  65. shortCircuit: true,
  66. };
  67. }
  68. return {
  69. source: _wrapSource(transpiledSource, filename),
  70. format: "module",
  71. shortCircuit: true,
  72. };
  73. }
  74. function _wrapSource(source, filename) {
  75. const _jitiPath = new URL("jiti.mjs", import.meta.url).href;
  76. return /*js*/ `import { createJiti as __createJiti__ } from ${JSON.stringify(_jitiPath)};async function _module(exports, require, module, __filename, __dirname, jitiImport) { ${source}\n};
  77. // GENERATED BY JITI ESM LOADER
  78. const filename = ${JSON.stringify(filename)};
  79. const dirname = ${JSON.stringify(dirname(filename))};
  80. const jiti = __createJiti__(filename);
  81. const module = { exports: Object.create(null) };
  82. await _module(module.exports, jiti, module, filename, dirname, jiti.import);
  83. if (module.exports && module.exports.__JITI_ERROR__) {
  84. const { filename, line, column, code, message } =
  85. module.exports.__JITI_ERROR__;
  86. const loc = [filename, line, column].join(':');
  87. const err = new Error(code + ": " + message + " " + loc);
  88. Error.captureStackTrace(err, _module);
  89. throw err;
  90. }
  91. export default module.exports;
  92. `;
  93. }
  94. function _shouldSkip(url) {
  95. return (
  96. !jiti ||
  97. url.endsWith(".mjs") ||
  98. url.endsWith(".cjs") ||
  99. (!url.startsWith("./") && !url.startsWith("file://")) ||
  100. isBuiltin(url)
  101. );
  102. }
  103. async function _findClosestPackageJson(dir) {
  104. if (dir === "/") return null;
  105. const packageJsonPath = join(dir, "package.json");
  106. if (existsSync(packageJsonPath)) {
  107. return JSON.parse(await readFile(packageJsonPath, "utf8"));
  108. }
  109. return _findClosestPackageJson(dirname(dir));
  110. }