esbuild-build.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. // scripts/esbuild_build.mjs (注意扩展名改成 .mjs 或启用 type: "module")
  2. import fs from "fs";
  3. import path from "path";
  4. import dotenv from 'dotenv';
  5. import esbuild from 'esbuild';
  6. import esbuildPluginPino from 'esbuild-plugin-pino';
  7. // 加载 .env 文件
  8. const define = {
  9. 'process.env.NODE_ENV': '"production"'
  10. }
  11. const env = dotenv.config({ path: path.resolve('.env') }).parsed;
  12. for (const key in env) {
  13. define[`process.env.${key}`] = JSON.stringify(env[key]);
  14. }
  15. const env_production = dotenv.config({ path: path.resolve('.env.production') }).parsed;
  16. for (const key in env_production) {
  17. define[`process.env.${key}`] = JSON.stringify(env_production[key]);
  18. }
  19. console.log({define})
  20. const builtins = [
  21. '_http_agent',
  22. '_http_client',
  23. '_http_common',
  24. '_http_incoming',
  25. '_http_outgoing',
  26. '_http_server',
  27. '_stream_duplex',
  28. '_stream_passthrough',
  29. '_stream_readable',
  30. '_stream_transform',
  31. '_stream_wrap',
  32. '_stream_writable',
  33. '_tls_common',
  34. '_tls_wrap',
  35. 'assert',
  36. 'async_hooks',
  37. 'buffer',
  38. 'child_process',
  39. 'cluster',
  40. 'console',
  41. 'constants',
  42. 'crypto',
  43. 'dgram',
  44. 'diagnostics_channel',
  45. 'dns',
  46. 'domain',
  47. 'events',
  48. 'fs',
  49. 'http',
  50. 'http2',
  51. 'https',
  52. 'inspector',
  53. 'module',
  54. 'net',
  55. 'os',
  56. 'path',
  57. 'perf_hooks',
  58. 'process',
  59. 'punycode',
  60. 'querystring',
  61. 'readline',
  62. 'repl',
  63. 'stream',
  64. 'string_decoder',
  65. 'sys',
  66. 'timers',
  67. 'tls',
  68. 'trace_events',
  69. 'tty',
  70. 'url',
  71. 'util',
  72. 'v8',
  73. 'vm',
  74. 'wasi',
  75. 'worker_threads',
  76. 'zlib'
  77. ]
  78. // 内置模块引入处理插件
  79. const SupportEsmPlugin = {
  80. name: 'SupportESM',
  81. setup(build) {
  82. build.onEnd(() => {
  83. const outdir = build.initialOptions.outdir;
  84. if (!outdir) return;
  85. const pattern = `\\b__require\\((['"\`])(?:node:)?(${builtins.join('|')})\\1\\)`;
  86. const rx = new RegExp(pattern, 'gm');
  87. const modules = new Map();
  88. const walk = (dir) => {
  89. for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
  90. const fullPath = path.join(dir, entry.name);
  91. console.log({fullPath})
  92. if (entry.isDirectory()) {
  93. walk(fullPath);
  94. } else if (/\.(js|ts|mjs|cjs)$/.test(entry.name)) {
  95. const data = fs.readFileSync(fullPath, 'utf8');
  96. const out = data.replace(rx, (_, __, mod) => {
  97. const id = `__import_${mod.toUpperCase()}`;
  98. modules.set(mod, id);
  99. return id;
  100. });
  101. fs.writeFileSync(fullPath, '');
  102. modules.forEach(function(val, key) {
  103. fs.appendFileSync(fullPath, `import ${val} from ${JSON.stringify(key)};\n`, 'utf8');
  104. })
  105. fs.appendFileSync(fullPath, out, 'utf8');
  106. }
  107. }
  108. };
  109. walk(outdir);
  110. });
  111. }
  112. }
  113. const entryFile = 'src/index.ts';
  114. // 模块强制引入处理插件
  115. const injectForceDepsPlugin = {
  116. name: 'inject-force-deps',
  117. setup(build) {
  118. const entryFilePath = path.resolve(entryFile);
  119. const depsFilePath = path.resolve('./scripts/force-deps.js');
  120. build.onLoad({ filter: /.*/, namespace: 'file' }, async (args) => {
  121. if (args.path === entryFilePath) {
  122. console.log({path: args.path})
  123. const original = await fs.promises.readFile(args.path, 'utf8');
  124. return {
  125. contents: `import "${depsFilePath}";\n${original}`,
  126. loader: 'ts',
  127. };
  128. }
  129. });
  130. }
  131. }
  132. esbuild.build({
  133. entryPoints: [entryFile],
  134. bundle: true,
  135. platform: 'node',
  136. target: 'esnext',
  137. format: 'esm', // ✅ 使用 ESM 输出格式
  138. outdir: "dist",
  139. outExtension: {
  140. '.js': '.mjs'
  141. },
  142. // outfile: 'dist/index.mjs',
  143. define,
  144. sourcemap: false,
  145. minify: false,
  146. external: ['node:*', ...builtins], // 忽略 Node 内置模块
  147. plugins: [
  148. esbuildPluginPino({ transports: ["pino", "pino-pretty"] }),
  149. SupportEsmPlugin,
  150. injectForceDepsPlugin
  151. ]
  152. }).then(() => {
  153. console.log('✅ Build finished!');
  154. }).catch((err) => {
  155. console.error('❌ Build failed:', err);
  156. process.exit(1);
  157. });