@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/CHANGELOG.md +160 -0
- package/README.md +301 -42
- package/bin/cli.js +29 -9
- package/bin/create.js +22 -22
- package/package.json +21 -13
- package/{activate-5LWUTBLL.js → src/_chunks/activate-TP6RQP47.js} +14 -11
- package/src/_chunks/build-V3IPZGKC.js +434 -0
- package/src/_chunks/chunk-ADR5RW57.js +78 -0
- package/src/_chunks/chunk-GRAFMTEH.js +1150 -0
- package/src/_chunks/chunk-JJFM7PO2.js +468 -0
- package/src/_chunks/develop-A7EU2ZDY.js +404 -0
- package/{info-PRYEMZS4.js → src/_chunks/info-TDUY3FZN.js} +1 -1
- package/build-NDUV2F2Z.js +0 -386
- package/chunk-CSH7M4MK.js +0 -861
- package/chunk-ILQUUH2L.js +0 -164
- package/develop-5ORIPB7M.js +0 -264
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createConfigPlugin,
|
|
3
|
+
createEntryPlugin,
|
|
4
|
+
getGitSHA
|
|
5
|
+
} from "./chunk-ADR5RW57.js";
|
|
6
|
+
import {
|
|
7
|
+
applyJSXOptions,
|
|
8
|
+
assetsPlugin,
|
|
9
|
+
importMetaPlugin,
|
|
10
|
+
loadJSXConfig
|
|
11
|
+
} from "./chunk-JJFM7PO2.js";
|
|
12
|
+
import {
|
|
13
|
+
findProjectRoot,
|
|
14
|
+
findWorkspaceRoot,
|
|
15
|
+
getNodeModulesPath
|
|
16
|
+
} from "./chunk-GRAFMTEH.js";
|
|
17
|
+
|
|
18
|
+
// src/commands/build.ts
|
|
19
|
+
import * as ESBuild from "esbuild";
|
|
20
|
+
import { builtinModules, createRequire } from "node:module";
|
|
21
|
+
import { resolve, join, dirname } from "path";
|
|
22
|
+
import { getLogger } from "@logtape/logtape";
|
|
23
|
+
import * as Platform from "@b9g/platform";
|
|
24
|
+
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
25
|
+
var logger = getLogger(["shovel"]);
|
|
26
|
+
function validateDynamicImports(result, context, excludePatterns = []) {
|
|
27
|
+
const dynamicImportWarnings = (result.warnings || []).filter(
|
|
28
|
+
(w) => (w.text.includes("cannot be bundled") || w.text.includes("import() call") || w.text.includes("dynamic import")) && // Exclude intentional dynamic imports
|
|
29
|
+
!excludePatterns.some((pattern) => w.text.includes(pattern))
|
|
30
|
+
);
|
|
31
|
+
if (dynamicImportWarnings.length > 0) {
|
|
32
|
+
const locations = dynamicImportWarnings.map((w) => {
|
|
33
|
+
const loc = w.location;
|
|
34
|
+
const file = loc?.file || "unknown";
|
|
35
|
+
const line = loc?.line || "?";
|
|
36
|
+
return ` ${file}:${line} - ${w.text}`;
|
|
37
|
+
}).join("\n");
|
|
38
|
+
throw new Error(
|
|
39
|
+
`Build failed (${context}): Non-analyzable dynamic imports found:
|
|
40
|
+
${locations}
|
|
41
|
+
|
|
42
|
+
Dynamic imports must use literal strings, not variables.
|
|
43
|
+
For config-driven providers, ensure they are registered in shovel.json.`
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function validateExternals(result, allowedExternals, context) {
|
|
48
|
+
if (!result.metafile)
|
|
49
|
+
return;
|
|
50
|
+
const allowedSet = new Set(allowedExternals);
|
|
51
|
+
const hasNodeWildcard = allowedExternals.includes("node:*");
|
|
52
|
+
const unexpectedExternals = [];
|
|
53
|
+
for (const path of Object.keys(result.metafile.inputs)) {
|
|
54
|
+
if (!path.startsWith("<external>:"))
|
|
55
|
+
continue;
|
|
56
|
+
const moduleName = path.slice("<external>:".length);
|
|
57
|
+
const isAllowed = allowedSet.has(moduleName) || hasNodeWildcard && moduleName.startsWith("node:") || builtinModules.includes(moduleName);
|
|
58
|
+
if (!isAllowed && !unexpectedExternals.includes(moduleName)) {
|
|
59
|
+
unexpectedExternals.push(moduleName);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (unexpectedExternals.length > 0) {
|
|
63
|
+
const externals = unexpectedExternals.map((e) => ` - ${e}`).join("\n");
|
|
64
|
+
throw new Error(
|
|
65
|
+
`Build failed (${context}): Unexpected external imports found:
|
|
66
|
+
${externals}
|
|
67
|
+
|
|
68
|
+
These modules are not bundled and won't be available at runtime.
|
|
69
|
+
Either bundle them or add them to the platform's external list.`
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
var BUILD_DEFAULTS = {
|
|
74
|
+
format: "esm",
|
|
75
|
+
target: "es2022",
|
|
76
|
+
outputFile: "index.js",
|
|
77
|
+
sourcemap: false,
|
|
78
|
+
minify: false,
|
|
79
|
+
treeShaking: true
|
|
80
|
+
};
|
|
81
|
+
var BUILD_STRUCTURE = {
|
|
82
|
+
serverDir: "server",
|
|
83
|
+
publicDir: "public"
|
|
84
|
+
};
|
|
85
|
+
async function buildForProduction({
|
|
86
|
+
entrypoint,
|
|
87
|
+
outDir,
|
|
88
|
+
platform = "node",
|
|
89
|
+
workerCount = 1,
|
|
90
|
+
userBuildConfig
|
|
91
|
+
}) {
|
|
92
|
+
const buildContext = await initializeBuild({
|
|
93
|
+
entrypoint,
|
|
94
|
+
outDir,
|
|
95
|
+
platform,
|
|
96
|
+
workerCount
|
|
97
|
+
});
|
|
98
|
+
const buildConfig = await createBuildConfig({
|
|
99
|
+
entryPath: buildContext.entryPath,
|
|
100
|
+
outputDir: buildContext.outputDir,
|
|
101
|
+
serverDir: buildContext.serverDir,
|
|
102
|
+
projectRoot: buildContext.projectRoot,
|
|
103
|
+
platform: buildContext.platform,
|
|
104
|
+
shovelBuildConfig: userBuildConfig
|
|
105
|
+
});
|
|
106
|
+
const result = await ESBuild.build(buildConfig);
|
|
107
|
+
validateDynamicImports(result, "main bundle");
|
|
108
|
+
const external = buildConfig.external ?? ["node:*"];
|
|
109
|
+
validateExternals(result, external, "main bundle");
|
|
110
|
+
await generatePackageJSON({
|
|
111
|
+
...buildContext,
|
|
112
|
+
entryPath: buildContext.entryPath
|
|
113
|
+
});
|
|
114
|
+
logger.debug("Built app to", { outputDir: buildContext.outputDir });
|
|
115
|
+
logger.debug("Server files", { dir: buildContext.serverDir });
|
|
116
|
+
logger.debug("Public files", { dir: join(buildContext.outputDir, "public") });
|
|
117
|
+
}
|
|
118
|
+
async function initializeBuild({
|
|
119
|
+
entrypoint,
|
|
120
|
+
outDir,
|
|
121
|
+
platform,
|
|
122
|
+
workerCount = 1
|
|
123
|
+
}) {
|
|
124
|
+
if (!entrypoint) {
|
|
125
|
+
throw new Error("Entry point is required");
|
|
126
|
+
}
|
|
127
|
+
if (!outDir) {
|
|
128
|
+
throw new Error("Output directory is required");
|
|
129
|
+
}
|
|
130
|
+
logger.debug("Entry:", { path: entrypoint });
|
|
131
|
+
logger.debug("Output:", { dir: outDir });
|
|
132
|
+
logger.debug("Target platform:", { platform });
|
|
133
|
+
const entryPath = resolve(entrypoint);
|
|
134
|
+
const outputDir = resolve(outDir);
|
|
135
|
+
try {
|
|
136
|
+
const stats = await readFile(entryPath, "utf8");
|
|
137
|
+
if (stats.length === 0) {
|
|
138
|
+
logger.warn("Entry point is empty", { entryPath });
|
|
139
|
+
}
|
|
140
|
+
} catch (error) {
|
|
141
|
+
throw new Error(`Entry point not found or not accessible: ${entryPath}`);
|
|
142
|
+
}
|
|
143
|
+
const validPlatforms = ["node", "bun", "cloudflare"];
|
|
144
|
+
if (!validPlatforms.includes(platform)) {
|
|
145
|
+
throw new Error(
|
|
146
|
+
`Invalid platform: ${platform}. Valid platforms: ${validPlatforms.join(", ")}`
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
const projectRoot = findProjectRoot(dirname(entryPath));
|
|
150
|
+
logger.debug("Entry:", { entryPath });
|
|
151
|
+
logger.debug("Output:", { outputDir });
|
|
152
|
+
logger.debug("Target platform:", { platform });
|
|
153
|
+
logger.debug("Project root:", { projectRoot });
|
|
154
|
+
try {
|
|
155
|
+
await mkdir(outputDir, { recursive: true });
|
|
156
|
+
await mkdir(join(outputDir, BUILD_STRUCTURE.serverDir), { recursive: true });
|
|
157
|
+
await mkdir(join(outputDir, BUILD_STRUCTURE.publicDir), { recursive: true });
|
|
158
|
+
} catch (error) {
|
|
159
|
+
throw new Error(`Failed to create output directory structure: ${error}`);
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
entryPath,
|
|
163
|
+
outputDir,
|
|
164
|
+
serverDir: join(outputDir, BUILD_STRUCTURE.serverDir),
|
|
165
|
+
projectRoot,
|
|
166
|
+
platform,
|
|
167
|
+
workerCount
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
async function loadUserPlugins(plugins, projectRoot) {
|
|
171
|
+
const loadedPlugins = [];
|
|
172
|
+
for (const pluginConfig of plugins) {
|
|
173
|
+
const {
|
|
174
|
+
module: modulePath,
|
|
175
|
+
export: exportName = "default",
|
|
176
|
+
...options
|
|
177
|
+
} = pluginConfig;
|
|
178
|
+
try {
|
|
179
|
+
const projectRequire = createRequire(join(projectRoot, "package.json"));
|
|
180
|
+
const resolvedPath = modulePath.startsWith(".") ? resolve(projectRoot, modulePath) : projectRequire.resolve(modulePath);
|
|
181
|
+
const mod = await import(resolvedPath);
|
|
182
|
+
const pluginFactory = exportName === "default" ? mod.default : mod[exportName];
|
|
183
|
+
if (typeof pluginFactory !== "function") {
|
|
184
|
+
throw new Error(
|
|
185
|
+
`Plugin export "${exportName}" from "${modulePath}" is not a function`
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
const hasOptions = Object.keys(options).length > 0;
|
|
189
|
+
const plugin = hasOptions ? pluginFactory(options) : pluginFactory();
|
|
190
|
+
loadedPlugins.push(plugin);
|
|
191
|
+
logger.debug("Loaded ESBuild plugin", {
|
|
192
|
+
module: modulePath,
|
|
193
|
+
export: exportName
|
|
194
|
+
});
|
|
195
|
+
} catch (error) {
|
|
196
|
+
throw new Error(
|
|
197
|
+
`Failed to load ESBuild plugin "${modulePath}": ${error instanceof Error ? error.message : error}`
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return loadedPlugins;
|
|
202
|
+
}
|
|
203
|
+
async function createBuildConfig({
|
|
204
|
+
entryPath,
|
|
205
|
+
outputDir,
|
|
206
|
+
serverDir,
|
|
207
|
+
projectRoot,
|
|
208
|
+
platform: platformName,
|
|
209
|
+
shovelBuildConfig
|
|
210
|
+
}) {
|
|
211
|
+
const platform = await Platform.createPlatform(platformName);
|
|
212
|
+
const platformESBuildConfig = platform.getESBuildConfig();
|
|
213
|
+
const platformDefaults = platform.getDefaults();
|
|
214
|
+
const entryWrapper = platform.getEntryWrapper(entryPath);
|
|
215
|
+
const bundlesUserCodeInline = platformESBuildConfig.bundlesUserCodeInline ?? false;
|
|
216
|
+
const jsxOptions = await loadJSXConfig(projectRoot || dirname(entryPath));
|
|
217
|
+
const target = shovelBuildConfig?.target ?? BUILD_DEFAULTS.target;
|
|
218
|
+
const minify = shovelBuildConfig?.minify ?? BUILD_DEFAULTS.minify;
|
|
219
|
+
const sourcemap = shovelBuildConfig?.sourcemap ?? BUILD_DEFAULTS.sourcemap;
|
|
220
|
+
const treeShaking = shovelBuildConfig?.treeShaking ?? BUILD_DEFAULTS.treeShaking;
|
|
221
|
+
const userPlugins = shovelBuildConfig?.plugins?.length ? await loadUserPlugins(shovelBuildConfig.plugins, projectRoot) : [];
|
|
222
|
+
try {
|
|
223
|
+
const platformExternal = platformESBuildConfig.external ?? ["node:*"];
|
|
224
|
+
const userExternal = shovelBuildConfig?.external ?? [];
|
|
225
|
+
const external = [...platformExternal, ...userExternal];
|
|
226
|
+
if (!bundlesUserCodeInline) {
|
|
227
|
+
const workerEntryWrapper = platform.getEntryWrapper(
|
|
228
|
+
"./server.js",
|
|
229
|
+
// Relative import to sibling output file
|
|
230
|
+
{ type: "worker", outDir: outputDir }
|
|
231
|
+
);
|
|
232
|
+
const workerBuildConfig = {
|
|
233
|
+
entryPoints: {
|
|
234
|
+
worker: "shovel:entry",
|
|
235
|
+
server: entryPath,
|
|
236
|
+
config: "shovel:config"
|
|
237
|
+
},
|
|
238
|
+
bundle: true,
|
|
239
|
+
format: BUILD_DEFAULTS.format,
|
|
240
|
+
target,
|
|
241
|
+
platform: platformESBuildConfig.platform ?? "node",
|
|
242
|
+
outdir: serverDir,
|
|
243
|
+
entryNames: "[name]",
|
|
244
|
+
absWorkingDir: projectRoot,
|
|
245
|
+
mainFields: ["module", "main"],
|
|
246
|
+
conditions: platformESBuildConfig.conditions ?? ["import", "module"],
|
|
247
|
+
// Resolve packages from the user's project node_modules
|
|
248
|
+
nodePaths: [getNodeModulesPath()],
|
|
249
|
+
// User plugins run first, then Shovel's core plugins
|
|
250
|
+
plugins: [
|
|
251
|
+
...userPlugins,
|
|
252
|
+
createConfigPlugin(projectRoot, outputDir, { platformDefaults }),
|
|
253
|
+
createEntryPlugin(projectRoot, workerEntryWrapper),
|
|
254
|
+
importMetaPlugin(),
|
|
255
|
+
assetsPlugin({
|
|
256
|
+
outDir: outputDir,
|
|
257
|
+
clientBuild: {
|
|
258
|
+
jsx: jsxOptions.jsx,
|
|
259
|
+
jsxFactory: jsxOptions.jsxFactory,
|
|
260
|
+
jsxFragment: jsxOptions.jsxFragment,
|
|
261
|
+
jsxImportSource: jsxOptions.jsxImportSource
|
|
262
|
+
}
|
|
263
|
+
})
|
|
264
|
+
],
|
|
265
|
+
metafile: true,
|
|
266
|
+
sourcemap,
|
|
267
|
+
minify,
|
|
268
|
+
treeShaking,
|
|
269
|
+
define: {
|
|
270
|
+
...platformESBuildConfig.define ?? {},
|
|
271
|
+
// User-defined constants
|
|
272
|
+
...shovelBuildConfig?.define ?? {},
|
|
273
|
+
// Inject output directory for runtime.outdir() resolution
|
|
274
|
+
__SHOVEL_OUTDIR__: JSON.stringify(outputDir),
|
|
275
|
+
// Inject git commit SHA for [git] placeholder
|
|
276
|
+
__SHOVEL_GIT__: JSON.stringify(getGitSHA(projectRoot))
|
|
277
|
+
},
|
|
278
|
+
// Path aliases from user config
|
|
279
|
+
alias: shovelBuildConfig?.alias,
|
|
280
|
+
// Mark ./server.js as external so it's imported at runtime (sibling output file)
|
|
281
|
+
external: [...external, "./server.js"]
|
|
282
|
+
};
|
|
283
|
+
applyJSXOptions(workerBuildConfig, jsxOptions);
|
|
284
|
+
const workerBuildResult = await ESBuild.build(workerBuildConfig);
|
|
285
|
+
validateDynamicImports(workerBuildResult, "worker bundle", [
|
|
286
|
+
"./server.js"
|
|
287
|
+
]);
|
|
288
|
+
validateExternals(workerBuildResult, external, "worker bundle");
|
|
289
|
+
}
|
|
290
|
+
const buildConfig = {
|
|
291
|
+
stdin: {
|
|
292
|
+
contents: entryWrapper,
|
|
293
|
+
// Use serverDir so ./server.js resolves to the built user code
|
|
294
|
+
resolveDir: serverDir,
|
|
295
|
+
sourcefile: "virtual-entry.js"
|
|
296
|
+
},
|
|
297
|
+
bundle: true,
|
|
298
|
+
format: BUILD_DEFAULTS.format,
|
|
299
|
+
target,
|
|
300
|
+
platform: platformESBuildConfig.platform ?? "node",
|
|
301
|
+
// Inline bundling (Cloudflare): single-file (server.js contains everything)
|
|
302
|
+
// Separate bundling (Node/Bun): multi-file (index.js is entry, server.js is user code)
|
|
303
|
+
outfile: join(
|
|
304
|
+
serverDir,
|
|
305
|
+
bundlesUserCodeInline ? "server.js" : BUILD_DEFAULTS.outputFile
|
|
306
|
+
),
|
|
307
|
+
absWorkingDir: projectRoot,
|
|
308
|
+
mainFields: ["module", "main"],
|
|
309
|
+
conditions: platformESBuildConfig.conditions ?? ["import", "module"],
|
|
310
|
+
// Resolve packages from the user's project node_modules
|
|
311
|
+
nodePaths: [getNodeModulesPath()],
|
|
312
|
+
// User plugins run first, then Shovel's core plugins
|
|
313
|
+
plugins: bundlesUserCodeInline ? [
|
|
314
|
+
...userPlugins,
|
|
315
|
+
createConfigPlugin(projectRoot, outputDir, { platformDefaults }),
|
|
316
|
+
importMetaPlugin(),
|
|
317
|
+
assetsPlugin({
|
|
318
|
+
outDir: outputDir,
|
|
319
|
+
clientBuild: {
|
|
320
|
+
jsx: jsxOptions.jsx,
|
|
321
|
+
jsxFactory: jsxOptions.jsxFactory,
|
|
322
|
+
jsxFragment: jsxOptions.jsxFragment,
|
|
323
|
+
jsxImportSource: jsxOptions.jsxImportSource
|
|
324
|
+
}
|
|
325
|
+
})
|
|
326
|
+
] : [createConfigPlugin(projectRoot, outputDir, { platformDefaults })],
|
|
327
|
+
// Config plugin needed for entry wrapper
|
|
328
|
+
metafile: true,
|
|
329
|
+
sourcemap,
|
|
330
|
+
minify,
|
|
331
|
+
treeShaking,
|
|
332
|
+
define: {
|
|
333
|
+
...platformESBuildConfig.define ?? {},
|
|
334
|
+
// User-defined constants
|
|
335
|
+
...shovelBuildConfig?.define ?? {},
|
|
336
|
+
// Inject output directory for runtime.outdir() resolution
|
|
337
|
+
__SHOVEL_OUTDIR__: JSON.stringify(outputDir),
|
|
338
|
+
// Inject git commit SHA for [git] placeholder
|
|
339
|
+
__SHOVEL_GIT__: JSON.stringify(getGitSHA(projectRoot))
|
|
340
|
+
},
|
|
341
|
+
// Path aliases from user config
|
|
342
|
+
alias: shovelBuildConfig?.alias,
|
|
343
|
+
external
|
|
344
|
+
};
|
|
345
|
+
if (bundlesUserCodeInline) {
|
|
346
|
+
applyJSXOptions(buildConfig, jsxOptions);
|
|
347
|
+
}
|
|
348
|
+
return buildConfig;
|
|
349
|
+
} catch (error) {
|
|
350
|
+
throw new Error(`Failed to create build configuration: ${error}`);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
async function generatePackageJSON({
|
|
354
|
+
serverDir,
|
|
355
|
+
platform,
|
|
356
|
+
entryPath
|
|
357
|
+
}) {
|
|
358
|
+
const entryDir = dirname(entryPath);
|
|
359
|
+
const sourcePackageJsonPath = resolve(entryDir, "package.json");
|
|
360
|
+
try {
|
|
361
|
+
const packageJSONContent = await readFile(sourcePackageJsonPath, "utf8");
|
|
362
|
+
try {
|
|
363
|
+
JSON.parse(packageJSONContent);
|
|
364
|
+
} catch (parseError) {
|
|
365
|
+
throw new Error(`Invalid package.json format: ${parseError}`);
|
|
366
|
+
}
|
|
367
|
+
await writeFile(
|
|
368
|
+
join(serverDir, "package.json"),
|
|
369
|
+
packageJSONContent,
|
|
370
|
+
"utf8"
|
|
371
|
+
);
|
|
372
|
+
logger.debug("Copied package.json", { serverDir });
|
|
373
|
+
} catch (error) {
|
|
374
|
+
logger.debug("Could not copy package.json: {error}", { error });
|
|
375
|
+
try {
|
|
376
|
+
const generatedPackageJson = await generateExecutablePackageJSON(platform);
|
|
377
|
+
await writeFile(
|
|
378
|
+
join(serverDir, "package.json"),
|
|
379
|
+
JSON.stringify(generatedPackageJson, null, 2),
|
|
380
|
+
"utf8"
|
|
381
|
+
);
|
|
382
|
+
logger.debug("Generated package.json", { platform });
|
|
383
|
+
} catch (generateError) {
|
|
384
|
+
logger.debug("Could not generate package.json: {error}", {
|
|
385
|
+
error: generateError
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
async function generateExecutablePackageJSON(platform) {
|
|
391
|
+
const packageJSON = {
|
|
392
|
+
name: "shovel-executable",
|
|
393
|
+
version: "1.0.0",
|
|
394
|
+
type: "module",
|
|
395
|
+
private: true,
|
|
396
|
+
dependencies: {}
|
|
397
|
+
};
|
|
398
|
+
const isWorkspaceEnvironment = findWorkspaceRoot() !== null;
|
|
399
|
+
if (isWorkspaceEnvironment) {
|
|
400
|
+
packageJSON.dependencies = {};
|
|
401
|
+
} else {
|
|
402
|
+
switch (platform) {
|
|
403
|
+
case "node":
|
|
404
|
+
packageJSON.dependencies["@b9g/platform-node"] = "^0.1.0";
|
|
405
|
+
break;
|
|
406
|
+
case "bun":
|
|
407
|
+
packageJSON.dependencies["@b9g/platform-bun"] = "^0.1.0";
|
|
408
|
+
break;
|
|
409
|
+
case "cloudflare":
|
|
410
|
+
packageJSON.dependencies["@b9g/platform-cloudflare"] = "^0.1.0";
|
|
411
|
+
break;
|
|
412
|
+
default:
|
|
413
|
+
packageJSON.dependencies["@b9g/platform"] = "^0.1.0";
|
|
414
|
+
}
|
|
415
|
+
packageJSON.dependencies["@b9g/cache"] = "^0.1.0";
|
|
416
|
+
packageJSON.dependencies["@b9g/filesystem"] = "^0.1.0";
|
|
417
|
+
}
|
|
418
|
+
return packageJSON;
|
|
419
|
+
}
|
|
420
|
+
async function buildCommand(entrypoint, options, config) {
|
|
421
|
+
const platform = Platform.resolvePlatform({ ...options, config });
|
|
422
|
+
await buildForProduction({
|
|
423
|
+
entrypoint,
|
|
424
|
+
outDir: "dist",
|
|
425
|
+
platform,
|
|
426
|
+
workerCount: options.workers ? parseInt(options.workers, 10) : config.workers,
|
|
427
|
+
userBuildConfig: config.build
|
|
428
|
+
});
|
|
429
|
+
process.exit(0);
|
|
430
|
+
}
|
|
431
|
+
export {
|
|
432
|
+
buildCommand,
|
|
433
|
+
buildForProduction
|
|
434
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import {
|
|
2
|
+
generateConfigModule,
|
|
3
|
+
generateStorageTypes,
|
|
4
|
+
loadRawConfig
|
|
5
|
+
} from "./chunk-GRAFMTEH.js";
|
|
6
|
+
|
|
7
|
+
// src/plugins/shovel.ts
|
|
8
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
9
|
+
import { join, isAbsolute } from "node:path";
|
|
10
|
+
function createConfigPlugin(projectRoot, outDir = "dist", options = {}) {
|
|
11
|
+
const rawConfig = loadRawConfig(projectRoot);
|
|
12
|
+
const absoluteOutDir = isAbsolute(outDir) ? outDir : join(projectRoot, outDir);
|
|
13
|
+
const configModuleCode = generateConfigModule(rawConfig, {
|
|
14
|
+
projectDir: projectRoot,
|
|
15
|
+
outDir: absoluteOutDir,
|
|
16
|
+
platformDefaults: options.platformDefaults
|
|
17
|
+
});
|
|
18
|
+
const typesCode = generateStorageTypes(rawConfig, {
|
|
19
|
+
platformDefaults: options.platformDefaults
|
|
20
|
+
});
|
|
21
|
+
if (typesCode) {
|
|
22
|
+
const outputDir = isAbsolute(outDir) ? outDir : join(projectRoot, outDir);
|
|
23
|
+
const serverOutDir = join(outputDir, "server");
|
|
24
|
+
mkdirSync(serverOutDir, { recursive: true });
|
|
25
|
+
const typesPath = join(serverOutDir, "shovel.d.ts");
|
|
26
|
+
writeFileSync(typesPath, typesCode);
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
name: "shovel-config",
|
|
30
|
+
setup(build) {
|
|
31
|
+
build.onResolve({ filter: /^shovel:config$/ }, (args) => ({
|
|
32
|
+
path: args.path,
|
|
33
|
+
namespace: "shovel-config"
|
|
34
|
+
}));
|
|
35
|
+
build.onLoad({ filter: /.*/, namespace: "shovel-config" }, () => ({
|
|
36
|
+
contents: configModuleCode,
|
|
37
|
+
loader: "js",
|
|
38
|
+
resolveDir: projectRoot
|
|
39
|
+
}));
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function createEntryPlugin(projectRoot, entryCode) {
|
|
44
|
+
return {
|
|
45
|
+
name: "shovel-entry",
|
|
46
|
+
setup(build) {
|
|
47
|
+
build.onResolve({ filter: /^shovel:entry$/ }, (args) => ({
|
|
48
|
+
path: args.path,
|
|
49
|
+
namespace: "shovel-entry"
|
|
50
|
+
}));
|
|
51
|
+
build.onLoad({ filter: /.*/, namespace: "shovel-entry" }, () => ({
|
|
52
|
+
contents: entryCode,
|
|
53
|
+
loader: "js",
|
|
54
|
+
resolveDir: projectRoot
|
|
55
|
+
}));
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// src/utils/git-sha.ts
|
|
61
|
+
import { execSync } from "child_process";
|
|
62
|
+
function getGitSHA(cwd) {
|
|
63
|
+
try {
|
|
64
|
+
return execSync("git rev-parse HEAD", {
|
|
65
|
+
encoding: "utf8",
|
|
66
|
+
cwd,
|
|
67
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
68
|
+
}).trim();
|
|
69
|
+
} catch (_err) {
|
|
70
|
+
return "";
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export {
|
|
75
|
+
createConfigPlugin,
|
|
76
|
+
createEntryPlugin,
|
|
77
|
+
getGitSHA
|
|
78
|
+
};
|