// scripts/esbuild_build.mjs (注意扩展名改成 .mjs 或启用 type: "module") import fs from "fs"; import path from "path"; import dotenv from 'dotenv'; import esbuild from 'esbuild'; import esbuildPluginPino from 'esbuild-plugin-pino'; // 加载 .env 文件 const define = { 'process.env.NODE_ENV': '"production"' } const env = dotenv.config({ path: path.resolve('.env') }).parsed; for (const key in env) { define[`process.env.${key}`] = JSON.stringify(env[key]); } const env_production = dotenv.config({ path: path.resolve('.env.production') }).parsed; for (const key in env_production) { define[`process.env.${key}`] = JSON.stringify(env_production[key]); } console.log({define}) const builtins = [ '_http_agent', '_http_client', '_http_common', '_http_incoming', '_http_outgoing', '_http_server', '_stream_duplex', '_stream_passthrough', '_stream_readable', '_stream_transform', '_stream_wrap', '_stream_writable', '_tls_common', '_tls_wrap', 'assert', 'async_hooks', 'buffer', 'child_process', 'cluster', 'console', 'constants', 'crypto', 'dgram', 'diagnostics_channel', 'dns', 'domain', 'events', 'fs', 'http', 'http2', 'https', 'inspector', 'module', 'net', 'os', 'path', 'perf_hooks', 'process', 'punycode', 'querystring', 'readline', 'repl', 'stream', 'string_decoder', 'sys', 'timers', 'tls', 'trace_events', 'tty', 'url', 'util', 'v8', 'vm', 'wasi', 'worker_threads', 'zlib' ] // 内置模块引入处理插件 const SupportEsmPlugin = { name: 'SupportESM', setup(build) { build.onEnd(() => { const outdir = build.initialOptions.outdir; if (!outdir) return; const pattern = `\\b__require\\((['"\`])(?:node:)?(${builtins.join('|')})\\1\\)`; const rx = new RegExp(pattern, 'gm'); const modules = new Map(); const walk = (dir) => { for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { const fullPath = path.join(dir, entry.name); console.log({fullPath}) if (entry.isDirectory()) { walk(fullPath); } else if (/\.(js|ts|mjs|cjs)$/.test(entry.name)) { const data = fs.readFileSync(fullPath, 'utf8'); const out = data.replace(rx, (_, __, mod) => { const id = `__import_${mod.toUpperCase()}`; modules.set(mod, id); return id; }); fs.writeFileSync(fullPath, ''); modules.forEach(function(val, key) { fs.appendFileSync(fullPath, `import ${val} from ${JSON.stringify(key)};\n`, 'utf8'); }) fs.appendFileSync(fullPath, out, 'utf8'); } } }; walk(outdir); }); } } const entryFile = 'src/index.ts'; // 模块强制引入处理插件 const injectForceDepsPlugin = { name: 'inject-force-deps', setup(build) { const entryFilePath = path.resolve(entryFile); const depsFilePath = path.resolve('./scripts/force-deps.js'); build.onLoad({ filter: /.*/, namespace: 'file' }, async (args) => { if (args.path === entryFilePath) { console.log({path: args.path}) const original = await fs.promises.readFile(args.path, 'utf8'); return { contents: `import "${depsFilePath}";\n${original}`, loader: 'ts', }; } }); } } esbuild.build({ entryPoints: [entryFile], bundle: true, platform: 'node', target: 'esnext', format: 'esm', // ✅ 使用 ESM 输出格式 outdir: "dist", outExtension: { '.js': '.mjs' }, // outfile: 'dist/index.mjs', define, sourcemap: false, minify: false, external: ['node:*', ...builtins], // 忽略 Node 内置模块 plugins: [ esbuildPluginPino({ transports: ["pino", "pino-pretty"] }), SupportEsmPlugin, injectForceDepsPlugin ] }).then(() => { console.log('✅ Build finished!'); }).catch((err) => { console.error('❌ Build failed:', err); process.exit(1); });