@b9g/shovel 0.2.0-beta.10 → 0.2.0-beta.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build-NDUV2F2Z.js DELETED
@@ -1,386 +0,0 @@
1
- import {
2
- applyJSXOptions,
3
- importMetaPlugin,
4
- loadJSXConfig
5
- } from "./chunk-ILQUUH2L.js";
6
- import {
7
- findProjectRoot,
8
- findWorkspaceRoot,
9
- generateConfigModule,
10
- getNodeModulesPath,
11
- loadRawConfig
12
- } from "./chunk-CSH7M4MK.js";
13
-
14
- // src/commands/build.ts
15
- import * as ESBuild from "esbuild";
16
- import { resolve, join, dirname } from "path";
17
- import { mkdir, readFile, writeFile } from "fs/promises";
18
- import { assetsPlugin } from "@b9g/assets/plugin";
19
- import { getLogger } from "@logtape/logtape";
20
- import * as Platform from "@b9g/platform";
21
- var logger = getLogger(["cli"]);
22
- function validateDynamicImports(result, context) {
23
- const dynamicImportWarnings = (result.warnings || []).filter(
24
- (w) => w.text.includes("cannot be bundled") || w.text.includes("import() call") || w.text.includes("dynamic import")
25
- );
26
- if (dynamicImportWarnings.length > 0) {
27
- const locations = dynamicImportWarnings.map((w) => {
28
- const loc = w.location;
29
- const file = loc?.file || "unknown";
30
- const line = loc?.line || "?";
31
- return ` ${file}:${line} - ${w.text}`;
32
- }).join("\n");
33
- throw new Error(
34
- `Build failed (${context}): Non-analyzable dynamic imports found:
35
- ${locations}
36
-
37
- Dynamic imports must use literal strings, not variables.
38
- For config-driven providers, ensure they are registered in shovel.json.`
39
- );
40
- }
41
- }
42
- var BUILD_DEFAULTS = {
43
- format: "esm",
44
- target: "es2022",
45
- outputFile: "index.js",
46
- sourcemap: false,
47
- minify: false,
48
- treeShaking: true
49
- };
50
- var BUILD_STRUCTURE = {
51
- serverDir: "server",
52
- staticDir: "static"
53
- };
54
- function createConfigPlugin(projectRoot) {
55
- const rawConfig = loadRawConfig(projectRoot);
56
- const configModuleCode = generateConfigModule(rawConfig);
57
- return {
58
- name: "shovel-config",
59
- setup(build2) {
60
- build2.onResolve({ filter: /^shovel:config$/ }, (args) => ({
61
- path: args.path,
62
- namespace: "shovel-config"
63
- }));
64
- build2.onLoad({ filter: /.*/, namespace: "shovel-config" }, () => ({
65
- contents: configModuleCode,
66
- loader: "js",
67
- resolveDir: projectRoot
68
- }));
69
- }
70
- };
71
- }
72
- async function buildForProduction({
73
- entrypoint,
74
- outDir,
75
- verbose,
76
- platform = "node",
77
- workerCount = 1
78
- }) {
79
- const buildContext = await initializeBuild({
80
- entrypoint,
81
- outDir,
82
- verbose,
83
- platform,
84
- workerCount
85
- });
86
- const buildConfig = await createBuildConfig(buildContext);
87
- const result = await ESBuild.build(buildConfig);
88
- validateDynamicImports(result, "main bundle");
89
- if (verbose && result.metafile) {
90
- await logBundleAnalysis(result.metafile);
91
- }
92
- await generatePackageJSON({
93
- ...buildContext,
94
- entryPath: buildContext.entryPath
95
- });
96
- if (verbose) {
97
- logger.info("Built app to", { outputDir: buildContext.outputDir });
98
- logger.info("Server files", { dir: buildContext.serverDir });
99
- logger.info("Static files", { dir: join(buildContext.outputDir, "static") });
100
- }
101
- }
102
- async function initializeBuild({
103
- entrypoint,
104
- outDir,
105
- verbose,
106
- platform,
107
- workerCount = 1
108
- }) {
109
- if (!entrypoint) {
110
- throw new Error("Entry point is required");
111
- }
112
- if (!outDir) {
113
- throw new Error("Output directory is required");
114
- }
115
- if (verbose) {
116
- logger.info("Entry:", { path: entrypoint });
117
- logger.info("Output:", { dir: outDir });
118
- logger.info("Target platform:", { platform });
119
- }
120
- const entryPath = resolve(entrypoint);
121
- const outputDir = resolve(outDir);
122
- try {
123
- const stats = await readFile(entryPath, "utf8");
124
- if (stats.length === 0) {
125
- logger.warn("Entry point is empty", { entryPath });
126
- }
127
- } catch (error) {
128
- throw new Error(`Entry point not found or not accessible: ${entryPath}`);
129
- }
130
- const validPlatforms = ["node", "bun", "cloudflare", "cloudflare-workers"];
131
- if (!validPlatforms.includes(platform)) {
132
- throw new Error(
133
- `Invalid platform: ${platform}. Valid platforms: ${validPlatforms.join(", ")}`
134
- );
135
- }
136
- const projectRoot = findProjectRoot();
137
- if (verbose) {
138
- logger.info("Entry:", { entryPath });
139
- logger.info("Output:", { outputDir });
140
- logger.info("Target platform:", { platform });
141
- logger.info("Project root:", { projectRoot });
142
- }
143
- try {
144
- await mkdir(outputDir, { recursive: true });
145
- await mkdir(join(outputDir, BUILD_STRUCTURE.serverDir), { recursive: true });
146
- await mkdir(join(outputDir, BUILD_STRUCTURE.staticDir), { recursive: true });
147
- } catch (error) {
148
- throw new Error(`Failed to create output directory structure: ${error}`);
149
- }
150
- return {
151
- entryPath,
152
- outputDir,
153
- serverDir: join(outputDir, BUILD_STRUCTURE.serverDir),
154
- projectRoot,
155
- platform,
156
- verbose,
157
- workerCount
158
- };
159
- }
160
- async function createBuildConfig({
161
- entryPath,
162
- outputDir,
163
- serverDir,
164
- projectRoot,
165
- platform: platformName
166
- }) {
167
- const platform = await Platform.createPlatform(platformName);
168
- const platformEsbuildConfig = platform.getEsbuildConfig();
169
- const entryWrapper = platform.getEntryWrapper(entryPath);
170
- const bundlesUserCodeInline = platformEsbuildConfig.bundlesUserCodeInline ?? false;
171
- const jsxOptions = await loadJSXConfig(projectRoot || dirname(entryPath));
172
- try {
173
- const external = platformEsbuildConfig.external ?? ["node:*"];
174
- if (!bundlesUserCodeInline) {
175
- const userBuildConfig = {
176
- entryPoints: [entryPath],
177
- bundle: true,
178
- format: BUILD_DEFAULTS.format,
179
- target: BUILD_DEFAULTS.target,
180
- platform: platformEsbuildConfig.platform ?? "node",
181
- outfile: join(serverDir, "server.js"),
182
- absWorkingDir: projectRoot,
183
- mainFields: ["module", "main"],
184
- conditions: platformEsbuildConfig.conditions ?? ["import", "module"],
185
- // Resolve packages from the user's project node_modules
186
- nodePaths: [getNodeModulesPath()],
187
- plugins: [
188
- importMetaPlugin(),
189
- assetsPlugin({
190
- outDir: outputDir,
191
- clientBuild: {
192
- jsx: jsxOptions.jsx,
193
- jsxFactory: jsxOptions.jsxFactory,
194
- jsxFragment: jsxOptions.jsxFragment,
195
- jsxImportSource: jsxOptions.jsxImportSource
196
- }
197
- })
198
- ],
199
- metafile: true,
200
- sourcemap: BUILD_DEFAULTS.sourcemap,
201
- minify: BUILD_DEFAULTS.minify,
202
- treeShaking: BUILD_DEFAULTS.treeShaking,
203
- define: platformEsbuildConfig.define ?? {},
204
- external
205
- };
206
- applyJSXOptions(userBuildConfig, jsxOptions);
207
- const userBuildResult = await ESBuild.build(userBuildConfig);
208
- validateDynamicImports(userBuildResult, "user code");
209
- const workerDestPath = join(serverDir, "worker.js");
210
- const virtualWorkerEntry = `
211
- import {configureLogging} from "@b9g/platform/runtime";
212
- import {config} from "shovel:config";
213
- await configureLogging(config.logging);
214
-
215
- // Import the actual worker (runs its initialization code)
216
- import "@b9g/platform/worker";
217
- `;
218
- await ESBuild.build({
219
- stdin: {
220
- contents: virtualWorkerEntry,
221
- resolveDir: projectRoot,
222
- sourcefile: "virtual-worker-entry.js"
223
- },
224
- bundle: true,
225
- format: "esm",
226
- target: "es2022",
227
- platform: "node",
228
- outfile: workerDestPath,
229
- external: ["node:*"],
230
- plugins: [createConfigPlugin(projectRoot)]
231
- });
232
- }
233
- const buildConfig = {
234
- stdin: {
235
- contents: entryWrapper,
236
- // Use serverDir so ./server.js resolves to the built user code
237
- resolveDir: serverDir,
238
- sourcefile: "virtual-entry.js"
239
- },
240
- bundle: true,
241
- format: BUILD_DEFAULTS.format,
242
- target: BUILD_DEFAULTS.target,
243
- platform: platformEsbuildConfig.platform ?? "node",
244
- // Inline bundling (Cloudflare): single-file (server.js contains everything)
245
- // Separate bundling (Node/Bun): multi-file (index.js is entry, server.js is user code)
246
- outfile: join(
247
- serverDir,
248
- bundlesUserCodeInline ? "server.js" : BUILD_DEFAULTS.outputFile
249
- ),
250
- absWorkingDir: projectRoot,
251
- mainFields: ["module", "main"],
252
- conditions: platformEsbuildConfig.conditions ?? ["import", "module"],
253
- // Resolve packages from the user's project node_modules
254
- nodePaths: [getNodeModulesPath()],
255
- plugins: bundlesUserCodeInline ? [
256
- createConfigPlugin(projectRoot),
257
- importMetaPlugin(),
258
- assetsPlugin({
259
- outDir: outputDir,
260
- clientBuild: {
261
- jsx: jsxOptions.jsx,
262
- jsxFactory: jsxOptions.jsxFactory,
263
- jsxFragment: jsxOptions.jsxFragment,
264
- jsxImportSource: jsxOptions.jsxImportSource
265
- }
266
- })
267
- ] : [createConfigPlugin(projectRoot)],
268
- // Config plugin needed for entry wrapper
269
- metafile: true,
270
- sourcemap: BUILD_DEFAULTS.sourcemap,
271
- minify: BUILD_DEFAULTS.minify,
272
- treeShaking: BUILD_DEFAULTS.treeShaking,
273
- define: platformEsbuildConfig.define ?? {},
274
- external
275
- };
276
- if (bundlesUserCodeInline) {
277
- applyJSXOptions(buildConfig, jsxOptions);
278
- }
279
- return buildConfig;
280
- } catch (error) {
281
- throw new Error(`Failed to create build configuration: ${error}`);
282
- }
283
- }
284
- async function logBundleAnalysis(metafile) {
285
- try {
286
- logger.info("Bundle analysis:", {});
287
- const analysis = await ESBuild.analyzeMetafile(metafile);
288
- logger.info(analysis, {});
289
- } catch (error) {
290
- logger.warn("Failed to analyze bundle: {error}", { error });
291
- }
292
- }
293
- async function generatePackageJSON({
294
- serverDir,
295
- platform,
296
- verbose,
297
- entryPath
298
- }) {
299
- const entryDir = dirname(entryPath);
300
- const sourcePackageJsonPath = resolve(entryDir, "package.json");
301
- try {
302
- const packageJSONContent = await readFile(sourcePackageJsonPath, "utf8");
303
- try {
304
- JSON.parse(packageJSONContent);
305
- } catch (parseError) {
306
- throw new Error(`Invalid package.json format: ${parseError}`);
307
- }
308
- await writeFile(
309
- join(serverDir, "package.json"),
310
- packageJSONContent,
311
- "utf8"
312
- );
313
- if (verbose) {
314
- logger.info("Copied package.json", { serverDir });
315
- }
316
- } catch (error) {
317
- if (verbose) {
318
- logger.warn("Could not copy package.json: {error}", { error });
319
- }
320
- try {
321
- const generatedPackageJson = await generateExecutablePackageJSON(platform);
322
- await writeFile(
323
- join(serverDir, "package.json"),
324
- JSON.stringify(generatedPackageJson, null, 2),
325
- "utf8"
326
- );
327
- if (verbose) {
328
- logger.info("Generated package.json", { platform });
329
- logger.info("Package.json contents", {
330
- contents: JSON.stringify(generatedPackageJson, null, 2)
331
- });
332
- }
333
- } catch (generateError) {
334
- if (verbose) {
335
- logger.warn("Could not generate package.json: {error}", {
336
- error: generateError
337
- });
338
- }
339
- }
340
- }
341
- }
342
- async function generateExecutablePackageJSON(platform) {
343
- const packageJSON = {
344
- name: "shovel-executable",
345
- version: "1.0.0",
346
- type: "module",
347
- private: true,
348
- dependencies: {}
349
- };
350
- const isWorkspaceEnvironment = findWorkspaceRoot() !== null;
351
- if (isWorkspaceEnvironment) {
352
- packageJSON.dependencies = {};
353
- } else {
354
- switch (platform) {
355
- case "node":
356
- packageJSON.dependencies["@b9g/platform-node"] = "^0.1.0";
357
- break;
358
- case "bun":
359
- packageJSON.dependencies["@b9g/platform-bun"] = "^0.1.0";
360
- break;
361
- case "cloudflare":
362
- packageJSON.dependencies["@b9g/platform-cloudflare"] = "^0.1.0";
363
- break;
364
- default:
365
- packageJSON.dependencies["@b9g/platform"] = "^0.1.0";
366
- }
367
- packageJSON.dependencies["@b9g/cache"] = "^0.1.0";
368
- packageJSON.dependencies["@b9g/filesystem"] = "^0.1.0";
369
- }
370
- return packageJSON;
371
- }
372
- async function buildCommand(entrypoint, options, config) {
373
- const platform = Platform.resolvePlatform({ ...options, config });
374
- await buildForProduction({
375
- entrypoint,
376
- outDir: "dist",
377
- verbose: options.verbose || false,
378
- platform,
379
- workerCount: options.workers ? parseInt(options.workers, 10) : config.workers
380
- });
381
- process.exit(0);
382
- }
383
- export {
384
- buildCommand,
385
- buildForProduction
386
- };