@b9g/shovel 0.2.0-beta.3 → 0.2.0-beta.5
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/bin/cli.js +123 -112
- package/package.json +15 -15
package/bin/cli.js
CHANGED
|
@@ -23,10 +23,9 @@ import * as Platform from "@b9g/platform";
|
|
|
23
23
|
|
|
24
24
|
// src/esbuild/watcher.ts
|
|
25
25
|
import * as ESBuild from "esbuild";
|
|
26
|
-
import { watch } from "fs";
|
|
27
26
|
import { resolve, dirname as dirname2, join } from "path";
|
|
28
27
|
import { readFileSync } from "fs";
|
|
29
|
-
import { mkdir } from "fs/promises";
|
|
28
|
+
import { mkdir, unlink } from "fs/promises";
|
|
30
29
|
import { assetsPlugin } from "@b9g/assets/plugin";
|
|
31
30
|
|
|
32
31
|
// src/esbuild/import-meta-plugin.ts
|
|
@@ -36,8 +35,8 @@ import { pathToFileURL } from "url";
|
|
|
36
35
|
function importMetaPlugin() {
|
|
37
36
|
return {
|
|
38
37
|
name: "import-meta-transform",
|
|
39
|
-
setup(
|
|
40
|
-
|
|
38
|
+
setup(build2) {
|
|
39
|
+
build2.onLoad({ filter: /\.[jt]sx?$/, namespace: "file" }, async (args) => {
|
|
41
40
|
if (args.path.includes("node_modules")) {
|
|
42
41
|
return null;
|
|
43
42
|
}
|
|
@@ -82,115 +81,128 @@ function importMetaPlugin() {
|
|
|
82
81
|
import { getLogger } from "@logtape/logtape";
|
|
83
82
|
var logger = getLogger(["watcher"]);
|
|
84
83
|
var Watcher = class {
|
|
85
|
-
#watcher;
|
|
86
|
-
#building;
|
|
87
84
|
#options;
|
|
85
|
+
#ctx;
|
|
86
|
+
#initialBuildComplete;
|
|
87
|
+
#initialBuildResolve;
|
|
88
|
+
#currentEntrypoint;
|
|
89
|
+
#previousEntrypoint;
|
|
88
90
|
constructor(options) {
|
|
89
|
-
this.#building = false;
|
|
90
91
|
this.#options = options;
|
|
92
|
+
this.#initialBuildComplete = false;
|
|
93
|
+
this.#currentEntrypoint = "";
|
|
94
|
+
this.#previousEntrypoint = "";
|
|
91
95
|
}
|
|
92
96
|
/**
|
|
93
97
|
* Start watching and building
|
|
98
|
+
* @returns Result with success status and the hashed entrypoint path
|
|
94
99
|
*/
|
|
95
100
|
async start() {
|
|
96
101
|
const entryPath = resolve(this.#options.entrypoint);
|
|
97
|
-
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
102
|
+
const outputDir = resolve(this.#options.outDir);
|
|
103
|
+
const workspaceRoot = this.#findWorkspaceRoot();
|
|
104
|
+
await mkdir(join(outputDir, "server"), { recursive: true });
|
|
105
|
+
await mkdir(join(outputDir, "static"), { recursive: true });
|
|
106
|
+
const initialBuildPromise = new Promise((resolve3) => {
|
|
107
|
+
this.#initialBuildResolve = resolve3;
|
|
108
|
+
});
|
|
109
|
+
this.#ctx = await ESBuild.context({
|
|
110
|
+
entryPoints: [entryPath],
|
|
111
|
+
bundle: true,
|
|
112
|
+
format: "esm",
|
|
113
|
+
target: "es2022",
|
|
114
|
+
platform: "node",
|
|
115
|
+
outdir: `${outputDir}/server`,
|
|
116
|
+
entryNames: "[name]-[hash]",
|
|
117
|
+
metafile: true,
|
|
118
|
+
absWorkingDir: workspaceRoot,
|
|
119
|
+
plugins: [
|
|
120
|
+
importMetaPlugin(),
|
|
121
|
+
assetsPlugin({
|
|
122
|
+
outDir: outputDir
|
|
123
|
+
}),
|
|
124
|
+
// Plugin to detect build completion (works with watch mode)
|
|
125
|
+
{
|
|
126
|
+
name: "build-notify",
|
|
127
|
+
setup: (build2) => {
|
|
128
|
+
build2.onStart(() => {
|
|
129
|
+
logger.info("Building", {
|
|
130
|
+
entrypoint: this.#options.entrypoint
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
build2.onEnd(async (result) => {
|
|
134
|
+
const success = result.errors.length === 0;
|
|
135
|
+
let outputPath = "";
|
|
136
|
+
if (result.metafile) {
|
|
137
|
+
const outputs = Object.keys(result.metafile.outputs);
|
|
138
|
+
const jsOutput = outputs.find((p) => p.endsWith(".js"));
|
|
139
|
+
if (jsOutput) {
|
|
140
|
+
outputPath = resolve(jsOutput);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (success) {
|
|
144
|
+
logger.info("Build complete", { entrypoint: outputPath });
|
|
145
|
+
if (this.#currentEntrypoint && this.#currentEntrypoint !== outputPath) {
|
|
146
|
+
try {
|
|
147
|
+
await unlink(this.#currentEntrypoint);
|
|
148
|
+
await unlink(this.#currentEntrypoint + ".map").catch(
|
|
149
|
+
() => {
|
|
150
|
+
}
|
|
151
|
+
);
|
|
152
|
+
logger.debug("Cleaned up old build", {
|
|
153
|
+
oldEntrypoint: this.#currentEntrypoint
|
|
154
|
+
});
|
|
155
|
+
} catch {
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
} else {
|
|
159
|
+
logger.error("Build errors", { errors: result.errors });
|
|
160
|
+
}
|
|
161
|
+
this.#previousEntrypoint = this.#currentEntrypoint;
|
|
162
|
+
this.#currentEntrypoint = outputPath;
|
|
163
|
+
if (!this.#initialBuildComplete) {
|
|
164
|
+
this.#initialBuildComplete = true;
|
|
165
|
+
this.#initialBuildResolve?.({ success, entrypoint: outputPath });
|
|
166
|
+
} else {
|
|
167
|
+
this.#options.onBuild?.(success, outputPath);
|
|
168
|
+
}
|
|
169
|
+
});
|
|
108
170
|
}
|
|
109
|
-
this.#debouncedBuild();
|
|
110
171
|
}
|
|
111
|
-
|
|
112
|
-
|
|
172
|
+
],
|
|
173
|
+
sourcemap: "inline",
|
|
174
|
+
minify: false,
|
|
175
|
+
treeShaking: true
|
|
176
|
+
});
|
|
177
|
+
logger.info("Starting esbuild watch mode");
|
|
178
|
+
await this.#ctx.watch();
|
|
179
|
+
return initialBuildPromise;
|
|
113
180
|
}
|
|
114
181
|
/**
|
|
115
|
-
* Stop watching
|
|
182
|
+
* Stop watching and dispose of esbuild context
|
|
116
183
|
*/
|
|
117
184
|
async stop() {
|
|
118
|
-
if (this.#
|
|
119
|
-
this.#
|
|
120
|
-
this.#
|
|
185
|
+
if (this.#ctx) {
|
|
186
|
+
await this.#ctx.dispose();
|
|
187
|
+
this.#ctx = void 0;
|
|
121
188
|
}
|
|
122
189
|
}
|
|
123
|
-
#
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
if (this.#building)
|
|
134
|
-
return;
|
|
135
|
-
this.#building = true;
|
|
136
|
-
try {
|
|
137
|
-
const entryPath = resolve(this.#options.entrypoint);
|
|
138
|
-
const outputDir = resolve(this.#options.outDir);
|
|
139
|
-
const version = Date.now();
|
|
140
|
-
const initialCwd = process.cwd();
|
|
141
|
-
let workspaceRoot = initialCwd;
|
|
142
|
-
while (workspaceRoot !== dirname2(workspaceRoot)) {
|
|
143
|
-
try {
|
|
144
|
-
const packageJSON = JSON.parse(
|
|
145
|
-
readFileSync(resolve(workspaceRoot, "package.json"), "utf8")
|
|
146
|
-
);
|
|
147
|
-
if (packageJSON.workspaces) {
|
|
148
|
-
break;
|
|
149
|
-
}
|
|
150
|
-
} catch {
|
|
190
|
+
#findWorkspaceRoot() {
|
|
191
|
+
const initialCwd = process.cwd();
|
|
192
|
+
let workspaceRoot = initialCwd;
|
|
193
|
+
while (workspaceRoot !== dirname2(workspaceRoot)) {
|
|
194
|
+
try {
|
|
195
|
+
const packageJSON = JSON.parse(
|
|
196
|
+
readFileSync(resolve(workspaceRoot, "package.json"), "utf8")
|
|
197
|
+
);
|
|
198
|
+
if (packageJSON.workspaces) {
|
|
199
|
+
return workspaceRoot;
|
|
151
200
|
}
|
|
152
|
-
|
|
201
|
+
} catch {
|
|
153
202
|
}
|
|
154
|
-
|
|
155
|
-
workspaceRoot = initialCwd;
|
|
156
|
-
}
|
|
157
|
-
logger.info("Building", { entryPath });
|
|
158
|
-
logger.info("Workspace root", { workspaceRoot });
|
|
159
|
-
await mkdir(join(outputDir, "server"), { recursive: true });
|
|
160
|
-
await mkdir(join(outputDir, "assets"), { recursive: true });
|
|
161
|
-
const result = await ESBuild.build({
|
|
162
|
-
entryPoints: [entryPath],
|
|
163
|
-
bundle: true,
|
|
164
|
-
format: "esm",
|
|
165
|
-
target: "es2022",
|
|
166
|
-
platform: "node",
|
|
167
|
-
outfile: `${outputDir}/server/app.js`,
|
|
168
|
-
packages: "external",
|
|
169
|
-
absWorkingDir: workspaceRoot,
|
|
170
|
-
plugins: [
|
|
171
|
-
importMetaPlugin(),
|
|
172
|
-
assetsPlugin({
|
|
173
|
-
outputDir: `${outputDir}/assets`,
|
|
174
|
-
manifest: `${outputDir}/server/asset-manifest.json`
|
|
175
|
-
})
|
|
176
|
-
],
|
|
177
|
-
sourcemap: "inline",
|
|
178
|
-
minify: false,
|
|
179
|
-
treeShaking: true
|
|
180
|
-
});
|
|
181
|
-
if (result.errors.length > 0) {
|
|
182
|
-
logger.error("Build errors", { errors: result.errors });
|
|
183
|
-
this.#options.onBuild?.(false, version);
|
|
184
|
-
} else {
|
|
185
|
-
logger.info("Build complete", { version });
|
|
186
|
-
this.#options.onBuild?.(true, version);
|
|
187
|
-
}
|
|
188
|
-
} catch (error) {
|
|
189
|
-
logger.error("Build failed", { error });
|
|
190
|
-
this.#options.onBuild?.(false, Date.now());
|
|
191
|
-
} finally {
|
|
192
|
-
this.#building = false;
|
|
203
|
+
workspaceRoot = dirname2(workspaceRoot);
|
|
193
204
|
}
|
|
205
|
+
return initialCwd;
|
|
194
206
|
}
|
|
195
207
|
};
|
|
196
208
|
|
|
@@ -238,20 +250,20 @@ async function developCommand(entrypoint, options) {
|
|
|
238
250
|
const watcher = new Watcher({
|
|
239
251
|
entrypoint,
|
|
240
252
|
outDir,
|
|
241
|
-
onBuild: async (success,
|
|
253
|
+
onBuild: async (success, builtEntrypoint2) => {
|
|
242
254
|
if (success && serviceWorker) {
|
|
243
|
-
logger2.info("Reloading Workers", {
|
|
255
|
+
logger2.info("Reloading Workers", { entrypoint: builtEntrypoint2 });
|
|
244
256
|
if (platformInstance && typeof platformInstance.reloadWorkers === "function") {
|
|
245
|
-
await platformInstance.reloadWorkers(
|
|
257
|
+
await platformInstance.reloadWorkers(builtEntrypoint2);
|
|
246
258
|
}
|
|
247
259
|
logger2.info("Workers reloaded", {});
|
|
248
260
|
}
|
|
249
261
|
}
|
|
250
262
|
});
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
263
|
+
const { success: buildSuccess, entrypoint: builtEntrypoint } = await watcher.start();
|
|
264
|
+
if (!buildSuccess) {
|
|
265
|
+
logger2.error("Initial build failed, watching for changes to retry", {});
|
|
266
|
+
}
|
|
255
267
|
serviceWorker = await platformInstance.loadServiceWorker(builtEntrypoint, {
|
|
256
268
|
hotReload: true,
|
|
257
269
|
workerCount
|
|
@@ -277,8 +289,7 @@ async function developCommand(entrypoint, options) {
|
|
|
277
289
|
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
278
290
|
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
279
291
|
} catch (error) {
|
|
280
|
-
logger2.error("Failed to start development server", {
|
|
281
|
-
error: error.message,
|
|
292
|
+
logger2.error("Failed to start development server:\n{stack}", {
|
|
282
293
|
stack: error.stack
|
|
283
294
|
});
|
|
284
295
|
process.exit(1);
|
|
@@ -385,8 +396,7 @@ var BUILD_DEFAULTS = {
|
|
|
385
396
|
};
|
|
386
397
|
var BUILD_STRUCTURE = {
|
|
387
398
|
serverDir: "server",
|
|
388
|
-
staticDir: "static"
|
|
389
|
-
assetsDir: "static/assets"
|
|
399
|
+
staticDir: "static"
|
|
390
400
|
};
|
|
391
401
|
async function buildForProduction({
|
|
392
402
|
entrypoint,
|
|
@@ -414,7 +424,7 @@ async function buildForProduction({
|
|
|
414
424
|
if (verbose) {
|
|
415
425
|
logger5.info("Built app to", { outputDir: buildContext.outputDir });
|
|
416
426
|
logger5.info("Server files", { dir: buildContext.serverDir });
|
|
417
|
-
logger5.info("
|
|
427
|
+
logger5.info("Static files", { dir: join2(buildContext.outputDir, "static") });
|
|
418
428
|
}
|
|
419
429
|
}
|
|
420
430
|
async function initializeBuild({
|
|
@@ -462,7 +472,6 @@ async function initializeBuild({
|
|
|
462
472
|
await mkdir2(outputDir, { recursive: true });
|
|
463
473
|
await mkdir2(join2(outputDir, BUILD_STRUCTURE.serverDir), { recursive: true });
|
|
464
474
|
await mkdir2(join2(outputDir, BUILD_STRUCTURE.staticDir), { recursive: true });
|
|
465
|
-
await mkdir2(join2(outputDir, BUILD_STRUCTURE.assetsDir), { recursive: true });
|
|
466
475
|
} catch (error) {
|
|
467
476
|
throw new Error(
|
|
468
477
|
`Failed to create output directory structure: ${error.message}`
|
|
@@ -472,7 +481,6 @@ async function initializeBuild({
|
|
|
472
481
|
entryPath,
|
|
473
482
|
outputDir,
|
|
474
483
|
serverDir: join2(outputDir, BUILD_STRUCTURE.serverDir),
|
|
475
|
-
assetsDir: join2(outputDir, BUILD_STRUCTURE.assetsDir),
|
|
476
484
|
workspaceRoot,
|
|
477
485
|
platform,
|
|
478
486
|
verbose,
|
|
@@ -517,8 +525,8 @@ async function findShovelPackageRoot() {
|
|
|
517
525
|
}
|
|
518
526
|
async function createBuildConfig({
|
|
519
527
|
entryPath,
|
|
528
|
+
outputDir,
|
|
520
529
|
serverDir,
|
|
521
|
-
assetsDir,
|
|
522
530
|
workspaceRoot,
|
|
523
531
|
platform,
|
|
524
532
|
workerCount
|
|
@@ -543,11 +551,15 @@ async function createBuildConfig({
|
|
|
543
551
|
absWorkingDir: workspaceRoot || dirname3(entryPath),
|
|
544
552
|
mainFields: ["module", "main"],
|
|
545
553
|
conditions: ["import", "module"],
|
|
554
|
+
// Allow user code to import @b9g packages from shovel's packages directory
|
|
555
|
+
nodePaths: [
|
|
556
|
+
join2(shovelRoot, "packages"),
|
|
557
|
+
join2(shovelRoot, "node_modules")
|
|
558
|
+
],
|
|
546
559
|
plugins: [
|
|
547
560
|
importMetaPlugin(),
|
|
548
561
|
assetsPlugin2({
|
|
549
|
-
|
|
550
|
-
manifest: join2(serverDir, "asset-manifest.json")
|
|
562
|
+
outDir: outputDir
|
|
551
563
|
})
|
|
552
564
|
],
|
|
553
565
|
metafile: true,
|
|
@@ -614,8 +626,7 @@ async function createBuildConfig({
|
|
|
614
626
|
plugins: isCloudflare ? [
|
|
615
627
|
importMetaPlugin(),
|
|
616
628
|
assetsPlugin2({
|
|
617
|
-
|
|
618
|
-
manifest: join2(serverDir, "asset-manifest.json")
|
|
629
|
+
outDir: outputDir
|
|
619
630
|
})
|
|
620
631
|
] : [],
|
|
621
632
|
// Assets already handled in user code build
|
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.5",
|
|
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": {
|
|
@@ -21,30 +21,30 @@
|
|
|
21
21
|
"source-map": "^0.7.4"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@b9g/assets": "^0.1.
|
|
24
|
+
"@b9g/assets": "^0.1.12",
|
|
25
25
|
"@b9g/cache": "^0.1.4",
|
|
26
26
|
"@b9g/crank": "^0.7.2",
|
|
27
|
-
"@b9g/filesystem": "^0.1.
|
|
28
|
-
"@b9g/http-errors": "^0.1.
|
|
27
|
+
"@b9g/filesystem": "^0.1.6",
|
|
28
|
+
"@b9g/http-errors": "^0.1.5",
|
|
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.9",
|
|
31
|
+
"@b9g/platform-bun": "^0.1.7",
|
|
32
|
+
"@b9g/platform-cloudflare": "^0.1.6",
|
|
33
|
+
"@b9g/platform-node": "^0.1.9",
|
|
34
|
+
"@b9g/router": "^0.1.7",
|
|
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
40
|
"@b9g/node-webworker": "^0.1.3",
|
|
41
|
-
"@b9g/platform": "^0.1.
|
|
42
|
-
"@b9g/platform-node": "^0.1.
|
|
43
|
-
"@b9g/platform-cloudflare": "^0.1.
|
|
44
|
-
"@b9g/platform-bun": "^0.1.
|
|
41
|
+
"@b9g/platform": "^0.1.9",
|
|
42
|
+
"@b9g/platform-node": "^0.1.9",
|
|
43
|
+
"@b9g/platform-cloudflare": "^0.1.6",
|
|
44
|
+
"@b9g/platform-bun": "^0.1.7",
|
|
45
45
|
"@b9g/cache": "^0.1.4",
|
|
46
|
-
"@b9g/filesystem": "^0.1.
|
|
47
|
-
"@b9g/http-errors": "^0.1.
|
|
46
|
+
"@b9g/filesystem": "^0.1.6",
|
|
47
|
+
"@b9g/http-errors": "^0.1.5"
|
|
48
48
|
},
|
|
49
49
|
"peerDependenciesMeta": {
|
|
50
50
|
"@b9g/platform": {
|