@b9g/shovel 0.2.0-beta.7 → 0.2.0-beta.8
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/README.md +1 -1
- package/bin/cli.js +205 -65
- package/package.json +19 -19
package/README.md
CHANGED
|
@@ -29,7 +29,7 @@ Shovel implements web platform APIs that server-side JavaScript is missing:
|
|
|
29
29
|
|-----|----------|--------------|
|
|
30
30
|
| `fetch` event | [Service Workers](https://w3c.github.io/ServiceWorker/) | Request handling |
|
|
31
31
|
| `self.caches` | [Cache API](https://w3c.github.io/ServiceWorker/#cache-interface) | Response caching |
|
|
32
|
-
| `self.buckets` | [
|
|
32
|
+
| `self.buckets` | [FileSystem API](https://fs.spec.whatwg.org/) | Storage (local, S3, R2) |
|
|
33
33
|
| `self.cookieStore` | [Cookie Store API](https://wicg.github.io/cookie-store/) | Cookie management |
|
|
34
34
|
| `URLPattern` | [URLPattern](https://urlpattern.spec.whatwg.org/) | Route matching (100% WPT) |
|
|
35
35
|
| `AsyncContext.Variable` | [TC39 Stage 2](https://github.com/tc39/proposal-async-context) | Request-scoped state |
|
package/bin/cli.js
CHANGED
|
@@ -20,11 +20,12 @@ var DEFAULTS = {
|
|
|
20
20
|
import { configure, getConsoleSink, getLogger as getLogger2 } from "@logtape/logtape";
|
|
21
21
|
import { AsyncContext } from "@b9g/async-context";
|
|
22
22
|
import * as Platform from "@b9g/platform";
|
|
23
|
+
import { loadConfig } from "@b9g/platform/config";
|
|
23
24
|
|
|
24
25
|
// src/esbuild/watcher.ts
|
|
25
26
|
import * as ESBuild from "esbuild";
|
|
26
|
-
import { existsSync } from "fs";
|
|
27
|
-
import { resolve, join, dirname as
|
|
27
|
+
import { existsSync as existsSync2 } from "fs";
|
|
28
|
+
import { resolve, join as join2, dirname as dirname3 } from "path";
|
|
28
29
|
import { mkdir } from "fs/promises";
|
|
29
30
|
import { assetsPlugin } from "@b9g/assets/plugin";
|
|
30
31
|
|
|
@@ -77,16 +78,129 @@ function importMetaPlugin() {
|
|
|
77
78
|
};
|
|
78
79
|
}
|
|
79
80
|
|
|
81
|
+
// src/esbuild/jsx-config.ts
|
|
82
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
83
|
+
import { join, dirname as dirname2 } from "path";
|
|
84
|
+
import { existsSync } from "fs";
|
|
85
|
+
var CRANK_JSX_DEFAULTS = {
|
|
86
|
+
jsx: "automatic",
|
|
87
|
+
jsxImportSource: "@b9g/crank"
|
|
88
|
+
};
|
|
89
|
+
async function findTsConfig(startDir) {
|
|
90
|
+
let dir = startDir;
|
|
91
|
+
while (dir !== dirname2(dir)) {
|
|
92
|
+
const tsconfigPath = join(dir, "tsconfig.json");
|
|
93
|
+
if (existsSync(tsconfigPath)) {
|
|
94
|
+
return tsconfigPath;
|
|
95
|
+
}
|
|
96
|
+
dir = dirname2(dir);
|
|
97
|
+
}
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
async function parseTsConfig(tsconfigPath) {
|
|
101
|
+
const content = await readFile2(tsconfigPath, "utf8");
|
|
102
|
+
const stripped = content.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
103
|
+
const config = JSON.parse(stripped);
|
|
104
|
+
if (config.extends) {
|
|
105
|
+
const baseDir = dirname2(tsconfigPath);
|
|
106
|
+
let extendsPath = config.extends;
|
|
107
|
+
if (extendsPath.startsWith(".")) {
|
|
108
|
+
extendsPath = join(baseDir, extendsPath);
|
|
109
|
+
} else {
|
|
110
|
+
extendsPath = join(baseDir, "node_modules", extendsPath);
|
|
111
|
+
}
|
|
112
|
+
if (!extendsPath.endsWith(".json")) {
|
|
113
|
+
extendsPath += ".json";
|
|
114
|
+
}
|
|
115
|
+
if (existsSync(extendsPath)) {
|
|
116
|
+
const baseConfig = await parseTsConfig(extendsPath);
|
|
117
|
+
return {
|
|
118
|
+
...baseConfig,
|
|
119
|
+
...config,
|
|
120
|
+
compilerOptions: {
|
|
121
|
+
...baseConfig.compilerOptions,
|
|
122
|
+
...config.compilerOptions
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return config;
|
|
128
|
+
}
|
|
129
|
+
function mapTsConfigToEsbuild(compilerOptions) {
|
|
130
|
+
const options = {};
|
|
131
|
+
if (compilerOptions.jsx) {
|
|
132
|
+
switch (compilerOptions.jsx) {
|
|
133
|
+
case "react":
|
|
134
|
+
case "react-native":
|
|
135
|
+
options.jsx = "transform";
|
|
136
|
+
break;
|
|
137
|
+
case "react-jsx":
|
|
138
|
+
case "react-jsxdev":
|
|
139
|
+
options.jsx = "automatic";
|
|
140
|
+
break;
|
|
141
|
+
case "preserve":
|
|
142
|
+
options.jsx = "preserve";
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (compilerOptions.jsxFactory) {
|
|
147
|
+
options.jsxFactory = compilerOptions.jsxFactory;
|
|
148
|
+
}
|
|
149
|
+
if (compilerOptions.jsxFragmentFactory) {
|
|
150
|
+
options.jsxFragment = compilerOptions.jsxFragmentFactory;
|
|
151
|
+
}
|
|
152
|
+
if (compilerOptions.jsxImportSource) {
|
|
153
|
+
options.jsxImportSource = compilerOptions.jsxImportSource;
|
|
154
|
+
}
|
|
155
|
+
return options;
|
|
156
|
+
}
|
|
157
|
+
async function loadJSXConfig(projectRoot) {
|
|
158
|
+
const tsconfigPath = await findTsConfig(projectRoot);
|
|
159
|
+
if (tsconfigPath) {
|
|
160
|
+
try {
|
|
161
|
+
const config = await parseTsConfig(tsconfigPath);
|
|
162
|
+
const compilerOptions = config.compilerOptions || {};
|
|
163
|
+
const hasJsxConfig = compilerOptions.jsx || compilerOptions.jsxFactory || compilerOptions.jsxFragmentFactory || compilerOptions.jsxImportSource;
|
|
164
|
+
if (hasJsxConfig) {
|
|
165
|
+
const tsOptions = mapTsConfigToEsbuild(compilerOptions);
|
|
166
|
+
return {
|
|
167
|
+
...CRANK_JSX_DEFAULTS,
|
|
168
|
+
...tsOptions
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
} catch {
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return { ...CRANK_JSX_DEFAULTS };
|
|
175
|
+
}
|
|
176
|
+
function applyJSXOptions(buildOptions, jsxOptions) {
|
|
177
|
+
if (jsxOptions.jsx) {
|
|
178
|
+
buildOptions.jsx = jsxOptions.jsx;
|
|
179
|
+
}
|
|
180
|
+
if (jsxOptions.jsxFactory) {
|
|
181
|
+
buildOptions.jsxFactory = jsxOptions.jsxFactory;
|
|
182
|
+
}
|
|
183
|
+
if (jsxOptions.jsxFragment) {
|
|
184
|
+
buildOptions.jsxFragment = jsxOptions.jsxFragment;
|
|
185
|
+
}
|
|
186
|
+
if (jsxOptions.jsxImportSource) {
|
|
187
|
+
buildOptions.jsxImportSource = jsxOptions.jsxImportSource;
|
|
188
|
+
}
|
|
189
|
+
if (jsxOptions.jsxSideEffects !== void 0) {
|
|
190
|
+
buildOptions.jsxSideEffects = jsxOptions.jsxSideEffects;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
80
194
|
// src/esbuild/watcher.ts
|
|
81
195
|
import { getLogger } from "@logtape/logtape";
|
|
82
196
|
var logger = getLogger(["watcher"]);
|
|
83
197
|
function findProjectRoot() {
|
|
84
198
|
let dir = process.cwd();
|
|
85
|
-
while (dir !==
|
|
86
|
-
if (
|
|
199
|
+
while (dir !== dirname3(dir)) {
|
|
200
|
+
if (existsSync2(join2(dir, "package.json"))) {
|
|
87
201
|
return dir;
|
|
88
202
|
}
|
|
89
|
-
dir =
|
|
203
|
+
dir = dirname3(dir);
|
|
90
204
|
}
|
|
91
205
|
return process.cwd();
|
|
92
206
|
}
|
|
@@ -110,12 +224,13 @@ var Watcher = class {
|
|
|
110
224
|
async start() {
|
|
111
225
|
const entryPath = resolve(this.#projectRoot, this.#options.entrypoint);
|
|
112
226
|
const outputDir = resolve(this.#projectRoot, this.#options.outDir);
|
|
113
|
-
await mkdir(
|
|
114
|
-
await mkdir(
|
|
227
|
+
await mkdir(join2(outputDir, "server"), { recursive: true });
|
|
228
|
+
await mkdir(join2(outputDir, "static"), { recursive: true });
|
|
229
|
+
const jsxOptions = await loadJSXConfig(this.#projectRoot);
|
|
115
230
|
const initialBuildPromise = new Promise((resolve3) => {
|
|
116
231
|
this.#initialBuildResolve = resolve3;
|
|
117
232
|
});
|
|
118
|
-
|
|
233
|
+
const buildOptions = {
|
|
119
234
|
entryPoints: [entryPath],
|
|
120
235
|
bundle: true,
|
|
121
236
|
format: "esm",
|
|
@@ -128,7 +243,13 @@ var Watcher = class {
|
|
|
128
243
|
plugins: [
|
|
129
244
|
importMetaPlugin(),
|
|
130
245
|
assetsPlugin({
|
|
131
|
-
outDir: outputDir
|
|
246
|
+
outDir: outputDir,
|
|
247
|
+
clientBuild: {
|
|
248
|
+
jsx: jsxOptions.jsx,
|
|
249
|
+
jsxFactory: jsxOptions.jsxFactory,
|
|
250
|
+
jsxFragment: jsxOptions.jsxFragment,
|
|
251
|
+
jsxImportSource: jsxOptions.jsxImportSource
|
|
252
|
+
}
|
|
132
253
|
}),
|
|
133
254
|
// Plugin to detect build completion (works with watch mode)
|
|
134
255
|
{
|
|
@@ -152,7 +273,7 @@ var Watcher = class {
|
|
|
152
273
|
if (success) {
|
|
153
274
|
logger.info("Build complete", { entrypoint: outputPath });
|
|
154
275
|
} else {
|
|
155
|
-
logger.error("Build errors", { errors: result.errors });
|
|
276
|
+
logger.error("Build errors: {errors}", { errors: result.errors });
|
|
156
277
|
}
|
|
157
278
|
this.#currentEntrypoint = outputPath;
|
|
158
279
|
if (!this.#initialBuildComplete) {
|
|
@@ -168,7 +289,9 @@ var Watcher = class {
|
|
|
168
289
|
sourcemap: "inline",
|
|
169
290
|
minify: false,
|
|
170
291
|
treeShaking: true
|
|
171
|
-
}
|
|
292
|
+
};
|
|
293
|
+
applyJSXOptions(buildOptions, jsxOptions);
|
|
294
|
+
this.#ctx = await ESBuild.context(buildOptions);
|
|
172
295
|
logger.info("Starting esbuild watch mode");
|
|
173
296
|
await this.#ctx.watch();
|
|
174
297
|
return initialBuildPromise;
|
|
@@ -206,8 +329,9 @@ await configure({
|
|
|
206
329
|
var logger2 = getLogger2(["cli"]);
|
|
207
330
|
async function developCommand(entrypoint, options) {
|
|
208
331
|
try {
|
|
209
|
-
const
|
|
210
|
-
const
|
|
332
|
+
const config = loadConfig(process.cwd());
|
|
333
|
+
const platformName = Platform.resolvePlatform({ ...options, config });
|
|
334
|
+
const workerCount = getWorkerCount(options, config);
|
|
211
335
|
if (options.verbose) {
|
|
212
336
|
Platform.displayPlatformInfo(platformName);
|
|
213
337
|
logger2.info("Worker configuration", { workerCount });
|
|
@@ -273,13 +397,16 @@ async function developCommand(entrypoint, options) {
|
|
|
273
397
|
process.exit(1);
|
|
274
398
|
}
|
|
275
399
|
}
|
|
276
|
-
function getWorkerCount(options) {
|
|
400
|
+
function getWorkerCount(options, config) {
|
|
277
401
|
if (options.workers) {
|
|
278
402
|
return parseInt(options.workers);
|
|
279
403
|
}
|
|
280
404
|
if (process.env.WORKER_COUNT) {
|
|
281
405
|
return parseInt(process.env.WORKER_COUNT);
|
|
282
406
|
}
|
|
407
|
+
if (config?.workers) {
|
|
408
|
+
return config.workers;
|
|
409
|
+
}
|
|
283
410
|
return DEFAULTS.WORKERS;
|
|
284
411
|
}
|
|
285
412
|
|
|
@@ -314,10 +441,7 @@ async function activateCommand(entrypoint, options) {
|
|
|
314
441
|
await serviceWorker.dispose();
|
|
315
442
|
await platformInstance.dispose();
|
|
316
443
|
} catch (error) {
|
|
317
|
-
logger3.error("ServiceWorker activation failed", { error
|
|
318
|
-
if (options.verbose) {
|
|
319
|
-
logger3.error("Stack trace", { stack: error.stack });
|
|
320
|
-
}
|
|
444
|
+
logger3.error("ServiceWorker activation failed: {error}", { error });
|
|
321
445
|
process.exit(1);
|
|
322
446
|
}
|
|
323
447
|
}
|
|
@@ -344,12 +468,14 @@ async function infoCommand() {
|
|
|
344
468
|
|
|
345
469
|
// src/commands/build.ts
|
|
346
470
|
import * as ESBuild2 from "esbuild";
|
|
347
|
-
import { resolve as resolve2, join as
|
|
348
|
-
import { mkdir as mkdir2, readFile as
|
|
471
|
+
import { resolve as resolve2, join as join3, dirname as dirname4 } from "path";
|
|
472
|
+
import { mkdir as mkdir2, readFile as readFile3, writeFile } from "fs/promises";
|
|
349
473
|
import { fileURLToPath } from "url";
|
|
350
474
|
import { assetsPlugin as assetsPlugin2 } from "@b9g/assets/plugin";
|
|
351
475
|
import { configure as configure2, getConsoleSink as getConsoleSink2, getLogger as getLogger5 } from "@logtape/logtape";
|
|
352
476
|
import { AsyncContext as AsyncContext2 } from "@b9g/async-context";
|
|
477
|
+
import * as Platform3 from "@b9g/platform";
|
|
478
|
+
import { loadConfig as loadConfig2 } from "@b9g/platform/config";
|
|
353
479
|
await configure2({
|
|
354
480
|
reset: true,
|
|
355
481
|
contextLocalStorage: new AsyncContext2.Variable(),
|
|
@@ -401,7 +527,7 @@ async function buildForProduction({
|
|
|
401
527
|
if (verbose) {
|
|
402
528
|
logger5.info("Built app to", { outputDir: buildContext.outputDir });
|
|
403
529
|
logger5.info("Server files", { dir: buildContext.serverDir });
|
|
404
|
-
logger5.info("Static files", { dir:
|
|
530
|
+
logger5.info("Static files", { dir: join3(buildContext.outputDir, "static") });
|
|
405
531
|
}
|
|
406
532
|
}
|
|
407
533
|
async function initializeBuild({
|
|
@@ -425,7 +551,7 @@ async function initializeBuild({
|
|
|
425
551
|
const entryPath = resolve2(entrypoint);
|
|
426
552
|
const outputDir = resolve2(outDir);
|
|
427
553
|
try {
|
|
428
|
-
const stats = await
|
|
554
|
+
const stats = await readFile3(entryPath, "utf8");
|
|
429
555
|
if (stats.length === 0) {
|
|
430
556
|
logger5.warn("Entry point is empty", { entryPath });
|
|
431
557
|
}
|
|
@@ -447,8 +573,8 @@ async function initializeBuild({
|
|
|
447
573
|
}
|
|
448
574
|
try {
|
|
449
575
|
await mkdir2(outputDir, { recursive: true });
|
|
450
|
-
await mkdir2(
|
|
451
|
-
await mkdir2(
|
|
576
|
+
await mkdir2(join3(outputDir, BUILD_STRUCTURE.serverDir), { recursive: true });
|
|
577
|
+
await mkdir2(join3(outputDir, BUILD_STRUCTURE.staticDir), { recursive: true });
|
|
452
578
|
} catch (error) {
|
|
453
579
|
throw new Error(
|
|
454
580
|
`Failed to create output directory structure: ${error.message}`
|
|
@@ -457,7 +583,7 @@ async function initializeBuild({
|
|
|
457
583
|
return {
|
|
458
584
|
entryPath,
|
|
459
585
|
outputDir,
|
|
460
|
-
serverDir:
|
|
586
|
+
serverDir: join3(outputDir, BUILD_STRUCTURE.serverDir),
|
|
461
587
|
workspaceRoot,
|
|
462
588
|
platform,
|
|
463
589
|
verbose,
|
|
@@ -466,37 +592,37 @@ async function initializeBuild({
|
|
|
466
592
|
}
|
|
467
593
|
async function findWorkspaceRoot() {
|
|
468
594
|
let workspaceRoot = process.cwd();
|
|
469
|
-
while (workspaceRoot !==
|
|
595
|
+
while (workspaceRoot !== dirname4(workspaceRoot)) {
|
|
470
596
|
try {
|
|
471
597
|
const packageJSON = JSON.parse(
|
|
472
|
-
await
|
|
598
|
+
await readFile3(resolve2(workspaceRoot, "package.json"), "utf8")
|
|
473
599
|
);
|
|
474
600
|
if (packageJSON.workspaces) {
|
|
475
601
|
return workspaceRoot;
|
|
476
602
|
}
|
|
477
603
|
} catch {
|
|
478
604
|
}
|
|
479
|
-
workspaceRoot =
|
|
605
|
+
workspaceRoot = dirname4(workspaceRoot);
|
|
480
606
|
}
|
|
481
607
|
return workspaceRoot;
|
|
482
608
|
}
|
|
483
609
|
async function findShovelPackageRoot() {
|
|
484
|
-
let currentDir =
|
|
610
|
+
let currentDir = dirname4(fileURLToPath(import.meta.url));
|
|
485
611
|
let packageRoot = currentDir;
|
|
486
|
-
while (packageRoot !==
|
|
612
|
+
while (packageRoot !== dirname4(packageRoot)) {
|
|
487
613
|
try {
|
|
488
|
-
const packageJSONPath =
|
|
489
|
-
const content = await
|
|
614
|
+
const packageJSONPath = join3(packageRoot, "package.json");
|
|
615
|
+
const content = await readFile3(packageJSONPath, "utf8");
|
|
490
616
|
const pkg2 = JSON.parse(content);
|
|
491
617
|
if (pkg2.name === "@b9g/shovel" || pkg2.name === "shovel") {
|
|
492
618
|
if (packageRoot.endsWith("/dist") || packageRoot.endsWith("\\dist")) {
|
|
493
|
-
return
|
|
619
|
+
return dirname4(packageRoot);
|
|
494
620
|
}
|
|
495
621
|
return packageRoot;
|
|
496
622
|
}
|
|
497
623
|
} catch {
|
|
498
624
|
}
|
|
499
|
-
packageRoot =
|
|
625
|
+
packageRoot = dirname4(packageRoot);
|
|
500
626
|
}
|
|
501
627
|
return currentDir;
|
|
502
628
|
}
|
|
@@ -509,6 +635,7 @@ async function createBuildConfig({
|
|
|
509
635
|
workerCount
|
|
510
636
|
}) {
|
|
511
637
|
const isCloudflare = platform === "cloudflare" || platform === "cloudflare-workers";
|
|
638
|
+
const jsxOptions = await loadJSXConfig(workspaceRoot || dirname4(entryPath));
|
|
512
639
|
try {
|
|
513
640
|
const virtualEntry = await createVirtualEntry(
|
|
514
641
|
entryPath,
|
|
@@ -524,19 +651,25 @@ async function createBuildConfig({
|
|
|
524
651
|
format: BUILD_DEFAULTS.format,
|
|
525
652
|
target: BUILD_DEFAULTS.target,
|
|
526
653
|
platform: "node",
|
|
527
|
-
outfile:
|
|
528
|
-
absWorkingDir: workspaceRoot ||
|
|
654
|
+
outfile: join3(serverDir, "server.js"),
|
|
655
|
+
absWorkingDir: workspaceRoot || dirname4(entryPath),
|
|
529
656
|
mainFields: ["module", "main"],
|
|
530
657
|
conditions: ["import", "module"],
|
|
531
658
|
// Allow user code to import @b9g packages from shovel's packages directory
|
|
532
659
|
nodePaths: [
|
|
533
|
-
|
|
534
|
-
|
|
660
|
+
join3(shovelRoot, "packages"),
|
|
661
|
+
join3(shovelRoot, "node_modules")
|
|
535
662
|
],
|
|
536
663
|
plugins: [
|
|
537
664
|
importMetaPlugin(),
|
|
538
665
|
assetsPlugin2({
|
|
539
|
-
outDir: outputDir
|
|
666
|
+
outDir: outputDir,
|
|
667
|
+
clientBuild: {
|
|
668
|
+
jsx: jsxOptions.jsx,
|
|
669
|
+
jsxFactory: jsxOptions.jsxFactory,
|
|
670
|
+
jsxFragment: jsxOptions.jsxFragment,
|
|
671
|
+
jsxImportSource: jsxOptions.jsxImportSource
|
|
672
|
+
}
|
|
540
673
|
})
|
|
541
674
|
],
|
|
542
675
|
metafile: true,
|
|
@@ -548,12 +681,13 @@ async function createBuildConfig({
|
|
|
548
681
|
define: platform === "node" ? { "import.meta.env": "process.env" } : {},
|
|
549
682
|
external
|
|
550
683
|
};
|
|
684
|
+
applyJSXOptions(userBuildConfig, jsxOptions);
|
|
551
685
|
await ESBuild2.build(userBuildConfig);
|
|
552
|
-
const runtimeSourcePath =
|
|
686
|
+
const runtimeSourcePath = join3(
|
|
553
687
|
shovelRoot,
|
|
554
688
|
"packages/platform/dist/src/runtime.js"
|
|
555
689
|
);
|
|
556
|
-
const workerDestPath =
|
|
690
|
+
const workerDestPath = join3(serverDir, "worker.js");
|
|
557
691
|
try {
|
|
558
692
|
await ESBuild2.build({
|
|
559
693
|
entryPoints: [runtimeSourcePath],
|
|
@@ -565,7 +699,7 @@ async function createBuildConfig({
|
|
|
565
699
|
external: ["node:*"]
|
|
566
700
|
});
|
|
567
701
|
} catch (error) {
|
|
568
|
-
const installedRuntimePath =
|
|
702
|
+
const installedRuntimePath = join3(
|
|
569
703
|
shovelRoot,
|
|
570
704
|
"node_modules/@b9g/platform/dist/src/runtime.js"
|
|
571
705
|
);
|
|
@@ -593,17 +727,23 @@ async function createBuildConfig({
|
|
|
593
727
|
platform: isCloudflare ? "browser" : "node",
|
|
594
728
|
// Cloudflare: single-file architecture (server.js contains everything)
|
|
595
729
|
// Node/Bun: multi-file architecture (index.js is entry, server.js is user code)
|
|
596
|
-
outfile:
|
|
730
|
+
outfile: join3(
|
|
597
731
|
serverDir,
|
|
598
732
|
isCloudflare ? "server.js" : BUILD_DEFAULTS.outputFile
|
|
599
733
|
),
|
|
600
|
-
absWorkingDir: workspaceRoot ||
|
|
734
|
+
absWorkingDir: workspaceRoot || dirname4(entryPath),
|
|
601
735
|
mainFields: ["module", "main"],
|
|
602
736
|
conditions: ["import", "module"],
|
|
603
737
|
plugins: isCloudflare ? [
|
|
604
738
|
importMetaPlugin(),
|
|
605
739
|
assetsPlugin2({
|
|
606
|
-
outDir: outputDir
|
|
740
|
+
outDir: outputDir,
|
|
741
|
+
clientBuild: {
|
|
742
|
+
jsx: jsxOptions.jsx,
|
|
743
|
+
jsxFactory: jsxOptions.jsxFactory,
|
|
744
|
+
jsxFragment: jsxOptions.jsxFragment,
|
|
745
|
+
jsxImportSource: jsxOptions.jsxImportSource
|
|
746
|
+
}
|
|
607
747
|
})
|
|
608
748
|
] : [],
|
|
609
749
|
// Assets already handled in user code build
|
|
@@ -617,6 +757,7 @@ async function createBuildConfig({
|
|
|
617
757
|
external
|
|
618
758
|
};
|
|
619
759
|
if (isCloudflare) {
|
|
760
|
+
applyJSXOptions(buildConfig, jsxOptions);
|
|
620
761
|
await configureCloudflareTarget(buildConfig);
|
|
621
762
|
}
|
|
622
763
|
return buildConfig;
|
|
@@ -642,22 +783,22 @@ import "${userEntryPath}";
|
|
|
642
783
|
return await createWorkerEntry(userEntryPath, workerCount, platform);
|
|
643
784
|
}
|
|
644
785
|
async function createWorkerEntry(userEntryPath, workerCount, platform) {
|
|
645
|
-
let currentDir =
|
|
786
|
+
let currentDir = dirname4(fileURLToPath(import.meta.url));
|
|
646
787
|
let packageRoot = currentDir;
|
|
647
|
-
while (packageRoot !==
|
|
788
|
+
while (packageRoot !== dirname4(packageRoot)) {
|
|
648
789
|
try {
|
|
649
|
-
const packageJSONPath =
|
|
650
|
-
await
|
|
790
|
+
const packageJSONPath = join3(packageRoot, "package.json");
|
|
791
|
+
await readFile3(packageJSONPath, "utf8");
|
|
651
792
|
break;
|
|
652
793
|
} catch {
|
|
653
|
-
packageRoot =
|
|
794
|
+
packageRoot = dirname4(packageRoot);
|
|
654
795
|
}
|
|
655
796
|
}
|
|
656
|
-
let templatePath =
|
|
797
|
+
let templatePath = join3(packageRoot, "src/worker-entry.ts");
|
|
657
798
|
try {
|
|
658
|
-
await
|
|
799
|
+
await readFile3(templatePath, "utf8");
|
|
659
800
|
} catch {
|
|
660
|
-
templatePath =
|
|
801
|
+
templatePath = join3(packageRoot, "src/worker-entry.js");
|
|
661
802
|
}
|
|
662
803
|
const transpileResult = await ESBuild2.build({
|
|
663
804
|
entryPoints: [templatePath],
|
|
@@ -680,21 +821,21 @@ async function logBundleAnalysis(metafile) {
|
|
|
680
821
|
const analysis = await ESBuild2.analyzeMetafile(metafile);
|
|
681
822
|
logger5.info(analysis, {});
|
|
682
823
|
} catch (error) {
|
|
683
|
-
logger5.warn("Failed to analyze bundle", { error
|
|
824
|
+
logger5.warn("Failed to analyze bundle: {error}", { error });
|
|
684
825
|
}
|
|
685
826
|
}
|
|
686
827
|
async function generatePackageJSON({ serverDir, platform, verbose, entryPath }) {
|
|
687
|
-
const entryDir =
|
|
828
|
+
const entryDir = dirname4(entryPath);
|
|
688
829
|
const sourcePackageJsonPath = resolve2(entryDir, "package.json");
|
|
689
830
|
try {
|
|
690
|
-
const packageJSONContent = await
|
|
831
|
+
const packageJSONContent = await readFile3(sourcePackageJsonPath, "utf8");
|
|
691
832
|
try {
|
|
692
833
|
JSON.parse(packageJSONContent);
|
|
693
834
|
} catch (parseError) {
|
|
694
835
|
throw new Error(`Invalid package.json format: ${parseError.message}`);
|
|
695
836
|
}
|
|
696
837
|
await writeFile(
|
|
697
|
-
|
|
838
|
+
join3(serverDir, "package.json"),
|
|
698
839
|
packageJSONContent,
|
|
699
840
|
"utf8"
|
|
700
841
|
);
|
|
@@ -703,12 +844,12 @@ async function generatePackageJSON({ serverDir, platform, verbose, entryPath })
|
|
|
703
844
|
}
|
|
704
845
|
} catch (error) {
|
|
705
846
|
if (verbose) {
|
|
706
|
-
logger5.warn("Could not copy package.json", { error
|
|
847
|
+
logger5.warn("Could not copy package.json: {error}", { error });
|
|
707
848
|
}
|
|
708
849
|
try {
|
|
709
850
|
const generatedPackageJson = await generateExecutablePackageJSON(platform);
|
|
710
851
|
await writeFile(
|
|
711
|
-
|
|
852
|
+
join3(serverDir, "package.json"),
|
|
712
853
|
JSON.stringify(generatedPackageJson, null, 2),
|
|
713
854
|
"utf8"
|
|
714
855
|
);
|
|
@@ -720,10 +861,7 @@ async function generatePackageJSON({ serverDir, platform, verbose, entryPath })
|
|
|
720
861
|
}
|
|
721
862
|
} catch (generateError) {
|
|
722
863
|
if (verbose) {
|
|
723
|
-
logger5.warn("Could not generate package.json", {
|
|
724
|
-
error: generateError.message
|
|
725
|
-
});
|
|
726
|
-
logger5.warn("Generation error details", { error: generateError });
|
|
864
|
+
logger5.warn("Could not generate package.json: {error}", { error: generateError });
|
|
727
865
|
}
|
|
728
866
|
}
|
|
729
867
|
}
|
|
@@ -760,12 +898,14 @@ async function generateExecutablePackageJSON(platform) {
|
|
|
760
898
|
return packageJSON;
|
|
761
899
|
}
|
|
762
900
|
async function buildCommand(entrypoint, options) {
|
|
901
|
+
const config = loadConfig2(process.cwd());
|
|
902
|
+
const platform = Platform3.resolvePlatform({ ...options, config });
|
|
763
903
|
await buildForProduction({
|
|
764
904
|
entrypoint,
|
|
765
905
|
outDir: "dist",
|
|
766
906
|
verbose: options.verbose || false,
|
|
767
|
-
platform
|
|
768
|
-
workerCount: options.workers ? parseInt(options.workers, 10) :
|
|
907
|
+
platform,
|
|
908
|
+
workerCount: options.workers ? parseInt(options.workers, 10) : config.workers
|
|
769
909
|
});
|
|
770
910
|
process.exit(0);
|
|
771
911
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@b9g/shovel",
|
|
3
|
-
"version": "0.2.0-beta.
|
|
3
|
+
"version": "0.2.0-beta.8",
|
|
4
4
|
"description": "ServiceWorker-first universal deployment platform. Write ServiceWorker apps once, deploy anywhere (Node/Bun/Cloudflare). Registry-based multi-app orchestration.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"create": "bin/create.js"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@b9g/async-context": "^0.1.
|
|
13
|
+
"@b9g/async-context": "^0.1.2",
|
|
14
14
|
"@clack/prompts": "^0.7.0",
|
|
15
15
|
"@logtape/logtape": "^1.2.0",
|
|
16
16
|
"commander": "^13.1.0",
|
|
@@ -21,30 +21,30 @@
|
|
|
21
21
|
"source-map": "^0.7.4"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@b9g/assets": "^0.1.
|
|
25
|
-
"@b9g/cache": "^0.1.
|
|
24
|
+
"@b9g/assets": "^0.1.14",
|
|
25
|
+
"@b9g/cache": "^0.1.5",
|
|
26
26
|
"@b9g/crank": "^0.7.2",
|
|
27
|
-
"@b9g/filesystem": "^0.1.
|
|
28
|
-
"@b9g/http-errors": "^0.1.
|
|
27
|
+
"@b9g/filesystem": "^0.1.7",
|
|
28
|
+
"@b9g/http-errors": "^0.1.6",
|
|
29
29
|
"@b9g/libuild": "^0.1.17",
|
|
30
|
-
"@b9g/platform": "^0.1.
|
|
31
|
-
"@b9g/platform-bun": "^0.1.
|
|
32
|
-
"@b9g/platform-cloudflare": "^0.1.
|
|
33
|
-
"@b9g/platform-node": "^0.1.
|
|
34
|
-
"@b9g/router": "^0.1.
|
|
30
|
+
"@b9g/platform": "^0.1.11",
|
|
31
|
+
"@b9g/platform-bun": "^0.1.9",
|
|
32
|
+
"@b9g/platform-cloudflare": "^0.1.8",
|
|
33
|
+
"@b9g/platform-node": "^0.1.11",
|
|
34
|
+
"@b9g/router": "^0.1.9",
|
|
35
35
|
"@types/bun": "^1.2.2",
|
|
36
36
|
"mitata": "^1.0.34",
|
|
37
37
|
"typescript": "^5.7.3"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
|
-
"@b9g/node-webworker": "^0.1.
|
|
41
|
-
"@b9g/platform": "^0.1.
|
|
42
|
-
"@b9g/platform-node": "^0.1.
|
|
43
|
-
"@b9g/platform-cloudflare": "^0.1.
|
|
44
|
-
"@b9g/platform-bun": "^0.1.
|
|
45
|
-
"@b9g/cache": "^0.1.
|
|
46
|
-
"@b9g/filesystem": "^0.1.
|
|
47
|
-
"@b9g/http-errors": "^0.1.
|
|
40
|
+
"@b9g/node-webworker": "^0.1.4",
|
|
41
|
+
"@b9g/platform": "^0.1.11",
|
|
42
|
+
"@b9g/platform-node": "^0.1.11",
|
|
43
|
+
"@b9g/platform-cloudflare": "^0.1.8",
|
|
44
|
+
"@b9g/platform-bun": "^0.1.9",
|
|
45
|
+
"@b9g/cache": "^0.1.5",
|
|
46
|
+
"@b9g/filesystem": "^0.1.7",
|
|
47
|
+
"@b9g/http-errors": "^0.1.6"
|
|
48
48
|
},
|
|
49
49
|
"peerDependenciesMeta": {
|
|
50
50
|
"@b9g/platform": {
|