@ionify/ionify 0.1.2 → 0.1.4
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 +2 -2
- package/dist/{cache-Y4NMRSZO.js → cache-LH24ZR2B.js} +1 -1
- package/dist/{chunk-GOZUBOYH.js → chunk-QQSYYX7B.js} +3 -0
- package/dist/cli/index.cjs +1544 -283
- package/dist/cli/index.js +1532 -282
- package/dist/client/hmr.js +39 -3
- package/dist/client/overlay.js +140 -25
- package/dist/client/react-refresh-runtime.js +57 -9
- package/dist/index.d.cts +71 -0
- package/dist/index.d.ts +71 -0
- package/dist/ionify_core.node +0 -0
- package/package.json +3 -2
package/dist/cli/index.cjs
CHANGED
|
@@ -30,12 +30,12 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
30
30
|
mod
|
|
31
31
|
));
|
|
32
32
|
|
|
33
|
-
// node_modules/.pnpm/tsup@8.5.
|
|
33
|
+
// node_modules/.pnpm/tsup@8.5.0_@swc+core@1.13.5_jiti@1.21.7_postcss@8.5.6_tsx@4.20.6_typescript@5.9.3_yaml@2.8.1/node_modules/tsup/assets/cjs_shims.js
|
|
34
34
|
var getImportMetaUrl, importMetaUrl;
|
|
35
35
|
var init_cjs_shims = __esm({
|
|
36
|
-
"node_modules/.pnpm/tsup@8.5.
|
|
36
|
+
"node_modules/.pnpm/tsup@8.5.0_@swc+core@1.13.5_jiti@1.21.7_postcss@8.5.6_tsx@4.20.6_typescript@5.9.3_yaml@2.8.1/node_modules/tsup/assets/cjs_shims.js"() {
|
|
37
37
|
"use strict";
|
|
38
|
-
getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.
|
|
38
|
+
getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.src || new URL("main.js", document.baseURI).href;
|
|
39
39
|
importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
40
40
|
}
|
|
41
41
|
});
|
|
@@ -170,6 +170,9 @@ function tryNativeTransform(mode, code, options) {
|
|
|
170
170
|
if (mode === "swc") throw err;
|
|
171
171
|
}
|
|
172
172
|
}
|
|
173
|
+
if (options.filename?.includes("Counter.jsx")) {
|
|
174
|
+
console.log("[TASK1 DEBUG] \u26A0\uFE0F No native transform available, returning null");
|
|
175
|
+
}
|
|
173
176
|
return null;
|
|
174
177
|
}
|
|
175
178
|
function ensureNativeGraph(graphPath, version) {
|
|
@@ -305,7 +308,7 @@ var import_chalk = __toESM(require("chalk"), 1);
|
|
|
305
308
|
function logInfo(message) {
|
|
306
309
|
console.log(import_chalk.default.cyan(`[Ionify] ${message}`));
|
|
307
310
|
}
|
|
308
|
-
function
|
|
311
|
+
function logWarn2(message) {
|
|
309
312
|
console.warn(import_chalk.default.yellow(`[Ionify] ${message}`));
|
|
310
313
|
}
|
|
311
314
|
function logError(message, err) {
|
|
@@ -317,8 +320,8 @@ function logError(message, err) {
|
|
|
317
320
|
init_cjs_shims();
|
|
318
321
|
var import_http = __toESM(require("http"), 1);
|
|
319
322
|
var import_url3 = __toESM(require("url"), 1);
|
|
320
|
-
var
|
|
321
|
-
var
|
|
323
|
+
var import_fs11 = __toESM(require("fs"), 1);
|
|
324
|
+
var import_path15 = __toESM(require("path"), 1);
|
|
322
325
|
var import_url4 = require("url");
|
|
323
326
|
var import_module3 = require("module");
|
|
324
327
|
init_cache();
|
|
@@ -738,9 +741,12 @@ function buildAliasEntries(aliases, baseDir) {
|
|
|
738
741
|
const entries = [];
|
|
739
742
|
for (const [pattern, value] of Object.entries(aliases)) {
|
|
740
743
|
const replacements = Array.isArray(value) ? value : [value];
|
|
741
|
-
const targets = replacements.filter((rep) => typeof rep === "string" && rep.trim().length > 0).map(
|
|
742
|
-
(rep
|
|
743
|
-
|
|
744
|
+
const targets = replacements.filter((rep) => typeof rep === "string" && rep.trim().length > 0).map((rep) => {
|
|
745
|
+
if (rep.startsWith("/")) {
|
|
746
|
+
return import_path4.default.resolve(baseDir, rep.slice(1));
|
|
747
|
+
}
|
|
748
|
+
return import_path4.default.isAbsolute(rep) ? rep : import_path4.default.resolve(baseDir, rep);
|
|
749
|
+
});
|
|
744
750
|
if (!targets.length) continue;
|
|
745
751
|
entries.push(createAliasEntry(pattern, targets));
|
|
746
752
|
}
|
|
@@ -771,20 +777,41 @@ function loadTsconfigAliases() {
|
|
|
771
777
|
return cachedTsconfigAliases;
|
|
772
778
|
}
|
|
773
779
|
function resolveFromEntries(entries, specifier) {
|
|
780
|
+
const debug = process.env.IONIFY_RESOLVE_DEBUG === "1";
|
|
774
781
|
for (const entry of entries) {
|
|
775
782
|
const candidates = entry.resolveCandidates(specifier);
|
|
783
|
+
if (debug && candidates.length > 0) {
|
|
784
|
+
console.log(`[RESOLVE] Candidates for ${specifier}:`, candidates);
|
|
785
|
+
}
|
|
776
786
|
for (const candidate of candidates) {
|
|
777
787
|
const resolved = tryWithExt(candidate);
|
|
778
|
-
if (resolved)
|
|
788
|
+
if (resolved) {
|
|
789
|
+
if (debug) console.log(`[RESOLVE] Found: ${resolved}`);
|
|
790
|
+
return resolved;
|
|
791
|
+
}
|
|
779
792
|
}
|
|
780
793
|
}
|
|
781
794
|
return null;
|
|
782
795
|
}
|
|
783
796
|
function resolveWithAliases(specifier) {
|
|
797
|
+
const debug = process.env.IONIFY_RESOLVE_DEBUG === "1";
|
|
798
|
+
if (debug) {
|
|
799
|
+
console.log(`[RESOLVE] Trying to resolve: ${specifier}`);
|
|
800
|
+
console.log(`[RESOLVE] Custom aliases count: ${customAliasEntries.length}`);
|
|
801
|
+
}
|
|
784
802
|
const custom = resolveFromEntries(customAliasEntries, specifier);
|
|
785
|
-
if (custom)
|
|
803
|
+
if (custom) {
|
|
804
|
+
if (debug) console.log(`[RESOLVE] \u2705 Resolved via custom alias: ${custom}`);
|
|
805
|
+
return custom;
|
|
806
|
+
}
|
|
786
807
|
const tsconfigEntries = loadTsconfigAliases();
|
|
787
|
-
|
|
808
|
+
if (debug) console.log(`[RESOLVE] Tsconfig aliases count: ${tsconfigEntries.length}`);
|
|
809
|
+
const result = resolveFromEntries(tsconfigEntries, specifier);
|
|
810
|
+
if (debug) {
|
|
811
|
+
if (result) console.log(`[RESOLVE] \u2705 Resolved via tsconfig: ${result}`);
|
|
812
|
+
else console.log(`[RESOLVE] \u274C Not resolved`);
|
|
813
|
+
}
|
|
814
|
+
return result;
|
|
788
815
|
}
|
|
789
816
|
function configureResolverAliases(aliases, baseDir) {
|
|
790
817
|
customAliasEntries = aliases ? buildAliasEntries(aliases, baseDir) : [];
|
|
@@ -855,12 +882,14 @@ function resolveImports(specs, importerAbs) {
|
|
|
855
882
|
init_cjs_shims();
|
|
856
883
|
var import_path5 = __toESM(require("path"), 1);
|
|
857
884
|
var import_fs5 = __toESM(require("fs"), 1);
|
|
885
|
+
init_native();
|
|
858
886
|
var DEFAULT_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".json", ".mjs"];
|
|
859
887
|
var DEFAULT_CONDITIONS = ["import", "default"];
|
|
860
888
|
var DEFAULT_MAIN_FIELDS = ["module", "main"];
|
|
861
889
|
var ModuleResolver = class {
|
|
862
890
|
options;
|
|
863
891
|
rootDir;
|
|
892
|
+
metadataByPath = /* @__PURE__ */ new Map();
|
|
864
893
|
constructor(rootDir, options = {}) {
|
|
865
894
|
this.rootDir = rootDir;
|
|
866
895
|
this.options = {
|
|
@@ -886,6 +915,9 @@ var ModuleResolver = class {
|
|
|
886
915
|
}
|
|
887
916
|
return this.resolveBareModule(importSpecifier, importer);
|
|
888
917
|
}
|
|
918
|
+
getMetadata(resolvedPath) {
|
|
919
|
+
return this.metadataByPath.get(resolvedPath);
|
|
920
|
+
}
|
|
889
921
|
resolveAlias(specifier) {
|
|
890
922
|
for (const [alias, target] of Object.entries(this.options.alias)) {
|
|
891
923
|
if (specifier === alias || specifier.startsWith(`${alias}/`)) {
|
|
@@ -926,6 +958,33 @@ var ModuleResolver = class {
|
|
|
926
958
|
return null;
|
|
927
959
|
}
|
|
928
960
|
resolveBareModule(specifier, importer) {
|
|
961
|
+
const nativeResolved = native?.resolveModule?.(specifier, importer);
|
|
962
|
+
if (nativeResolved?.kind) {
|
|
963
|
+
const fsPath = nativeResolved.fsPath ?? nativeResolved.fs_path ?? null;
|
|
964
|
+
const kind = normalizeResolveKind(nativeResolved.kind);
|
|
965
|
+
if (kind === "pkg_cjs") {
|
|
966
|
+
if (fsPath) {
|
|
967
|
+
this.metadataByPath.set(fsPath, {
|
|
968
|
+
format: "cjs",
|
|
969
|
+
needsInterop: true
|
|
970
|
+
});
|
|
971
|
+
}
|
|
972
|
+
if (process.env.IONIFY_DEBUG) {
|
|
973
|
+
const name = nativeResolved.pkg?.name ?? specifier;
|
|
974
|
+
console.log(`[resolver] CJS package detected: ${name} (conversion deferred)`);
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
if (kind === "pkg_esm" && fsPath) {
|
|
978
|
+
return fsPath;
|
|
979
|
+
}
|
|
980
|
+
if (kind === "pkg_cjs" && fsPath) {
|
|
981
|
+
return fsPath;
|
|
982
|
+
}
|
|
983
|
+
if (kind === "local" && fsPath) {
|
|
984
|
+
return fsPath;
|
|
985
|
+
}
|
|
986
|
+
return null;
|
|
987
|
+
}
|
|
929
988
|
const parts = specifier.split("/");
|
|
930
989
|
const packageName = parts[0].startsWith("@") ? `${parts[0]}/${parts[1]}` : parts[0];
|
|
931
990
|
const subpath = parts.slice(packageName.startsWith("@") ? 2 : 1).join("/");
|
|
@@ -1007,6 +1066,19 @@ var ModuleResolver = class {
|
|
|
1007
1066
|
return null;
|
|
1008
1067
|
}
|
|
1009
1068
|
};
|
|
1069
|
+
function normalizeResolveKind(kind) {
|
|
1070
|
+
const mapping = {
|
|
1071
|
+
PkgEsm: "pkg_esm",
|
|
1072
|
+
PkgCjs: "pkg_cjs",
|
|
1073
|
+
Builtin: "builtin",
|
|
1074
|
+
Virtual: "virtual",
|
|
1075
|
+
Local: "local"
|
|
1076
|
+
};
|
|
1077
|
+
if (kind in mapping) {
|
|
1078
|
+
return mapping[kind];
|
|
1079
|
+
}
|
|
1080
|
+
return kind.toLowerCase();
|
|
1081
|
+
}
|
|
1010
1082
|
|
|
1011
1083
|
// src/core/watcher.ts
|
|
1012
1084
|
init_cjs_shims();
|
|
@@ -1144,16 +1216,16 @@ var TransformEngine = class {
|
|
|
1144
1216
|
}
|
|
1145
1217
|
async run(ctx) {
|
|
1146
1218
|
const { getCacheKey: getCacheKey2 } = await Promise.resolve().then(() => (init_cache(), cache_exports));
|
|
1147
|
-
const
|
|
1148
|
-
const
|
|
1219
|
+
const path19 = await import("path");
|
|
1220
|
+
const fs15 = await import("fs");
|
|
1149
1221
|
const { getCasArtifactPath: getCasArtifactPath2 } = await Promise.resolve().then(() => (init_cas(), cas_exports));
|
|
1150
1222
|
const moduleHash = ctx.moduleHash || getCacheKey2(ctx.code);
|
|
1151
1223
|
const loaderSig = this.loaders.map((l) => l.name || "loader").join("|");
|
|
1152
1224
|
const loaderHash = getCacheKey2(loaderSig);
|
|
1153
1225
|
const memKey = `${moduleHash}-${loaderHash}`;
|
|
1154
1226
|
const casDir = this.casRoot && this.versionHash ? getCasArtifactPath2(this.casRoot, this.versionHash, moduleHash) : null;
|
|
1155
|
-
const casFile = casDir ?
|
|
1156
|
-
const casMapFile = casDir ?
|
|
1227
|
+
const casFile = casDir ? path19.join(casDir, "transformed.js") : null;
|
|
1228
|
+
const casMapFile = casDir ? path19.join(casDir, "transformed.js.map") : null;
|
|
1157
1229
|
const debug = process.env.IONIFY_DEV_TRANSFORM_CACHE_DEBUG === "1";
|
|
1158
1230
|
if (this.cacheEnabled) {
|
|
1159
1231
|
const memHit = transformCache.get(memKey);
|
|
@@ -1163,10 +1235,10 @@ var TransformEngine = class {
|
|
|
1163
1235
|
}
|
|
1164
1236
|
return { code: memHit.transformed, map: memHit.map };
|
|
1165
1237
|
}
|
|
1166
|
-
if (casFile &&
|
|
1238
|
+
if (casFile && fs15.existsSync(casFile)) {
|
|
1167
1239
|
try {
|
|
1168
|
-
const code =
|
|
1169
|
-
const map = casMapFile &&
|
|
1240
|
+
const code = fs15.readFileSync(casFile, "utf8");
|
|
1241
|
+
const map = casMapFile && fs15.existsSync(casMapFile) ? fs15.readFileSync(casMapFile, "utf8") : void 0;
|
|
1170
1242
|
const parsed = { code, map };
|
|
1171
1243
|
transformCache.set(memKey, {
|
|
1172
1244
|
hash: moduleHash,
|
|
@@ -1203,10 +1275,10 @@ var TransformEngine = class {
|
|
|
1203
1275
|
});
|
|
1204
1276
|
if (casFile) {
|
|
1205
1277
|
try {
|
|
1206
|
-
|
|
1207
|
-
|
|
1278
|
+
fs15.mkdirSync(path19.dirname(casFile), { recursive: true });
|
|
1279
|
+
fs15.writeFileSync(casFile, result.code, "utf8");
|
|
1208
1280
|
if (result.map && casMapFile) {
|
|
1209
|
-
|
|
1281
|
+
fs15.writeFileSync(casMapFile, typeof result.map === "string" ? result.map : JSON.stringify(result.map), "utf8");
|
|
1210
1282
|
}
|
|
1211
1283
|
} catch {
|
|
1212
1284
|
}
|
|
@@ -1345,17 +1417,6 @@ async function compileCss({
|
|
|
1345
1417
|
rootDir,
|
|
1346
1418
|
modules = false
|
|
1347
1419
|
}) {
|
|
1348
|
-
const loaderHash = getCacheKey(JSON.stringify({ modules, filePath: filePath.replace(/\\+/g, "/") }));
|
|
1349
|
-
const contentHash = getCacheKey(code);
|
|
1350
|
-
const cacheKey = `${contentHash}-${loaderHash}`;
|
|
1351
|
-
const cached = transformCache.get(cacheKey);
|
|
1352
|
-
if (cached) {
|
|
1353
|
-
try {
|
|
1354
|
-
const parsed = JSON.parse(cached.transformed);
|
|
1355
|
-
return parsed;
|
|
1356
|
-
} catch {
|
|
1357
|
-
}
|
|
1358
|
-
}
|
|
1359
1420
|
const { plugins, options } = await getPostcssConfig(rootDir);
|
|
1360
1421
|
const pipeline = [...plugins];
|
|
1361
1422
|
let tokens;
|
|
@@ -1380,16 +1441,34 @@ async function compileCss({
|
|
|
1380
1441
|
from: filePath,
|
|
1381
1442
|
map: false
|
|
1382
1443
|
});
|
|
1444
|
+
const deps = [];
|
|
1445
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1446
|
+
const addDep = (depPath) => {
|
|
1447
|
+
const normalized = depPath.replace(/\\+/g, "/");
|
|
1448
|
+
if (seen.has(normalized)) return;
|
|
1449
|
+
seen.add(normalized);
|
|
1450
|
+
deps.push({ filePath: depPath, kind: "dependency" });
|
|
1451
|
+
};
|
|
1452
|
+
for (const message of result.messages || []) {
|
|
1453
|
+
const anyMsg = message;
|
|
1454
|
+
if (anyMsg?.type === "dependency" && typeof anyMsg.file === "string") {
|
|
1455
|
+
addDep(anyMsg.file);
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
const importRe = /@import\s+(?:url\(\s*)?(?:'([^']+)'|"([^"]+)"|([^'"\s)]+))\s*\)?[^;]*;/gi;
|
|
1459
|
+
let match;
|
|
1460
|
+
while (match = importRe.exec(code)) {
|
|
1461
|
+
const spec = (match[1] || match[2] || match[3] || "").trim();
|
|
1462
|
+
if (!spec) continue;
|
|
1463
|
+
if (/^(data:|https?:|\/\/)/i.test(spec)) continue;
|
|
1464
|
+
const resolved = spec.startsWith("/") ? import_path8.default.resolve(rootDir, "." + spec) : import_path8.default.resolve(import_path8.default.dirname(filePath), spec);
|
|
1465
|
+
addDep(resolved);
|
|
1466
|
+
}
|
|
1383
1467
|
const compiled = {
|
|
1384
1468
|
css: result.css,
|
|
1385
|
-
tokens
|
|
1469
|
+
tokens,
|
|
1470
|
+
deps
|
|
1386
1471
|
};
|
|
1387
|
-
transformCache.set(cacheKey, {
|
|
1388
|
-
hash: contentHash,
|
|
1389
|
-
loaderHash,
|
|
1390
|
-
transformed: JSON.stringify(compiled),
|
|
1391
|
-
timestamp: Date.now()
|
|
1392
|
-
});
|
|
1393
1472
|
return compiled;
|
|
1394
1473
|
}
|
|
1395
1474
|
function renderCssModule({
|
|
@@ -1401,6 +1480,7 @@ function renderCssModule({
|
|
|
1401
1480
|
const styleId = `ionify-css-${getCacheKey(filePath).slice(0, 8)}`;
|
|
1402
1481
|
const tokensJson = tokens ? JSON.stringify(tokens) : "null";
|
|
1403
1482
|
return `
|
|
1483
|
+
// ionify:css
|
|
1404
1484
|
const cssText = ${cssJson};
|
|
1405
1485
|
const styleId = ${JSON.stringify(styleId)};
|
|
1406
1486
|
let style = document.querySelector(\`style[data-ionify-id="\${styleId}"]\`);
|
|
@@ -1423,6 +1503,22 @@ if (import.meta.hot) {
|
|
|
1423
1503
|
}
|
|
1424
1504
|
`.trim();
|
|
1425
1505
|
}
|
|
1506
|
+
function renderCssRawStringModule(cssText) {
|
|
1507
|
+
return `
|
|
1508
|
+
// ionify:css
|
|
1509
|
+
const css = ${JSON.stringify(cssText)};
|
|
1510
|
+
export { css };
|
|
1511
|
+
export default css;
|
|
1512
|
+
`.trim();
|
|
1513
|
+
}
|
|
1514
|
+
function renderCssUrlModule(url2) {
|
|
1515
|
+
return `
|
|
1516
|
+
// ionify:css
|
|
1517
|
+
const url = ${JSON.stringify(url2)};
|
|
1518
|
+
export { url };
|
|
1519
|
+
export default url;
|
|
1520
|
+
`.trim();
|
|
1521
|
+
}
|
|
1426
1522
|
|
|
1427
1523
|
// src/core/loaders/asset.ts
|
|
1428
1524
|
init_cjs_shims();
|
|
@@ -1524,17 +1620,354 @@ init_cjs_shims();
|
|
|
1524
1620
|
var import_core = require("@swc/core");
|
|
1525
1621
|
var import_es_module_lexer = require("es-module-lexer");
|
|
1526
1622
|
init_native();
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1623
|
+
|
|
1624
|
+
// src/core/deps/registry.ts
|
|
1625
|
+
init_cjs_shims();
|
|
1626
|
+
var import_crypto3 = __toESM(require("crypto"), 1);
|
|
1627
|
+
var import_fs7 = __toESM(require("fs"), 1);
|
|
1628
|
+
var import_path10 = __toESM(require("path"), 1);
|
|
1629
|
+
var registry = /* @__PURE__ */ new Map();
|
|
1630
|
+
function computeStableDepFileName(options) {
|
|
1631
|
+
const pkgName = sanitizePackageName(options.packageName);
|
|
1632
|
+
const pkgVersion = options.packageVersion || "0.0.0";
|
|
1633
|
+
const subpath = normalizeSubpath(options.subpath);
|
|
1634
|
+
let canonicalPath = options.entryPath;
|
|
1635
|
+
try {
|
|
1636
|
+
canonicalPath = import_fs7.default.realpathSync(options.entryPath);
|
|
1637
|
+
} catch {
|
|
1638
|
+
}
|
|
1639
|
+
const hash = import_crypto3.default.createHash("sha256").update(canonicalPath).digest("hex").slice(0, 6);
|
|
1640
|
+
const subpathSuffix = subpath ? `__${subpath}` : "";
|
|
1641
|
+
return `${pkgName}@${pkgVersion}${subpathSuffix}_${hash}.js`;
|
|
1642
|
+
}
|
|
1643
|
+
function registerDepEntry(entry) {
|
|
1644
|
+
const fileName = computeStableDepFileName({
|
|
1645
|
+
entryPath: entry.entryPath,
|
|
1646
|
+
packageName: entry.packageName,
|
|
1647
|
+
packageVersion: entry.packageVersion,
|
|
1648
|
+
subpath: entry.subpath
|
|
1649
|
+
});
|
|
1650
|
+
const existing = registry.get(fileName);
|
|
1651
|
+
if (existing) {
|
|
1652
|
+
return existing;
|
|
1653
|
+
}
|
|
1654
|
+
const record = { ...entry, fileName };
|
|
1655
|
+
registry.set(fileName, record);
|
|
1656
|
+
return record;
|
|
1657
|
+
}
|
|
1658
|
+
function getDepEntry(fileName) {
|
|
1659
|
+
return registry.get(fileName);
|
|
1660
|
+
}
|
|
1661
|
+
function computeSubpathFromEntryPath(entryPath) {
|
|
1662
|
+
const packageRoot = findPackageRoot(entryPath);
|
|
1663
|
+
if (!packageRoot) {
|
|
1664
|
+
if (process.env.DEBUG_DEPS) {
|
|
1665
|
+
console.log(`[computeSubpathFromEntryPath] No package root for: ${entryPath}`);
|
|
1666
|
+
}
|
|
1667
|
+
return "";
|
|
1668
|
+
}
|
|
1669
|
+
let rel = import_path10.default.relative(packageRoot, entryPath).replace(/\\/g, "/");
|
|
1670
|
+
const extIndex = rel.lastIndexOf(".");
|
|
1671
|
+
if (extIndex !== -1) {
|
|
1672
|
+
rel = rel.substring(0, extIndex);
|
|
1673
|
+
}
|
|
1674
|
+
if (rel.endsWith("/index")) {
|
|
1675
|
+
rel = rel.substring(0, rel.length - "/index".length);
|
|
1676
|
+
}
|
|
1677
|
+
const pkgName = import_path10.default.basename(packageRoot);
|
|
1678
|
+
if (process.env.DEBUG_DEPS) {
|
|
1679
|
+
console.log(`[subpath] entry: ${import_path10.default.basename(entryPath)}, root: ${pkgName}, rel: "${rel}", isMain: ${rel === pkgName}`);
|
|
1680
|
+
}
|
|
1681
|
+
if (rel === pkgName || rel === "index" || rel === "" || rel === ".") {
|
|
1682
|
+
return "";
|
|
1683
|
+
}
|
|
1684
|
+
return rel || "";
|
|
1685
|
+
}
|
|
1686
|
+
function findPackageRoot(entryPath) {
|
|
1687
|
+
let currentDir = import_path10.default.dirname(entryPath);
|
|
1688
|
+
let previousDir = entryPath;
|
|
1689
|
+
while (currentDir && currentDir !== previousDir) {
|
|
1690
|
+
const parent = import_path10.default.dirname(currentDir);
|
|
1691
|
+
const grandparent = import_path10.default.dirname(parent);
|
|
1692
|
+
if (import_path10.default.basename(parent) === "node_modules") {
|
|
1693
|
+
const pkgJsonPath = import_path10.default.join(currentDir, "package.json");
|
|
1694
|
+
if (import_fs7.default.existsSync(pkgJsonPath)) {
|
|
1695
|
+
return currentDir;
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
if (import_path10.default.basename(grandparent) === "node_modules" && import_path10.default.basename(parent).startsWith("@")) {
|
|
1699
|
+
const pkgJsonPath = import_path10.default.join(currentDir, "package.json");
|
|
1700
|
+
if (import_fs7.default.existsSync(pkgJsonPath)) {
|
|
1701
|
+
return currentDir;
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1704
|
+
previousDir = currentDir;
|
|
1705
|
+
currentDir = parent;
|
|
1706
|
+
}
|
|
1707
|
+
return null;
|
|
1708
|
+
}
|
|
1709
|
+
function sanitizePackageName(name) {
|
|
1710
|
+
return name.replace(/^@/, "").replace(/\//g, "__");
|
|
1711
|
+
}
|
|
1712
|
+
function normalizeSubpath(subpath) {
|
|
1713
|
+
if (!subpath) return "";
|
|
1714
|
+
const cleaned = subpath.replace(/^\.\//, "").replace(/^\//, "");
|
|
1715
|
+
if (!cleaned || cleaned === "." || cleaned === "index") return "";
|
|
1716
|
+
return cleaned.replace(/\//g, "__");
|
|
1717
|
+
}
|
|
1718
|
+
|
|
1719
|
+
// src/core/refresh/reactRefreshInstrumentation.ts
|
|
1720
|
+
init_cjs_shims();
|
|
1721
|
+
function isPascalCaseIdentifier(name) {
|
|
1722
|
+
return /^[A-Z][A-Za-z0-9_$]*$/.test(name);
|
|
1723
|
+
}
|
|
1724
|
+
function hasRefreshRegistrationsAlready(code) {
|
|
1725
|
+
return /\$RefreshReg\$/.test(code);
|
|
1726
|
+
}
|
|
1727
|
+
function dedupeByExportName(items) {
|
|
1728
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1729
|
+
const out = [];
|
|
1730
|
+
for (const it of items) {
|
|
1731
|
+
const key = `${it.exportName}::${it.localName}`;
|
|
1732
|
+
if (seen.has(key)) continue;
|
|
1733
|
+
seen.add(key);
|
|
1734
|
+
out.push(it);
|
|
1735
|
+
}
|
|
1736
|
+
return out;
|
|
1737
|
+
}
|
|
1738
|
+
function detectRefreshBoundaryExports(code) {
|
|
1739
|
+
const out = [];
|
|
1740
|
+
function isValidIdentifier(name) {
|
|
1741
|
+
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name);
|
|
1742
|
+
}
|
|
1743
|
+
{
|
|
1744
|
+
const re = /export\s+(?:async\s+)?function\s+([A-Z][A-Za-z0-9_$]*)\s*\(/g;
|
|
1745
|
+
let m;
|
|
1746
|
+
while (m = re.exec(code)) {
|
|
1747
|
+
const name = m[1];
|
|
1748
|
+
out.push({ exportName: name, localName: name });
|
|
1749
|
+
}
|
|
1750
|
+
}
|
|
1751
|
+
{
|
|
1752
|
+
const re = /export\s+(?:const|let)\s+([A-Z][A-Za-z0-9_$]*)\s*=\s*(?:async\s*)?(?:function\b|\([^)]*\)\s*=>|[A-Za-z_$][A-Za-z0-9_$]*\s*=>)/g;
|
|
1753
|
+
let m;
|
|
1754
|
+
while (m = re.exec(code)) {
|
|
1755
|
+
const name = m[1];
|
|
1756
|
+
out.push({ exportName: name, localName: name });
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
{
|
|
1760
|
+
const re = /export\s+default\s+(?:async\s+)?function\s+([A-Za-z_$][A-Za-z0-9_$]*)\b/g;
|
|
1761
|
+
const m = re.exec(code);
|
|
1762
|
+
if (m?.[1]) {
|
|
1763
|
+
const local = m[1];
|
|
1764
|
+
if (isPascalCaseIdentifier(local)) {
|
|
1765
|
+
out.push({ exportName: "default", localName: local });
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1769
|
+
{
|
|
1770
|
+
const re = /export\s+default\s+([A-Za-z_$][A-Za-z0-9_$]*)\s*;?/g;
|
|
1771
|
+
let m;
|
|
1772
|
+
while (m = re.exec(code)) {
|
|
1773
|
+
const local = m[1];
|
|
1774
|
+
if (local === "function" || local === "class") continue;
|
|
1775
|
+
if (isPascalCaseIdentifier(local)) {
|
|
1776
|
+
out.push({ exportName: "default", localName: local });
|
|
1777
|
+
}
|
|
1778
|
+
}
|
|
1779
|
+
}
|
|
1780
|
+
{
|
|
1781
|
+
const re = /export\s+(default\s+)?class\s+([A-Z][A-Za-z0-9_$]*)\b/g;
|
|
1782
|
+
let m;
|
|
1783
|
+
while (m = re.exec(code)) {
|
|
1784
|
+
const isDefault = Boolean(m[1]);
|
|
1785
|
+
const local = m[2];
|
|
1786
|
+
if (!isPascalCaseIdentifier(local)) continue;
|
|
1787
|
+
out.push({ exportName: isDefault ? "default" : local, localName: local });
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
{
|
|
1791
|
+
const re = /export\s+(?:const|let)\s+([A-Z][A-Za-z0-9_$]*)\s*=\s*class\b/g;
|
|
1792
|
+
let m;
|
|
1793
|
+
while (m = re.exec(code)) {
|
|
1794
|
+
const name = m[1];
|
|
1795
|
+
if (!isPascalCaseIdentifier(name)) continue;
|
|
1796
|
+
out.push({ exportName: name, localName: name });
|
|
1797
|
+
}
|
|
1798
|
+
}
|
|
1799
|
+
{
|
|
1800
|
+
const re = /export\s*{\s*([^}]+)\s*}\s*(?:from\s*(['"][^'"]+['"]))?\s*;?/g;
|
|
1801
|
+
let m;
|
|
1802
|
+
while (m = re.exec(code)) {
|
|
1803
|
+
const from = m[2];
|
|
1804
|
+
if (from) continue;
|
|
1805
|
+
const specList = m[1] ?? "";
|
|
1806
|
+
const parts = specList.split(",").map((p) => p.trim()).filter(Boolean);
|
|
1807
|
+
for (const part of parts) {
|
|
1808
|
+
if (part.startsWith("type ")) continue;
|
|
1809
|
+
const asMatch = part.split(/\s+as\s+/);
|
|
1810
|
+
const local = (asMatch[0] ?? "").trim();
|
|
1811
|
+
const exported = (asMatch[1] ?? local).trim();
|
|
1812
|
+
if (!local || !exported) continue;
|
|
1813
|
+
if (local === "default") continue;
|
|
1814
|
+
if (!isValidIdentifier(local) || !isValidIdentifier(exported)) continue;
|
|
1815
|
+
if (!isPascalCaseIdentifier(local)) continue;
|
|
1816
|
+
if (exported !== "default" && !isPascalCaseIdentifier(exported)) continue;
|
|
1817
|
+
out.push({ exportName: exported, localName: local });
|
|
1818
|
+
}
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
return dedupeByExportName(out);
|
|
1822
|
+
}
|
|
1823
|
+
async function buildReactRefreshRegistrations(code, _filePath) {
|
|
1824
|
+
if (hasRefreshRegistrationsAlready(code)) return "";
|
|
1825
|
+
const candidates = detectRefreshBoundaryExports(code);
|
|
1826
|
+
if (!candidates.length) return "";
|
|
1827
|
+
const lines = candidates.map(({ exportName, localName }) => {
|
|
1828
|
+
return `window.$RefreshReg$?.(${localName}, normalizeRefreshModuleId(import.meta.url) + ":" + ${JSON.stringify(exportName)});`;
|
|
1829
|
+
});
|
|
1830
|
+
return "\n" + lines.join("\n") + "\n";
|
|
1831
|
+
}
|
|
1832
|
+
function needsReactRefresh(ext, isDev) {
|
|
1833
|
+
if (!isDev) return false;
|
|
1834
|
+
return ext === ".jsx" || ext === ".tsx";
|
|
1835
|
+
}
|
|
1836
|
+
async function instrumentReactRefresh(options) {
|
|
1837
|
+
const { code, filePath, ext, isDev, isEntry = false } = options;
|
|
1838
|
+
if (!needsReactRefresh(ext, isDev)) {
|
|
1839
|
+
return { shouldInstrument: false, prologue: "", registrations: "", epilogue: "" };
|
|
1840
|
+
}
|
|
1841
|
+
const registrations = isEntry ? "" : await buildReactRefreshRegistrations(code, filePath);
|
|
1842
|
+
const prologue = `import { setupReactRefresh, normalizeRefreshModuleId } from "/__ionify_react_refresh.js";
|
|
1843
|
+
const __ionifyRefresh__ = setupReactRefresh(import.meta.hot ?? { accept() {}, dispose() {} }, normalizeRefreshModuleId(import.meta.url));
|
|
1844
|
+
`;
|
|
1845
|
+
const epilogue = `
|
|
1846
|
+
__ionifyRefresh__?.finalize?.();
|
|
1847
|
+
|
|
1848
|
+
if (import.meta.hot) {
|
|
1849
|
+
import.meta.hot.accept((newModule) => {
|
|
1850
|
+
__ionifyRefresh__?.refresh?.(newModule);
|
|
1851
|
+
});
|
|
1852
|
+
import.meta.hot.dispose(() => {
|
|
1853
|
+
__ionifyRefresh__?.dispose?.();
|
|
1854
|
+
});
|
|
1855
|
+
}
|
|
1856
|
+
`;
|
|
1857
|
+
return { shouldInstrument: true, prologue, registrations, epilogue };
|
|
1858
|
+
}
|
|
1859
|
+
|
|
1860
|
+
// src/core/refresh/entryDetection.ts
|
|
1861
|
+
init_cjs_shims();
|
|
1862
|
+
var import_path11 = __toESM(require("path"), 1);
|
|
1863
|
+
var ENTRY_PATTERNS = [
|
|
1864
|
+
/\/src\/main\.(tsx?|jsx?)$/,
|
|
1865
|
+
/\/src\/index\.(tsx?|jsx?)$/
|
|
1866
|
+
];
|
|
1867
|
+
function normalizePath(input) {
|
|
1868
|
+
const normalized = import_path11.default.normalize(input).replace(/\\/g, "/");
|
|
1869
|
+
return process.platform === "win32" ? normalized.toLowerCase() : normalized;
|
|
1870
|
+
}
|
|
1871
|
+
function isEntryModule(filePath, config) {
|
|
1872
|
+
const normalized = normalizePath(import_path11.default.resolve(filePath));
|
|
1873
|
+
if (config?.entry) {
|
|
1874
|
+
const root = config.root ?? process.cwd();
|
|
1875
|
+
const entries = Array.isArray(config.entry) ? config.entry : [config.entry];
|
|
1876
|
+
for (const entry of entries) {
|
|
1877
|
+
const resolvedEntry = import_path11.default.resolve(root, entry);
|
|
1878
|
+
const normalizedEntry = normalizePath(resolvedEntry);
|
|
1879
|
+
if (normalized === normalizedEntry) return true;
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1882
|
+
return ENTRY_PATTERNS.some((pattern) => pattern.test(normalized));
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1885
|
+
// src/core/refresh/refreshEligibility.ts
|
|
1886
|
+
init_cjs_shims();
|
|
1887
|
+
function containsJSX(code) {
|
|
1888
|
+
const sample = code.slice(0, 8 * 1024);
|
|
1889
|
+
if (sample.includes("React.createElement")) return true;
|
|
1890
|
+
if (/\bjsx(?:s)?\s*\(/.test(sample)) return true;
|
|
1891
|
+
if (sample.includes("<>") || sample.includes("</>")) return true;
|
|
1892
|
+
if (/<[A-Za-z][A-Za-z0-9.$_-]*\b[^>]*\/>/.test(sample)) return true;
|
|
1893
|
+
if (/<[A-Za-z][A-Za-z0-9.$_-]*\b[^>]*>/.test(sample) && /<\/[A-Za-z]/.test(sample)) {
|
|
1894
|
+
return true;
|
|
1895
|
+
}
|
|
1896
|
+
return false;
|
|
1897
|
+
}
|
|
1898
|
+
function shouldUseReactRefresh(options) {
|
|
1899
|
+
const { ext, code, isDev, config } = options;
|
|
1900
|
+
if (!isDev) return false;
|
|
1901
|
+
if (config?.fastRefresh === false) return false;
|
|
1902
|
+
if (ext === ".jsx" || ext === ".tsx") return containsJSX(code);
|
|
1903
|
+
if (ext === ".js" || ext === ".ts" || ext === ".mjs" || ext === ".mts") return containsJSX(code);
|
|
1531
1904
|
return false;
|
|
1532
1905
|
}
|
|
1906
|
+
|
|
1907
|
+
// src/core/loaders/js.ts
|
|
1908
|
+
var import_fs8 = __toESM(require("fs"), 1);
|
|
1909
|
+
var import_path12 = __toESM(require("path"), 1);
|
|
1910
|
+
var JS_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs", ".mts", ".cts"]);
|
|
1533
1911
|
function shouldTransform(ext, filePath) {
|
|
1534
1912
|
if (!JS_EXTENSIONS.has(ext)) return false;
|
|
1535
1913
|
if (filePath.endsWith(".d.ts")) return false;
|
|
1536
1914
|
return true;
|
|
1537
1915
|
}
|
|
1916
|
+
function computeSubpathForDep(fsPath, pkg) {
|
|
1917
|
+
const computed = computeSubpathFromEntryPath(fsPath);
|
|
1918
|
+
if (!computed && !import_fs8.default.existsSync(fsPath) && pkg && typeof pkg.subpath === "string") {
|
|
1919
|
+
const raw = pkg.subpath;
|
|
1920
|
+
const cleaned = raw.replace(/^\.\//, "").replace(/^\/+/, "");
|
|
1921
|
+
if (cleaned && cleaned !== "." && cleaned !== "index") {
|
|
1922
|
+
return cleaned;
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1925
|
+
if (process.env.DEBUG_DEPS) {
|
|
1926
|
+
console.log(`[computeSubpathForDep] fsPath: ${fsPath}`);
|
|
1927
|
+
console.log(`[computeSubpathForDep] pkg.name: ${pkg?.name}, pkg.subpath: ${pkg?.subpath}`);
|
|
1928
|
+
console.log(`[computeSubpathForDep] computed: "${computed}"`);
|
|
1929
|
+
}
|
|
1930
|
+
return computed || null;
|
|
1931
|
+
}
|
|
1932
|
+
function looksLikeCjsWrapperSource(source) {
|
|
1933
|
+
const sample = source.slice(0, 16 * 1024);
|
|
1934
|
+
return sample.includes("module.exports") || sample.includes("exports.") || sample.includes("Object.defineProperty(exports") || sample.includes("Object.defineProperty(module.exports") || sample.includes("require(") || sample.includes("require (");
|
|
1935
|
+
}
|
|
1936
|
+
function looksLikeEsmSource(source) {
|
|
1937
|
+
const sample = source.slice(0, 16 * 1024);
|
|
1938
|
+
return sample.includes("import ") || sample.includes("export ") || sample.includes("import{") || sample.includes("export{") || sample.includes("import(");
|
|
1939
|
+
}
|
|
1940
|
+
function findNearestPackageJson(filePath) {
|
|
1941
|
+
let current = import_path12.default.dirname(filePath);
|
|
1942
|
+
for (let i = 0; i < 25; i++) {
|
|
1943
|
+
const candidate = import_path12.default.join(current, "package.json");
|
|
1944
|
+
if (import_fs8.default.existsSync(candidate)) return candidate;
|
|
1945
|
+
const parent = import_path12.default.dirname(current);
|
|
1946
|
+
if (parent === current) break;
|
|
1947
|
+
current = parent;
|
|
1948
|
+
}
|
|
1949
|
+
return null;
|
|
1950
|
+
}
|
|
1951
|
+
function makeDepsProxyForFile(filePath, code) {
|
|
1952
|
+
if (!looksLikeCjsWrapperSource(code)) return null;
|
|
1953
|
+
const pkgJsonPath = findNearestPackageJson(filePath);
|
|
1954
|
+
if (!pkgJsonPath) return null;
|
|
1955
|
+
try {
|
|
1956
|
+
const pkg = JSON.parse(import_fs8.default.readFileSync(pkgJsonPath, "utf8"));
|
|
1957
|
+
const fileName = registerDepEntry({
|
|
1958
|
+
entryPath: filePath,
|
|
1959
|
+
packageName: pkg?.name ?? "dep",
|
|
1960
|
+
packageVersion: pkg?.version ?? "0.0.0",
|
|
1961
|
+
subpath: null
|
|
1962
|
+
}).fileName;
|
|
1963
|
+
return `import * as __ionify_dep__ from "/@deps/${fileName}";
|
|
1964
|
+
export default __ionify_dep__;
|
|
1965
|
+
export * from "/@deps/${fileName}";
|
|
1966
|
+
`;
|
|
1967
|
+
} catch {
|
|
1968
|
+
return null;
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1538
1971
|
async function swcTranspile(code, filePath, ext, reactRefresh) {
|
|
1539
1972
|
const isTypeScript = ext === ".ts" || ext === ".tsx";
|
|
1540
1973
|
const isTsx = ext === ".tsx";
|
|
@@ -1580,18 +2013,30 @@ var jsLoader = {
|
|
|
1580
2013
|
name: "js",
|
|
1581
2014
|
order: 0,
|
|
1582
2015
|
test: ({ ext, path: filePath }) => shouldTransform(ext, filePath),
|
|
1583
|
-
transform: async ({ path: filePath, code, ext }) => {
|
|
2016
|
+
transform: async ({ path: filePath, code, ext, config }) => {
|
|
1584
2017
|
const isNodeModules = filePath.includes("node_modules");
|
|
2018
|
+
const rewriteDebug = process.env.IONIFY_IMPORT_REWRITE_DEBUG === "1";
|
|
1585
2019
|
let output = code;
|
|
1586
2020
|
if (isNodeModules) {
|
|
1587
|
-
const
|
|
1588
|
-
if (
|
|
1589
|
-
output =
|
|
2021
|
+
const depsProxy = makeDepsProxyForFile(filePath, code);
|
|
2022
|
+
if (depsProxy) {
|
|
2023
|
+
output = depsProxy;
|
|
1590
2024
|
} else {
|
|
1591
|
-
|
|
2025
|
+
const shouldAttemptBundle = ext === ".cjs" || looksLikeCjsWrapperSource(code) || !looksLikeEsmSource(code) && ext !== ".mjs";
|
|
2026
|
+
if (shouldAttemptBundle) {
|
|
2027
|
+
const bundled = tryBundleNodeModule(filePath, code);
|
|
2028
|
+
if (bundled) {
|
|
2029
|
+
output = bundled;
|
|
2030
|
+
} else {
|
|
2031
|
+
output = code;
|
|
2032
|
+
}
|
|
2033
|
+
} else {
|
|
2034
|
+
output = code;
|
|
2035
|
+
}
|
|
1592
2036
|
}
|
|
1593
2037
|
} else {
|
|
1594
|
-
const
|
|
2038
|
+
const isDev = process.env.NODE_ENV !== "production";
|
|
2039
|
+
const reactRefresh = shouldUseReactRefresh({ ext, code, isDev, config });
|
|
1595
2040
|
const mode = currentMode();
|
|
1596
2041
|
const nativeResult = tryNativeTransform(mode, code, {
|
|
1597
2042
|
filename: filePath,
|
|
@@ -1605,22 +2050,29 @@ var jsLoader = {
|
|
|
1605
2050
|
output = await swcTranspile(code, filePath, ext, reactRefresh);
|
|
1606
2051
|
}
|
|
1607
2052
|
if (reactRefresh) {
|
|
1608
|
-
const
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
}
|
|
2053
|
+
const isEntry = isEntryModule(filePath, config ?? void 0);
|
|
2054
|
+
if (process.env.IONIFY_REFRESH_DEBUG === "1") {
|
|
2055
|
+
console.log(`[Refresh] ${filePath} \u2192 isEntry=${isEntry}, ext=${ext}`);
|
|
2056
|
+
}
|
|
2057
|
+
const result = await instrumentReactRefresh({
|
|
2058
|
+
code: output,
|
|
2059
|
+
filePath,
|
|
2060
|
+
ext,
|
|
2061
|
+
isDev,
|
|
2062
|
+
isEntry
|
|
2063
|
+
});
|
|
2064
|
+
if (process.env.IONIFY_REFRESH_DEBUG === "1") {
|
|
2065
|
+
console.log(
|
|
2066
|
+
`[Refresh] instrument=${result.shouldInstrument} ${filePath} \u2192 isEntry=${isEntry}`
|
|
2067
|
+
);
|
|
2068
|
+
}
|
|
2069
|
+
if (result.shouldInstrument) {
|
|
2070
|
+
output = result.prologue + output + result.registrations + result.epilogue;
|
|
2071
|
+
} else {
|
|
2072
|
+
output += `
|
|
2073
|
+
if (import.meta.hot) import.meta.hot.accept();
|
|
1622
2074
|
`;
|
|
1623
|
-
|
|
2075
|
+
}
|
|
1624
2076
|
} else {
|
|
1625
2077
|
output += `
|
|
1626
2078
|
if (import.meta.hot) {
|
|
@@ -1631,8 +2083,11 @@ if (import.meta.hot) {
|
|
|
1631
2083
|
}
|
|
1632
2084
|
await import_es_module_lexer.init;
|
|
1633
2085
|
const [imports] = (0, import_es_module_lexer.parse)(output);
|
|
2086
|
+
if (rewriteDebug && ext === ".mjs" && isNodeModules) {
|
|
2087
|
+
console.warn(`[Ionify][rewrite] scanning ${imports.length} import(s) in ${filePath}`);
|
|
2088
|
+
}
|
|
1634
2089
|
if (imports.length) {
|
|
1635
|
-
const rootDir = process.cwd();
|
|
2090
|
+
const rootDir = config?.root ? import_path12.default.resolve(config.root) : process.cwd();
|
|
1636
2091
|
let rewritten = "";
|
|
1637
2092
|
let lastIndex = 0;
|
|
1638
2093
|
let mutated = false;
|
|
@@ -1651,8 +2106,96 @@ if (import.meta.hot) {
|
|
|
1651
2106
|
pathPart = spec.slice(0, splitIndex);
|
|
1652
2107
|
suffix = spec.slice(splitIndex);
|
|
1653
2108
|
}
|
|
2109
|
+
const isBare = !pathPart.startsWith(".") && !pathPart.startsWith("/") && !pathPart.startsWith("http://") && !pathPart.startsWith("https://");
|
|
2110
|
+
if (isBare && native?.resolveModule) {
|
|
2111
|
+
const resolvedNative = native.resolveModule(pathPart, filePath);
|
|
2112
|
+
const kind = resolvedNative?.kind;
|
|
2113
|
+
const fsPath = resolvedNative?.fsPath ?? resolvedNative?.fs_path ?? null;
|
|
2114
|
+
if (kind === "PkgCjs" && fsPath) {
|
|
2115
|
+
const pkg = resolvedNative?.pkg;
|
|
2116
|
+
const fileName = registerDepEntry({
|
|
2117
|
+
entryPath: fsPath,
|
|
2118
|
+
packageName: pkg?.name ?? pathPart,
|
|
2119
|
+
packageVersion: pkg?.version ?? "0.0.0",
|
|
2120
|
+
subpath: computeSubpathForDep(fsPath, pkg)
|
|
2121
|
+
}).fileName;
|
|
2122
|
+
const replacement2 = `/@deps/${fileName}`;
|
|
2123
|
+
if (!mutated) {
|
|
2124
|
+
mutated = true;
|
|
2125
|
+
}
|
|
2126
|
+
if (record.t === 2) {
|
|
2127
|
+
rewritten += output.slice(lastIndex, record.s + 1);
|
|
2128
|
+
rewritten += replacement2;
|
|
2129
|
+
rewritten += output[record.e - 1];
|
|
2130
|
+
lastIndex = record.e;
|
|
2131
|
+
} else {
|
|
2132
|
+
rewritten += output.slice(lastIndex, record.s);
|
|
2133
|
+
rewritten += replacement2;
|
|
2134
|
+
lastIndex = record.e;
|
|
2135
|
+
}
|
|
2136
|
+
continue;
|
|
2137
|
+
}
|
|
2138
|
+
if (kind === "PkgEsm" && fsPath) {
|
|
2139
|
+
try {
|
|
2140
|
+
const resolvedCode = import_fs8.default.readFileSync(fsPath, "utf8");
|
|
2141
|
+
if (looksLikeCjsWrapperSource(resolvedCode)) {
|
|
2142
|
+
const pkg2 = resolvedNative?.pkg;
|
|
2143
|
+
const fileName2 = registerDepEntry({
|
|
2144
|
+
entryPath: fsPath,
|
|
2145
|
+
packageName: pkg2?.name ?? pathPart,
|
|
2146
|
+
packageVersion: pkg2?.version ?? "0.0.0",
|
|
2147
|
+
subpath: computeSubpathForDep(fsPath, pkg2)
|
|
2148
|
+
}).fileName;
|
|
2149
|
+
const replacement3 = `/@deps/${fileName2}`;
|
|
2150
|
+
if (!mutated) mutated = true;
|
|
2151
|
+
if (record.t === 2) {
|
|
2152
|
+
rewritten += output.slice(lastIndex, record.s + 1);
|
|
2153
|
+
rewritten += replacement3;
|
|
2154
|
+
rewritten += output[record.e - 1];
|
|
2155
|
+
lastIndex = record.e;
|
|
2156
|
+
} else {
|
|
2157
|
+
rewritten += output.slice(lastIndex, record.s);
|
|
2158
|
+
rewritten += replacement3;
|
|
2159
|
+
lastIndex = record.e;
|
|
2160
|
+
}
|
|
2161
|
+
continue;
|
|
2162
|
+
}
|
|
2163
|
+
} catch {
|
|
2164
|
+
}
|
|
2165
|
+
const pkg = resolvedNative?.pkg;
|
|
2166
|
+
const fileName = registerDepEntry({
|
|
2167
|
+
entryPath: fsPath,
|
|
2168
|
+
packageName: pkg?.name ?? pathPart,
|
|
2169
|
+
packageVersion: pkg?.version ?? "0.0.0",
|
|
2170
|
+
subpath: computeSubpathForDep(fsPath, pkg)
|
|
2171
|
+
}).fileName;
|
|
2172
|
+
const replacement2 = `/@deps/${fileName}`;
|
|
2173
|
+
if (!mutated) mutated = true;
|
|
2174
|
+
if (record.t === 2) {
|
|
2175
|
+
rewritten += output.slice(lastIndex, record.s + 1);
|
|
2176
|
+
rewritten += replacement2;
|
|
2177
|
+
rewritten += output[record.e - 1];
|
|
2178
|
+
lastIndex = record.e;
|
|
2179
|
+
} else {
|
|
2180
|
+
rewritten += output.slice(lastIndex, record.s);
|
|
2181
|
+
rewritten += replacement2;
|
|
2182
|
+
lastIndex = record.e;
|
|
2183
|
+
}
|
|
2184
|
+
continue;
|
|
2185
|
+
}
|
|
2186
|
+
if (kind === "Builtin" || kind === "Virtual") {
|
|
2187
|
+
continue;
|
|
2188
|
+
}
|
|
2189
|
+
}
|
|
1654
2190
|
const resolved = resolveImport(pathPart, filePath);
|
|
1655
|
-
if (!resolved)
|
|
2191
|
+
if (!resolved) {
|
|
2192
|
+
if (rewriteDebug) {
|
|
2193
|
+
console.warn(
|
|
2194
|
+
`[Ionify][rewrite] FAILED to resolve '${pathPart}' from '${filePath}'`
|
|
2195
|
+
);
|
|
2196
|
+
}
|
|
2197
|
+
continue;
|
|
2198
|
+
}
|
|
1656
2199
|
const resolvedExt = resolved.slice(resolved.lastIndexOf("."));
|
|
1657
2200
|
let augmentedSuffix = suffix;
|
|
1658
2201
|
if (resolvedExt === ".css" && !suffix) {
|
|
@@ -1696,6 +2239,11 @@ if (import.meta.hot) {
|
|
|
1696
2239
|
if (mutated) {
|
|
1697
2240
|
rewritten += output.slice(lastIndex);
|
|
1698
2241
|
output = rewritten;
|
|
2242
|
+
} else if (rewriteDebug && isNodeModules) {
|
|
2243
|
+
const sample = imports.slice(0, 8).map((r) => r.n).filter(Boolean).join(", ");
|
|
2244
|
+
console.warn(
|
|
2245
|
+
`[Ionify][rewrite] no rewrites applied for ${filePath}; first imports: ${sample}`
|
|
2246
|
+
);
|
|
1699
2247
|
}
|
|
1700
2248
|
}
|
|
1701
2249
|
return { code: output };
|
|
@@ -1703,12 +2251,12 @@ if (import.meta.hot) {
|
|
|
1703
2251
|
};
|
|
1704
2252
|
|
|
1705
2253
|
// src/core/loaders/registry.ts
|
|
1706
|
-
var
|
|
2254
|
+
var registry2 = /* @__PURE__ */ new Set();
|
|
1707
2255
|
function registerLoader(registration) {
|
|
1708
|
-
|
|
2256
|
+
registry2.add(registration);
|
|
1709
2257
|
}
|
|
1710
2258
|
async function applyRegisteredLoaders(engine, config) {
|
|
1711
|
-
for (const registration of
|
|
2259
|
+
for (const registration of registry2) {
|
|
1712
2260
|
await registration(engine, config ?? null);
|
|
1713
2261
|
}
|
|
1714
2262
|
if (config?.plugins) {
|
|
@@ -1720,9 +2268,8 @@ async function applyRegisteredLoaders(engine, config) {
|
|
|
1720
2268
|
}
|
|
1721
2269
|
if (plugin.setup) {
|
|
1722
2270
|
const context = {
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
}
|
|
2271
|
+
config: config ?? null,
|
|
2272
|
+
registerLoader: (loader) => engine.useLoader(loader)
|
|
1726
2273
|
};
|
|
1727
2274
|
await plugin.setup(context);
|
|
1728
2275
|
}
|
|
@@ -1740,8 +2287,8 @@ registerLoader((engine) => {
|
|
|
1740
2287
|
|
|
1741
2288
|
// src/cli/utils/config.ts
|
|
1742
2289
|
init_cjs_shims();
|
|
1743
|
-
var
|
|
1744
|
-
var
|
|
2290
|
+
var import_fs9 = __toESM(require("fs"), 1);
|
|
2291
|
+
var import_path13 = __toESM(require("path"), 1);
|
|
1745
2292
|
var import_url2 = require("url");
|
|
1746
2293
|
var import_esbuild = require("esbuild");
|
|
1747
2294
|
var CONFIG_BASENAMES = [
|
|
@@ -1754,7 +2301,7 @@ var CONFIG_BASENAMES = [
|
|
|
1754
2301
|
var cachedConfig2 = null;
|
|
1755
2302
|
var configLoaded = false;
|
|
1756
2303
|
async function bundleConfig(entry) {
|
|
1757
|
-
const absDir =
|
|
2304
|
+
const absDir = import_path13.default.dirname(entry);
|
|
1758
2305
|
const inlineIonifyPlugin = {
|
|
1759
2306
|
name: "inline-ionify",
|
|
1760
2307
|
setup(build2) {
|
|
@@ -1802,8 +2349,8 @@ const __filename = ${filenameLiteral};
|
|
|
1802
2349
|
}
|
|
1803
2350
|
function findConfigFile(cwd) {
|
|
1804
2351
|
for (const name of CONFIG_BASENAMES) {
|
|
1805
|
-
const candidate =
|
|
1806
|
-
if (
|
|
2352
|
+
const candidate = import_path13.default.resolve(cwd, name);
|
|
2353
|
+
if (import_fs9.default.existsSync(candidate) && import_fs9.default.statSync(candidate).isFile()) {
|
|
1807
2354
|
return candidate;
|
|
1808
2355
|
}
|
|
1809
2356
|
}
|
|
@@ -1814,7 +2361,7 @@ async function loadIonifyConfig(cwd = process.cwd()) {
|
|
|
1814
2361
|
configLoaded = true;
|
|
1815
2362
|
const configPath = findConfigFile(cwd);
|
|
1816
2363
|
if (!configPath) {
|
|
1817
|
-
cachedConfig2 =
|
|
2364
|
+
cachedConfig2 = { root: cwd };
|
|
1818
2365
|
configureResolverAliases(void 0, cwd);
|
|
1819
2366
|
return cachedConfig2;
|
|
1820
2367
|
}
|
|
@@ -1830,15 +2377,33 @@ async function loadIonifyConfig(cwd = process.cwd()) {
|
|
|
1830
2377
|
resolved = await resolved;
|
|
1831
2378
|
}
|
|
1832
2379
|
if (resolved && typeof resolved === "object") {
|
|
2380
|
+
if (resolved.root) {
|
|
2381
|
+
const rootPath = import_path13.default.isAbsolute(resolved.root) ? resolved.root : import_path13.default.resolve(import_path13.default.dirname(configPath), resolved.root);
|
|
2382
|
+
if (!import_fs9.default.existsSync(rootPath)) {
|
|
2383
|
+
logError(`Config error: root directory does not exist: ${rootPath}`);
|
|
2384
|
+
throw new Error(`Invalid root: ${rootPath}`);
|
|
2385
|
+
}
|
|
2386
|
+
if (!import_fs9.default.statSync(rootPath).isDirectory()) {
|
|
2387
|
+
logError(`Config error: root must be a directory: ${rootPath}`);
|
|
2388
|
+
throw new Error(`Invalid root: ${rootPath}`);
|
|
2389
|
+
}
|
|
2390
|
+
resolved.root = rootPath;
|
|
2391
|
+
logInfo(`Using project root: ${import_path13.default.relative(cwd, rootPath)}`);
|
|
2392
|
+
} else {
|
|
2393
|
+
resolved.root = import_path13.default.dirname(configPath);
|
|
2394
|
+
}
|
|
2395
|
+
if (resolved.optimizeDeps?.esbuildOptions) {
|
|
2396
|
+
logWarn("optimizeDeps.esbuildOptions is not supported in Ionify (uses native Rust optimizer). This option will be ignored.");
|
|
2397
|
+
}
|
|
1833
2398
|
cachedConfig2 = resolved;
|
|
1834
|
-
const baseDir =
|
|
2399
|
+
const baseDir = import_path13.default.dirname(configPath);
|
|
1835
2400
|
const aliases = resolved?.resolve?.alias;
|
|
1836
2401
|
if (aliases && typeof aliases === "object") {
|
|
1837
2402
|
configureResolverAliases(aliases, baseDir);
|
|
1838
2403
|
} else {
|
|
1839
2404
|
configureResolverAliases(void 0, baseDir);
|
|
1840
2405
|
}
|
|
1841
|
-
logInfo(`Loaded ionify config from ${
|
|
2406
|
+
logInfo(`Loaded ionify config from ${import_path13.default.relative(cwd, configPath)}`);
|
|
1842
2407
|
} else {
|
|
1843
2408
|
throw new Error("Config did not export an object");
|
|
1844
2409
|
}
|
|
@@ -1869,14 +2434,11 @@ function resolveMinifier(config, opts = {}) {
|
|
|
1869
2434
|
if (fromConfig) return fromConfig;
|
|
1870
2435
|
return "auto";
|
|
1871
2436
|
}
|
|
1872
|
-
function applyMinifierEnv(choice) {
|
|
1873
|
-
process.env.IONIFY_MINIFIER = choice;
|
|
1874
|
-
}
|
|
1875
2437
|
|
|
1876
2438
|
// src/cli/utils/env.ts
|
|
1877
2439
|
init_cjs_shims();
|
|
1878
|
-
var
|
|
1879
|
-
var
|
|
2440
|
+
var import_fs10 = __toESM(require("fs"), 1);
|
|
2441
|
+
var import_path14 = __toESM(require("path"), 1);
|
|
1880
2442
|
function parseValue(raw) {
|
|
1881
2443
|
let value = raw.trim();
|
|
1882
2444
|
if (!value) return "";
|
|
@@ -1908,11 +2470,11 @@ function loadEnv(mode = "development", rootDir = process.cwd()) {
|
|
|
1908
2470
|
];
|
|
1909
2471
|
const merged = {};
|
|
1910
2472
|
for (const name of candidates) {
|
|
1911
|
-
const filePath =
|
|
1912
|
-
if (!
|
|
2473
|
+
const filePath = import_path14.default.resolve(rootDir, name);
|
|
2474
|
+
if (!import_fs10.default.existsSync(filePath) || !import_fs10.default.statSync(filePath).isFile()) {
|
|
1913
2475
|
continue;
|
|
1914
2476
|
}
|
|
1915
|
-
const contents =
|
|
2477
|
+
const contents = import_fs10.default.readFileSync(filePath, "utf8");
|
|
1916
2478
|
const parsed = parseEnvFile(contents);
|
|
1917
2479
|
Object.assign(merged, parsed);
|
|
1918
2480
|
}
|
|
@@ -1999,11 +2561,6 @@ function resolveTreeshake(input, options = {}) {
|
|
|
1999
2561
|
}
|
|
2000
2562
|
return resolved;
|
|
2001
2563
|
}
|
|
2002
|
-
function applyTreeshakeEnv(resolved) {
|
|
2003
|
-
process.env.IONIFY_TREESHAKE = resolved.mode;
|
|
2004
|
-
process.env.IONIFY_TREESHAKE_INCLUDE = JSON.stringify(resolved.include);
|
|
2005
|
-
process.env.IONIFY_TREESHAKE_EXCLUDE = JSON.stringify(resolved.exclude);
|
|
2006
|
-
}
|
|
2007
2564
|
|
|
2008
2565
|
// src/cli/utils/scope-hoist.ts
|
|
2009
2566
|
init_cjs_shims();
|
|
@@ -2067,12 +2624,6 @@ function resolveScopeHoist(configValue, options = {}) {
|
|
|
2067
2624
|
}
|
|
2068
2625
|
return resolved;
|
|
2069
2626
|
}
|
|
2070
|
-
function applyScopeHoistEnv(result) {
|
|
2071
|
-
process.env.IONIFY_SCOPE_HOIST = result.enable ? "true" : "false";
|
|
2072
|
-
process.env.IONIFY_SCOPE_HOIST_INLINE = result.inlineFunctions ? "true" : "false";
|
|
2073
|
-
process.env.IONIFY_SCOPE_HOIST_CONST = result.constantFolding ? "true" : "false";
|
|
2074
|
-
process.env.IONIFY_SCOPE_HOIST_COMBINE = result.combineVariables ? "true" : "false";
|
|
2075
|
-
}
|
|
2076
2627
|
|
|
2077
2628
|
// src/cli/utils/parser.ts
|
|
2078
2629
|
init_cjs_shims();
|
|
@@ -2098,19 +2649,97 @@ function applyParserEnv(mode) {
|
|
|
2098
2649
|
// src/cli/commands/dev.ts
|
|
2099
2650
|
init_cas();
|
|
2100
2651
|
init_native();
|
|
2101
|
-
|
|
2652
|
+
|
|
2653
|
+
// src/core/utils/define.ts
|
|
2654
|
+
init_cjs_shims();
|
|
2655
|
+
function applyDefineReplacements(code, definitions) {
|
|
2656
|
+
if (!definitions || Object.keys(definitions).length === 0) {
|
|
2657
|
+
return code;
|
|
2658
|
+
}
|
|
2659
|
+
let result = code;
|
|
2660
|
+
const sortedKeys = Object.keys(definitions).sort((a, b) => b.length - a.length);
|
|
2661
|
+
for (const key of sortedKeys) {
|
|
2662
|
+
const value = definitions[key];
|
|
2663
|
+
let replacement;
|
|
2664
|
+
if (typeof value === "string") {
|
|
2665
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
2666
|
+
replacement = value;
|
|
2667
|
+
} else {
|
|
2668
|
+
replacement = JSON.stringify(value);
|
|
2669
|
+
}
|
|
2670
|
+
} else if (typeof value === "number" || typeof value === "boolean") {
|
|
2671
|
+
replacement = String(value);
|
|
2672
|
+
} else if (value === null || value === void 0) {
|
|
2673
|
+
replacement = "null";
|
|
2674
|
+
} else {
|
|
2675
|
+
replacement = JSON.stringify(value);
|
|
2676
|
+
}
|
|
2677
|
+
if (key.includes(".")) {
|
|
2678
|
+
result = replaceMemberExpression(result, key, replacement);
|
|
2679
|
+
} else {
|
|
2680
|
+
result = replaceIdentifier(result, key, replacement);
|
|
2681
|
+
}
|
|
2682
|
+
}
|
|
2683
|
+
return result;
|
|
2684
|
+
}
|
|
2685
|
+
function replaceIdentifier(code, identifier, replacement) {
|
|
2686
|
+
const regex = new RegExp(
|
|
2687
|
+
`(?<![\\w.$])${escapeRegExp(identifier)}(?![\\w])`,
|
|
2688
|
+
"g"
|
|
2689
|
+
);
|
|
2690
|
+
return code.replace(regex, replacement);
|
|
2691
|
+
}
|
|
2692
|
+
function replaceMemberExpression(code, expression, replacement) {
|
|
2693
|
+
const parts = expression.split(".");
|
|
2694
|
+
const pattern = parts.map(escapeRegExp).join("\\s*\\.\\s*");
|
|
2695
|
+
const regex = new RegExp(
|
|
2696
|
+
`(?<![\\w.$])${pattern}(?![\\w.])`,
|
|
2697
|
+
"g"
|
|
2698
|
+
);
|
|
2699
|
+
return code.replace(regex, replacement);
|
|
2700
|
+
}
|
|
2701
|
+
function escapeRegExp(str) {
|
|
2702
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2703
|
+
}
|
|
2704
|
+
function buildDefineConfig(userDefine, envValues, envPrefix = ["VITE_", "IONIFY_"]) {
|
|
2705
|
+
const define = { ...userDefine || {} };
|
|
2706
|
+
const prefixes = Array.isArray(envPrefix) ? envPrefix : [envPrefix];
|
|
2707
|
+
for (const [key, value] of Object.entries(envValues)) {
|
|
2708
|
+
const hasPrefix = prefixes.some((prefix) => key.startsWith(prefix));
|
|
2709
|
+
if (hasPrefix || key === "NODE_ENV" || key === "MODE") {
|
|
2710
|
+
const importMetaKey = `import.meta.env.${key}`;
|
|
2711
|
+
if (!(importMetaKey in define)) {
|
|
2712
|
+
define[importMetaKey] = value;
|
|
2713
|
+
}
|
|
2714
|
+
}
|
|
2715
|
+
}
|
|
2716
|
+
if (!("import.meta.env.DEV" in define)) {
|
|
2717
|
+
define["import.meta.env.DEV"] = envValues.MODE !== "production";
|
|
2718
|
+
}
|
|
2719
|
+
if (!("import.meta.env.PROD" in define)) {
|
|
2720
|
+
define["import.meta.env.PROD"] = envValues.MODE === "production";
|
|
2721
|
+
}
|
|
2722
|
+
return define;
|
|
2723
|
+
}
|
|
2724
|
+
|
|
2725
|
+
// src/cli/commands/dev.ts
|
|
2726
|
+
var import_crypto4 = __toESM(require("crypto"), 1);
|
|
2727
|
+
var import_zlib = __toESM(require("zlib"), 1);
|
|
2728
|
+
var IONIFY_CSS_JS_MARKER = "// ionify:css";
|
|
2729
|
+
var IONIFY_VENDOR_PACK_MARKER = "// ionify:vendor-pack";
|
|
2102
2730
|
var __filename2 = (0, import_url4.fileURLToPath)(importMetaUrl);
|
|
2103
|
-
var __dirname =
|
|
2104
|
-
var CLIENT_DIR =
|
|
2105
|
-
var CLIENT_FALLBACK_DIR =
|
|
2731
|
+
var __dirname = import_path15.default.dirname(__filename2);
|
|
2732
|
+
var CLIENT_DIR = import_path15.default.resolve(__dirname, "../client");
|
|
2733
|
+
var CLIENT_FALLBACK_DIR = import_path15.default.resolve(process.cwd(), "src/client");
|
|
2734
|
+
var DEPS_PREFIX = "/@deps/";
|
|
2106
2735
|
function readClientAssetFile(fileName) {
|
|
2107
|
-
const primary =
|
|
2108
|
-
if (
|
|
2109
|
-
return { filePath: primary, code:
|
|
2736
|
+
const primary = import_path15.default.join(CLIENT_DIR, fileName);
|
|
2737
|
+
if (import_fs11.default.existsSync(primary)) {
|
|
2738
|
+
return { filePath: primary, code: import_fs11.default.readFileSync(primary, "utf8") };
|
|
2110
2739
|
}
|
|
2111
|
-
const fallback =
|
|
2112
|
-
if (
|
|
2113
|
-
return { filePath: fallback, code:
|
|
2740
|
+
const fallback = import_path15.default.join(CLIENT_FALLBACK_DIR, fileName);
|
|
2741
|
+
if (import_fs11.default.existsSync(fallback)) {
|
|
2742
|
+
return { filePath: fallback, code: import_fs11.default.readFileSync(fallback, "utf8") };
|
|
2114
2743
|
}
|
|
2115
2744
|
throw new Error(`Missing Ionify client asset: ${fileName}`);
|
|
2116
2745
|
}
|
|
@@ -2118,7 +2747,7 @@ function readClientAsset(fileName) {
|
|
|
2118
2747
|
return readClientAssetFile(fileName).code;
|
|
2119
2748
|
}
|
|
2120
2749
|
function guessContentType(filePath) {
|
|
2121
|
-
const ext =
|
|
2750
|
+
const ext = import_path15.default.extname(filePath);
|
|
2122
2751
|
if (ext === ".html") return "text/html; charset=utf-8";
|
|
2123
2752
|
if (ext === ".css") return "text/css; charset=utf-8";
|
|
2124
2753
|
if (ext === ".json") return "application/json; charset=utf-8";
|
|
@@ -2130,16 +2759,289 @@ function guessContentType(filePath) {
|
|
|
2130
2759
|
return "application/json; charset=utf-8";
|
|
2131
2760
|
return "text/plain; charset=utf-8";
|
|
2132
2761
|
}
|
|
2762
|
+
function mergeVaryHeader(existing, next) {
|
|
2763
|
+
const parts = /* @__PURE__ */ new Set();
|
|
2764
|
+
const add = (value) => {
|
|
2765
|
+
value.split(",").map((v) => v.trim()).filter(Boolean).forEach((v) => parts.add(v));
|
|
2766
|
+
};
|
|
2767
|
+
if (typeof existing === "string") add(existing);
|
|
2768
|
+
else if (Array.isArray(existing)) existing.forEach(add);
|
|
2769
|
+
add(next);
|
|
2770
|
+
return Array.from(parts).join(", ");
|
|
2771
|
+
}
|
|
2772
|
+
function normalizeEtag(tag) {
|
|
2773
|
+
return tag.trim().replace(/^W\//, "");
|
|
2774
|
+
}
|
|
2775
|
+
function isNotModified(req, etag) {
|
|
2776
|
+
const header = req.headers["if-none-match"];
|
|
2777
|
+
const value = Array.isArray(header) ? header.join(",") : header;
|
|
2778
|
+
if (!value) return false;
|
|
2779
|
+
if (value.trim() === "*") return true;
|
|
2780
|
+
const expected = normalizeEtag(etag);
|
|
2781
|
+
return value.split(",").map((t) => t.trim()).filter(Boolean).some((t) => normalizeEtag(t) === expected);
|
|
2782
|
+
}
|
|
2783
|
+
function weakEtagFromStat(prefix, stat) {
|
|
2784
|
+
const mtime = Math.floor(stat.mtimeMs);
|
|
2785
|
+
return `W/"${prefix}-${stat.size}-${mtime}"`;
|
|
2786
|
+
}
|
|
2787
|
+
function shouldCompressContentType(contentType) {
|
|
2788
|
+
const ct = contentType.toLowerCase();
|
|
2789
|
+
return ct.startsWith("text/") || ct.includes("javascript") || ct.includes("json") || ct.includes("xml") || ct.includes("svg");
|
|
2790
|
+
}
|
|
2791
|
+
function selectCompressionEncoding(req) {
|
|
2792
|
+
const header = req.headers["accept-encoding"];
|
|
2793
|
+
const value = Array.isArray(header) ? header.join(",") : header;
|
|
2794
|
+
if (!value) return null;
|
|
2795
|
+
const enc = value.toLowerCase();
|
|
2796
|
+
if (enc.includes("gzip")) return "gzip";
|
|
2797
|
+
return null;
|
|
2798
|
+
}
|
|
2799
|
+
function looksLikeIonifyCssJsModule(body) {
|
|
2800
|
+
const head = body.subarray(0, 96).toString("utf8");
|
|
2801
|
+
return head.trimStart().startsWith(IONIFY_CSS_JS_MARKER);
|
|
2802
|
+
}
|
|
2803
|
+
function computeDepsStampHash(depsAbs) {
|
|
2804
|
+
if (!depsAbs.length) return "0";
|
|
2805
|
+
const entries = [];
|
|
2806
|
+
for (const dep of depsAbs) {
|
|
2807
|
+
const abs = import_path15.default.resolve(dep);
|
|
2808
|
+
try {
|
|
2809
|
+
const stat = import_fs11.default.statSync(abs);
|
|
2810
|
+
entries.push(`${abs}:${stat.size}:${Math.floor(stat.mtimeMs)}`);
|
|
2811
|
+
} catch {
|
|
2812
|
+
entries.push(`${abs}:missing`);
|
|
2813
|
+
}
|
|
2814
|
+
}
|
|
2815
|
+
entries.sort();
|
|
2816
|
+
return getCacheKey(entries.join("|"));
|
|
2817
|
+
}
|
|
2818
|
+
function sendBuffer(req, res, status, contentType, body, opts) {
|
|
2819
|
+
res.setHeader("Content-Type", contentType);
|
|
2820
|
+
res.setHeader("Cache-Control", opts?.cacheControl ?? "no-cache");
|
|
2821
|
+
const etag = opts?.etag;
|
|
2822
|
+
if (etag) {
|
|
2823
|
+
res.setHeader("ETag", etag);
|
|
2824
|
+
if (isNotModified(req, etag)) {
|
|
2825
|
+
res.statusCode = 304;
|
|
2826
|
+
res.end();
|
|
2827
|
+
return;
|
|
2828
|
+
}
|
|
2829
|
+
}
|
|
2830
|
+
const encoding = body.length >= 1024 && shouldCompressContentType(contentType) ? selectCompressionEncoding(req) : null;
|
|
2831
|
+
if (encoding === "gzip") {
|
|
2832
|
+
res.setHeader("Vary", mergeVaryHeader(res.getHeader("Vary"), "Accept-Encoding"));
|
|
2833
|
+
res.setHeader("Content-Encoding", "gzip");
|
|
2834
|
+
res.statusCode = status;
|
|
2835
|
+
res.end(import_zlib.default.gzipSync(body, { level: 1 }));
|
|
2836
|
+
return;
|
|
2837
|
+
}
|
|
2838
|
+
res.statusCode = status;
|
|
2839
|
+
res.end(body);
|
|
2840
|
+
}
|
|
2841
|
+
var LOCKFILE_ORDER = [
|
|
2842
|
+
"pnpm-lock.yaml",
|
|
2843
|
+
"package-lock.json",
|
|
2844
|
+
"yarn.lock",
|
|
2845
|
+
"bun.lockb"
|
|
2846
|
+
];
|
|
2847
|
+
function readLockfile(rootDir) {
|
|
2848
|
+
for (const name of LOCKFILE_ORDER) {
|
|
2849
|
+
const filePath = import_path15.default.join(rootDir, name);
|
|
2850
|
+
if (!import_fs11.default.existsSync(filePath)) continue;
|
|
2851
|
+
const contents = import_fs11.default.readFileSync(filePath);
|
|
2852
|
+
const packageCount = estimateLockfilePackageCount(name, contents);
|
|
2853
|
+
return { name, path: filePath, contents, packageCount };
|
|
2854
|
+
}
|
|
2855
|
+
return null;
|
|
2856
|
+
}
|
|
2857
|
+
function estimateLockfilePackageCount(name, contents) {
|
|
2858
|
+
if (name === "package-lock.json") {
|
|
2859
|
+
try {
|
|
2860
|
+
const parsed = JSON.parse(contents.toString("utf8"));
|
|
2861
|
+
if (parsed?.packages && typeof parsed.packages === "object") {
|
|
2862
|
+
return Object.keys(parsed.packages).length;
|
|
2863
|
+
}
|
|
2864
|
+
} catch {
|
|
2865
|
+
return null;
|
|
2866
|
+
}
|
|
2867
|
+
}
|
|
2868
|
+
if (name === "pnpm-lock.yaml") {
|
|
2869
|
+
const text = contents.toString("utf8");
|
|
2870
|
+
return text.split("\n").filter((line) => line.trimStart().startsWith("/")).length;
|
|
2871
|
+
}
|
|
2872
|
+
if (name === "yarn.lock") {
|
|
2873
|
+
const text = contents.toString("utf8");
|
|
2874
|
+
return text.split("\n").filter((line) => line && !line.startsWith(" ") && line.endsWith(":")).length;
|
|
2875
|
+
}
|
|
2876
|
+
return null;
|
|
2877
|
+
}
|
|
2878
|
+
function computeDepsHash(configHash, lockfile, opts) {
|
|
2879
|
+
const hash = import_crypto4.default.createHash("sha256");
|
|
2880
|
+
hash.update(configHash);
|
|
2881
|
+
if (lockfile) {
|
|
2882
|
+
hash.update(lockfile.contents);
|
|
2883
|
+
}
|
|
2884
|
+
hash.update(`NODE_ENV=${opts.nodeEnv}`);
|
|
2885
|
+
hash.update(`optimizeDeps.sourcemap=${opts.sourcemap ? "1" : "0"}`);
|
|
2886
|
+
hash.update(`optimizeDeps.bundleEsm=${opts.bundleEsm ? "1" : "0"}`);
|
|
2887
|
+
return hash.digest("hex").slice(0, 16);
|
|
2888
|
+
}
|
|
2889
|
+
function readProjectPackageJson(rootDir) {
|
|
2890
|
+
const pkgPath = import_path15.default.join(rootDir, "package.json");
|
|
2891
|
+
if (!import_fs11.default.existsSync(pkgPath)) return null;
|
|
2892
|
+
try {
|
|
2893
|
+
return JSON.parse(import_fs11.default.readFileSync(pkgPath, "utf8"));
|
|
2894
|
+
} catch {
|
|
2895
|
+
return null;
|
|
2896
|
+
}
|
|
2897
|
+
}
|
|
2898
|
+
function detectVendorSpecifiers(pkgJson) {
|
|
2899
|
+
if (!pkgJson || typeof pkgJson !== "object") return [];
|
|
2900
|
+
const deps = {
|
|
2901
|
+
...pkgJson.dependencies || {},
|
|
2902
|
+
...pkgJson.devDependencies || {},
|
|
2903
|
+
...pkgJson.peerDependencies || {}
|
|
2904
|
+
};
|
|
2905
|
+
const has = (name) => Object.prototype.hasOwnProperty.call(deps, name);
|
|
2906
|
+
if (has("react") || has("react-dom")) {
|
|
2907
|
+
return [
|
|
2908
|
+
"react",
|
|
2909
|
+
"react-dom",
|
|
2910
|
+
"react-dom/client",
|
|
2911
|
+
"scheduler",
|
|
2912
|
+
"react/jsx-runtime",
|
|
2913
|
+
"react/jsx-dev-runtime",
|
|
2914
|
+
"react-refresh"
|
|
2915
|
+
];
|
|
2916
|
+
}
|
|
2917
|
+
if (has("vue")) {
|
|
2918
|
+
return ["vue", "@vue/runtime-dom", "@vue/runtime-core"];
|
|
2919
|
+
}
|
|
2920
|
+
if (has("svelte")) {
|
|
2921
|
+
return ["svelte", "svelte/internal"];
|
|
2922
|
+
}
|
|
2923
|
+
return [];
|
|
2924
|
+
}
|
|
2925
|
+
function computeSubpathForDep2(fsPath, pkg) {
|
|
2926
|
+
const computed = computeSubpathFromEntryPath(fsPath);
|
|
2927
|
+
if (computed) return computed;
|
|
2928
|
+
if (import_fs11.default.existsSync(fsPath)) return null;
|
|
2929
|
+
const raw = pkg?.subpath;
|
|
2930
|
+
if (typeof raw === "string") {
|
|
2931
|
+
const cleaned = raw.replace(/^\.\//, "").replace(/^\/+/, "");
|
|
2932
|
+
if (cleaned && cleaned !== "." && cleaned !== "index") {
|
|
2933
|
+
return cleaned;
|
|
2934
|
+
}
|
|
2935
|
+
}
|
|
2936
|
+
return null;
|
|
2937
|
+
}
|
|
2938
|
+
function resolveVendorDeps(rootDir, specifiers) {
|
|
2939
|
+
if (!native?.resolveModule) return [];
|
|
2940
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2941
|
+
const resolved = [];
|
|
2942
|
+
for (const spec of specifiers) {
|
|
2943
|
+
try {
|
|
2944
|
+
const r = native.resolveModule(spec, rootDir);
|
|
2945
|
+
const fsPath = r?.fsPath ?? r?.fs_path ?? null;
|
|
2946
|
+
if (!fsPath || typeof fsPath !== "string") continue;
|
|
2947
|
+
const pkg = r?.pkg ?? null;
|
|
2948
|
+
const packageName = typeof pkg?.name === "string" ? pkg.name : spec;
|
|
2949
|
+
const packageVersion = typeof pkg?.version === "string" ? pkg.version : "0.0.0";
|
|
2950
|
+
const subpath = computeSubpathForDep2(fsPath, pkg);
|
|
2951
|
+
const entry = registerDepEntry({
|
|
2952
|
+
entryPath: fsPath,
|
|
2953
|
+
packageName,
|
|
2954
|
+
packageVersion,
|
|
2955
|
+
subpath
|
|
2956
|
+
});
|
|
2957
|
+
if (seen.has(entry.fileName)) continue;
|
|
2958
|
+
seen.add(entry.fileName);
|
|
2959
|
+
resolved.push({
|
|
2960
|
+
specifier: spec,
|
|
2961
|
+
entryPath: fsPath,
|
|
2962
|
+
fileName: entry.fileName,
|
|
2963
|
+
packageLabel: formatDepLabel(packageName, subpath)
|
|
2964
|
+
});
|
|
2965
|
+
} catch {
|
|
2966
|
+
}
|
|
2967
|
+
}
|
|
2968
|
+
return resolved;
|
|
2969
|
+
}
|
|
2970
|
+
function injectModulePreload(html, href) {
|
|
2971
|
+
const tag = `<link rel="modulepreload" href="${href}">`;
|
|
2972
|
+
if (html.includes(tag)) return html;
|
|
2973
|
+
const headCloseMatch = html.match(/<\/head>/i);
|
|
2974
|
+
if (headCloseMatch?.index !== void 0) {
|
|
2975
|
+
const idx = headCloseMatch.index;
|
|
2976
|
+
return `${html.slice(0, idx)}${tag}
|
|
2977
|
+
${html.slice(idx)}`;
|
|
2978
|
+
}
|
|
2979
|
+
const headOpenMatch = html.match(/<head[^>]*>/i);
|
|
2980
|
+
if (headOpenMatch?.index !== void 0) {
|
|
2981
|
+
const idx = headOpenMatch.index + headOpenMatch[0].length;
|
|
2982
|
+
return `${html.slice(0, idx)}
|
|
2983
|
+
${tag}${html.slice(idx)}`;
|
|
2984
|
+
}
|
|
2985
|
+
return `${tag}
|
|
2986
|
+
${html}`;
|
|
2987
|
+
}
|
|
2988
|
+
function pruneDepsCache(rootDir, depsHash) {
|
|
2989
|
+
const depsRoot = import_path15.default.join(rootDir, ".ionify", "deps");
|
|
2990
|
+
if (!import_fs11.default.existsSync(depsRoot)) return;
|
|
2991
|
+
const entries = import_fs11.default.readdirSync(depsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => {
|
|
2992
|
+
const fullPath = import_path15.default.join(depsRoot, entry.name);
|
|
2993
|
+
const stat = import_fs11.default.statSync(fullPath);
|
|
2994
|
+
return { name: entry.name, path: fullPath, mtimeMs: stat.mtimeMs };
|
|
2995
|
+
}).sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
2996
|
+
const keep = /* @__PURE__ */ new Set();
|
|
2997
|
+
keep.add(depsHash);
|
|
2998
|
+
for (const entry of entries.slice(0, 2)) {
|
|
2999
|
+
keep.add(entry.name);
|
|
3000
|
+
}
|
|
3001
|
+
for (const entry of entries) {
|
|
3002
|
+
if (!keep.has(entry.name)) {
|
|
3003
|
+
import_fs11.default.rmSync(entry.path, { recursive: true, force: true });
|
|
3004
|
+
}
|
|
3005
|
+
}
|
|
3006
|
+
}
|
|
3007
|
+
function loadDepsManifestIndex(depsRoot) {
|
|
3008
|
+
const manifestPath = import_path15.default.join(depsRoot, "manifest.json");
|
|
3009
|
+
if (!import_fs11.default.existsSync(manifestPath)) return /* @__PURE__ */ new Map();
|
|
3010
|
+
try {
|
|
3011
|
+
const raw = import_fs11.default.readFileSync(manifestPath, "utf8");
|
|
3012
|
+
const parsed = JSON.parse(raw);
|
|
3013
|
+
const entries = parsed?.entries ?? {};
|
|
3014
|
+
const map = /* @__PURE__ */ new Map();
|
|
3015
|
+
for (const [entryPath, entry] of Object.entries(entries)) {
|
|
3016
|
+
if (!entry?.outFile) continue;
|
|
3017
|
+
map.set(entry.outFile, {
|
|
3018
|
+
entryPath,
|
|
3019
|
+
packageLabel: entry.package || "unknown",
|
|
3020
|
+
hasSourcemap: entry.hasSourcemap === true
|
|
3021
|
+
});
|
|
3022
|
+
}
|
|
3023
|
+
return map;
|
|
3024
|
+
} catch {
|
|
3025
|
+
return /* @__PURE__ */ new Map();
|
|
3026
|
+
}
|
|
3027
|
+
}
|
|
3028
|
+
function formatDepLabel(name, subpath) {
|
|
3029
|
+
if (!subpath) return name;
|
|
3030
|
+
const cleaned = subpath.replace(/^\.\//, "").replace(/^\/+/, "");
|
|
3031
|
+
if (!cleaned || cleaned === ".") return name;
|
|
3032
|
+
return `${name}/${cleaned}`;
|
|
3033
|
+
}
|
|
2133
3034
|
async function startDevServer({
|
|
2134
3035
|
port = 5173,
|
|
3036
|
+
host = process.env.IONIFY_HOST || "127.0.0.1",
|
|
2135
3037
|
enableSignalHandlers = true
|
|
2136
3038
|
} = {}) {
|
|
2137
|
-
const
|
|
3039
|
+
const bootStartMs = Date.now();
|
|
3040
|
+
const userConfig = await loadIonifyConfig();
|
|
3041
|
+
const rootDir = userConfig?.root || process.cwd();
|
|
2138
3042
|
const watcher = new IonifyWatcher(rootDir);
|
|
2139
3043
|
const cacheDebug = process.env.IONIFY_DEV_TRANSFORM_CACHE_DEBUG === "1";
|
|
2140
|
-
const userConfig = await loadIonifyConfig();
|
|
2141
3044
|
const minifier = resolveMinifier(userConfig, { envVar: process.env.IONIFY_MINIFIER });
|
|
2142
|
-
applyMinifierEnv(minifier);
|
|
2143
3045
|
const parserMode = resolveParser(userConfig, { envMode: process.env.IONIFY_PARSER });
|
|
2144
3046
|
applyParserEnv(parserMode);
|
|
2145
3047
|
const treeshake = resolveTreeshake(userConfig?.treeshake, {
|
|
@@ -2147,15 +3049,15 @@ async function startDevServer({
|
|
|
2147
3049
|
includeEnv: process.env.IONIFY_TREESHAKE_INCLUDE,
|
|
2148
3050
|
excludeEnv: process.env.IONIFY_TREESHAKE_EXCLUDE
|
|
2149
3051
|
});
|
|
2150
|
-
applyTreeshakeEnv(treeshake);
|
|
2151
3052
|
const scopeHoist = resolveScopeHoist(userConfig?.scopeHoist, {
|
|
2152
3053
|
envMode: process.env.IONIFY_SCOPE_HOIST,
|
|
2153
3054
|
inlineEnv: process.env.IONIFY_SCOPE_HOIST_INLINE,
|
|
2154
3055
|
constantEnv: process.env.IONIFY_SCOPE_HOIST_CONST,
|
|
2155
3056
|
combineEnv: process.env.IONIFY_SCOPE_HOIST_COMBINE
|
|
2156
3057
|
});
|
|
2157
|
-
|
|
2158
|
-
|
|
3058
|
+
const resolvedEntries = userConfig?.entry ? (Array.isArray(userConfig.entry) ? userConfig.entry : [userConfig.entry]).map(
|
|
3059
|
+
(entry) => entry.startsWith("/") ? import_path15.default.join(rootDir, entry) : import_path15.default.resolve(rootDir, entry)
|
|
3060
|
+
) : void 0;
|
|
2159
3061
|
const pluginNames = Array.isArray(userConfig?.plugins) ? userConfig.plugins.map((p) => typeof p === "string" ? p : p?.name).filter((name) => typeof name === "string" && name.length > 0) : void 0;
|
|
2160
3062
|
const rawVersionInputs = {
|
|
2161
3063
|
parserMode,
|
|
@@ -2163,14 +3065,64 @@ async function startDevServer({
|
|
|
2163
3065
|
treeshake,
|
|
2164
3066
|
scopeHoist,
|
|
2165
3067
|
plugins: pluginNames,
|
|
2166
|
-
entry:
|
|
3068
|
+
entry: resolvedEntries ?? null,
|
|
2167
3069
|
cssOptions: userConfig?.css,
|
|
2168
3070
|
assetOptions: userConfig?.assets ?? userConfig?.asset
|
|
2169
3071
|
};
|
|
2170
3072
|
const configHash = computeGraphVersion(rawVersionInputs);
|
|
2171
3073
|
logInfo(`[Dev] Version hash: ${configHash}`);
|
|
2172
3074
|
process.env.IONIFY_CONFIG_HASH = configHash;
|
|
2173
|
-
const casRoot =
|
|
3075
|
+
const casRoot = import_path15.default.join(rootDir, ".ionify", "cas");
|
|
3076
|
+
const lockfile = readLockfile(rootDir);
|
|
3077
|
+
if (lockfile) {
|
|
3078
|
+
const countLabel = lockfile.packageCount === null ? "unknown" : lockfile.packageCount;
|
|
3079
|
+
logInfo(`[deps] SCAN lockfile: ${lockfile.name} (${countLabel} packages)`);
|
|
3080
|
+
}
|
|
3081
|
+
const depsSourcemapEnabled = userConfig?.optimizeDeps?.sourcemap === true;
|
|
3082
|
+
const depsBundleEsmEnabled = userConfig?.optimizeDeps?.bundleEsm !== false;
|
|
3083
|
+
const depsNodeEnv = process.env.NODE_ENV ?? "development";
|
|
3084
|
+
const depsHash = computeDepsHash(configHash, lockfile, {
|
|
3085
|
+
nodeEnv: depsNodeEnv,
|
|
3086
|
+
sourcemap: depsSourcemapEnabled,
|
|
3087
|
+
bundleEsm: depsBundleEsmEnabled
|
|
3088
|
+
});
|
|
3089
|
+
logInfo(`[deps] depsHash: ${depsHash} from ${lockfile?.name ?? "config"}`);
|
|
3090
|
+
const depsRoot = import_path15.default.join(rootDir, ".ionify", "deps", depsHash);
|
|
3091
|
+
import_fs11.default.mkdirSync(depsRoot, { recursive: true });
|
|
3092
|
+
pruneDepsCache(rootDir, depsHash);
|
|
3093
|
+
const depsManifestIndex = loadDepsManifestIndex(depsRoot);
|
|
3094
|
+
const optimizeVendorMode = userConfig?.optimizeDeps?.vendor ?? "auto";
|
|
3095
|
+
const optimizeExclude = Array.isArray(userConfig?.optimizeDeps?.exclude) ? new Set(userConfig.optimizeDeps.exclude) : null;
|
|
3096
|
+
const autoVendor = optimizeVendorMode === "auto";
|
|
3097
|
+
const vendorSpecifiersRaw = optimizeVendorMode === false ? [] : Array.isArray(optimizeVendorMode) ? optimizeVendorMode : autoVendor ? detectVendorSpecifiers(readProjectPackageJson(rootDir)) : [];
|
|
3098
|
+
const vendorSpecifiers = vendorSpecifiersRaw.map((s) => String(s).trim()).filter(Boolean).filter((s) => !optimizeExclude?.has(s));
|
|
3099
|
+
const vendorDeps = resolveVendorDeps(rootDir, vendorSpecifiers);
|
|
3100
|
+
const vendorPackFileName = vendorDeps.length > 0 ? `vendor.${depsHash}.js` : null;
|
|
3101
|
+
const vendorPackUrl = vendorPackFileName ? `${DEPS_PREFIX}${vendorPackFileName}` : null;
|
|
3102
|
+
const ensureVendorPackFile = () => {
|
|
3103
|
+
if (!vendorPackFileName || !vendorPackUrl || vendorDeps.length === 0) return;
|
|
3104
|
+
const vendorKey = getCacheKey(
|
|
3105
|
+
`vendor:v1:${vendorDeps.map((d) => `${d.specifier}:${d.fileName}`).sort().join("|")}`
|
|
3106
|
+
);
|
|
3107
|
+
const filePath = import_path15.default.join(depsRoot, vendorPackFileName);
|
|
3108
|
+
if (import_fs11.default.existsSync(filePath)) {
|
|
3109
|
+
try {
|
|
3110
|
+
const head = import_fs11.default.readFileSync(filePath, "utf8").slice(0, 256);
|
|
3111
|
+
if (head.includes(`${IONIFY_VENDOR_PACK_MARKER} ${vendorKey}`)) return;
|
|
3112
|
+
} catch {
|
|
3113
|
+
}
|
|
3114
|
+
}
|
|
3115
|
+
const imports = vendorDeps.slice().sort((a, b) => a.specifier.localeCompare(b.specifier)).map((d) => `import "${DEPS_PREFIX}${d.fileName}";`).join("\n");
|
|
3116
|
+
const body = `${IONIFY_VENDOR_PACK_MARKER} ${vendorKey}
|
|
3117
|
+
// depsHash: ${depsHash}
|
|
3118
|
+
// vendor: ${vendorDeps.map((d) => d.specifier).join(", ")}
|
|
3119
|
+
${imports}
|
|
3120
|
+
`;
|
|
3121
|
+
try {
|
|
3122
|
+
import_fs11.default.writeFileSync(filePath, body, "utf8");
|
|
3123
|
+
} catch {
|
|
3124
|
+
}
|
|
3125
|
+
};
|
|
2174
3126
|
const transformer = new TransformEngine({ casRoot, versionHash: configHash });
|
|
2175
3127
|
const graph = new Graph(rawVersionInputs);
|
|
2176
3128
|
if (native?.initAstCache) {
|
|
@@ -2181,7 +3133,7 @@ async function startDevServer({
|
|
|
2181
3133
|
try {
|
|
2182
3134
|
native.astCacheWarmup();
|
|
2183
3135
|
} catch (err) {
|
|
2184
|
-
|
|
3136
|
+
logWarn2(`AST cache warmup skipped: ${err}`);
|
|
2185
3137
|
}
|
|
2186
3138
|
}
|
|
2187
3139
|
if (native?.astCacheStats) {
|
|
@@ -2212,6 +3164,9 @@ async function startDevServer({
|
|
|
2212
3164
|
NODE_ENV: process.env.NODE_ENV,
|
|
2213
3165
|
MODE: process.env.MODE
|
|
2214
3166
|
};
|
|
3167
|
+
const envPrefix = userConfig?.envPrefix || ["VITE_", "IONIFY_"];
|
|
3168
|
+
const defineConfig = buildDefineConfig(userConfig?.define, envValues, envPrefix);
|
|
3169
|
+
logInfo(`[define] ${Object.keys(defineConfig).length} replacements configured`);
|
|
2215
3170
|
const envPlaceholderPattern = /%([A-Z0-9_]+)%/g;
|
|
2216
3171
|
const envEnabledExts = /* @__PURE__ */ new Set([
|
|
2217
3172
|
".html",
|
|
@@ -2255,7 +3210,7 @@ async function startDevServer({
|
|
|
2255
3210
|
const buildUpdatePayload = async (modules) => {
|
|
2256
3211
|
const updates = [];
|
|
2257
3212
|
for (const mod of modules) {
|
|
2258
|
-
const exists =
|
|
3213
|
+
const exists = import_fs11.default.existsSync(mod.absPath);
|
|
2259
3214
|
if (mod.reason === "deleted" || !exists) {
|
|
2260
3215
|
graph.removeFile(mod.absPath);
|
|
2261
3216
|
watcher.unwatchFile(mod.absPath);
|
|
@@ -2269,9 +3224,53 @@ async function startDevServer({
|
|
|
2269
3224
|
continue;
|
|
2270
3225
|
}
|
|
2271
3226
|
watcher.watchFile(mod.absPath);
|
|
3227
|
+
const ext = import_path15.default.extname(mod.absPath).toLowerCase();
|
|
3228
|
+
if (ext === ".css") {
|
|
3229
|
+
let hash2 = mod.hash;
|
|
3230
|
+
if (!hash2) {
|
|
3231
|
+
try {
|
|
3232
|
+
hash2 = getCacheKey(import_fs11.default.readFileSync(mod.absPath, "utf8"));
|
|
3233
|
+
} catch {
|
|
3234
|
+
hash2 = graph.getNode(mod.absPath)?.hash ?? getCacheKey(mod.absPath);
|
|
3235
|
+
}
|
|
3236
|
+
}
|
|
3237
|
+
const depsAbs2 = graph.getNode(mod.absPath)?.deps ?? [];
|
|
3238
|
+
const kind = /\.module\.css$/i.test(mod.absPath) ? "css-module" : "css";
|
|
3239
|
+
graph.recordFile(mod.absPath, hash2, depsAbs2, [], kind);
|
|
3240
|
+
updates.push({
|
|
3241
|
+
url: mod.url,
|
|
3242
|
+
hash: hash2,
|
|
3243
|
+
deps: depsAbs2.map((dep) => normalizeUrlFromFs(rootDir, dep)),
|
|
3244
|
+
reason: mod.reason,
|
|
3245
|
+
status: "updated",
|
|
3246
|
+
code: ""
|
|
3247
|
+
});
|
|
3248
|
+
continue;
|
|
3249
|
+
}
|
|
3250
|
+
if (isAssetExt(ext)) {
|
|
3251
|
+
let hash2 = mod.hash;
|
|
3252
|
+
if (!hash2) {
|
|
3253
|
+
try {
|
|
3254
|
+
const buf = import_fs11.default.readFileSync(mod.absPath);
|
|
3255
|
+
hash2 = import_crypto4.default.createHash("sha256").update(buf).digest("hex");
|
|
3256
|
+
} catch {
|
|
3257
|
+
hash2 = graph.getNode(mod.absPath)?.hash ?? getCacheKey(mod.absPath);
|
|
3258
|
+
}
|
|
3259
|
+
}
|
|
3260
|
+
graph.recordFile(mod.absPath, hash2, [], [], "asset");
|
|
3261
|
+
updates.push({
|
|
3262
|
+
url: mod.url,
|
|
3263
|
+
hash: hash2,
|
|
3264
|
+
deps: [],
|
|
3265
|
+
reason: mod.reason,
|
|
3266
|
+
status: "updated",
|
|
3267
|
+
code: ""
|
|
3268
|
+
});
|
|
3269
|
+
continue;
|
|
3270
|
+
}
|
|
2272
3271
|
let code;
|
|
2273
3272
|
try {
|
|
2274
|
-
code =
|
|
3273
|
+
code = import_fs11.default.readFileSync(mod.absPath, "utf8");
|
|
2275
3274
|
} catch (err) {
|
|
2276
3275
|
logError("Failed to read module during HMR apply", err);
|
|
2277
3276
|
throw err;
|
|
@@ -2299,13 +3298,14 @@ async function startDevServer({
|
|
|
2299
3298
|
const result = await transformer.run({
|
|
2300
3299
|
path: mod.absPath,
|
|
2301
3300
|
code,
|
|
2302
|
-
ext:
|
|
2303
|
-
moduleHash: hash
|
|
3301
|
+
ext: import_path15.default.extname(mod.absPath),
|
|
3302
|
+
moduleHash: hash,
|
|
3303
|
+
config: userConfig ?? null
|
|
2304
3304
|
});
|
|
2305
3305
|
const transformed = result.code;
|
|
2306
3306
|
const envApplied = applyEnvPlaceholders(
|
|
2307
3307
|
transformed,
|
|
2308
|
-
|
|
3308
|
+
import_path15.default.extname(mod.absPath)
|
|
2309
3309
|
);
|
|
2310
3310
|
updates.push({
|
|
2311
3311
|
url: mod.url,
|
|
@@ -2346,7 +3346,7 @@ async function startDevServer({
|
|
|
2346
3346
|
const asset = readClientAssetFile("react-refresh-runtime.js");
|
|
2347
3347
|
let reactRefreshPath;
|
|
2348
3348
|
try {
|
|
2349
|
-
const projectRequire = (0, import_module3.createRequire)(
|
|
3349
|
+
const projectRequire = (0, import_module3.createRequire)(import_path15.default.join(rootDir, "package.json"));
|
|
2350
3350
|
reactRefreshPath = projectRequire.resolve("react-refresh/runtime");
|
|
2351
3351
|
} catch (err) {
|
|
2352
3352
|
logError("Failed to resolve react-refresh/runtime", err);
|
|
@@ -2429,6 +3429,108 @@ async function startDevServer({
|
|
|
2429
3429
|
sendJson(res, 200, { ok: true });
|
|
2430
3430
|
return;
|
|
2431
3431
|
}
|
|
3432
|
+
if (reqPath.startsWith(DEPS_PREFIX)) {
|
|
3433
|
+
const fileName = reqPath.slice(DEPS_PREFIX.length);
|
|
3434
|
+
if (vendorPackFileName && fileName === vendorPackFileName) {
|
|
3435
|
+
ensureVendorPackFile();
|
|
3436
|
+
}
|
|
3437
|
+
if (fileName.endsWith(".js.map")) {
|
|
3438
|
+
const mapPath = import_path15.default.join(depsRoot, fileName);
|
|
3439
|
+
if (import_fs11.default.existsSync(mapPath)) {
|
|
3440
|
+
const stat = import_fs11.default.statSync(mapPath);
|
|
3441
|
+
const etag = weakEtagFromStat(`deps-map-${depsHash}`, stat);
|
|
3442
|
+
if (isNotModified(req, etag)) {
|
|
3443
|
+
res.setHeader("ETag", etag);
|
|
3444
|
+
res.setHeader("Cache-Control", "public, max-age=31536000, immutable");
|
|
3445
|
+
res.statusCode = 304;
|
|
3446
|
+
res.end();
|
|
3447
|
+
return;
|
|
3448
|
+
}
|
|
3449
|
+
sendBuffer(
|
|
3450
|
+
req,
|
|
3451
|
+
res,
|
|
3452
|
+
200,
|
|
3453
|
+
"application/json; charset=utf-8",
|
|
3454
|
+
import_fs11.default.readFileSync(mapPath),
|
|
3455
|
+
{ etag, cacheControl: "public, max-age=31536000, immutable" }
|
|
3456
|
+
);
|
|
3457
|
+
return;
|
|
3458
|
+
}
|
|
3459
|
+
}
|
|
3460
|
+
const depsFilePath = import_path15.default.join(depsRoot, fileName);
|
|
3461
|
+
const entryFromManifest = depsManifestIndex.get(fileName);
|
|
3462
|
+
const entryFromRegistry = getDepEntry(fileName);
|
|
3463
|
+
const entryPath = entryFromManifest?.entryPath ?? entryFromRegistry?.entryPath;
|
|
3464
|
+
const packageLabel = entryFromRegistry?.packageName ? formatDepLabel(entryFromRegistry.packageName, entryFromRegistry.subpath) : entryFromManifest?.packageLabel ?? fileName;
|
|
3465
|
+
if (import_fs11.default.existsSync(depsFilePath)) {
|
|
3466
|
+
const stat = import_fs11.default.statSync(depsFilePath);
|
|
3467
|
+
const etag = weakEtagFromStat(`deps-${depsHash}`, stat);
|
|
3468
|
+
if (isNotModified(req, etag)) {
|
|
3469
|
+
res.setHeader("ETag", etag);
|
|
3470
|
+
res.setHeader("Cache-Control", "public, max-age=31536000, immutable");
|
|
3471
|
+
res.statusCode = 304;
|
|
3472
|
+
res.end();
|
|
3473
|
+
logInfo(`[deps] OPTIMIZE ${packageLabel}: HIT from cache (304)`);
|
|
3474
|
+
return;
|
|
3475
|
+
}
|
|
3476
|
+
sendBuffer(
|
|
3477
|
+
req,
|
|
3478
|
+
res,
|
|
3479
|
+
200,
|
|
3480
|
+
"application/javascript; charset=utf-8",
|
|
3481
|
+
import_fs11.default.readFileSync(depsFilePath),
|
|
3482
|
+
{ etag, cacheControl: "public, max-age=31536000, immutable" }
|
|
3483
|
+
);
|
|
3484
|
+
logInfo(`[deps] OPTIMIZE ${packageLabel}: HIT from cache`);
|
|
3485
|
+
return;
|
|
3486
|
+
}
|
|
3487
|
+
if (!entryPath || !native?.optimizeDependency) {
|
|
3488
|
+
res.statusCode = 404;
|
|
3489
|
+
res.end("Dependency not found");
|
|
3490
|
+
return;
|
|
3491
|
+
}
|
|
3492
|
+
try {
|
|
3493
|
+
const start = Date.now();
|
|
3494
|
+
const rawSize = import_fs11.default.existsSync(entryPath) ? import_fs11.default.statSync(entryPath).size : 0;
|
|
3495
|
+
const result2 = native.optimizeDependency(entryPath, depsHash, depsSourcemapEnabled, depsBundleEsmEnabled);
|
|
3496
|
+
const outPath = result2?.out_path ?? result2?.outPath ?? depsFilePath;
|
|
3497
|
+
const mapPath = result2?.map_path ?? result2?.mapPath ?? null;
|
|
3498
|
+
const resolvedOutPath = import_path15.default.isAbsolute(outPath) ? outPath : import_path15.default.join(depsRoot, outPath);
|
|
3499
|
+
if (!import_fs11.default.existsSync(resolvedOutPath)) {
|
|
3500
|
+
throw new Error("Optimizer did not produce output");
|
|
3501
|
+
}
|
|
3502
|
+
const outBuffer = import_fs11.default.readFileSync(resolvedOutPath);
|
|
3503
|
+
const optimizedSize = outBuffer.length;
|
|
3504
|
+
const stat = import_fs11.default.statSync(resolvedOutPath);
|
|
3505
|
+
const etag = weakEtagFromStat(`deps-${depsHash}`, stat);
|
|
3506
|
+
sendBuffer(req, res, 200, "application/javascript; charset=utf-8", outBuffer, {
|
|
3507
|
+
etag,
|
|
3508
|
+
cacheControl: "public, max-age=31536000, immutable"
|
|
3509
|
+
});
|
|
3510
|
+
const elapsed = Date.now() - start;
|
|
3511
|
+
const rawKb = (rawSize / 1024).toFixed(1);
|
|
3512
|
+
const optKb = (optimizedSize / 1024).toFixed(1);
|
|
3513
|
+
const mapSuffix = mapPath ? ` map=${import_path15.default.basename(mapPath)}` : "";
|
|
3514
|
+
logInfo(`[deps] OPTIMIZE ${packageLabel}: MISS \u2192 BUILD (${elapsed}ms, ${rawKb}KB \u2192 ${optKb}KB)${mapSuffix}`);
|
|
3515
|
+
const refreshed = loadDepsManifestIndex(depsRoot);
|
|
3516
|
+
refreshed.forEach((value, key) => depsManifestIndex.set(key, value));
|
|
3517
|
+
return;
|
|
3518
|
+
} catch (err) {
|
|
3519
|
+
logWarn2(
|
|
3520
|
+
`[deps] WARN: Optimization failed for ${packageLabel}, serving raw (fallback): ${String(err)}`
|
|
3521
|
+
);
|
|
3522
|
+
try {
|
|
3523
|
+
const raw = import_fs11.default.readFileSync(entryPath);
|
|
3524
|
+
res.writeHead(200, { "Content-Type": "application/javascript; charset=utf-8" });
|
|
3525
|
+
res.end(raw);
|
|
3526
|
+
} catch (readErr) {
|
|
3527
|
+
logError("Failed to read raw dependency", readErr);
|
|
3528
|
+
res.statusCode = 500;
|
|
3529
|
+
res.end("Dependency optimization failed");
|
|
3530
|
+
}
|
|
3531
|
+
return;
|
|
3532
|
+
}
|
|
3533
|
+
}
|
|
2432
3534
|
const fsPath = decodePublicPath(rootDir, reqPath);
|
|
2433
3535
|
if (!fsPath) {
|
|
2434
3536
|
res.statusCode = 404;
|
|
@@ -2437,12 +3539,12 @@ async function startDevServer({
|
|
|
2437
3539
|
}
|
|
2438
3540
|
let effectiveFsPath = fsPath;
|
|
2439
3541
|
let effectiveUrlPath = reqPath;
|
|
2440
|
-
if (
|
|
3542
|
+
if (import_fs11.default.existsSync(effectiveFsPath) && import_fs11.default.statSync(effectiveFsPath).isDirectory()) {
|
|
2441
3543
|
const indexExtensions = [".html", ".js", ".ts", ".tsx", ".jsx"];
|
|
2442
3544
|
let found = false;
|
|
2443
3545
|
for (const ext2 of indexExtensions) {
|
|
2444
|
-
const indexFile =
|
|
2445
|
-
if (
|
|
3546
|
+
const indexFile = import_path15.default.join(effectiveFsPath, `index${ext2}`);
|
|
3547
|
+
if (import_fs11.default.existsSync(indexFile)) {
|
|
2446
3548
|
effectiveFsPath = indexFile;
|
|
2447
3549
|
effectiveUrlPath = effectiveUrlPath.endsWith("/") ? `${effectiveUrlPath}index${ext2}` : `${effectiveUrlPath}/index${ext2}`;
|
|
2448
3550
|
found = true;
|
|
@@ -2450,13 +3552,13 @@ async function startDevServer({
|
|
|
2450
3552
|
}
|
|
2451
3553
|
}
|
|
2452
3554
|
if (!found) {
|
|
2453
|
-
const packageJson =
|
|
2454
|
-
if (
|
|
3555
|
+
const packageJson = import_path15.default.join(effectiveFsPath, "package.json");
|
|
3556
|
+
if (import_fs11.default.existsSync(packageJson)) {
|
|
2455
3557
|
try {
|
|
2456
|
-
const pkg = JSON.parse(
|
|
3558
|
+
const pkg = JSON.parse(import_fs11.default.readFileSync(packageJson, "utf8"));
|
|
2457
3559
|
if (pkg.main) {
|
|
2458
|
-
const mainFile =
|
|
2459
|
-
if (
|
|
3560
|
+
const mainFile = import_path15.default.join(effectiveFsPath, pkg.main);
|
|
3561
|
+
if (import_fs11.default.existsSync(mainFile)) {
|
|
2460
3562
|
effectiveFsPath = mainFile;
|
|
2461
3563
|
found = true;
|
|
2462
3564
|
}
|
|
@@ -2467,8 +3569,8 @@ async function startDevServer({
|
|
|
2467
3569
|
}
|
|
2468
3570
|
if (!found) {
|
|
2469
3571
|
for (const ext2 of indexExtensions) {
|
|
2470
|
-
const moduleFile =
|
|
2471
|
-
if (
|
|
3572
|
+
const moduleFile = import_path15.default.join(effectiveFsPath, `module${ext2}`);
|
|
3573
|
+
if (import_fs11.default.existsSync(moduleFile)) {
|
|
2472
3574
|
effectiveFsPath = moduleFile;
|
|
2473
3575
|
found = true;
|
|
2474
3576
|
break;
|
|
@@ -2481,16 +3583,16 @@ async function startDevServer({
|
|
|
2481
3583
|
return;
|
|
2482
3584
|
}
|
|
2483
3585
|
}
|
|
2484
|
-
if (!
|
|
3586
|
+
if (!import_fs11.default.existsSync(effectiveFsPath)) {
|
|
2485
3587
|
res.statusCode = 404;
|
|
2486
3588
|
res.end("Not found");
|
|
2487
3589
|
return;
|
|
2488
3590
|
}
|
|
2489
|
-
const ext =
|
|
3591
|
+
const ext = import_path15.default.extname(effectiveFsPath);
|
|
2490
3592
|
if (isAssetExt(ext)) {
|
|
2491
3593
|
try {
|
|
2492
|
-
const data =
|
|
2493
|
-
const assetHash =
|
|
3594
|
+
const data = import_fs11.default.readFileSync(effectiveFsPath);
|
|
3595
|
+
const assetHash = import_crypto4.default.createHash("sha256").update(data).digest("hex");
|
|
2494
3596
|
const kind = "asset";
|
|
2495
3597
|
const changed2 = graph.recordFile(effectiveFsPath, assetHash, [], [], kind);
|
|
2496
3598
|
watcher.watchFile(effectiveFsPath);
|
|
@@ -2506,67 +3608,115 @@ async function startDevServer({
|
|
|
2506
3608
|
return;
|
|
2507
3609
|
} else {
|
|
2508
3610
|
res.writeHead(200, { "Content-Type": contentTypeForAsset(ext) });
|
|
2509
|
-
|
|
3611
|
+
import_fs11.default.createReadStream(effectiveFsPath).pipe(res);
|
|
2510
3612
|
return;
|
|
2511
3613
|
}
|
|
2512
3614
|
}
|
|
2513
3615
|
if (ext === ".css") {
|
|
2514
3616
|
try {
|
|
2515
|
-
const cssSource =
|
|
3617
|
+
const cssSource = import_fs11.default.readFileSync(effectiveFsPath, "utf8");
|
|
2516
3618
|
const isModule = "module" in q || /\.module\.css$/i.test(effectiveFsPath);
|
|
2517
|
-
const
|
|
2518
|
-
const mode = isModule ? "css:module" : isInline ? "css:inline" : "css:raw";
|
|
3619
|
+
const mode = "raw" in q ? "css:raw-string" : "url" in q ? "css:url" : isModule ? "css:module" : "inline" in q ? "css:inline" : "css:raw";
|
|
2519
3620
|
const contentHash = getCacheKey(cssSource);
|
|
2520
3621
|
watcher.watchFile(effectiveFsPath);
|
|
2521
3622
|
const kind = isModule ? "css-module" : "css";
|
|
2522
|
-
const
|
|
2523
|
-
const
|
|
2524
|
-
|
|
3623
|
+
const prevDeps = graph.getNode(effectiveFsPath)?.deps ?? [];
|
|
3624
|
+
for (const dep of prevDeps) {
|
|
3625
|
+
watcher.watchFile(dep);
|
|
3626
|
+
}
|
|
3627
|
+
const depsStampHash = computeDepsStampHash(prevDeps);
|
|
3628
|
+
let artifactHash = getCacheKey(
|
|
3629
|
+
`css:v2:${effectiveFsPath}:${contentHash}:${mode}:${depsStampHash}`
|
|
3630
|
+
);
|
|
3631
|
+
let casDir = getCasArtifactPath(casRoot, configHash, artifactHash);
|
|
3632
|
+
const jsMode = mode !== "css:raw";
|
|
3633
|
+
let casFile = import_path15.default.join(casDir, jsMode ? "transformed.js" : "transformed.css");
|
|
2525
3634
|
let finalBuffer = null;
|
|
2526
|
-
if (
|
|
3635
|
+
if (import_fs11.default.existsSync(casFile)) {
|
|
2527
3636
|
try {
|
|
2528
|
-
finalBuffer =
|
|
2529
|
-
|
|
3637
|
+
finalBuffer = import_fs11.default.readFileSync(casFile);
|
|
3638
|
+
const ok = jsMode ? looksLikeIonifyCssJsModule(finalBuffer) : !looksLikeIonifyCssJsModule(finalBuffer);
|
|
3639
|
+
if (ok) {
|
|
3640
|
+
res.setHeader("X-Ionify-Cache", "HIT");
|
|
3641
|
+
} else {
|
|
3642
|
+
finalBuffer = null;
|
|
3643
|
+
res.setHeader("X-Ionify-Cache", "MISMATCH");
|
|
3644
|
+
}
|
|
2530
3645
|
} catch {
|
|
2531
3646
|
finalBuffer = null;
|
|
2532
3647
|
}
|
|
2533
3648
|
}
|
|
2534
3649
|
if (!finalBuffer) {
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
3650
|
+
let body;
|
|
3651
|
+
if (mode === "css:url") {
|
|
3652
|
+
const rawUrl = `${effectiveUrlPath}?v=${contentHash}-${depsStampHash.slice(0, 8)}`;
|
|
3653
|
+
body = renderCssUrlModule(rawUrl);
|
|
3654
|
+
} else {
|
|
3655
|
+
const { css: compiledCss, tokens, deps } = await compileCss({
|
|
3656
|
+
code: cssSource,
|
|
3657
|
+
filePath: effectiveFsPath,
|
|
3658
|
+
rootDir,
|
|
3659
|
+
modules: isModule
|
|
3660
|
+
});
|
|
3661
|
+
const depsAbs2 = deps.map((d) => d.filePath).filter(Boolean);
|
|
3662
|
+
const nextDepsStampHash = computeDepsStampHash(depsAbs2);
|
|
3663
|
+
artifactHash = getCacheKey(
|
|
3664
|
+
`css:v2:${effectiveFsPath}:${contentHash}:${mode}:${nextDepsStampHash}`
|
|
3665
|
+
);
|
|
3666
|
+
casDir = getCasArtifactPath(casRoot, configHash, artifactHash);
|
|
3667
|
+
casFile = import_path15.default.join(casDir, jsMode ? "transformed.js" : "transformed.css");
|
|
3668
|
+
const changed2 = graph.recordFile(effectiveFsPath, contentHash, depsAbs2, [], kind);
|
|
3669
|
+
if (changed2) {
|
|
3670
|
+
logInfo(`[Graph] CSS updated: ${effectiveFsPath}`);
|
|
3671
|
+
}
|
|
3672
|
+
for (const dep of depsAbs2) {
|
|
3673
|
+
watcher.watchFile(dep);
|
|
3674
|
+
}
|
|
3675
|
+
if (mode === "css:raw") {
|
|
3676
|
+
body = compiledCss;
|
|
3677
|
+
} else if (mode === "css:raw-string") {
|
|
3678
|
+
body = renderCssRawStringModule(compiledCss);
|
|
3679
|
+
} else {
|
|
3680
|
+
body = renderCssModule({
|
|
3681
|
+
css: compiledCss,
|
|
3682
|
+
filePath: effectiveFsPath,
|
|
3683
|
+
tokens: isModule ? tokens ?? {} : void 0
|
|
3684
|
+
});
|
|
3685
|
+
}
|
|
3686
|
+
}
|
|
2546
3687
|
finalBuffer = Buffer.from(body, "utf8");
|
|
2547
3688
|
res.setHeader("X-Ionify-Cache", "MISS");
|
|
2548
3689
|
try {
|
|
2549
|
-
|
|
2550
|
-
|
|
3690
|
+
import_fs11.default.mkdirSync(casDir, { recursive: true });
|
|
3691
|
+
import_fs11.default.writeFileSync(casFile, finalBuffer);
|
|
2551
3692
|
} catch {
|
|
2552
3693
|
}
|
|
2553
3694
|
}
|
|
2554
|
-
|
|
2555
|
-
|
|
3695
|
+
const etag = `W/"css-${configHash}-${artifactHash}-${mode}"`;
|
|
3696
|
+
if (jsMode) {
|
|
3697
|
+
sendBuffer(req, res, 200, "application/javascript; charset=utf-8", finalBuffer, {
|
|
3698
|
+
etag,
|
|
3699
|
+
cacheControl: "no-cache"
|
|
3700
|
+
});
|
|
2556
3701
|
} else {
|
|
2557
|
-
|
|
3702
|
+
sendBuffer(req, res, 200, "text/css; charset=utf-8", finalBuffer, {
|
|
3703
|
+
etag,
|
|
3704
|
+
cacheControl: "no-cache"
|
|
3705
|
+
});
|
|
2558
3706
|
}
|
|
2559
|
-
|
|
2560
|
-
logInfo(`Served: ${effectiveUrlPath} deps:0 ${changed2 ? "(updated)" : "(cached)"}`);
|
|
3707
|
+
logInfo(`Served: ${effectiveUrlPath} ${mode}`);
|
|
2561
3708
|
return;
|
|
2562
3709
|
} catch (err) {
|
|
2563
3710
|
logError("Failed to process CSS", err);
|
|
3711
|
+
hmr.broadcastError({
|
|
3712
|
+
message: err instanceof Error ? `Failed to process CSS: ${err.stack || err.message}` : `Failed to process CSS: ${String(err)}`
|
|
3713
|
+
});
|
|
2564
3714
|
res.statusCode = 500;
|
|
2565
3715
|
res.end("Failed to process CSS");
|
|
2566
3716
|
return;
|
|
2567
3717
|
}
|
|
2568
3718
|
}
|
|
2569
|
-
const code =
|
|
3719
|
+
const code = import_fs11.default.readFileSync(effectiveFsPath, "utf8");
|
|
2570
3720
|
let hash;
|
|
2571
3721
|
let specs;
|
|
2572
3722
|
if (native?.parseModuleIr) {
|
|
@@ -2588,23 +3738,40 @@ async function startDevServer({
|
|
|
2588
3738
|
for (const dep of depsAbs) {
|
|
2589
3739
|
watcher.watchFile(dep);
|
|
2590
3740
|
}
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
3741
|
+
let result;
|
|
3742
|
+
try {
|
|
3743
|
+
result = await transformer.run({
|
|
3744
|
+
path: effectiveFsPath,
|
|
3745
|
+
code,
|
|
3746
|
+
ext,
|
|
3747
|
+
moduleHash: hash,
|
|
3748
|
+
config: userConfig ?? null
|
|
3749
|
+
});
|
|
3750
|
+
} catch (err) {
|
|
3751
|
+
const message = err instanceof Error ? err.stack || err.message : String(err);
|
|
3752
|
+
hmr.broadcastError({ message: `Failed to transform ${effectiveUrlPath}: ${message}` });
|
|
3753
|
+
throw err;
|
|
3754
|
+
}
|
|
2597
3755
|
const transformedCode = result.code;
|
|
2598
3756
|
res.setHeader("X-Ionify-Cache", changed ? "MISS" : "HIT");
|
|
2599
|
-
const
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
3757
|
+
const withDefine = applyDefineReplacements(transformedCode, defineConfig);
|
|
3758
|
+
const envApplied = applyEnvPlaceholders(withDefine, ext);
|
|
3759
|
+
if (import_path15.default.extname(effectiveFsPath) === ".html") {
|
|
3760
|
+
ensureVendorPackFile();
|
|
3761
|
+
const withVendor = vendorPackUrl ? injectModulePreload(envApplied, vendorPackUrl) : envApplied;
|
|
3762
|
+
const injected = injectHMRClient(withVendor);
|
|
3763
|
+
const etag = `W/"html-${configHash}-${hash}"`;
|
|
3764
|
+
sendBuffer(req, res, 200, "text/html; charset=utf-8", Buffer.from(injected, "utf8"), {
|
|
3765
|
+
etag,
|
|
3766
|
+
cacheControl: "no-cache"
|
|
3767
|
+
});
|
|
2604
3768
|
} else {
|
|
2605
3769
|
const finalBuffer = Buffer.from(envApplied);
|
|
2606
|
-
|
|
2607
|
-
res
|
|
3770
|
+
const etag = `W/"mod-${configHash}-${hash}"`;
|
|
3771
|
+
sendBuffer(req, res, 200, guessContentType(effectiveFsPath), finalBuffer, {
|
|
3772
|
+
etag,
|
|
3773
|
+
cacheControl: "no-cache"
|
|
3774
|
+
});
|
|
2608
3775
|
}
|
|
2609
3776
|
logInfo(`Served: ${effectiveUrlPath} deps:${depsAbs.length} ${changed ? "(updated)" : "(cached)"}`);
|
|
2610
3777
|
if (cacheDebug) {
|
|
@@ -2619,7 +3786,16 @@ async function startDevServer({
|
|
|
2619
3786
|
});
|
|
2620
3787
|
watcher.on("change", (file, status) => {
|
|
2621
3788
|
logInfo(`[Watcher] ${status}: ${file}`);
|
|
2622
|
-
const
|
|
3789
|
+
const ext = import_path15.default.extname(file).toLowerCase();
|
|
3790
|
+
const isReactFastRefreshBoundary = status !== "deleted" && (ext === ".tsx" || ext === ".jsx");
|
|
3791
|
+
const isCssBoundary = status !== "deleted" && ext === ".css";
|
|
3792
|
+
const collected = graph.collectAffected([file]);
|
|
3793
|
+
const affected = isReactFastRefreshBoundary || isCssBoundary ? [
|
|
3794
|
+
file,
|
|
3795
|
+
...collected.filter(
|
|
3796
|
+
(absPath) => absPath !== file && import_path15.default.extname(absPath).toLowerCase() === ".css"
|
|
3797
|
+
)
|
|
3798
|
+
] : collected;
|
|
2623
3799
|
if (!affected.includes(file)) {
|
|
2624
3800
|
affected.unshift(file);
|
|
2625
3801
|
}
|
|
@@ -2630,7 +3806,7 @@ async function startDevServer({
|
|
|
2630
3806
|
if (reason !== "deleted") {
|
|
2631
3807
|
if (absPath === file) {
|
|
2632
3808
|
try {
|
|
2633
|
-
const code =
|
|
3809
|
+
const code = import_fs11.default.readFileSync(absPath, "utf8");
|
|
2634
3810
|
hash = getCacheKey(code);
|
|
2635
3811
|
} catch {
|
|
2636
3812
|
hash = graph.getNode(absPath)?.hash ?? null;
|
|
@@ -2641,7 +3817,7 @@ async function startDevServer({
|
|
|
2641
3817
|
}
|
|
2642
3818
|
modules.push({
|
|
2643
3819
|
absPath,
|
|
2644
|
-
url: normalizeUrlFromFs(rootDir, absPath),
|
|
3820
|
+
url: import_path15.default.extname(absPath).toLowerCase() === ".css" ? `${normalizeUrlFromFs(rootDir, absPath)}?inline` : isAssetExt(import_path15.default.extname(absPath).toLowerCase()) ? `${normalizeUrlFromFs(rootDir, absPath)}?import` : normalizeUrlFromFs(rootDir, absPath),
|
|
2645
3821
|
hash,
|
|
2646
3822
|
reason
|
|
2647
3823
|
});
|
|
@@ -2729,13 +3905,98 @@ async function startDevServer({
|
|
|
2729
3905
|
signalHandlers.push({ event: "SIGINT", handler: onSignal });
|
|
2730
3906
|
signalHandlers.push({ event: "SIGTERM", handler: onSignal });
|
|
2731
3907
|
}
|
|
2732
|
-
await new Promise((resolve) => {
|
|
2733
|
-
|
|
3908
|
+
await new Promise((resolve, reject) => {
|
|
3909
|
+
const onError = (err) => reject(err);
|
|
3910
|
+
server.once("error", onError);
|
|
3911
|
+
server.listen(port, host, () => {
|
|
3912
|
+
server.off("error", onError);
|
|
3913
|
+
resolve();
|
|
3914
|
+
});
|
|
2734
3915
|
});
|
|
2735
3916
|
const address = server.address();
|
|
2736
3917
|
const actualPort = address && typeof address === "object" && address?.port ? address.port : port;
|
|
2737
3918
|
logInfo(`Ionify Dev Server (Phase 2) at http://localhost:${actualPort}`);
|
|
3919
|
+
logInfo(`Ready in ${Date.now() - bootStartMs}ms`);
|
|
2738
3920
|
logInfo(`HMR listening at /__ionify_hmr (SSE)`);
|
|
3921
|
+
if (vendorDeps.length > 0) {
|
|
3922
|
+
const vendorLabels = vendorDeps.map((d) => d.packageLabel).join(", ");
|
|
3923
|
+
logInfo(`[deps] Vendor pack detected (${vendorDeps.length}): ${vendorLabels}`);
|
|
3924
|
+
ensureVendorPackFile();
|
|
3925
|
+
const missing = vendorDeps.filter((d) => !import_fs11.default.existsSync(import_path15.default.join(depsRoot, d.fileName)));
|
|
3926
|
+
if (missing.length > 0) {
|
|
3927
|
+
const entryCount = missing.length;
|
|
3928
|
+
logInfo(`[deps] Pre-warming vendor deps (${entryCount}) in parallel...`);
|
|
3929
|
+
Promise.resolve().then(() => {
|
|
3930
|
+
if (native?.optimizeDependenciesBatch && !depsSourcemapEnabled && depsBundleEsmEnabled) {
|
|
3931
|
+
const results = native.optimizeDependenciesBatch(
|
|
3932
|
+
missing.map((d) => ({ entryPath: d.entryPath, depsHash }))
|
|
3933
|
+
);
|
|
3934
|
+
results.forEach((r, idx) => {
|
|
3935
|
+
const dep = missing[idx];
|
|
3936
|
+
if (r?.error) {
|
|
3937
|
+
logWarn2(`[deps] Vendor prewarm failed ${dep.packageLabel}: ${r.error}`);
|
|
3938
|
+
} else if (r?.out_path || r?.outPath) {
|
|
3939
|
+
const outPath = r.out_path ?? r.outPath;
|
|
3940
|
+
logInfo(
|
|
3941
|
+
`[deps] \u2713 Vendor prewarmed ${dep.packageLabel} \u2192 ${import_path15.default.basename(outPath)}`
|
|
3942
|
+
);
|
|
3943
|
+
}
|
|
3944
|
+
});
|
|
3945
|
+
return;
|
|
3946
|
+
}
|
|
3947
|
+
if (!native?.optimizeDependency) return;
|
|
3948
|
+
for (const dep of missing) {
|
|
3949
|
+
try {
|
|
3950
|
+
const result = native.optimizeDependency(
|
|
3951
|
+
dep.entryPath,
|
|
3952
|
+
depsHash,
|
|
3953
|
+
depsSourcemapEnabled,
|
|
3954
|
+
depsBundleEsmEnabled
|
|
3955
|
+
);
|
|
3956
|
+
const outPath = result?.out_path ?? result?.outPath ?? null;
|
|
3957
|
+
if (outPath) {
|
|
3958
|
+
logInfo(`[deps] \u2713 Vendor prewarmed ${dep.packageLabel} \u2192 ${import_path15.default.basename(outPath)}`);
|
|
3959
|
+
}
|
|
3960
|
+
} catch (err) {
|
|
3961
|
+
logWarn2(`[deps] Vendor prewarm failed ${dep.packageLabel}: ${String(err)}`);
|
|
3962
|
+
}
|
|
3963
|
+
}
|
|
3964
|
+
}).catch((err) => {
|
|
3965
|
+
logWarn2(`[deps] Vendor prewarm error: ${err}`);
|
|
3966
|
+
});
|
|
3967
|
+
}
|
|
3968
|
+
}
|
|
3969
|
+
if (userConfig?.optimizeDeps?.include && Array.isArray(userConfig.optimizeDeps.include)) {
|
|
3970
|
+
const includes = userConfig.optimizeDeps.include;
|
|
3971
|
+
if (includes.length > 0) {
|
|
3972
|
+
logInfo(`[deps] Pre-warming ${includes.length} dependencies: ${includes.join(", ")}`);
|
|
3973
|
+
Promise.all(
|
|
3974
|
+
includes.map(async (pkgName) => {
|
|
3975
|
+
try {
|
|
3976
|
+
if (!native?.resolveModule || !native?.optimizeDependency) {
|
|
3977
|
+
logWarn2(`[deps] Cannot pre-warm ${pkgName}: native functions not available`);
|
|
3978
|
+
return;
|
|
3979
|
+
}
|
|
3980
|
+
const resolved = native.resolveModule(pkgName, rootDir);
|
|
3981
|
+
if (!resolved || !resolved.fsPath && !resolved.fs_path) {
|
|
3982
|
+
logWarn2(`[deps] Cannot pre-warm ${pkgName}: resolution failed`);
|
|
3983
|
+
return;
|
|
3984
|
+
}
|
|
3985
|
+
const entryPath = resolved.fsPath || resolved.fs_path;
|
|
3986
|
+
const result = native.optimizeDependency(entryPath, depsHash, depsSourcemapEnabled, depsBundleEsmEnabled);
|
|
3987
|
+
if (result?.out_path) {
|
|
3988
|
+
const fileName = import_path15.default.basename(result.out_path);
|
|
3989
|
+
logInfo(`[deps] \u2713 Pre-warmed ${pkgName} \u2192 ${fileName}`);
|
|
3990
|
+
}
|
|
3991
|
+
} catch (err) {
|
|
3992
|
+
logWarn2(`[deps] Failed to pre-warm ${pkgName}: ${err}`);
|
|
3993
|
+
}
|
|
3994
|
+
})
|
|
3995
|
+
).catch((err) => {
|
|
3996
|
+
logWarn2(`[deps] Pre-warming error: ${err}`);
|
|
3997
|
+
});
|
|
3998
|
+
}
|
|
3999
|
+
}
|
|
2739
4000
|
return {
|
|
2740
4001
|
server,
|
|
2741
4002
|
port: actualPort,
|
|
@@ -2747,14 +4008,14 @@ async function startDevServer({
|
|
|
2747
4008
|
|
|
2748
4009
|
// src/cli/commands/analyze.ts
|
|
2749
4010
|
init_cjs_shims();
|
|
2750
|
-
var
|
|
2751
|
-
var
|
|
4011
|
+
var import_fs12 = __toESM(require("fs"), 1);
|
|
4012
|
+
var import_path16 = __toESM(require("path"), 1);
|
|
2752
4013
|
init_native();
|
|
2753
4014
|
function readGraphFromDisk(root) {
|
|
2754
|
-
const file =
|
|
2755
|
-
if (!
|
|
4015
|
+
const file = import_path16.default.join(root, ".ionify", "graph.json");
|
|
4016
|
+
if (!import_fs12.default.existsSync(file)) return null;
|
|
2756
4017
|
try {
|
|
2757
|
-
const raw =
|
|
4018
|
+
const raw = import_fs12.default.readFileSync(file, "utf8");
|
|
2758
4019
|
const snapshot = JSON.parse(raw);
|
|
2759
4020
|
if (snapshot?.version !== 1 || !snapshot?.nodes) return null;
|
|
2760
4021
|
return Object.entries(snapshot.nodes).map(([id, node]) => ({
|
|
@@ -2851,8 +4112,8 @@ async function runAnalyzeCommand(options = {}) {
|
|
|
2851
4112
|
|
|
2852
4113
|
// src/cli/commands/build.ts
|
|
2853
4114
|
init_cjs_shims();
|
|
2854
|
-
var
|
|
2855
|
-
var
|
|
4115
|
+
var import_fs14 = __toESM(require("fs"), 1);
|
|
4116
|
+
var import_path18 = __toESM(require("path"), 1);
|
|
2856
4117
|
init_native();
|
|
2857
4118
|
init_cas();
|
|
2858
4119
|
|
|
@@ -2945,9 +4206,9 @@ function resolveOptimizationLevel(configLevel, options = {}) {
|
|
|
2945
4206
|
|
|
2946
4207
|
// src/core/bundler.ts
|
|
2947
4208
|
init_cjs_shims();
|
|
2948
|
-
var
|
|
2949
|
-
var
|
|
2950
|
-
var
|
|
4209
|
+
var import_fs13 = __toESM(require("fs"), 1);
|
|
4210
|
+
var import_path17 = __toESM(require("path"), 1);
|
|
4211
|
+
var import_crypto5 = __toESM(require("crypto"), 1);
|
|
2951
4212
|
init_native();
|
|
2952
4213
|
init_cache();
|
|
2953
4214
|
function readGraphSnapshot() {
|
|
@@ -2964,13 +4225,13 @@ function readGraphSnapshot() {
|
|
|
2964
4225
|
}));
|
|
2965
4226
|
}
|
|
2966
4227
|
} catch (err) {
|
|
2967
|
-
|
|
4228
|
+
logWarn2(`Failed to load native graph: ${String(err)}`);
|
|
2968
4229
|
}
|
|
2969
4230
|
}
|
|
2970
|
-
const file =
|
|
2971
|
-
if (!
|
|
4231
|
+
const file = import_path17.default.join(process.cwd(), ".ionify", "graph.json");
|
|
4232
|
+
if (!import_fs13.default.existsSync(file)) return [];
|
|
2972
4233
|
try {
|
|
2973
|
-
const raw =
|
|
4234
|
+
const raw = import_fs13.default.readFileSync(file, "utf8");
|
|
2974
4235
|
const snapshot = JSON.parse(raw);
|
|
2975
4236
|
if (snapshot?.version !== 1 || !snapshot?.nodes) return [];
|
|
2976
4237
|
return Object.entries(snapshot.nodes).map(([id, node]) => ({
|
|
@@ -2979,20 +4240,20 @@ function readGraphSnapshot() {
|
|
|
2979
4240
|
deps: Array.isArray(node.deps) ? node.deps : []
|
|
2980
4241
|
}));
|
|
2981
4242
|
} catch (err) {
|
|
2982
|
-
|
|
4243
|
+
logWarn2(`Failed to read graph snapshot: ${String(err)}`);
|
|
2983
4244
|
return [];
|
|
2984
4245
|
}
|
|
2985
4246
|
}
|
|
2986
4247
|
var JS_EXTENSIONS2 = /* @__PURE__ */ new Set([".js", ".mjs", ".cjs", ".ts", ".tsx", ".jsx"]);
|
|
2987
4248
|
var CSS_EXTENSIONS = /* @__PURE__ */ new Set([".css"]);
|
|
2988
4249
|
function classifyModuleKind(id) {
|
|
2989
|
-
const ext =
|
|
4250
|
+
const ext = import_path17.default.extname(id).toLowerCase();
|
|
2990
4251
|
if (CSS_EXTENSIONS.has(ext)) return "css";
|
|
2991
4252
|
if (JS_EXTENSIONS2.has(ext)) return "js";
|
|
2992
4253
|
return "asset";
|
|
2993
4254
|
}
|
|
2994
4255
|
var isNonEmptyString = (value) => typeof value === "string" && value.length > 0;
|
|
2995
|
-
var toPosix = (p) => p.split(
|
|
4256
|
+
var toPosix = (p) => p.split(import_path17.default.sep).join("/");
|
|
2996
4257
|
function minifyCss(input) {
|
|
2997
4258
|
return input.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\s+/g, " ").replace(/\s*([{};:,])\s*/g, "$1").trim();
|
|
2998
4259
|
}
|
|
@@ -3127,7 +4388,7 @@ function fallbackPlan(entries) {
|
|
|
3127
4388
|
async function generateBuildPlan(entries, versionInputs) {
|
|
3128
4389
|
const version = versionInputs ? computeGraphVersion(versionInputs) : void 0;
|
|
3129
4390
|
logInfo(`Graph version: ${version || "default"}`);
|
|
3130
|
-
const graphDbPath =
|
|
4391
|
+
const graphDbPath = import_path17.default.join(process.cwd(), ".ionify", "graph.db");
|
|
3131
4392
|
ensureNativeGraph(graphDbPath, version);
|
|
3132
4393
|
let moduleCount = 0;
|
|
3133
4394
|
if (native?.graphLoadMap) {
|
|
@@ -3140,19 +4401,19 @@ async function generateBuildPlan(entries, versionInputs) {
|
|
|
3140
4401
|
logInfo(`Loaded persisted graph with ${graphSize} modules`);
|
|
3141
4402
|
}
|
|
3142
4403
|
} catch (err) {
|
|
3143
|
-
|
|
4404
|
+
logWarn2(`Failed to load persisted graph: ${String(err)}`);
|
|
3144
4405
|
}
|
|
3145
4406
|
} else {
|
|
3146
|
-
|
|
4407
|
+
logWarn2(`graphLoadMap not available, native binding: ${!!native}`);
|
|
3147
4408
|
}
|
|
3148
4409
|
if (moduleCount === 0 && entries?.length && native) {
|
|
3149
|
-
|
|
4410
|
+
logWarn2(`[Build] Graph is empty \u2014 rebuilding dependency graph from entries...`);
|
|
3150
4411
|
const queue = [...entries];
|
|
3151
4412
|
const seen = new Set(queue);
|
|
3152
4413
|
while (queue.length) {
|
|
3153
4414
|
const file = queue.shift();
|
|
3154
|
-
if (!
|
|
3155
|
-
const code =
|
|
4415
|
+
if (!import_fs13.default.existsSync(file)) continue;
|
|
4416
|
+
const code = import_fs13.default.readFileSync(file, "utf8");
|
|
3156
4417
|
let hash = getCacheKey(code);
|
|
3157
4418
|
let specs = [];
|
|
3158
4419
|
if (native.parseModuleIr) {
|
|
@@ -3198,7 +4459,7 @@ async function generateBuildPlan(entries, versionInputs) {
|
|
|
3198
4459
|
logInfo(`[Planner] Native plan returned: ${plan.entries.length} entries, ${plan.chunks.length} chunks in ${Date.now() - start}ms`);
|
|
3199
4460
|
return normalizePlan(plan);
|
|
3200
4461
|
} catch (err) {
|
|
3201
|
-
|
|
4462
|
+
logWarn2(`plannerPlanBuild failed, falling back to JS planner: ${String(err)}`);
|
|
3202
4463
|
}
|
|
3203
4464
|
}
|
|
3204
4465
|
return fallbackPlan(entries);
|
|
@@ -3224,14 +4485,14 @@ async function writeBuildManifest(outputDir, plan, artifacts) {
|
|
|
3224
4485
|
files: filesByChunk.get(chunk.id) ?? { js: [], css: [], assets: [] }
|
|
3225
4486
|
}))
|
|
3226
4487
|
};
|
|
3227
|
-
const dir =
|
|
3228
|
-
await
|
|
3229
|
-
const file =
|
|
3230
|
-
await
|
|
4488
|
+
const dir = import_path17.default.resolve(outputDir);
|
|
4489
|
+
await import_fs13.default.promises.mkdir(dir, { recursive: true });
|
|
4490
|
+
const file = import_path17.default.join(dir, "manifest.json");
|
|
4491
|
+
await import_fs13.default.promises.writeFile(file, JSON.stringify(manifest, null, 2), "utf8");
|
|
3231
4492
|
}
|
|
3232
4493
|
async function emitChunks(outputDir, plan, moduleOutputs, opts) {
|
|
3233
4494
|
if (!native?.buildChunks) {
|
|
3234
|
-
|
|
4495
|
+
logWarn2("Native buildChunks binding is not available; using JS fallback emitter.");
|
|
3235
4496
|
const rawArtifacts2 = buildJsFallbackArtifacts(plan, moduleOutputs);
|
|
3236
4497
|
return emitChunksFromArtifacts(outputDir, plan, moduleOutputs, rawArtifacts2);
|
|
3237
4498
|
}
|
|
@@ -3254,7 +4515,7 @@ ${output.code}`);
|
|
|
3254
4515
|
}
|
|
3255
4516
|
for (const assetPath of chunk.assets) {
|
|
3256
4517
|
try {
|
|
3257
|
-
const data =
|
|
4518
|
+
const data = import_fs13.default.readFileSync(assetPath);
|
|
3258
4519
|
if (data.length < 4096) {
|
|
3259
4520
|
const mime = "application/octet-stream";
|
|
3260
4521
|
const inline = `data:${mime};base64,${data.toString("base64")}`;
|
|
@@ -3262,15 +4523,15 @@ ${output.code}`);
|
|
|
3262
4523
|
export const __ionify_asset = "${inline}";`);
|
|
3263
4524
|
continue;
|
|
3264
4525
|
}
|
|
3265
|
-
const hash =
|
|
3266
|
-
const ext =
|
|
4526
|
+
const hash = import_crypto5.default.createHash("sha256").update(data).digest("hex").slice(0, 16);
|
|
4527
|
+
const ext = import_path17.default.extname(assetPath) || ".bin";
|
|
3267
4528
|
const fileName = `assets/${hash}${ext}`;
|
|
3268
4529
|
assets.push({
|
|
3269
4530
|
source: assetPath,
|
|
3270
4531
|
file_name: fileName
|
|
3271
4532
|
});
|
|
3272
4533
|
} catch {
|
|
3273
|
-
const fileName =
|
|
4534
|
+
const fileName = import_path17.default.basename(assetPath) || "asset";
|
|
3274
4535
|
assets.push({
|
|
3275
4536
|
source: assetPath,
|
|
3276
4537
|
file_name: fileName
|
|
@@ -3303,15 +4564,15 @@ function normalizeNativeArtifact(raw) {
|
|
|
3303
4564
|
const map_bytes = typeof raw.map_bytes === "number" ? raw.map_bytes : map ? Buffer.byteLength(map, "utf8") : 0;
|
|
3304
4565
|
const assets = Array.isArray(raw.assets) ? raw.assets.map((asset) => ({
|
|
3305
4566
|
source: asset.source,
|
|
3306
|
-
file_name: asset.file_name ?? asset.fileName ??
|
|
4567
|
+
file_name: asset.file_name ?? asset.fileName ?? import_path17.default.basename(asset.source ?? "asset")
|
|
3307
4568
|
})) : [];
|
|
3308
4569
|
return { id, file_name, code, map, assets, code_bytes, map_bytes };
|
|
3309
4570
|
}
|
|
3310
4571
|
async function emitChunksFromArtifacts(outputDir, plan, moduleOutputs, rawArtifacts) {
|
|
3311
|
-
const chunkDir =
|
|
3312
|
-
await
|
|
3313
|
-
const assetsDir =
|
|
3314
|
-
await
|
|
4572
|
+
const chunkDir = import_path17.default.join(outputDir, "chunks");
|
|
4573
|
+
await import_fs13.default.promises.mkdir(chunkDir, { recursive: true });
|
|
4574
|
+
const assetsDir = import_path17.default.join(outputDir, "assets");
|
|
4575
|
+
await import_fs13.default.promises.mkdir(assetsDir, { recursive: true });
|
|
3315
4576
|
const enableSourceMaps = process.env.IONIFY_SOURCEMAPS === "true";
|
|
3316
4577
|
const grouped = /* @__PURE__ */ new Map();
|
|
3317
4578
|
for (const raw of rawArtifacts) {
|
|
@@ -3328,8 +4589,8 @@ async function emitChunksFromArtifacts(outputDir, plan, moduleOutputs, rawArtifa
|
|
|
3328
4589
|
if (!artifacts || !artifacts.length) {
|
|
3329
4590
|
throw new Error(`Native bundler did not emit artifacts for ${chunk.id}`);
|
|
3330
4591
|
}
|
|
3331
|
-
const chunkOutDir =
|
|
3332
|
-
await
|
|
4592
|
+
const chunkOutDir = import_path17.default.join(chunkDir, chunk.id);
|
|
4593
|
+
await import_fs13.default.promises.mkdir(chunkOutDir, { recursive: true });
|
|
3333
4594
|
artifacts.sort((a, b) => {
|
|
3334
4595
|
if (a.id === chunk.id) return -1;
|
|
3335
4596
|
if (b.id === chunk.id) return 1;
|
|
@@ -3342,14 +4603,14 @@ async function emitChunksFromArtifacts(outputDir, plan, moduleOutputs, rawArtifa
|
|
|
3342
4603
|
const copyAssets = async (assets) => {
|
|
3343
4604
|
for (const asset of assets) {
|
|
3344
4605
|
if (!asset?.source) continue;
|
|
3345
|
-
const relName = asset.file_name ??
|
|
3346
|
-
const assetFile =
|
|
4606
|
+
const relName = asset.file_name ?? import_path17.default.basename(asset.source);
|
|
4607
|
+
const assetFile = import_path17.default.join(outputDir, relName);
|
|
3347
4608
|
if (assetWritten.has(assetFile)) continue;
|
|
3348
4609
|
try {
|
|
3349
|
-
const data = await
|
|
3350
|
-
await
|
|
3351
|
-
await
|
|
3352
|
-
const rel = toPosix(
|
|
4610
|
+
const data = await import_fs13.default.promises.readFile(asset.source);
|
|
4611
|
+
await import_fs13.default.promises.mkdir(import_path17.default.dirname(assetFile), { recursive: true });
|
|
4612
|
+
await import_fs13.default.promises.writeFile(assetFile, data);
|
|
4613
|
+
const rel = toPosix(import_path17.default.relative(outputDir, assetFile));
|
|
3353
4614
|
buildStats[rel] = {
|
|
3354
4615
|
bytes: data.length,
|
|
3355
4616
|
emitter: "native",
|
|
@@ -3358,7 +4619,7 @@ async function emitChunksFromArtifacts(outputDir, plan, moduleOutputs, rawArtifa
|
|
|
3358
4619
|
assetFiles.push(rel);
|
|
3359
4620
|
assetWritten.add(assetFile);
|
|
3360
4621
|
} catch (err) {
|
|
3361
|
-
|
|
4622
|
+
logWarn2(`Failed to emit asset ${asset.source}: ${String(err)}`);
|
|
3362
4623
|
}
|
|
3363
4624
|
}
|
|
3364
4625
|
};
|
|
@@ -3369,11 +4630,11 @@ async function emitChunksFromArtifacts(outputDir, plan, moduleOutputs, rawArtifa
|
|
|
3369
4630
|
const cssPieces = [];
|
|
3370
4631
|
for (const cssPath of cssOrder) {
|
|
3371
4632
|
let cssSource = moduleOutputs.get(cssPath)?.code;
|
|
3372
|
-
if (!cssSource &&
|
|
4633
|
+
if (!cssSource && import_fs13.default.existsSync(cssPath)) {
|
|
3373
4634
|
try {
|
|
3374
|
-
cssSource = await
|
|
4635
|
+
cssSource = await import_fs13.default.promises.readFile(cssPath, "utf8");
|
|
3375
4636
|
} catch (err) {
|
|
3376
|
-
|
|
4637
|
+
logWarn2(`Failed to read CSS source ${cssPath}: ${String(err)}`);
|
|
3377
4638
|
}
|
|
3378
4639
|
}
|
|
3379
4640
|
if (!cssSource) continue;
|
|
@@ -3388,9 +4649,9 @@ async function emitChunksFromArtifacts(outputDir, plan, moduleOutputs, rawArtifa
|
|
|
3388
4649
|
const combinedCss = cssPieces.join("\n");
|
|
3389
4650
|
const cssHash = getCacheKey(combinedCss).slice(0, 8);
|
|
3390
4651
|
const cssFileName = `assets/${chunk.id}.${cssHash}.css`;
|
|
3391
|
-
const cssFilePath =
|
|
3392
|
-
await
|
|
3393
|
-
cssFileRel = toPosix(
|
|
4652
|
+
const cssFilePath = import_path17.default.join(outputDir, cssFileName);
|
|
4653
|
+
await import_fs13.default.promises.writeFile(cssFilePath, combinedCss, "utf8");
|
|
4654
|
+
cssFileRel = toPosix(import_path17.default.relative(outputDir, cssFilePath));
|
|
3394
4655
|
buildStats[cssFileRel] = {
|
|
3395
4656
|
bytes: Buffer.byteLength(combinedCss),
|
|
3396
4657
|
emitter: "native",
|
|
@@ -3400,11 +4661,11 @@ async function emitChunksFromArtifacts(outputDir, plan, moduleOutputs, rawArtifa
|
|
|
3400
4661
|
}
|
|
3401
4662
|
}
|
|
3402
4663
|
for (const artifact of artifacts) {
|
|
3403
|
-
const nativeFile =
|
|
4664
|
+
const nativeFile = import_path17.default.join(chunkOutDir, artifact.file_name);
|
|
3404
4665
|
let nativeCode = artifact.code;
|
|
3405
4666
|
if (cssFileRel) {
|
|
3406
|
-
const absCss =
|
|
3407
|
-
const relCss = toPosix(
|
|
4667
|
+
const absCss = import_path17.default.join(outputDir, cssFileRel);
|
|
4668
|
+
const relCss = toPosix(import_path17.default.relative(import_path17.default.dirname(nativeFile), absCss));
|
|
3408
4669
|
const inject = `(()=>{const url=new URL(${JSON.stringify(
|
|
3409
4670
|
relCss
|
|
3410
4671
|
)},import.meta.url).toString();if(typeof document!=="undefined"&&!document.querySelector('link[data-ionify-css="'+url+'"]')){const l=document.createElement("link");l.rel="stylesheet";l.href=url;l.setAttribute("data-ionify-css",url);document.head.appendChild(l);}})();`;
|
|
@@ -3413,10 +4674,10 @@ ${nativeCode}`;
|
|
|
3413
4674
|
}
|
|
3414
4675
|
if (enableSourceMaps && artifact.map) {
|
|
3415
4676
|
const mapFile = `${nativeFile}.map`;
|
|
3416
|
-
await
|
|
4677
|
+
await import_fs13.default.promises.writeFile(mapFile, artifact.map, "utf8");
|
|
3417
4678
|
nativeCode = `${nativeCode}
|
|
3418
|
-
//# sourceMappingURL=${
|
|
3419
|
-
const relMap = toPosix(
|
|
4679
|
+
//# sourceMappingURL=${import_path17.default.basename(mapFile)}`;
|
|
4680
|
+
const relMap = toPosix(import_path17.default.relative(outputDir, mapFile));
|
|
3420
4681
|
buildStats[relMap] = {
|
|
3421
4682
|
bytes: artifact.map_bytes,
|
|
3422
4683
|
emitter: "native",
|
|
@@ -3424,8 +4685,8 @@ ${nativeCode}`;
|
|
|
3424
4685
|
};
|
|
3425
4686
|
jsFiles.push(relMap);
|
|
3426
4687
|
}
|
|
3427
|
-
await
|
|
3428
|
-
const relNative = toPosix(
|
|
4688
|
+
await import_fs13.default.promises.writeFile(nativeFile, nativeCode, "utf8");
|
|
4689
|
+
const relNative = toPosix(import_path17.default.relative(outputDir, nativeFile));
|
|
3429
4690
|
buildStats[relNative] = {
|
|
3430
4691
|
bytes: artifact.code_bytes,
|
|
3431
4692
|
emitter: "native",
|
|
@@ -3442,21 +4703,21 @@ ${nativeCode}`;
|
|
|
3442
4703
|
const output = moduleOutputs.get(cssPath);
|
|
3443
4704
|
if (output?.type === "css") {
|
|
3444
4705
|
cssSources.push(output.code);
|
|
3445
|
-
} else if (
|
|
4706
|
+
} else if (import_fs13.default.existsSync(cssPath)) {
|
|
3446
4707
|
try {
|
|
3447
|
-
cssSources.push(await
|
|
4708
|
+
cssSources.push(await import_fs13.default.promises.readFile(cssPath, "utf8"));
|
|
3448
4709
|
} catch (err) {
|
|
3449
|
-
|
|
4710
|
+
logWarn2(`Failed to read CSS source ${cssPath}: ${String(err)}`);
|
|
3450
4711
|
}
|
|
3451
4712
|
}
|
|
3452
4713
|
}
|
|
3453
4714
|
if (cssSources.length) {
|
|
3454
4715
|
const combinedCss = cssSources.join("\n\n");
|
|
3455
|
-
const cssHash =
|
|
4716
|
+
const cssHash = import_crypto5.default.createHash("sha256").update(combinedCss).digest("hex").slice(0, 8);
|
|
3456
4717
|
const cssFileName = `${chunk.id}.${cssHash}.native.css`;
|
|
3457
|
-
const cssFilePath =
|
|
3458
|
-
await
|
|
3459
|
-
const relCss =
|
|
4718
|
+
const cssFilePath = import_path17.default.join(chunkOutDir, cssFileName);
|
|
4719
|
+
await import_fs13.default.promises.writeFile(cssFilePath, combinedCss, "utf8");
|
|
4720
|
+
const relCss = import_path17.default.relative(outputDir, cssFilePath);
|
|
3460
4721
|
buildStats[relCss] = {
|
|
3461
4722
|
bytes: Buffer.byteLength(combinedCss),
|
|
3462
4723
|
emitter: "native",
|
|
@@ -3477,14 +4738,14 @@ ${nativeCode}`;
|
|
|
3477
4738
|
return { artifacts: results, stats: buildStats };
|
|
3478
4739
|
}
|
|
3479
4740
|
async function writeAssetsManifest(outputDir, artifacts) {
|
|
3480
|
-
const dir =
|
|
3481
|
-
await
|
|
3482
|
-
const file =
|
|
4741
|
+
const dir = import_path17.default.resolve(outputDir);
|
|
4742
|
+
await import_fs13.default.promises.mkdir(dir, { recursive: true });
|
|
4743
|
+
const file = import_path17.default.join(dir, "manifest.assets.json");
|
|
3483
4744
|
const payload = {
|
|
3484
4745
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3485
4746
|
chunks: artifacts
|
|
3486
4747
|
};
|
|
3487
|
-
await
|
|
4748
|
+
await import_fs13.default.promises.writeFile(file, JSON.stringify(payload, null, 2), "utf8");
|
|
3488
4749
|
}
|
|
3489
4750
|
|
|
3490
4751
|
// src/core/worker/pool.ts
|
|
@@ -3527,7 +4788,7 @@ var TransformWorkerPool = class {
|
|
|
3527
4788
|
this.dequeue(worker);
|
|
3528
4789
|
});
|
|
3529
4790
|
worker.on("error", (err) => {
|
|
3530
|
-
|
|
4791
|
+
logWarn2(`Transform worker error: ${String(err)}`);
|
|
3531
4792
|
const item = this.active.get(id);
|
|
3532
4793
|
if (item) {
|
|
3533
4794
|
this.active.delete(id);
|
|
@@ -3542,7 +4803,7 @@ var TransformWorkerPool = class {
|
|
|
3542
4803
|
this.queue.unshift(item);
|
|
3543
4804
|
}
|
|
3544
4805
|
if (!this.closed && code !== 0) {
|
|
3545
|
-
|
|
4806
|
+
logWarn2(`Transform worker exited unexpectedly (${code}), respawning`);
|
|
3546
4807
|
this.spawnWorker();
|
|
3547
4808
|
}
|
|
3548
4809
|
});
|
|
@@ -3618,6 +4879,7 @@ init_cache();
|
|
|
3618
4879
|
async function runBuildCommand(options = {}) {
|
|
3619
4880
|
try {
|
|
3620
4881
|
const config = await loadIonifyConfig();
|
|
4882
|
+
const rootDir = config?.root || process.cwd();
|
|
3621
4883
|
const optLevel = resolveOptimizationLevel(config?.optimizationLevel, {
|
|
3622
4884
|
cliLevel: options.level,
|
|
3623
4885
|
envLevel: process.env.IONIFY_OPTIMIZATION_LEVEL
|
|
@@ -3646,11 +4908,10 @@ async function runBuildCommand(options = {}) {
|
|
|
3646
4908
|
combineEnv: process.env.IONIFY_SCOPE_HOIST_COMBINE
|
|
3647
4909
|
});
|
|
3648
4910
|
}
|
|
3649
|
-
applyMinifierEnv(minifier);
|
|
3650
4911
|
applyParserEnv(parserMode);
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
4912
|
+
const entries = config?.entry ? (Array.isArray(config.entry) ? config.entry : [config.entry]).map(
|
|
4913
|
+
(entry) => entry.startsWith("/") ? import_path18.default.join(rootDir, entry) : import_path18.default.resolve(rootDir, entry)
|
|
4914
|
+
) : void 0;
|
|
3654
4915
|
if (entries) {
|
|
3655
4916
|
logInfo(`Build entries: ${entries.join(", ")}`);
|
|
3656
4917
|
} else {
|
|
@@ -3692,11 +4953,11 @@ async function runBuildCommand(options = {}) {
|
|
|
3692
4953
|
const moduleOutputs = /* @__PURE__ */ new Map();
|
|
3693
4954
|
const pool = new TransformWorkerPool();
|
|
3694
4955
|
try {
|
|
3695
|
-
const jobs = Array.from(uniqueModules).filter((filePath) =>
|
|
3696
|
-
const code =
|
|
4956
|
+
const jobs = Array.from(uniqueModules).filter((filePath) => import_fs14.default.existsSync(filePath)).map((filePath) => {
|
|
4957
|
+
const code = import_fs14.default.readFileSync(filePath, "utf8");
|
|
3697
4958
|
const sourceHash = getCacheKey(code);
|
|
3698
4959
|
const moduleHash = moduleHashes.get(filePath) ?? sourceHash;
|
|
3699
|
-
const cacheKey = getCacheKey(`build-worker:v1:${
|
|
4960
|
+
const cacheKey = getCacheKey(`build-worker:v1:${import_path18.default.extname(filePath)}:${moduleHash}:${filePath}`);
|
|
3700
4961
|
const cached = readCache(cacheKey);
|
|
3701
4962
|
if (cached) {
|
|
3702
4963
|
try {
|
|
@@ -3704,13 +4965,13 @@ async function runBuildCommand(options = {}) {
|
|
|
3704
4965
|
if (parsed?.code) {
|
|
3705
4966
|
const transformedHash = getCacheKey(parsed.code);
|
|
3706
4967
|
moduleHashes.set(filePath, transformedHash);
|
|
3707
|
-
const casRoot2 =
|
|
4968
|
+
const casRoot2 = import_path18.default.join(rootDir, ".ionify", "cas");
|
|
3708
4969
|
const cacheDir = getCasArtifactPath(casRoot2, configHash, transformedHash);
|
|
3709
|
-
if (!
|
|
3710
|
-
|
|
3711
|
-
|
|
4970
|
+
if (!import_fs14.default.existsSync(import_path18.default.join(cacheDir, "transformed.js"))) {
|
|
4971
|
+
import_fs14.default.mkdirSync(cacheDir, { recursive: true });
|
|
4972
|
+
import_fs14.default.writeFileSync(import_path18.default.join(cacheDir, "transformed.js"), parsed.code, "utf8");
|
|
3712
4973
|
if (parsed.map) {
|
|
3713
|
-
|
|
4974
|
+
import_fs14.default.writeFileSync(import_path18.default.join(cacheDir, "transformed.js.map"), parsed.map, "utf8");
|
|
3714
4975
|
}
|
|
3715
4976
|
}
|
|
3716
4977
|
moduleOutputs.set(filePath, { code: parsed.code, type: parsed.type ?? "js" });
|
|
@@ -3722,7 +4983,7 @@ async function runBuildCommand(options = {}) {
|
|
|
3722
4983
|
return {
|
|
3723
4984
|
id: filePath,
|
|
3724
4985
|
filePath,
|
|
3725
|
-
ext:
|
|
4986
|
+
ext: import_path18.default.extname(filePath),
|
|
3726
4987
|
code,
|
|
3727
4988
|
cacheKey
|
|
3728
4989
|
};
|
|
@@ -3745,13 +5006,13 @@ async function runBuildCommand(options = {}) {
|
|
|
3745
5006
|
writeCache(job.cacheKey, Buffer.from(payload));
|
|
3746
5007
|
const transformedHash = getCacheKey(result.code);
|
|
3747
5008
|
const moduleHash = transformedHash;
|
|
3748
|
-
const casRoot2 =
|
|
5009
|
+
const casRoot2 = import_path18.default.join(rootDir, ".ionify", "cas");
|
|
3749
5010
|
const versionHash = configHash;
|
|
3750
5011
|
const cacheDir = getCasArtifactPath(casRoot2, versionHash, moduleHash);
|
|
3751
|
-
|
|
3752
|
-
|
|
5012
|
+
import_fs14.default.mkdirSync(cacheDir, { recursive: true });
|
|
5013
|
+
import_fs14.default.writeFileSync(import_path18.default.join(cacheDir, "transformed.js"), result.code, "utf8");
|
|
3753
5014
|
if (result.map) {
|
|
3754
|
-
|
|
5015
|
+
import_fs14.default.writeFileSync(import_path18.default.join(cacheDir, "transformed.js.map"), result.map, "utf8");
|
|
3755
5016
|
}
|
|
3756
5017
|
moduleHashes.set(job.filePath, moduleHash);
|
|
3757
5018
|
for (const chunk of plan.chunks) {
|
|
@@ -3774,20 +5035,20 @@ async function runBuildCommand(options = {}) {
|
|
|
3774
5035
|
}
|
|
3775
5036
|
}
|
|
3776
5037
|
}
|
|
3777
|
-
const absOutDir =
|
|
3778
|
-
const casRoot =
|
|
5038
|
+
const absOutDir = import_path18.default.resolve(outDir);
|
|
5039
|
+
const casRoot = import_path18.default.join(rootDir, ".ionify", "cas");
|
|
3779
5040
|
const { artifacts, stats } = await emitChunks(absOutDir, plan, moduleOutputs, {
|
|
3780
5041
|
casRoot,
|
|
3781
5042
|
versionHash: configHash
|
|
3782
5043
|
});
|
|
3783
5044
|
await writeBuildManifest(absOutDir, plan, artifacts);
|
|
3784
5045
|
await writeAssetsManifest(absOutDir, artifacts);
|
|
3785
|
-
await
|
|
3786
|
-
|
|
5046
|
+
await import_fs14.default.promises.writeFile(
|
|
5047
|
+
import_path18.default.join(absOutDir, "build.stats.json"),
|
|
3787
5048
|
JSON.stringify(stats, null, 2),
|
|
3788
5049
|
"utf8"
|
|
3789
5050
|
);
|
|
3790
|
-
logInfo(`Build plan generated \u2192 ${
|
|
5051
|
+
logInfo(`Build plan generated \u2192 ${import_path18.default.join(absOutDir, "manifest.json")}`);
|
|
3791
5052
|
logInfo(`Entries: ${plan.entries.length}, Chunks: ${plan.chunks.length}`);
|
|
3792
5053
|
logInfo(`Modules transformed: ${moduleOutputs.size}`);
|
|
3793
5054
|
} catch (err) {
|