@powerhousedao/builder-tools 6.2.3-dev.8 → 6.2.3-staging.0
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/dist/index.d.mts +163 -78
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +244 -74
- package/dist/index.mjs.map +1 -1
- package/dist/service-worker/service-worker.ts +8 -2
- package/package.json +9 -9
package/dist/index.mjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import { createHash, randomUUID } from "node:crypto";
|
|
3
|
-
import fs, { createReadStream, existsSync, mkdirSync, mkdtempSync, readFileSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
3
|
+
import fs, { chmodSync, createReadStream, existsSync, mkdirSync, mkdtempSync, readFileSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
4
4
|
import path, { dirname, extname, isAbsolute, join, resolve } from "node:path";
|
|
5
5
|
import { exec, execSync, spawn } from "node:child_process";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
|
+
import { DYNAMIC_BASE_PLACEHOLDER, PWA_FILE_HANDLER_ACTION, buildRuntimeConfig, deepMerge, loadConnectEnv, mergeManifest, mergePwaConfig, normalizeBasePath, phConnectRuntimeConfigSchema, powerhousePackageSchema, resolveSourceConnect, setConnectEnv, unionStrings, withInferredCategory } from "@powerhousedao/shared/connect";
|
|
7
8
|
import MagicString from "magic-string";
|
|
8
9
|
import { readFile, writeFile } from "node:fs/promises";
|
|
9
10
|
import { cwd } from "node:process";
|
|
10
|
-
import { DEFAULT_CONNECT_CONFIG, PWA_FILE_HANDLER_ACTION, buildRuntimeConfig, deepMerge, loadConnectEnv, mergeManifest, mergePwaConfig, normalizeBasePath, phConnectRuntimeConfigSchema, powerhousePackageSchema, setConnectEnv, unionStrings, withInferredCategory } from "@powerhousedao/shared/connect";
|
|
11
11
|
import { getConfig } from "@powerhousedao/config/node";
|
|
12
12
|
import tailwind from "@tailwindcss/vite";
|
|
13
13
|
import react from "@vitejs/plugin-react";
|
|
@@ -44,7 +44,8 @@ function computeBuildHash(input) {
|
|
|
44
44
|
*/
|
|
45
45
|
function readConnectVersion(projectRoot) {
|
|
46
46
|
try {
|
|
47
|
-
|
|
47
|
+
const entry = createRequire(join(projectRoot, "package.json")).resolve("@powerhousedao/connect", { paths: [projectRoot] });
|
|
48
|
+
let dir = dirname(entry);
|
|
48
49
|
for (;;) {
|
|
49
50
|
try {
|
|
50
51
|
const pkg = JSON.parse(readFileSync(join(dir, "package.json"), "utf-8"));
|
|
@@ -91,16 +92,6 @@ function connectBuildHashPlugin(buildHash) {
|
|
|
91
92
|
//#endregion
|
|
92
93
|
//#region connect-utils/vite-plugins/dynamic-base.ts
|
|
93
94
|
/**
|
|
94
|
-
* Placeholder base used when Connect is built in dynamic-base mode. The Vite
|
|
95
|
-
* `base` option is set to this token; this plugin rewrites it in the emitted
|
|
96
|
-
* output so the effective base is resolved at serve time from a global instead
|
|
97
|
-
* of being baked at build time.
|
|
98
|
-
*
|
|
99
|
-
* Trailing slash matches `normalizeBasePath` output, so the token sits in the
|
|
100
|
-
* same syntactic position as a concrete base would.
|
|
101
|
-
*/
|
|
102
|
-
const DYNAMIC_BASE_PLACEHOLDER = "/__PH_DYNAMIC_BASE__/";
|
|
103
|
-
/**
|
|
104
95
|
* Global the runtime (ph-clint proxy) must set before the entry bundle loads.
|
|
105
96
|
* Value is the normalized deploy base, e.g. "/myagent/" or "/". The JS rewrite
|
|
106
97
|
* below resolves all asset / lazy-chunk / BASE_URL references against it.
|
|
@@ -108,7 +99,8 @@ const DYNAMIC_BASE_PLACEHOLDER = "/__PH_DYNAMIC_BASE__/";
|
|
|
108
99
|
const RUNTIME_GLOBAL = "globalThis.__PH_DYNAMIC_BASE__";
|
|
109
100
|
const BASE_EXPR = `(${RUNTIME_GLOBAL}||"/")`;
|
|
110
101
|
function workerPrelude(stripPrefix) {
|
|
111
|
-
|
|
102
|
+
const prefix = escapeForRegExp(stripPrefix).replace(/\//g, "\\/");
|
|
103
|
+
return `${RUNTIME_GLOBAL}=self.location.pathname.replace(/${prefix}assets\\/[^/]*$/,"");\n`;
|
|
112
104
|
}
|
|
113
105
|
const PLACEHOLDER_LITERAL = new RegExp(`(["'\`])${escapeForRegExp(DYNAMIC_BASE_PLACEHOLDER)}((?:(?!\\1)[^$])*)\\1`, "g");
|
|
114
106
|
/**
|
|
@@ -144,7 +136,7 @@ function connectDynamicBasePlugin(options = {}) {
|
|
|
144
136
|
name: "ph-connect-dynamic-base",
|
|
145
137
|
enforce: "post",
|
|
146
138
|
renderChunk(code, chunk) {
|
|
147
|
-
if (!code.includes(
|
|
139
|
+
if (!code.includes(DYNAMIC_BASE_PLACEHOLDER)) return null;
|
|
148
140
|
const s = new MagicString(code);
|
|
149
141
|
for (const match of code.matchAll(PLACEHOLDER_LITERAL)) {
|
|
150
142
|
const rest = match[2];
|
|
@@ -161,7 +153,7 @@ function connectDynamicBasePlugin(options = {}) {
|
|
|
161
153
|
};
|
|
162
154
|
},
|
|
163
155
|
generateBundle(_options, bundle) {
|
|
164
|
-
for (const file of Object.values(bundle)) if ((file.type === "chunk" ? file.code : file.fileName.endsWith(".css") && typeof file.source === "string" ? file.source : void 0)?.includes(
|
|
156
|
+
for (const file of Object.values(bundle)) if ((file.type === "chunk" ? file.code : file.fileName.endsWith(".css") && typeof file.source === "string" ? file.source : void 0)?.includes(DYNAMIC_BASE_PLACEHOLDER)) this.error(`dynamic-base: unrewritten placeholder ${DYNAMIC_BASE_PLACEHOLDER} remains in ${file.fileName}`);
|
|
165
157
|
}
|
|
166
158
|
};
|
|
167
159
|
}
|
|
@@ -241,31 +233,34 @@ async function prebuildConnectVendor(options) {
|
|
|
241
233
|
const vendorDir = options.vendorDir ?? join(options.dirname, "node_modules/.ph-vendor");
|
|
242
234
|
const importMapPath = join(vendorDir, "import-map.json");
|
|
243
235
|
const versionDigest = resolveVersionDigest(options.dirname, [...include, ...external]);
|
|
236
|
+
const versions = resolveDepVersions(options.dirname, [...include, ...external]);
|
|
237
|
+
const base = options.base ?? VENDOR_DYNAMIC_BASE;
|
|
238
|
+
const nodeEnv = options.nodeEnv ?? "development";
|
|
244
239
|
try {
|
|
245
240
|
const hit = readCacheHit(importMapPath, include, external, versionDigest);
|
|
246
241
|
if (hit) return {
|
|
247
242
|
vendorDir,
|
|
248
|
-
|
|
243
|
+
...hit
|
|
249
244
|
};
|
|
250
245
|
const lockDir = `${vendorDir}.lock`;
|
|
251
246
|
const lock = acquireLock(lockDir);
|
|
252
247
|
if (!lock) {
|
|
253
|
-
const
|
|
254
|
-
return
|
|
248
|
+
const hit = await waitForCacheHit(importMapPath, include, external, versionDigest, lockDir);
|
|
249
|
+
return hit ? {
|
|
255
250
|
vendorDir,
|
|
256
|
-
|
|
251
|
+
...hit
|
|
257
252
|
} : null;
|
|
258
253
|
}
|
|
259
254
|
try {
|
|
260
255
|
const raced = readCacheHit(importMapPath, include, external, versionDigest);
|
|
261
256
|
if (raced) return {
|
|
262
257
|
vendorDir,
|
|
263
|
-
|
|
258
|
+
...raced
|
|
264
259
|
};
|
|
265
|
-
const
|
|
266
|
-
return
|
|
260
|
+
const result = await buildVendorAtomic(options.dirname, vendorDir, include, external, versionDigest, versions, base, nodeEnv);
|
|
261
|
+
return result ? {
|
|
267
262
|
vendorDir,
|
|
268
|
-
|
|
263
|
+
...result
|
|
269
264
|
} : null;
|
|
270
265
|
} finally {
|
|
271
266
|
releaseLock(lock);
|
|
@@ -279,27 +274,73 @@ function readCacheHit(importMapPath, include, external, versionDigest) {
|
|
|
279
274
|
if (!existsSync(importMapPath)) return null;
|
|
280
275
|
try {
|
|
281
276
|
const cached = JSON.parse(readFileSync(importMapPath, "utf8"));
|
|
282
|
-
if (sameSet(cached.include, include) && sameSet(cached.external, external) && cached.versionDigest === versionDigest) return
|
|
277
|
+
if (sameSet(cached.include, include) && sameSet(cached.external, external) && cached.versionDigest === versionDigest) return {
|
|
278
|
+
imports: cached.imports,
|
|
279
|
+
versions: cached.versions ?? {}
|
|
280
|
+
};
|
|
283
281
|
} catch {}
|
|
284
282
|
return null;
|
|
285
283
|
}
|
|
286
|
-
|
|
287
|
-
|
|
284
|
+
/**
|
|
285
|
+
* Resolve the installed version of each spec's owning package, deduped by
|
|
286
|
+
* package name. Resolution order per spec:
|
|
287
|
+
* 1. the project itself, when it IS the owning package (a self-vendoring
|
|
288
|
+
* app has no node_modules self-link);
|
|
289
|
+
* 2. the project's own node_modules link (works for pnpm-strict and
|
|
290
|
+
* hoisted layouts alike, and — unlike `require.resolve` — for
|
|
291
|
+
* ESM-only packages whose exports map has no CJS condition);
|
|
292
|
+
* 3. Node's own module resolution (covers transitive installs), walking
|
|
293
|
+
* the entry up to the owning package's package.json.
|
|
294
|
+
* Unresolvable specs contribute a "missing" sentinel, unknown versions
|
|
295
|
+
* "unknown".
|
|
296
|
+
*/
|
|
297
|
+
function resolveDepVersions(dirname$2, specs) {
|
|
298
|
+
const req = createRequire(join(dirname$2, "noop.js"));
|
|
299
|
+
const seen = {};
|
|
300
|
+
let selfMeta = null;
|
|
288
301
|
for (const spec of specs) {
|
|
289
302
|
const { pkg } = parsePkg(spec);
|
|
290
|
-
if (seen
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
303
|
+
if (pkg in seen) continue;
|
|
304
|
+
if (selfMeta === null) try {
|
|
305
|
+
selfMeta = JSON.parse(readFileSync(join(dirname$2, "package.json"), "utf8"));
|
|
306
|
+
} catch {
|
|
307
|
+
selfMeta = {};
|
|
308
|
+
}
|
|
309
|
+
let version;
|
|
310
|
+
if (typeof selfMeta.name === "string" && selfMeta.name === pkg && typeof selfMeta.version === "string") version = selfMeta.version;
|
|
311
|
+
else {
|
|
312
|
+
version = "missing";
|
|
313
|
+
try {
|
|
314
|
+
const pkgRoot = realpathSync(join(dirname$2, "node_modules", pkg));
|
|
315
|
+
const meta = JSON.parse(readFileSync(join(pkgRoot, "package.json"), "utf8"));
|
|
316
|
+
version = String(meta.version ?? "unknown");
|
|
317
|
+
} catch {
|
|
318
|
+
try {
|
|
319
|
+
const entry = req.resolve(spec);
|
|
320
|
+
let dir = dirname(entry);
|
|
321
|
+
for (let depth = 0; depth < 8; depth++) {
|
|
322
|
+
if (existsSync(join(dir, "package.json"))) {
|
|
323
|
+
const meta = JSON.parse(readFileSync(join(dir, "package.json"), "utf8"));
|
|
324
|
+
version = String(meta.version ?? "unknown");
|
|
325
|
+
break;
|
|
326
|
+
}
|
|
327
|
+
const parent = dirname(dir);
|
|
328
|
+
if (parent === dir) break;
|
|
329
|
+
dir = parent;
|
|
330
|
+
}
|
|
331
|
+
} catch {}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
seen[pkg] = version;
|
|
298
335
|
}
|
|
336
|
+
return seen;
|
|
337
|
+
}
|
|
338
|
+
function resolveVersionDigest(dirname, specs) {
|
|
339
|
+
const versions = resolveDepVersions(dirname, specs);
|
|
299
340
|
const h = createHash("sha256");
|
|
300
341
|
const workerHash = createHash("sha256").update(VENDOR_BUILD_WORKER).digest("hex");
|
|
301
342
|
h.update(`worker:${workerHash}\n`);
|
|
302
|
-
for (const pkg of
|
|
343
|
+
for (const pkg of Object.keys(versions).sort()) h.update(`${pkg}@${versions[pkg]}\n`);
|
|
303
344
|
return h.digest("hex").slice(0, 16);
|
|
304
345
|
}
|
|
305
346
|
function sameSet(a, b) {
|
|
@@ -307,7 +348,7 @@ function sameSet(a, b) {
|
|
|
307
348
|
const s = new Set(a);
|
|
308
349
|
return b.every((x) => s.has(x));
|
|
309
350
|
}
|
|
310
|
-
const LOCK_STALE_MS =
|
|
351
|
+
const LOCK_STALE_MS = 3e5;
|
|
311
352
|
const LOCK_HEARTBEAT_MS = 6e4;
|
|
312
353
|
const ownerFile = (lockDir) => join(lockDir, "owner");
|
|
313
354
|
function lockIsStale(lockDir) {
|
|
@@ -406,11 +447,16 @@ function parsePkg(spec) {
|
|
|
406
447
|
* `@powerhousedao/design-system/connect/toast`, `zod/v4/core`). Those bare
|
|
407
448
|
* imports need their own import-map entry, so expand each listed spec to its
|
|
408
449
|
* package's concrete (non-wildcard, JS) subpath exports that share the spec's
|
|
409
|
-
* prefix. Unresolvable / CSS / JSON targets are skipped.
|
|
410
|
-
*
|
|
450
|
+
* prefix. Unresolvable / CSS / JSON targets are skipped.
|
|
451
|
+
*
|
|
452
|
+
* A spec whose package isn't installed in `dirname` is dropped entirely
|
|
453
|
+
* rather than kept for the worker: the worker cannot build an entry for a
|
|
454
|
+
* missing package (its `await import` and the vite resolution both fail),
|
|
455
|
+
* and a bare re-export entry would fail the whole vendor build. The
|
|
456
|
+
* importer of a missing shared dep simply bundles its own copy.
|
|
411
457
|
*/
|
|
412
458
|
function expandIncludeSubpaths(dirname, include) {
|
|
413
|
-
const out = new Set(
|
|
459
|
+
const out = /* @__PURE__ */ new Set();
|
|
414
460
|
for (const spec of include) {
|
|
415
461
|
const { pkg, sub } = parsePkg(spec);
|
|
416
462
|
let exp;
|
|
@@ -421,6 +467,7 @@ function expandIncludeSubpaths(dirname, include) {
|
|
|
421
467
|
} catch {
|
|
422
468
|
continue;
|
|
423
469
|
}
|
|
470
|
+
out.add(sub ? spec : pkg);
|
|
424
471
|
if (!exp || typeof exp !== "object") continue;
|
|
425
472
|
const expMap = exp;
|
|
426
473
|
const prefixKey = sub ? `./${sub}` : ".";
|
|
@@ -437,34 +484,72 @@ function expandIncludeSubpaths(dirname, include) {
|
|
|
437
484
|
return [...out];
|
|
438
485
|
}
|
|
439
486
|
/**
|
|
487
|
+
* The published specifiers whose entry file the vendor build never emitted.
|
|
488
|
+
* URLs are base-less (`/__vendor__/x.js`) and resolve inside `vendorDir`.
|
|
489
|
+
*/
|
|
490
|
+
function missingVendorEntries(vendorDir, imports) {
|
|
491
|
+
const prefix = VENDOR_URL_PREFIX;
|
|
492
|
+
return Object.entries(imports).filter(([, url]) => {
|
|
493
|
+
const rel = url.startsWith(prefix) ? url.slice(12) : url;
|
|
494
|
+
return !existsSync(join(vendorDir, rel));
|
|
495
|
+
}).map(([spec, url]) => ({
|
|
496
|
+
spec,
|
|
497
|
+
url
|
|
498
|
+
}));
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* Rebase the vendor's base-less entry URLs (`/__vendor__/x.js`) onto the
|
|
502
|
+
* deploy base, so a consumer that resolves them against the page origin lands
|
|
503
|
+
* under that base rather than the server root. A dynamic-base build keeps its
|
|
504
|
+
* placeholder, which the runtime substitutes.
|
|
505
|
+
*
|
|
506
|
+
* `base` is the app base from `prebuildConnectVendor` callers, but the
|
|
507
|
+
* VENDOR_DYNAMIC_BASE default already carries the vendor segment — that
|
|
508
|
+
* trailing segment is dropped first so it is never doubled.
|
|
509
|
+
*/
|
|
510
|
+
function withVendorBase(imports, base) {
|
|
511
|
+
const segment = VENDOR_URL_PREFIX.replace(/^\/+/, "");
|
|
512
|
+
const appBase = base.endsWith(segment) ? base.slice(0, base.length - segment.length) : base;
|
|
513
|
+
return Object.fromEntries(Object.entries(imports).map(([spec, url]) => [spec, `${appBase}/${url}`.replace(/([^:])\/{2,}/g, "$1/").replace(/^\/{2,}/, "/")]));
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
440
516
|
* Build the vendor into a unique temp dir, then atomically swap it into place,
|
|
441
517
|
* so a concurrent reader never sees a partial bundle or import-map.json. Runs
|
|
442
518
|
* the build in a throwaway subprocess (its peak memory is reclaimed on exit);
|
|
443
|
-
* the parent augments the import map with the version digest
|
|
444
|
-
*
|
|
519
|
+
* the parent augments the import map with the version digest + the version
|
|
520
|
+
* table, writes the runtime shared-deps module, and does the swap.
|
|
521
|
+
* Returns the published import map + versions, or null on failure.
|
|
445
522
|
*/
|
|
446
|
-
async function buildVendorAtomic(dirname$
|
|
523
|
+
async function buildVendorAtomic(dirname$3, vendorDir, include, external, versionDigest, versions, base, nodeEnv) {
|
|
447
524
|
const parent = dirname(vendorDir);
|
|
448
525
|
mkdirSync(parent, { recursive: true });
|
|
449
526
|
const tmpDir = mkdtempSync(join(parent, ".ph-vendor.tmp-"));
|
|
450
527
|
try {
|
|
451
|
-
const { ok, stderr } = await runBuildWorker(dirname$
|
|
528
|
+
const { ok, stderr } = await runBuildWorker(dirname$3, tmpDir, include, external, base, nodeEnv);
|
|
452
529
|
const tmpMap = join(tmpDir, "import-map.json");
|
|
453
530
|
if (!ok || !existsSync(tmpMap)) {
|
|
454
531
|
const detail = stderr.trim();
|
|
455
532
|
throw new Error(`vendor build failed${detail ? `:\n${detail}` : " (no output captured)"}`);
|
|
456
533
|
}
|
|
457
534
|
const meta = JSON.parse(readFileSync(tmpMap, "utf8"));
|
|
535
|
+
const unbacked = missingVendorEntries(tmpDir, meta.imports);
|
|
536
|
+
if (unbacked.length > 0) throw new Error(`vendor build published ${unbacked.length} import-map ${unbacked.length === 1 ? "entry" : "entries"} with no file behind ${unbacked.length === 1 ? "it" : "them"}:\n` + unbacked.map((e) => ` ${e.spec} -> ${e.url}`).join("\n"));
|
|
458
537
|
meta.versionDigest = versionDigest;
|
|
538
|
+
meta.versions = versions;
|
|
459
539
|
writeFileSync(tmpMap, JSON.stringify(meta, null, 2));
|
|
540
|
+
writeFileSync(join(tmpDir, "shared-deps.js"), `export const imports = ${JSON.stringify(withVendorBase(meta.imports, base))};\nexport const versions = ${JSON.stringify(versions)};\n`);
|
|
460
541
|
const oldDir = `${vendorDir}.old-${process.pid}-${Date.now()}`;
|
|
461
542
|
if (existsSync(vendorDir)) renameSync(vendorDir, oldDir);
|
|
462
543
|
renameSync(tmpDir, vendorDir);
|
|
544
|
+
chmodSync(vendorDir, 493);
|
|
463
545
|
rmSync(oldDir, {
|
|
464
546
|
recursive: true,
|
|
465
547
|
force: true
|
|
466
548
|
});
|
|
467
|
-
return
|
|
549
|
+
return {
|
|
550
|
+
imports: meta.imports,
|
|
551
|
+
versions
|
|
552
|
+
};
|
|
468
553
|
} catch (err) {
|
|
469
554
|
rmSync(tmpDir, {
|
|
470
555
|
recursive: true,
|
|
@@ -473,16 +558,29 @@ async function buildVendorAtomic(dirname$2, vendorDir, include, external, versio
|
|
|
473
558
|
throw err;
|
|
474
559
|
}
|
|
475
560
|
}
|
|
561
|
+
function resolveSelfModulePath() {
|
|
562
|
+
const selfPath = fileURLToPath(import.meta.url);
|
|
563
|
+
if (!selfPath.endsWith(".ts")) return selfPath;
|
|
564
|
+
let dir = dirname(selfPath);
|
|
565
|
+
for (let depth = 0; depth < 4; depth++) {
|
|
566
|
+
const candidate = join(dir, "dist", "index.mjs");
|
|
567
|
+
if (existsSync(candidate)) return candidate;
|
|
568
|
+
const parent = dirname(dir);
|
|
569
|
+
if (parent === dir) break;
|
|
570
|
+
dir = parent;
|
|
571
|
+
}
|
|
572
|
+
throw new Error("vendor build needs the built builder-tools bundle (dist/index.mjs); build the package first");
|
|
573
|
+
}
|
|
476
574
|
/**
|
|
477
575
|
* Spawn a throwaway worker that generates one entry per specifier (CJS deps get
|
|
478
576
|
* explicit named re-exports, ESM deps `export *`), `vite build`s them into the
|
|
479
577
|
* given out dir, and writes the import map. Captures stdout/stderr so a failure
|
|
480
578
|
* is debuggable; the normal path stays quiet.
|
|
481
579
|
*/
|
|
482
|
-
function runBuildWorker(dirname, outDir, include, external) {
|
|
580
|
+
function runBuildWorker(dirname, outDir, include, external, base, nodeEnv) {
|
|
483
581
|
const workerPath = join(outDir, "build-worker.mjs");
|
|
484
582
|
writeFileSync(workerPath, VENDOR_BUILD_WORKER);
|
|
485
|
-
const selfModulePath =
|
|
583
|
+
const selfModulePath = resolveSelfModulePath();
|
|
486
584
|
return new Promise((resolve) => {
|
|
487
585
|
const child = spawn(process.execPath, [
|
|
488
586
|
workerPath,
|
|
@@ -492,7 +590,9 @@ function runBuildWorker(dirname, outDir, include, external) {
|
|
|
492
590
|
VENDOR_URL_PREFIX,
|
|
493
591
|
JSON.stringify(external),
|
|
494
592
|
VENDOR_DYNAMIC_BASE,
|
|
495
|
-
selfModulePath
|
|
593
|
+
selfModulePath,
|
|
594
|
+
base,
|
|
595
|
+
nodeEnv
|
|
496
596
|
], {
|
|
497
597
|
cwd: dirname,
|
|
498
598
|
stdio: [
|
|
@@ -522,14 +622,22 @@ function runBuildWorker(dirname, outDir, include, external) {
|
|
|
522
622
|
* The vendor build worker, written to disk and run as a subprocess. Loads
|
|
523
623
|
* `vite` from the project and `connectDynamicBasePlugin` from builder-tools' own
|
|
524
624
|
* built bundle (selfModulePath). argv: dirname, vendorDir, includeJSON,
|
|
525
|
-
* urlPrefix, externalJSON, dynamicBase, selfModulePath
|
|
625
|
+
* urlPrefix, externalJSON, dynamicBase, selfModulePath, base (app base),
|
|
626
|
+
* nodeEnv.
|
|
526
627
|
*/
|
|
527
628
|
const VENDOR_BUILD_WORKER = `
|
|
528
629
|
import { createRequire } from 'node:module';
|
|
529
630
|
import { mkdirSync, writeFileSync, rmSync } from 'node:fs';
|
|
530
631
|
import { join, isAbsolute } from 'node:path';
|
|
531
632
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
532
|
-
const [dirname, vendorDir, includeJSON, urlPrefix, externalJSON, dynamicBase, selfModulePath] = process.argv.slice(2);
|
|
633
|
+
const [dirname, vendorDir, includeJSON, urlPrefix, externalJSON, dynamicBase, selfModulePath, baseArg, nodeEnvArg] = process.argv.slice(2);
|
|
634
|
+
// Trailing argv are optional (older callers): base defaults to the dynamic
|
|
635
|
+
// placeholder behavior, nodeEnv to development. baseArg is the APP base —
|
|
636
|
+
// the same string the app build uses; the build base appends the vendor
|
|
637
|
+
// segment so emitted asset URLs land under <app-base>__vendor__/.
|
|
638
|
+
const segment = urlPrefix.replace(/^\\/+/, '');
|
|
639
|
+
const base = baseArg ? baseArg + segment : dynamicBase;
|
|
640
|
+
const nodeEnv = nodeEnvArg ?? 'development';
|
|
533
641
|
const include = JSON.parse(includeJSON);
|
|
534
642
|
const external = JSON.parse(externalJSON ?? '[]');
|
|
535
643
|
const externalSet = new Set(external);
|
|
@@ -602,14 +710,17 @@ const phVendorResolve = {
|
|
|
602
710
|
};
|
|
603
711
|
await build({
|
|
604
712
|
root: dirname, configFile: false, logLevel: 'error',
|
|
605
|
-
//
|
|
606
|
-
// emitted chunk/asset URLs to resolve
|
|
607
|
-
base
|
|
713
|
+
// Caller-provided build base (or the dynamic placeholder default):
|
|
714
|
+
// connectDynamicBasePlugin rewrites emitted chunk/asset URLs to resolve
|
|
715
|
+
// against the deploy base at serve time.
|
|
716
|
+
base,
|
|
608
717
|
define: {
|
|
609
|
-
'process.env.NODE_ENV':
|
|
718
|
+
'process.env.NODE_ENV': JSON.stringify(nodeEnv),
|
|
610
719
|
// BASE_URL resolves to the deploy base (not the vendor prefix) so vendored
|
|
611
720
|
// Connect's router basename + BASE_URL-relative fetches use the right path.
|
|
612
|
-
|
|
721
|
+
// The app base when provided (concrete or placeholder), the placeholder
|
|
722
|
+
// otherwise (dev flow — rewritten at serve time by the dynamic-base plugin).
|
|
723
|
+
'import.meta.env.BASE_URL': JSON.stringify(baseArg ?? DYNAMIC_BASE_PLACEHOLDER),
|
|
613
724
|
},
|
|
614
725
|
// phVendorResolve (pre) resolves bares from the worker; esmExternalRequirePlugin owns
|
|
615
726
|
// react/virtual externalization; connectDynamicBasePlugin (post) rewrites the placeholder base.
|
|
@@ -618,7 +729,9 @@ await build({
|
|
|
618
729
|
// segment so the worker recovers the deploy base, not the vendor prefix.
|
|
619
730
|
worker: { format: 'es', plugins: () => [connectDynamicBasePlugin({ forWorker: true, workerStripPrefix: urlPrefix.replace(/^\\/+/, '') })] },
|
|
620
731
|
build: {
|
|
621
|
-
|
|
732
|
+
// Production ships this to every visitor, so minify it like the app's own
|
|
733
|
+
// chunks; dev keeps readable output and the faster build.
|
|
734
|
+
outDir: vendorDir, emptyOutDir: false, minify: nodeEnv === 'production', target: 'esnext', cssCodeSplit: true,
|
|
622
735
|
rollupOptions: {
|
|
623
736
|
input, preserveEntrySignatures: 'strict',
|
|
624
737
|
output: { format: 'es', entryFileNames: '[name].js', chunkFileNames: 'chunks/[name]-[hash].js', assetFileNames: 'assets/[name]-[hash][extname]' },
|
|
@@ -655,7 +768,8 @@ function resolveConnectPackageJson(root = process.cwd()) {
|
|
|
655
768
|
*/
|
|
656
769
|
function resolveConnectBundle(root = process.cwd()) {
|
|
657
770
|
const connectIndexPath = resolvePackage("@powerhousedao/connect", root);
|
|
658
|
-
|
|
771
|
+
const connectRootPath = connectIndexPath.substring(0, connectIndexPath.indexOf("connect") + 7);
|
|
772
|
+
return join(connectRootPath, "dist/");
|
|
659
773
|
}
|
|
660
774
|
function resolveConnectPublicDir(root = process.cwd()) {
|
|
661
775
|
const connectIconPath = resolvePackage("@powerhousedao/connect/public/icon.ico", root);
|
|
@@ -1002,7 +1116,7 @@ async function devReactImportmapPlugin(projectRoot = process.cwd()) {
|
|
|
1002
1116
|
REACT_DEPS.forEach((d) => include.add(d));
|
|
1003
1117
|
if (vendorActive) {
|
|
1004
1118
|
HEAVY_LIBS.forEach((d) => include.delete(d));
|
|
1005
|
-
cfg.optimizeDeps.exclude = [
|
|
1119
|
+
cfg.optimizeDeps.exclude = [.../* @__PURE__ */ new Set([...cfg.optimizeDeps.exclude ?? [], ...HEAVY_LIBS])];
|
|
1006
1120
|
}
|
|
1007
1121
|
cfg.optimizeDeps.include = [...include];
|
|
1008
1122
|
},
|
|
@@ -1118,7 +1232,7 @@ function connectFaviconPlugin(opts = {}) {
|
|
|
1118
1232
|
res.end(readFileSync(resolved.id));
|
|
1119
1233
|
}).catch(() => next());
|
|
1120
1234
|
};
|
|
1121
|
-
const paths = new Set([faviconRoute, "/icon.ico"]);
|
|
1235
|
+
const paths = /* @__PURE__ */ new Set([faviconRoute, "/icon.ico"]);
|
|
1122
1236
|
for (const path of paths) server.middlewares.use(path, handler);
|
|
1123
1237
|
},
|
|
1124
1238
|
async generateBundle(_options, bundle) {
|
|
@@ -1158,13 +1272,17 @@ function readProjectPackageInfo(projectRoot) {
|
|
|
1158
1272
|
}
|
|
1159
1273
|
function phConfigPlugin(options) {
|
|
1160
1274
|
const localPackage = readProjectPackageInfo(options.projectRoot ?? process.cwd());
|
|
1161
|
-
const withDefaults =
|
|
1275
|
+
const withDefaults = resolveSourceConnect({
|
|
1276
|
+
connect: options.connect,
|
|
1277
|
+
workflows: options.workflows
|
|
1278
|
+
});
|
|
1162
1279
|
const mergedConnect = options.cliConnectOverride ? deepMerge(withDefaults, options.cliConnectOverride) : withDefaults;
|
|
1163
|
-
const
|
|
1280
|
+
const source = {
|
|
1164
1281
|
packages: options.packages,
|
|
1165
1282
|
packageRegistryUrl: options.packageRegistryUrl,
|
|
1166
1283
|
connect: mergedConnect
|
|
1167
|
-
}
|
|
1284
|
+
};
|
|
1285
|
+
const runtimeConfig = buildRuntimeConfig(source, localPackage);
|
|
1168
1286
|
const content = JSON.stringify({
|
|
1169
1287
|
$schema: RUNTIME_CONFIG_SCHEMA_URL,
|
|
1170
1288
|
...runtimeConfig
|
|
@@ -1217,11 +1335,13 @@ function toPwaContribution(manifest, fallbackLabel, onWarn) {
|
|
|
1217
1335
|
if (!isPlainObject(manifest)) return null;
|
|
1218
1336
|
const label = typeof manifest.name === "string" && manifest.name ? manifest.name : fallbackLabel;
|
|
1219
1337
|
let config = {};
|
|
1220
|
-
if (manifest.pwa !== void 0)
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1338
|
+
if (manifest.pwa !== void 0) {
|
|
1339
|
+
if (!isPlainObject(manifest.pwa)) onWarn(`PWA config: ${label} declares a non-object 'pwa' field in its manifest; ignored.`);
|
|
1340
|
+
else {
|
|
1341
|
+
const parsed = PwaConfigSchema.safeParse(manifest.pwa);
|
|
1342
|
+
if (!parsed.success) onWarn(`PWA config: ${label}'s pwa fragment is invalid; ignored. ${formatZodIssues(parsed.error)}`);
|
|
1343
|
+
else config = parsed.data;
|
|
1344
|
+
}
|
|
1225
1345
|
}
|
|
1226
1346
|
config = withInferredCategory(config, manifest.category);
|
|
1227
1347
|
if (Object.keys(config).length === 0) return null;
|
|
@@ -1330,7 +1450,8 @@ function collectProjectPwaContribution(options) {
|
|
|
1330
1450
|
}
|
|
1331
1451
|
if (!isPlainObject(manifest)) return null;
|
|
1332
1452
|
const label = typeof manifest.name === "string" && manifest.name ? manifest.name : "project manifest";
|
|
1333
|
-
const
|
|
1453
|
+
const config = manifest.pwa === void 0 ? {} : parsePwaConfigStrict(manifest.pwa, `pwa in ${manifestPath}`);
|
|
1454
|
+
const withCategory = withInferredCategory(config, manifest.category);
|
|
1334
1455
|
if (Object.keys(withCategory).length === 0) return null;
|
|
1335
1456
|
return {
|
|
1336
1457
|
source: label,
|
|
@@ -1471,7 +1592,7 @@ const BASE_MANIFEST = {
|
|
|
1471
1592
|
* declarative runtimeCaching option.
|
|
1472
1593
|
*/
|
|
1473
1594
|
const BASE_PRECACHE = {
|
|
1474
|
-
maximumFileSizeToCacheInBytes:
|
|
1595
|
+
maximumFileSizeToCacheInBytes: 16777216,
|
|
1475
1596
|
globPatterns: ["**/*.{js,css,html,wasm,data,ico,png,svg,webp,woff,woff2}"],
|
|
1476
1597
|
globIgnores: [
|
|
1477
1598
|
"**/powerhouse.config.json",
|
|
@@ -1776,6 +1897,48 @@ function connectThemeBootPlugin() {
|
|
|
1776
1897
|
};
|
|
1777
1898
|
}
|
|
1778
1899
|
//#endregion
|
|
1900
|
+
//#region connect-utils/vite-plugins/vendor-import-map.ts
|
|
1901
|
+
function extractImports(raw) {
|
|
1902
|
+
if (typeof raw !== "object" || raw === null) return {};
|
|
1903
|
+
const imports = "imports" in raw ? raw.imports : void 0;
|
|
1904
|
+
if (typeof imports !== "object" || imports === null) return {};
|
|
1905
|
+
const out = {};
|
|
1906
|
+
for (const [key, value] of Object.entries(imports)) if (typeof value === "string") out[key] = value;
|
|
1907
|
+
return out;
|
|
1908
|
+
}
|
|
1909
|
+
function parseImportMap(raw) {
|
|
1910
|
+
try {
|
|
1911
|
+
return extractImports(JSON.parse(raw));
|
|
1912
|
+
} catch {
|
|
1913
|
+
return {};
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1916
|
+
const INLINE_IMPORTMAP = /<script type="importmap">([\s\S]*?)<\/script>/;
|
|
1917
|
+
function vendorImportMapPlugin(options) {
|
|
1918
|
+
const vendorEntries = Object.keys(options.imports).length;
|
|
1919
|
+
return {
|
|
1920
|
+
name: "ph-vendor-import-map",
|
|
1921
|
+
apply: "build",
|
|
1922
|
+
transformIndexHtml(html) {
|
|
1923
|
+
if (!vendorEntries) return;
|
|
1924
|
+
const match = INLINE_IMPORTMAP.exec(html);
|
|
1925
|
+
if (match) {
|
|
1926
|
+
const merged = { imports: {
|
|
1927
|
+
...parseImportMap(match[1]),
|
|
1928
|
+
...options.imports
|
|
1929
|
+
} };
|
|
1930
|
+
return html.replace(INLINE_IMPORTMAP, `<script type="importmap">${JSON.stringify(merged)}<\/script>`);
|
|
1931
|
+
}
|
|
1932
|
+
return [{
|
|
1933
|
+
tag: "script",
|
|
1934
|
+
attrs: { type: "importmap" },
|
|
1935
|
+
children: JSON.stringify({ imports: options.imports }),
|
|
1936
|
+
injectTo: "head-prepend"
|
|
1937
|
+
}];
|
|
1938
|
+
}
|
|
1939
|
+
};
|
|
1940
|
+
}
|
|
1941
|
+
//#endregion
|
|
1779
1942
|
//#region connect-utils/vite-config.ts
|
|
1780
1943
|
function getConnectHtmlTags(options = {}) {
|
|
1781
1944
|
const { registryUrl, injectTo = "head" } = options;
|
|
@@ -1896,7 +2059,8 @@ function getLocalPackageNamesFromPowerhouseConfig({ packages }) {
|
|
|
1896
2059
|
}
|
|
1897
2060
|
function getConnectBaseViteConfig(options) {
|
|
1898
2061
|
const mode = options.mode;
|
|
1899
|
-
const
|
|
2062
|
+
const envDir = options.envDir ?? options.dirname;
|
|
2063
|
+
const fileEnv = loadEnv(mode, envDir, "PH_");
|
|
1900
2064
|
const env = loadConnectEnv({
|
|
1901
2065
|
processEnv: process.env,
|
|
1902
2066
|
fileEnv
|
|
@@ -1968,9 +2132,10 @@ function getConnectBaseViteConfig(options) {
|
|
|
1968
2132
|
});
|
|
1969
2133
|
const projectContribution = collectProjectPwaContribution({ projectRoot: options.dirname });
|
|
1970
2134
|
if (projectContribution) contributions.push(projectContribution);
|
|
2135
|
+
const mergedPwa = mergePwaConfig(contributions, projectPwa, pwaWarn);
|
|
1971
2136
|
return connectPwaPlugins({
|
|
1972
2137
|
offlineEnabled,
|
|
1973
|
-
pwa:
|
|
2138
|
+
pwa: mergedPwa
|
|
1974
2139
|
});
|
|
1975
2140
|
})();
|
|
1976
2141
|
const reactExternal = [
|
|
@@ -2023,6 +2188,7 @@ function getConnectBaseViteConfig(options) {
|
|
|
2023
2188
|
packages: phPackages,
|
|
2024
2189
|
projectRoot: options.dirname,
|
|
2025
2190
|
connect: phConfig.connect,
|
|
2191
|
+
workflows: phConfig.workflows,
|
|
2026
2192
|
packageRegistryUrl: phPackageRegistryUrl ?? void 0,
|
|
2027
2193
|
cliConnectOverride: options.cliConnectOverride
|
|
2028
2194
|
}),
|
|
@@ -2032,11 +2198,12 @@ function getConnectBaseViteConfig(options) {
|
|
|
2032
2198
|
}),
|
|
2033
2199
|
devReactImportmapPlugin(options.dirname),
|
|
2034
2200
|
...plugins,
|
|
2035
|
-
esmExternalRequirePlugin({ external: reactExternal }),
|
|
2201
|
+
esmExternalRequirePlugin({ external: [...reactExternal, ...options.vendor && mode === "production" ? Object.keys(options.vendor.imports) : []] }),
|
|
2036
2202
|
reactSelfHostPlugin({
|
|
2037
2203
|
dirname: options.dirname,
|
|
2038
2204
|
dev: mode !== "production" || isDebug
|
|
2039
2205
|
}),
|
|
2206
|
+
...options.vendor && mode === "production" ? [vendorImportMapPlugin({ imports: options.vendor.imports })] : [],
|
|
2040
2207
|
connectFaviconPlugin({ faviconPath: options.favicon }),
|
|
2041
2208
|
connectThemeBootPlugin(),
|
|
2042
2209
|
connectBuildHashPlugin(buildHash),
|
|
@@ -2047,10 +2214,13 @@ function getConnectBaseViteConfig(options) {
|
|
|
2047
2214
|
format: "es",
|
|
2048
2215
|
...options.dynamicBase ? { plugins: () => [connectDynamicBasePlugin({ forWorker: true })] } : {}
|
|
2049
2216
|
},
|
|
2050
|
-
build: {
|
|
2217
|
+
build: {
|
|
2218
|
+
sourcemap: true,
|
|
2219
|
+
rolldownOptions: { shimMissingExports: true }
|
|
2220
|
+
}
|
|
2051
2221
|
};
|
|
2052
2222
|
}
|
|
2053
2223
|
//#endregion
|
|
2054
|
-
export { BUILD_HASH_FILE, DEFAULT_CONNECT_OUTDIR, DEFAULT_VENDOR_INCLUDE, DYNAMIC_BASE_PLACEHOLDER, EXTERNAL_PACKAGES_IMPORT, IMPORT_SCRIPT_FILE, LOCAL_PACKAGE_ID, PH_DIR_NAME, RUNTIME_CONFIG_SCHEMA_ID, RUNTIME_CONFIG_SCHEMA_URL, THEME_BOOT_MARKER, VENDOR_EXTERNAL, VENDOR_URL_PREFIX, appendToHtmlHead, backupIndexHtml, buildHashFromBuildOptions, computeBuildHash, connectBuildHashPlugin, connectDynamicBasePlugin, connectThemeBootPlugin, copyConnect, ensureNodeVersion, escapeForRegExp, getConnectBaseViteConfig, getConnectHtmlTags, makeImportScriptFromPackages, phConfigPlugin, prebuildConnectVendor, prependToHtmlHead, readJsonFile, removeBase64EnvValues, resolveConnectBundle, resolveConnectPackageJson, resolveConnectPublicDir, resolvePackage, resolveViteConfigPath, runShellScriptPlugin, runTsc, runtimeConfigSchema, stripVersionFromPackage };
|
|
2224
|
+
export { BUILD_HASH_FILE, DEFAULT_CONNECT_OUTDIR, DEFAULT_VENDOR_INCLUDE, DYNAMIC_BASE_PLACEHOLDER, EXTERNAL_PACKAGES_IMPORT, IMPORT_SCRIPT_FILE, LOCAL_PACKAGE_ID, PH_DIR_NAME, RUNTIME_CONFIG_SCHEMA_ID, RUNTIME_CONFIG_SCHEMA_URL, THEME_BOOT_MARKER, VENDOR_EXTERNAL, VENDOR_URL_PREFIX, appendToHtmlHead, backupIndexHtml, buildHashFromBuildOptions, computeBuildHash, connectBuildHashPlugin, connectDynamicBasePlugin, connectThemeBootPlugin, copyConnect, ensureNodeVersion, escapeForRegExp, getConnectBaseViteConfig, getConnectHtmlTags, makeImportScriptFromPackages, missingVendorEntries, phConfigPlugin, prebuildConnectVendor, prependToHtmlHead, readJsonFile, removeBase64EnvValues, resolveConnectBundle, resolveConnectPackageJson, resolveConnectPublicDir, resolvePackage, resolveViteConfigPath, runShellScriptPlugin, runTsc, runtimeConfigSchema, stripVersionFromPackage, vendorImportMapPlugin, withVendorBase };
|
|
2055
2225
|
|
|
2056
2226
|
//# sourceMappingURL=index.mjs.map
|