@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/client/hmr.js
CHANGED
|
@@ -12,6 +12,29 @@ const ERROR_URL = "/__ionify_hmr/error";
|
|
|
12
12
|
const log = (...args) => console.log("[Ionify HMR]", ...args);
|
|
13
13
|
const warn = (...args) => console.warn("[Ionify HMR]", ...args);
|
|
14
14
|
|
|
15
|
+
// Surface runtime errors even when they don't occur during an HMR import().
|
|
16
|
+
// This catches errors thrown during module evaluation and async rejections.
|
|
17
|
+
globalThis.addEventListener?.("error", (event) => {
|
|
18
|
+
try {
|
|
19
|
+
const message = event?.message || "Runtime error";
|
|
20
|
+
const details = event?.error?.stack || event?.error?.message;
|
|
21
|
+
showErrorOverlay(message, details);
|
|
22
|
+
} catch {
|
|
23
|
+
// ignore
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
globalThis.addEventListener?.("unhandledrejection", (event) => {
|
|
28
|
+
try {
|
|
29
|
+
const reason = event?.reason;
|
|
30
|
+
const message = reason instanceof Error ? reason.message : "Unhandled promise rejection";
|
|
31
|
+
const details = reason instanceof Error ? reason.stack : String(reason ?? "");
|
|
32
|
+
showErrorOverlay(message, details);
|
|
33
|
+
} catch {
|
|
34
|
+
// ignore
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
15
38
|
// Establish SSE channel used to notify about pending graph diffs.
|
|
16
39
|
const source = new EventSource(SSE_URL);
|
|
17
40
|
|
|
@@ -22,14 +45,15 @@ source.addEventListener("ready", () => {
|
|
|
22
45
|
source.addEventListener("error", (e) => {
|
|
23
46
|
warn("SSE error", e);
|
|
24
47
|
// Show overlay if server streamed a structured error payload.
|
|
25
|
-
|
|
48
|
+
const data = e && typeof e === "object" && "data" in e ? e.data : undefined;
|
|
49
|
+
if (data) {
|
|
26
50
|
try {
|
|
27
|
-
const payload = JSON.parse(
|
|
51
|
+
const payload = JSON.parse(data);
|
|
28
52
|
if (payload?.message) {
|
|
29
53
|
showErrorOverlay(payload.message, payload.id ? `Update ${payload.id}` : undefined);
|
|
30
54
|
}
|
|
31
55
|
} catch {
|
|
32
|
-
showErrorOverlay(String(
|
|
56
|
+
showErrorOverlay(String(data || "HMR connection error"));
|
|
33
57
|
}
|
|
34
58
|
}
|
|
35
59
|
});
|
|
@@ -119,6 +143,18 @@ async function applyUpdate(payload) {
|
|
|
119
143
|
return;
|
|
120
144
|
}
|
|
121
145
|
}
|
|
146
|
+
|
|
147
|
+
// If React Refresh runtime is present, trigger it after importing updated modules.
|
|
148
|
+
try {
|
|
149
|
+
const refreshRuntime = globalThis.__IONIFY_REACT_REFRESH__;
|
|
150
|
+
if (refreshRuntime?.performReactRefresh) {
|
|
151
|
+
refreshRuntime.performReactRefresh();
|
|
152
|
+
log("react refresh performed");
|
|
153
|
+
}
|
|
154
|
+
} catch (err) {
|
|
155
|
+
warn("React Refresh failed", err);
|
|
156
|
+
}
|
|
157
|
+
|
|
122
158
|
log(`update ${payload?.id ?? "unknown"} applied`);
|
|
123
159
|
clearErrorOverlay();
|
|
124
160
|
}
|
package/dist/client/overlay.js
CHANGED
|
@@ -1,42 +1,157 @@
|
|
|
1
|
-
// Basic DOM overlay used to surface build/transform errors during HMR.
|
|
2
|
-
const
|
|
1
|
+
// Basic DOM overlay used to surface build/transform errors (and warnings) during HMR.
|
|
2
|
+
const ERROR_OVERLAY_ID = "ionify-error-overlay";
|
|
3
|
+
const WARNING_OVERLAY_ID = "ionify-warning-overlay";
|
|
3
4
|
|
|
4
|
-
function ensureOverlay() {
|
|
5
|
-
let overlay = document.getElementById(
|
|
5
|
+
function ensureOverlay(id) {
|
|
6
|
+
let overlay = document.getElementById(id);
|
|
6
7
|
if (!overlay) {
|
|
7
8
|
overlay = document.createElement("div");
|
|
8
|
-
overlay.id =
|
|
9
|
-
overlay.style.position = "fixed";
|
|
10
|
-
overlay.style.inset = "0";
|
|
11
|
-
overlay.style.background = "rgba(0,0,0,0.8)";
|
|
12
|
-
overlay.style.color = "#f87171";
|
|
13
|
-
overlay.style.fontFamily = "Menlo, Consolas, monospace";
|
|
14
|
-
overlay.style.fontSize = "14px";
|
|
15
|
-
overlay.style.padding = "32px";
|
|
16
|
-
overlay.style.zIndex = "2147483647";
|
|
17
|
-
overlay.style.overflowY = "auto";
|
|
18
|
-
overlay.style.whiteSpace = "pre-wrap";
|
|
9
|
+
overlay.id = id;
|
|
19
10
|
document.body.appendChild(overlay);
|
|
20
11
|
}
|
|
21
12
|
return overlay;
|
|
22
13
|
}
|
|
23
14
|
|
|
15
|
+
function buildOverlayContent({
|
|
16
|
+
title,
|
|
17
|
+
message,
|
|
18
|
+
details,
|
|
19
|
+
onClose,
|
|
20
|
+
accentColor,
|
|
21
|
+
}) {
|
|
22
|
+
const root = document.createElement("div");
|
|
23
|
+
root.style.display = "flex";
|
|
24
|
+
root.style.flexDirection = "column";
|
|
25
|
+
root.style.gap = "12px";
|
|
26
|
+
|
|
27
|
+
const headerRow = document.createElement("div");
|
|
28
|
+
headerRow.style.display = "flex";
|
|
29
|
+
headerRow.style.alignItems = "flex-start";
|
|
30
|
+
headerRow.style.justifyContent = "space-between";
|
|
31
|
+
headerRow.style.gap = "12px";
|
|
32
|
+
|
|
33
|
+
const header = document.createElement("div");
|
|
34
|
+
header.style.fontWeight = "600";
|
|
35
|
+
header.style.fontSize = "16px";
|
|
36
|
+
header.textContent = title;
|
|
37
|
+
|
|
38
|
+
const close = document.createElement("button");
|
|
39
|
+
close.type = "button";
|
|
40
|
+
close.setAttribute("aria-label", "Close overlay");
|
|
41
|
+
close.textContent = "×";
|
|
42
|
+
close.style.border = "1px solid rgba(255,255,255,0.25)";
|
|
43
|
+
close.style.background = "transparent";
|
|
44
|
+
close.style.color = "inherit";
|
|
45
|
+
close.style.borderRadius = "8px";
|
|
46
|
+
close.style.width = "32px";
|
|
47
|
+
close.style.height = "32px";
|
|
48
|
+
close.style.cursor = "pointer";
|
|
49
|
+
close.style.fontSize = "20px";
|
|
50
|
+
close.style.lineHeight = "28px";
|
|
51
|
+
close.style.padding = "0";
|
|
52
|
+
close.onclick = onClose;
|
|
53
|
+
|
|
54
|
+
headerRow.appendChild(header);
|
|
55
|
+
headerRow.appendChild(close);
|
|
56
|
+
|
|
57
|
+
const body = document.createElement("div");
|
|
58
|
+
body.textContent = message ?? "";
|
|
59
|
+
|
|
60
|
+
root.appendChild(headerRow);
|
|
61
|
+
root.appendChild(body);
|
|
62
|
+
|
|
63
|
+
if (details) {
|
|
64
|
+
const pre = document.createElement("pre");
|
|
65
|
+
pre.style.margin = "0";
|
|
66
|
+
pre.style.whiteSpace = "pre-wrap";
|
|
67
|
+
pre.style.color = accentColor;
|
|
68
|
+
pre.textContent = details;
|
|
69
|
+
root.appendChild(pre);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return root;
|
|
73
|
+
}
|
|
74
|
+
|
|
24
75
|
export function showErrorOverlay(message, details) {
|
|
25
76
|
if (typeof document === "undefined") return;
|
|
26
|
-
const overlay = ensureOverlay();
|
|
27
|
-
|
|
28
|
-
overlay.
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
77
|
+
const overlay = ensureOverlay(ERROR_OVERLAY_ID);
|
|
78
|
+
|
|
79
|
+
overlay.style.position = "fixed";
|
|
80
|
+
overlay.style.inset = "0";
|
|
81
|
+
overlay.style.background = "rgba(0,0,0,0.86)";
|
|
82
|
+
overlay.style.color = "#f87171";
|
|
83
|
+
overlay.style.fontFamily = "Menlo, Consolas, monospace";
|
|
84
|
+
overlay.style.fontSize = "14px";
|
|
85
|
+
overlay.style.padding = "32px";
|
|
86
|
+
overlay.style.zIndex = "2147483647";
|
|
87
|
+
overlay.style.overflowY = "auto";
|
|
88
|
+
overlay.style.whiteSpace = "pre-wrap";
|
|
89
|
+
|
|
90
|
+
overlay.replaceChildren(
|
|
91
|
+
buildOverlayContent({
|
|
92
|
+
title: "Ionify Build Error",
|
|
93
|
+
message: message ?? "Unknown error",
|
|
94
|
+
details,
|
|
95
|
+
onClose: clearErrorOverlay,
|
|
96
|
+
accentColor: "#fca5a5",
|
|
97
|
+
})
|
|
98
|
+
);
|
|
35
99
|
}
|
|
36
100
|
|
|
37
101
|
export function clearErrorOverlay() {
|
|
38
102
|
if (typeof document === "undefined") return;
|
|
39
|
-
const overlay = document.getElementById(
|
|
103
|
+
const overlay = document.getElementById(ERROR_OVERLAY_ID);
|
|
104
|
+
if (overlay && overlay.parentElement) {
|
|
105
|
+
overlay.parentElement.removeChild(overlay);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function showWarningOverlay(message, details) {
|
|
110
|
+
if (typeof document === "undefined") return;
|
|
111
|
+
const overlay = ensureOverlay(WARNING_OVERLAY_ID);
|
|
112
|
+
|
|
113
|
+
// Full-screen, transparent backdrop with a top-center panel.
|
|
114
|
+
// Keep the app interactive by letting only the panel receive pointer events.
|
|
115
|
+
overlay.style.position = "fixed";
|
|
116
|
+
overlay.style.inset = "0";
|
|
117
|
+
overlay.style.background = "rgba(0,0,0,0.35)";
|
|
118
|
+
overlay.style.zIndex = "2147483646";
|
|
119
|
+
overlay.style.pointerEvents = "none";
|
|
120
|
+
|
|
121
|
+
const panel = document.createElement("div");
|
|
122
|
+
panel.style.position = "absolute";
|
|
123
|
+
panel.style.top = "16px";
|
|
124
|
+
panel.style.left = "50%";
|
|
125
|
+
panel.style.transform = "translateX(-50%)";
|
|
126
|
+
panel.style.maxWidth = "min(760px, calc(100vw - 32px))";
|
|
127
|
+
panel.style.width = "fit-content";
|
|
128
|
+
panel.style.background = "rgba(17,24,39,0.92)";
|
|
129
|
+
panel.style.color = "#fbbf24";
|
|
130
|
+
panel.style.fontFamily = "Menlo, Consolas, monospace";
|
|
131
|
+
panel.style.fontSize = "13px";
|
|
132
|
+
panel.style.padding = "16px";
|
|
133
|
+
panel.style.border = "1px solid rgba(251,191,36,0.45)";
|
|
134
|
+
panel.style.borderRadius = "12px";
|
|
135
|
+
panel.style.boxShadow = "0 10px 30px rgba(0,0,0,0.35)";
|
|
136
|
+
panel.style.overflow = "hidden";
|
|
137
|
+
panel.style.pointerEvents = "auto";
|
|
138
|
+
|
|
139
|
+
panel.appendChild(
|
|
140
|
+
buildOverlayContent({
|
|
141
|
+
title: "Ionify Warning",
|
|
142
|
+
message: message ?? "",
|
|
143
|
+
details,
|
|
144
|
+
onClose: clearWarningOverlay,
|
|
145
|
+
accentColor: "#fde68a",
|
|
146
|
+
})
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
overlay.replaceChildren(panel);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function clearWarningOverlay() {
|
|
153
|
+
if (typeof document === "undefined") return;
|
|
154
|
+
const overlay = document.getElementById(WARNING_OVERLAY_ID);
|
|
40
155
|
if (overlay && overlay.parentElement) {
|
|
41
156
|
overlay.parentElement.removeChild(overlay);
|
|
42
157
|
}
|
|
@@ -4,6 +4,31 @@ let installed = false;
|
|
|
4
4
|
const moduleInfo = new Map();
|
|
5
5
|
const warnedClassModules = new Set();
|
|
6
6
|
|
|
7
|
+
export function normalizeRefreshModuleId(url) {
|
|
8
|
+
if (typeof url !== "string") return "";
|
|
9
|
+
if (!url.includes("?") && !url.includes("#")) return url;
|
|
10
|
+
|
|
11
|
+
// Absolute URL: keep origin + pathname + hash, drop search.
|
|
12
|
+
try {
|
|
13
|
+
const parsed = new URL(url);
|
|
14
|
+
return parsed.origin + parsed.pathname + parsed.hash;
|
|
15
|
+
} catch {
|
|
16
|
+
// Fall through for non-absolute URLs.
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Relative URL: keep pathname + hash, drop search.
|
|
20
|
+
try {
|
|
21
|
+
const parsed = new URL(url, "http://ionify.invalid");
|
|
22
|
+
return parsed.pathname + parsed.hash;
|
|
23
|
+
} catch {
|
|
24
|
+
// Final fallback: conservative string manipulation.
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const [beforeHash, hash = ""] = url.split("#", 2);
|
|
28
|
+
const [pathPart] = beforeHash.split("?", 2);
|
|
29
|
+
return pathPart + (hash ? `#${hash}` : "");
|
|
30
|
+
}
|
|
31
|
+
|
|
7
32
|
function ensureRuntime() {
|
|
8
33
|
if (installed) return RefreshRuntime;
|
|
9
34
|
RefreshRuntime.injectIntoGlobalHook(window);
|
|
@@ -14,26 +39,55 @@ function ensureRuntime() {
|
|
|
14
39
|
return RefreshRuntime;
|
|
15
40
|
}
|
|
16
41
|
|
|
42
|
+
// Ensure the global hook is installed as early as possible (before React modules execute).
|
|
43
|
+
// Guarded so Node-side unit tests can import helpers from this file.
|
|
44
|
+
if (typeof window !== "undefined") {
|
|
45
|
+
try {
|
|
46
|
+
ensureRuntime();
|
|
47
|
+
} catch {
|
|
48
|
+
// Runtime injection is best-effort; transform-side warnings handle failures.
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
17
52
|
export function setupReactRefresh(importMetaHot, moduleId) {
|
|
18
53
|
if (!importMetaHot) return null;
|
|
19
54
|
const runtime = ensureRuntime();
|
|
55
|
+
const stableModuleId = normalizeRefreshModuleId(moduleId);
|
|
20
56
|
|
|
21
57
|
// Track metadata for this module so we can make refresh decisions later.
|
|
22
58
|
const record = {
|
|
23
59
|
hasReactExport: false,
|
|
24
60
|
hasClassComponent: false,
|
|
25
61
|
};
|
|
26
|
-
moduleInfo.set(
|
|
62
|
+
moduleInfo.set(stableModuleId, record);
|
|
27
63
|
|
|
28
64
|
const prevReg = window.$RefreshReg$;
|
|
29
65
|
const prevSig = window.$RefreshSig$;
|
|
30
66
|
|
|
31
67
|
window.$RefreshReg$ = (type, id) => {
|
|
32
|
-
runtime.register(type,
|
|
68
|
+
runtime.register(type, stableModuleId + " " + id);
|
|
33
69
|
if (type) {
|
|
34
70
|
record.hasReactExport = true;
|
|
35
71
|
if (type.prototype && type.prototype.isReactComponent) {
|
|
36
72
|
record.hasClassComponent = true;
|
|
73
|
+
|
|
74
|
+
// Show the warning even if a refresh never runs (e.g. first load),
|
|
75
|
+
// but dedupe per stable module id.
|
|
76
|
+
if (!warnedClassModules.has(stableModuleId)) {
|
|
77
|
+
const warning = `[Ionify] React Fast Refresh cannot preserve state for class components (module: ${stableModuleId}). State will reset after edits.`;
|
|
78
|
+
console.warn(warning);
|
|
79
|
+
|
|
80
|
+
if (typeof document !== "undefined") {
|
|
81
|
+
import("/__ionify_overlay.js")
|
|
82
|
+
.then((mod) => {
|
|
83
|
+
if (typeof mod?.showWarningOverlay === "function") {
|
|
84
|
+
mod.showWarningOverlay(warning, stableModuleId);
|
|
85
|
+
}
|
|
86
|
+
})
|
|
87
|
+
.catch(() => {});
|
|
88
|
+
}
|
|
89
|
+
warnedClassModules.add(stableModuleId);
|
|
90
|
+
}
|
|
37
91
|
}
|
|
38
92
|
}
|
|
39
93
|
};
|
|
@@ -45,17 +99,11 @@ export function setupReactRefresh(importMetaHot, moduleId) {
|
|
|
45
99
|
};
|
|
46
100
|
|
|
47
101
|
const dispose = () => {
|
|
48
|
-
moduleInfo.delete(
|
|
102
|
+
moduleInfo.delete(stableModuleId);
|
|
49
103
|
};
|
|
50
104
|
|
|
51
105
|
const refresh = () => {
|
|
52
106
|
if (!record.hasReactExport) return false;
|
|
53
|
-
if (record.hasClassComponent && !warnedClassModules.has(moduleId)) {
|
|
54
|
-
console.warn(
|
|
55
|
-
`[Ionify] React Fast Refresh cannot preserve state for class components (module: ${moduleId}). State will reset after edits.`
|
|
56
|
-
);
|
|
57
|
-
warnedClassModules.add(moduleId);
|
|
58
|
-
}
|
|
59
107
|
queueMicrotask(() => {
|
|
60
108
|
runtime.performReactRefresh();
|
|
61
109
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -2,7 +2,21 @@ interface IonifyResolveConfig {
|
|
|
2
2
|
baseUrl?: string;
|
|
3
3
|
paths?: Record<string, string[]>;
|
|
4
4
|
alias?: Record<string, string>;
|
|
5
|
+
/**
|
|
6
|
+
* File extensions to try when resolving imports.
|
|
7
|
+
* @default ['.mjs', '.js', '.mts', '.ts', '.jsx', '.tsx', '.json']
|
|
8
|
+
*/
|
|
5
9
|
extensions?: string[];
|
|
10
|
+
/**
|
|
11
|
+
* Conditions to use when resolving package.json "exports" field.
|
|
12
|
+
* @default ['import', 'module', 'browser', 'default']
|
|
13
|
+
*/
|
|
14
|
+
conditions?: string[];
|
|
15
|
+
/**
|
|
16
|
+
* Fields to check in package.json for entry point resolution.
|
|
17
|
+
* @default ['module', 'jsnext:main', 'jsnext', 'main']
|
|
18
|
+
*/
|
|
19
|
+
mainFields?: string[];
|
|
6
20
|
}
|
|
7
21
|
interface IonifyServerConfig {
|
|
8
22
|
port?: number;
|
|
@@ -51,7 +65,19 @@ interface IonifyScopeHoistConfig {
|
|
|
51
65
|
combineVariables?: boolean;
|
|
52
66
|
}
|
|
53
67
|
interface IonifyConfig {
|
|
68
|
+
/**
|
|
69
|
+
* Project root directory. All paths are resolved relative to root.
|
|
70
|
+
* Affects: module resolution, watcher, public URLs, CAS location.
|
|
71
|
+
* @default process.cwd()
|
|
72
|
+
*/
|
|
54
73
|
root?: string;
|
|
74
|
+
/**
|
|
75
|
+
* Entry point(s) for the application (relative to root or project-relative with leading '/').
|
|
76
|
+
* Accepts a single entry or multiple entries.
|
|
77
|
+
* @example '/src/main.tsx'
|
|
78
|
+
* @example ['src/main.tsx', 'src/admin.tsx']
|
|
79
|
+
*/
|
|
80
|
+
entry?: string | string[];
|
|
55
81
|
base?: string;
|
|
56
82
|
mode?: string;
|
|
57
83
|
/** Runtime-resolved minifier selection ('auto' by default). */
|
|
@@ -74,11 +100,56 @@ interface IonifyConfig {
|
|
|
74
100
|
build?: IonifyBuildConfig;
|
|
75
101
|
css?: IonifyCSSConfig;
|
|
76
102
|
optimizeDeps?: {
|
|
103
|
+
/**
|
|
104
|
+
* Dependencies to pre-optimize on server start.
|
|
105
|
+
* Useful for ensuring common dependencies are bundled before first request.
|
|
106
|
+
* @example ['react', 'react-dom', 'lodash']
|
|
107
|
+
*/
|
|
77
108
|
include?: string[];
|
|
78
109
|
exclude?: string[];
|
|
110
|
+
/**
|
|
111
|
+
* Generate sourcemaps for optimized dependencies.
|
|
112
|
+
* Disabled by default to speed up dependency optimization.
|
|
113
|
+
*/
|
|
114
|
+
sourcemap?: boolean;
|
|
115
|
+
/**
|
|
116
|
+
* Bundle ESM dependencies instead of serving them as-is with proxies.
|
|
117
|
+
* When `true` (default), ESM deps are bundled into single self-contained
|
|
118
|
+
* files with synthesized named exports, eliminating request waterfalls.
|
|
119
|
+
* Set to `false` for debugging (to inspect original package source).
|
|
120
|
+
* @default true
|
|
121
|
+
*/
|
|
122
|
+
bundleEsm?: boolean;
|
|
123
|
+
/**
|
|
124
|
+
* Build a framework "vendor preloader" module in dev to reduce cold-start waterfalls.
|
|
125
|
+
* - `'auto'` (default): detect framework deps from package.json and generate `vendor.<depsHash>.js`
|
|
126
|
+
* - `string[]`: explicit vendor specifiers (e.g. ['react','react-dom/client'])
|
|
127
|
+
* - `false`: disable vendor preloading
|
|
128
|
+
*/
|
|
129
|
+
vendor?: "auto" | string[] | false;
|
|
130
|
+
/**
|
|
131
|
+
* @deprecated esbuildOptions are not supported in Ionify.
|
|
132
|
+
* Ionify uses native Rust optimizer. This option is ignored with a warning.
|
|
133
|
+
*/
|
|
134
|
+
esbuildOptions?: Record<string, unknown>;
|
|
79
135
|
};
|
|
80
136
|
plugins?: any[];
|
|
137
|
+
/**
|
|
138
|
+
* Define global constant replacements.
|
|
139
|
+
* Values are JSON-stringified and replaced at compile time using AST transformation.
|
|
140
|
+
* @example
|
|
141
|
+
* define: {
|
|
142
|
+
* __APP_VERSION__: JSON.stringify('1.0.0'),
|
|
143
|
+
* __API_URL__: JSON.stringify('https://api.example.com'),
|
|
144
|
+
* 'process.env.NODE_ENV': JSON.stringify('production')
|
|
145
|
+
* }
|
|
146
|
+
*/
|
|
81
147
|
define?: Record<string, any>;
|
|
148
|
+
/**
|
|
149
|
+
* Environment variables to expose to the client.
|
|
150
|
+
* All variables starting with VITE_ or IONIFY_ are automatically exposed as import.meta.env.*
|
|
151
|
+
*/
|
|
152
|
+
envPrefix?: string | string[];
|
|
82
153
|
}
|
|
83
154
|
|
|
84
155
|
interface BuildChunkAsset {
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,21 @@ interface IonifyResolveConfig {
|
|
|
2
2
|
baseUrl?: string;
|
|
3
3
|
paths?: Record<string, string[]>;
|
|
4
4
|
alias?: Record<string, string>;
|
|
5
|
+
/**
|
|
6
|
+
* File extensions to try when resolving imports.
|
|
7
|
+
* @default ['.mjs', '.js', '.mts', '.ts', '.jsx', '.tsx', '.json']
|
|
8
|
+
*/
|
|
5
9
|
extensions?: string[];
|
|
10
|
+
/**
|
|
11
|
+
* Conditions to use when resolving package.json "exports" field.
|
|
12
|
+
* @default ['import', 'module', 'browser', 'default']
|
|
13
|
+
*/
|
|
14
|
+
conditions?: string[];
|
|
15
|
+
/**
|
|
16
|
+
* Fields to check in package.json for entry point resolution.
|
|
17
|
+
* @default ['module', 'jsnext:main', 'jsnext', 'main']
|
|
18
|
+
*/
|
|
19
|
+
mainFields?: string[];
|
|
6
20
|
}
|
|
7
21
|
interface IonifyServerConfig {
|
|
8
22
|
port?: number;
|
|
@@ -51,7 +65,19 @@ interface IonifyScopeHoistConfig {
|
|
|
51
65
|
combineVariables?: boolean;
|
|
52
66
|
}
|
|
53
67
|
interface IonifyConfig {
|
|
68
|
+
/**
|
|
69
|
+
* Project root directory. All paths are resolved relative to root.
|
|
70
|
+
* Affects: module resolution, watcher, public URLs, CAS location.
|
|
71
|
+
* @default process.cwd()
|
|
72
|
+
*/
|
|
54
73
|
root?: string;
|
|
74
|
+
/**
|
|
75
|
+
* Entry point(s) for the application (relative to root or project-relative with leading '/').
|
|
76
|
+
* Accepts a single entry or multiple entries.
|
|
77
|
+
* @example '/src/main.tsx'
|
|
78
|
+
* @example ['src/main.tsx', 'src/admin.tsx']
|
|
79
|
+
*/
|
|
80
|
+
entry?: string | string[];
|
|
55
81
|
base?: string;
|
|
56
82
|
mode?: string;
|
|
57
83
|
/** Runtime-resolved minifier selection ('auto' by default). */
|
|
@@ -74,11 +100,56 @@ interface IonifyConfig {
|
|
|
74
100
|
build?: IonifyBuildConfig;
|
|
75
101
|
css?: IonifyCSSConfig;
|
|
76
102
|
optimizeDeps?: {
|
|
103
|
+
/**
|
|
104
|
+
* Dependencies to pre-optimize on server start.
|
|
105
|
+
* Useful for ensuring common dependencies are bundled before first request.
|
|
106
|
+
* @example ['react', 'react-dom', 'lodash']
|
|
107
|
+
*/
|
|
77
108
|
include?: string[];
|
|
78
109
|
exclude?: string[];
|
|
110
|
+
/**
|
|
111
|
+
* Generate sourcemaps for optimized dependencies.
|
|
112
|
+
* Disabled by default to speed up dependency optimization.
|
|
113
|
+
*/
|
|
114
|
+
sourcemap?: boolean;
|
|
115
|
+
/**
|
|
116
|
+
* Bundle ESM dependencies instead of serving them as-is with proxies.
|
|
117
|
+
* When `true` (default), ESM deps are bundled into single self-contained
|
|
118
|
+
* files with synthesized named exports, eliminating request waterfalls.
|
|
119
|
+
* Set to `false` for debugging (to inspect original package source).
|
|
120
|
+
* @default true
|
|
121
|
+
*/
|
|
122
|
+
bundleEsm?: boolean;
|
|
123
|
+
/**
|
|
124
|
+
* Build a framework "vendor preloader" module in dev to reduce cold-start waterfalls.
|
|
125
|
+
* - `'auto'` (default): detect framework deps from package.json and generate `vendor.<depsHash>.js`
|
|
126
|
+
* - `string[]`: explicit vendor specifiers (e.g. ['react','react-dom/client'])
|
|
127
|
+
* - `false`: disable vendor preloading
|
|
128
|
+
*/
|
|
129
|
+
vendor?: "auto" | string[] | false;
|
|
130
|
+
/**
|
|
131
|
+
* @deprecated esbuildOptions are not supported in Ionify.
|
|
132
|
+
* Ionify uses native Rust optimizer. This option is ignored with a warning.
|
|
133
|
+
*/
|
|
134
|
+
esbuildOptions?: Record<string, unknown>;
|
|
79
135
|
};
|
|
80
136
|
plugins?: any[];
|
|
137
|
+
/**
|
|
138
|
+
* Define global constant replacements.
|
|
139
|
+
* Values are JSON-stringified and replaced at compile time using AST transformation.
|
|
140
|
+
* @example
|
|
141
|
+
* define: {
|
|
142
|
+
* __APP_VERSION__: JSON.stringify('1.0.0'),
|
|
143
|
+
* __API_URL__: JSON.stringify('https://api.example.com'),
|
|
144
|
+
* 'process.env.NODE_ENV': JSON.stringify('production')
|
|
145
|
+
* }
|
|
146
|
+
*/
|
|
81
147
|
define?: Record<string, any>;
|
|
148
|
+
/**
|
|
149
|
+
* Environment variables to expose to the client.
|
|
150
|
+
* All variables starting with VITE_ or IONIFY_ are automatically exposed as import.meta.env.*
|
|
151
|
+
*/
|
|
152
|
+
envPrefix?: string | string[];
|
|
82
153
|
}
|
|
83
154
|
|
|
84
155
|
interface BuildChunkAsset {
|
package/dist/ionify_core.node
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ionify/ionify",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A web infrastructure intelligence engine",
|
|
6
6
|
"bin": {
|
|
7
|
-
"ionify": "
|
|
7
|
+
"ionify": "dist/cli/index.js"
|
|
8
8
|
},
|
|
9
9
|
"main": "./dist/index.js",
|
|
10
10
|
"module": "./dist/index.js",
|
|
@@ -68,6 +68,7 @@
|
|
|
68
68
|
"@types/node": "^22.0.0",
|
|
69
69
|
"esbuild-plugin-alias": "^0.2.1",
|
|
70
70
|
"eslint": "^9.14.0",
|
|
71
|
+
"lodash": "4.17.21",
|
|
71
72
|
"tsconfig-paths": "^4.2.0",
|
|
72
73
|
"tsup": "^8.0.0",
|
|
73
74
|
"tsx": "^4.19.0",
|