|
| 1 | +import { createRequire } from "node:module"; |
| 2 | +import path from "node:path"; |
| 3 | +import { build } from "esbuild"; |
| 4 | +import { nodeless } from "unenv"; |
| 5 | + |
| 6 | +const require = createRequire(import.meta.url); |
| 7 | + |
| 8 | +// When importing the Node API (e.g., `import path from "node:path"`), |
| 9 | +// the unenv package should be bundled to run even in the Function service. |
| 10 | +// Functions that are difficult to execute in the Function service (e.g., `fs.writeFile`) |
| 11 | +// will be bundled as mocks and will throw a "not implemented" error at runtime. |
| 12 | +const unenvAlias = { |
| 13 | + name: "unenv-alias", |
| 14 | + setup(build) { |
| 15 | + const alias = nodeless.alias; |
| 16 | + const re = new RegExp(`^(${Object.keys(alias).join("|")})$`); |
| 17 | + |
| 18 | + build.onResolve({ filter: re }, (args) => { |
| 19 | + const resolved = require.resolve(alias[args.path]); |
| 20 | + // Since require.resolve() always resolves to cjs, |
| 21 | + // it needs to be converted to mjs when this callback is invoked via import. |
| 22 | + const path = |
| 23 | + args.kind === "require-call" |
| 24 | + ? resolved |
| 25 | + : resolved.replace(/\.cjs$/, ".mjs"); |
| 26 | + return { path }; |
| 27 | + }); |
| 28 | + }, |
| 29 | +}; |
| 30 | + |
| 31 | +// Inject the unenv package to emulate the behavior of global variables (e.g., process) |
| 32 | +// that do not exist within the Function service. |
| 33 | +const unenvInject = { |
| 34 | + name: "unenv-inject", |
| 35 | + setup(build) { |
| 36 | + const inject = nodeless.inject; |
| 37 | + const re = /unenv-inject-([^.]+)\.js$/; |
| 38 | + const prefix = path.join(import.meta.dirname, "unenv-inject-"); |
| 39 | + |
| 40 | + build.initialOptions.inject = [ |
| 41 | + ...(build.initialOptions.inject ?? []), |
| 42 | + ...Object.keys(inject).map((globalName) => `${prefix}${globalName}.js`), |
| 43 | + ]; |
| 44 | + |
| 45 | + build.onResolve({ filter: re }, ({ path }) => ({ path })); |
| 46 | + |
| 47 | + build.onLoad({ filter: re }, ({ path }) => { |
| 48 | + const globalName = path.match(re)[1]; |
| 49 | + return { |
| 50 | + contents: getInjectContent(globalName, inject[globalName]), |
| 51 | + }; |
| 52 | + }); |
| 53 | + }, |
| 54 | +}; |
| 55 | + |
| 56 | +const getInjectContent = (globalName, globalInject) => { |
| 57 | + if (typeof globalInject === "string") { |
| 58 | + return `import globalVar from "${globalInject}"; globalThis.${globalName} = globalVar;`; |
| 59 | + } |
| 60 | + const [moduleSpecifier, exportName] = globalInject; |
| 61 | + return `import { ${exportName} } from "${moduleSpecifier}"; globalThis.${globalName} = ${exportName};`; |
| 62 | +}; |
| 63 | + |
| 64 | +// Due to the use of dynamic require, bundling `git-diff` is difficult. |
| 65 | +// However, since it's not used in this use case, we can mock it instead. |
| 66 | +const mockGitDiff = { |
| 67 | + name: "mock-git-diff", |
| 68 | + setup(build) { |
| 69 | + build.onResolve({ filter: /^git-diff$/ }, (args) => { |
| 70 | + return { path: args.path, namespace: "git-diff" }; |
| 71 | + }); |
| 72 | + build.onLoad({ filter: /.*/, namespace: "git-diff" }, () => { |
| 73 | + return { contents: "export default null" }; |
| 74 | + }); |
| 75 | + }, |
| 76 | +}; |
| 77 | + |
| 78 | +build({ |
| 79 | + entryPoints: ["src/function.ts"], |
| 80 | + outfile: "dist/function.js", |
| 81 | + format: "esm", |
| 82 | + bundle: true, |
| 83 | + minify: true, |
| 84 | + define: { |
| 85 | + global: "globalThis", |
| 86 | + }, |
| 87 | + plugins: [unenvAlias, unenvInject, mockGitDiff], |
| 88 | + // Unused drivers are left unbundled as-is. |
| 89 | + // Note that future updates to `kysely-codegen` may introduce new drivers. |
| 90 | + external: [ |
| 91 | + "@libsql/kysely-libsql", |
| 92 | + "@tediousjs/connection-string", |
| 93 | + "better-sqlite3", |
| 94 | + "bun:sqlite", |
| 95 | + "kysely-bun-sqlite", |
| 96 | + "mysql2", |
| 97 | + "pg", |
| 98 | + "tarn", |
| 99 | + "tedious", |
| 100 | + ], |
| 101 | +}); |
| 102 | + |
| 103 | +build({ |
| 104 | + entryPoints: ["src/cli.ts"], |
| 105 | + outfile: "dist/cli.js", |
| 106 | + format: "esm", |
| 107 | +}); |
0 commit comments