-
Notifications
You must be signed in to change notification settings - Fork 762
/
Copy pathbundle.ts
141 lines (130 loc) · 4.26 KB
/
bundle.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import { writeFileSync } from "node:fs";
import path from "node:path";
import * as esbuild from "esbuild";
import { EXTERNAL_DEPENDENCIES } from "./deps";
import type { BuildContext, BuildOptions, Plugin } from "esbuild";
// the expectation is that this is being run from the project root
type BuildFlags = {
watch?: boolean;
};
const WATCH = process.argv.includes("--watch");
const TEMPLATES_DIR = path.join(__dirname, "../templates");
async function buildMain(flags: BuildFlags = {}) {
const outdir = path.resolve("./wrangler-dist");
const wranglerPackageDir = path.resolve(".");
/**
* The relative path between the bundled code and the Wrangler package.
* This is used as a reliable way to compute paths relative to the Wrangler package
* in the source files, rather than relying upon `__dirname` which can change depending
* on whether the source files have been bundled and the location of the outdir.
*
* This is exposed in the source via the `getBasePath()` function, which should be used
* in place of `__dirname` and similar Node.js constants.
*/
const __RELATIVE_PACKAGE_PATH__ = `"${path.relative(
outdir,
wranglerPackageDir
)}"`;
const options: BuildOptions = {
keepNames: true,
entryPoints: ["./src/cli.ts"],
bundle: true,
outdir,
platform: "node",
format: "cjs",
metafile: true,
external: EXTERNAL_DEPENDENCIES,
sourcemap: process.env.SOURCEMAPS !== "false",
inject: [path.join(__dirname, "../import_meta_url.js")],
// This is required to support jsonc-parser. See https://github.com/microsoft/node-jsonc-parser/issues/57
mainFields: ["module", "main"],
define: {
__RELATIVE_PACKAGE_PATH__,
"import.meta.url": "import_meta_url",
"process.env.NODE_ENV": `'${process.env.NODE_ENV || "production"}'`,
"process.env.SPARROW_SOURCE_KEY": JSON.stringify(
process.env.SPARROW_SOURCE_KEY ?? ""
),
...(process.env.ALGOLIA_APP_ID
? { ALGOLIA_APP_ID: `"${process.env.ALGOLIA_APP_ID}"` }
: {}),
...(process.env.ALGOLIA_PUBLIC_KEY
? { ALGOLIA_PUBLIC_KEY: `"${process.env.ALGOLIA_PUBLIC_KEY}"` }
: {}),
...(process.env.SENTRY_DSN
? { SENTRY_DSN: `"${process.env.SENTRY_DSN}"` }
: {}),
},
plugins: [embedWorkersPlugin],
};
if (flags.watch) {
const ctx = await esbuild.context(options);
await ctx.watch();
} else {
const res = await esbuild.build(options);
writeFileSync("metafile.json", JSON.stringify(res.metafile));
}
}
const workersContexts = new Map<string, BuildContext>();
const embedWorkersPlugin: Plugin = {
name: "embed-workers",
setup(build) {
const namespace = "embed-worker";
build.onResolve({ filter: /^worker:/ }, async (args) => {
const name = args.path.substring("worker:".length);
// Use `build.resolve()` API so Workers can be written as `m?[jt]s` files
const result = await build.resolve("./" + name, {
kind: "import-statement",
resolveDir: TEMPLATES_DIR,
});
if (result.errors.length > 0) {
return { errors: result.errors };
}
return { path: result.path, namespace };
});
build.onLoad({ filter: /.*/, namespace }, async (args) => {
const ctx =
workersContexts.get(args.path) ??
(await esbuild.context({
platform: "node", // Marks `node:*` imports as external
format: "esm",
target: "esnext",
bundle: true,
sourcemap: true,
sourcesContent: false,
metafile: true,
entryPoints: [args.path],
outdir: build.initialOptions.outdir,
}));
const result = await ctx.rebuild();
workersContexts.set(args.path, ctx);
const watchFiles = Object.keys(result?.metafile?.inputs ?? {});
const scriptPath = Object.keys(result?.metafile?.outputs ?? {}).find(
(filepath) => filepath.endsWith(".js")
);
const contents = `
import path from "node:path";
const scriptPath = path.resolve(__dirname, "..", "${scriptPath}");
export default scriptPath;
`;
return { contents, loader: "js", watchFiles };
});
},
};
async function run() {
// main cli
await buildMain();
// After built once completely, rerun them both in watch mode
if (WATCH) {
console.log("Built. Watching for changes...");
await buildMain({ watch: true });
} else {
for (const ctx of workersContexts.values()) {
await ctx.dispose();
}
}
}
run().catch((e) => {
console.error(e);
process.exit(1);
});