dinou 6.1.1 → 7.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +106 -0
- package/README.md +9352 -1081
- package/cli.js +314 -91
- package/dinou/adapters/bun.js +62 -0
- package/dinou/adapters/cloudflare.js +65 -0
- package/dinou/adapters/deno.js +48 -0
- package/dinou/adapters/netlify.js +85 -0
- package/dinou/adapters/node.mjs +31 -0
- package/dinou/bun/build.mjs +1077 -0
- package/dinou/cloudflare/build.mjs +1121 -0
- package/dinou/cloudflare/shims/child_process.js +14 -0
- package/dinou/cloudflare/shims/empty.js +2 -0
- package/dinou/cloudflare/shims/fs.js +99 -0
- package/dinou/cloudflare/shims/os.js +29 -0
- package/dinou/config.js +1 -0
- package/dinou/config.mjs +2 -0
- package/dinou/constants.js +29 -4
- package/dinou/core/babel-esm-loader.js +66 -37
- package/dinou/core/bailout-proxy.js +61 -0
- package/dinou/core/build-static-pages.js +322 -165
- package/dinou/core/cache-revalidate.js +471 -144
- package/dinou/core/cache-slot.js +387 -0
- package/dinou/core/client-redirect.jsx +12 -7
- package/dinou/core/client-webpack.jsx +457 -82
- package/dinou/core/client.jsx +452 -82
- package/dinou/core/config.js +11 -0
- package/dinou/core/dinou-paths.js +52 -0
- package/dinou/core/edge-ssr.js +122 -0
- package/dinou/core/export-static.mjs +64 -0
- package/dinou/core/generate-route-types.js +252 -0
- package/dinou/core/generate-static-page.js +55 -94
- package/dinou/core/generate-static-rsc.js +47 -15
- package/dinou/core/generate-static.js +212 -10
- package/dinou/core/generating-isg.js +5 -0
- package/dinou/core/get-asset-from-manifest.js +9 -3
- package/dinou/core/get-error-jsx.js +221 -41
- package/dinou/core/get-file-path-and-dynamic-params.js +9 -13
- package/dinou/core/get-jsx.js +175 -96
- package/dinou/core/handler.js +2303 -0
- package/dinou/core/http-adapter.js +115 -0
- package/dinou/core/import-module.js +83 -53
- package/dinou/core/layout-functions.js +183 -0
- package/dinou/core/link.jsx +18 -6
- package/dinou/core/load-dinou-config.js +60 -0
- package/dinou/core/manifest-provider.js +261 -0
- package/dinou/core/navigation-utils.js +4 -0
- package/dinou/core/navigation.js +50 -39
- package/dinou/core/parse-exports.js +252 -2
- package/dinou/core/ppr-context.js +105 -0
- package/dinou/core/ppr-runtime.js +263 -0
- package/dinou/core/redirect.jsx +20 -19
- package/dinou/core/render-jsx-to-client-jsx.js +91 -87
- package/dinou/core/request-context.js +47 -13
- package/dinou/core/resolve-module-ppr.js +34 -0
- package/dinou/core/revalidating.js +28 -9
- package/dinou/core/route-generator.js +107 -0
- package/dinou/core/rsc-renderer.js +90 -0
- package/dinou/core/run-ssg.js +19 -0
- package/dinou/core/scan-dependency-components.js +218 -0
- package/dinou/core/server-function-proxy-webpack.js +3 -0
- package/dinou/core/server-function-proxy.js +3 -0
- package/dinou/core/slot.js +302 -0
- package/dinou/core/status-manifest.js +41 -1
- package/dinou/core/storage-adapter.js +522 -0
- package/dinou/core/url-resolver.js +16 -16
- package/dinou/core/vfs.js +139 -68
- package/dinou/deno/build.mjs +1112 -0
- package/dinou/deno/seed-kv.js +115 -0
- package/dinou/esbuild/build.mjs +51 -1
- package/dinou/esbuild/dev.mjs +290 -224
- package/dinou/esbuild/helpers-esbuild/get-config-esbuild-prod.mjs +3 -2
- package/dinou/esbuild/helpers-esbuild/get-config-esbuild.mjs +104 -16
- package/dinou/esbuild/helpers-esbuild/get-esbuild-entries.mjs +31 -19
- package/dinou/esbuild/helpers-esbuild/strip-namespace.mjs +9 -0
- package/dinou/esbuild/helpers-esbuild/swc-disk-cache.mjs +225 -0
- package/dinou/esbuild/helpers-esbuild/update-manifest-for-module.mjs +7 -0
- package/dinou/esbuild/helpers-esbuild/write.mjs +111 -2
- package/dinou/esbuild/plugins-esbuild/assets-plugin.mjs +236 -161
- package/dinou/esbuild/plugins-esbuild/css-processor-plugin.mjs +101 -5
- package/dinou/esbuild/plugins-esbuild/react-client-manifest-plugin.mjs +63 -24
- package/dinou/esbuild/plugins-esbuild/server-functions-plugin.mjs +177 -56
- package/dinou/esbuild/plugins-esbuild/skip-missing-entry-points-plugin.mjs +3 -0
- package/dinou/esbuild/plugins-esbuild/stable-chunk-names-and-maps-plugin.mjs +182 -137
- package/dinou/esbuild/plugins-postcss/postcss-extract-plugin.js +38 -11
- package/dinou/esbuild/react-refresh/esm-hmr/client.mjs +55 -8
- package/dinou/esbuild/react-refresh/esm-hmr/server.js +1 -1
- package/dinou/esbuild/react-refresh/esm-hmr-plugin.mjs +238 -101
- package/dinou/esbuild/react-refresh/is-react-refresh-boundary.mjs +18 -4
- package/dinou/index.d.ts +315 -11
- package/dinou/index.js +12 -6
- package/dinou/index.mjs +9 -0
- package/dinou/node/build.mjs +195 -0
- package/dinou/node/bundle-dual-engine.mjs +1012 -0
- package/dinou/node/dev.mjs +2589 -0
- package/dinou/node/port-selector.mjs +164 -0
- package/dinou/node/terminal-status.mjs +345 -0
- package/dinou/package.json +16 -14
- package/dinou/rollup/react-refresh/esm-hmr/client.js +66 -10
- package/dinou/rollup/react-refresh/esm-hmr/server.js +1 -1
- package/dinou/rollup/react-refresh/is-react-refresh-boundary.js +24 -5
- package/dinou/rollup/react-refresh/react-refresh-runtime.js +13 -6
- package/dinou/rollup/react-refresh/react-refresh-wrap-modules.js +56 -11
- package/dinou/rollup/react-refresh/rollup-plugin-esm-hmr.js +176 -48
- package/dinou/rollup/rollup-plugins/dinou-asset-plugin.js +9 -5
- package/dinou/rollup/rollup-plugins/rollup-plugin-memory.js +66 -0
- package/dinou/rollup/rollup-plugins/rollup-plugin-react-client-manifest.js +468 -123
- package/dinou/rollup/rollup-plugins/rollup-plugin-server-functions.js +44 -12
- package/dinou/rollup/rollup-plugins/rollup-plugin-swc.js +100 -0
- package/dinou/rollup/rollup.config.js +155 -43
- package/dinou/server.d.ts +114 -12
- package/dinou/server.js +35 -10
- package/dinou/server.mjs +30 -9
- package/dinou/webpack/helpers/get-webpack-entries.js +14 -19
- package/dinou/webpack/loaders/server-functions-loader.js +22 -1
- package/dinou/webpack/loaders/swc-loader.js +76 -0
- package/dinou/webpack/plugins/manifest-generator-plugin.js +1 -0
- package/dinou/webpack/plugins/server-functions-plugin.js +75 -19
- package/dinou/webpack/plugins/webpack-memory-plugin.js +66 -0
- package/dinou/webpack/webpack.config.js +227 -29
- package/eject.js +113 -34
- package/package.json +18 -16
- package/dinou/core/asset-require-hook.js +0 -58
- package/dinou/core/client-error-webpack.jsx +0 -432
- package/dinou/core/client-error.jsx +0 -432
- package/dinou/core/concurrency-manager.js +0 -48
- package/dinou/core/context-proxy.js +0 -68
- package/dinou/core/generate-static-pages.js +0 -130
- package/dinou/core/generate-static-rscs.js +0 -151
- package/dinou/core/get-ssg-metadata.js +0 -31
- package/dinou/core/register-loader.mjs +0 -11
- package/dinou/core/register-paths.js +0 -27
- package/dinou/core/render-app-to-html.js +0 -430
- package/dinou/core/render-html.js +0 -407
- package/dinou/core/server.js +0 -1542
- package/dinou/esbuild/plugins-esbuild/write-metafile-plugin.mjs +0 -16
|
@@ -96,35 +96,49 @@ class HotModuleState {
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
export function createHotContext(id) {
|
|
99
|
-
const
|
|
99
|
+
const normId = id.startsWith("/") ? id : "/" + id;
|
|
100
|
+
const existing = REGISTERED_MODULES[normId] || REGISTERED_MODULES[id];
|
|
100
101
|
if (existing) {
|
|
101
|
-
existing.
|
|
102
|
+
existing.isLocked = false;
|
|
103
|
+
existing.acceptCallbacks = [];
|
|
102
104
|
return existing;
|
|
103
105
|
}
|
|
104
|
-
const state = new HotModuleState(
|
|
106
|
+
const state = new HotModuleState(normId);
|
|
107
|
+
REGISTERED_MODULES[normId] = state;
|
|
105
108
|
REGISTERED_MODULES[id] = state;
|
|
106
109
|
return state;
|
|
107
110
|
}
|
|
108
111
|
|
|
109
112
|
async function applyUpdate(id) {
|
|
110
|
-
const
|
|
113
|
+
const clean = id ? id.split("?")[0] : "";
|
|
114
|
+
const normId = clean.startsWith("/") ? clean : "/" + clean;
|
|
115
|
+
const state = REGISTERED_MODULES[normId] || REGISTERED_MODULES[clean] || REGISTERED_MODULES[id];
|
|
111
116
|
if (!state || state.isDeclined) {
|
|
112
117
|
return false;
|
|
113
118
|
}
|
|
114
119
|
|
|
115
|
-
const acceptCallbacks = state.acceptCallbacks;
|
|
116
|
-
const disposeCallbacks = state.disposeCallbacks;
|
|
120
|
+
const acceptCallbacks = [...state.acceptCallbacks];
|
|
121
|
+
const disposeCallbacks = [...state.disposeCallbacks];
|
|
117
122
|
state.disposeCallbacks = [];
|
|
118
123
|
state.data = {};
|
|
119
124
|
|
|
120
|
-
disposeCallbacks.forEach((callback) =>
|
|
125
|
+
disposeCallbacks.forEach((callback) => {
|
|
126
|
+
try {
|
|
127
|
+
callback();
|
|
128
|
+
} catch (e) {
|
|
129
|
+
console.warn("[ESM-HMR] dispose callback error:", e);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
121
132
|
|
|
122
133
|
const updateID = Date.now();
|
|
123
134
|
|
|
124
135
|
for (const { deps, callback: acceptCallback } of acceptCallbacks) {
|
|
125
136
|
const [module, ...depModules] = await Promise.all([
|
|
126
|
-
import(
|
|
127
|
-
...deps.map((d) =>
|
|
137
|
+
import(normId + `?mtime=${updateID}`),
|
|
138
|
+
...deps.map((d) => {
|
|
139
|
+
const depId = d.startsWith("/") ? d : "/" + d;
|
|
140
|
+
return import(depId + `?mtime=${updateID}`);
|
|
141
|
+
}),
|
|
128
142
|
]);
|
|
129
143
|
acceptCallback({ module, deps: depModules });
|
|
130
144
|
}
|
|
@@ -142,18 +156,60 @@ socket.addEventListener("message", ({ data: _data }) => {
|
|
|
142
156
|
return;
|
|
143
157
|
}
|
|
144
158
|
|
|
159
|
+
if (data.type === "rsc-update") {
|
|
160
|
+
if (typeof window !== "undefined" && typeof window.__DINOU_ROUTER_REFRESH__ === "function") {
|
|
161
|
+
window.__DINOU_ROUTER_REFRESH__();
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
reload();
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (
|
|
169
|
+
data.type === "style-update" ||
|
|
170
|
+
(data.type === "update" && data.url && (data.url.endsWith(".css") || data.url.includes("styles.css")))
|
|
171
|
+
) {
|
|
172
|
+
const targetUrl = data.url ? data.url.split("?")[0] : "";
|
|
173
|
+
const links = document.querySelectorAll('link[rel="stylesheet"]');
|
|
174
|
+
for (const link of links) {
|
|
175
|
+
const rawHref = link.getAttribute("href");
|
|
176
|
+
if (!rawHref) continue;
|
|
177
|
+
const cleanHref = rawHref.split("?")[0];
|
|
178
|
+
if (!targetUrl || cleanHref.endsWith(targetUrl) || targetUrl.endsWith(cleanHref) || cleanHref.includes("styles.css")) {
|
|
179
|
+
const nextUrl = new URL(link.href, window.location.origin);
|
|
180
|
+
nextUrl.searchParams.set("t", String(Date.now()));
|
|
181
|
+
link.href = nextUrl.href;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
145
187
|
if (data.type !== "update") {
|
|
146
188
|
return;
|
|
147
189
|
}
|
|
148
190
|
|
|
191
|
+
const tRecv = Date.now();
|
|
192
|
+
const isDebug = typeof window !== "undefined" && Boolean(window.__DINOU_DEBUG__);
|
|
193
|
+
|
|
194
|
+
if (isDebug) {
|
|
195
|
+
console.log(`⏱️ [BROWSER HMR] Received update for ${data.url} at ${new Date().toTimeString().slice(0, 8)}.${String(Date.now() % 1000).padStart(3, '0')}`);
|
|
196
|
+
}
|
|
197
|
+
|
|
149
198
|
applyUpdate(data.url)
|
|
150
199
|
.then((ok) => {
|
|
151
200
|
if (!ok) {
|
|
201
|
+
if (isDebug) console.warn(`⏱️ [BROWSER HMR] applyUpdate returned false, falling back to full reload!`);
|
|
152
202
|
reload();
|
|
203
|
+
} else {
|
|
204
|
+
if (isDebug) {
|
|
205
|
+
console.log(`⏱️ [BROWSER HMR] Fast Refresh finished applying in ${Date.now() - tRecv}ms!`);
|
|
206
|
+
} else {
|
|
207
|
+
console.log(`[ESM-HMR] hot updated: ${data.url}`);
|
|
208
|
+
}
|
|
153
209
|
}
|
|
154
210
|
})
|
|
155
211
|
.catch((err) => {
|
|
156
|
-
console.error(err);
|
|
212
|
+
console.error(`[ESM-HMR] applyUpdate error:`, err);
|
|
157
213
|
reload();
|
|
158
214
|
});
|
|
159
215
|
});
|
|
@@ -16,7 +16,7 @@ class EsmHmrEngine {
|
|
|
16
16
|
this.dependencyTree = map;
|
|
17
17
|
const wss = options.server
|
|
18
18
|
? new WebSocket.Server({ noServer: true })
|
|
19
|
-
: new WebSocket.Server({ port: 3001 });
|
|
19
|
+
: new WebSocket.Server({ port: options.port || Number(process.env.HMR_PORT) || 3001 });
|
|
20
20
|
|
|
21
21
|
if (options.server) {
|
|
22
22
|
options.server.on("upgrade", (req, socket, head) => {
|
|
@@ -9,13 +9,32 @@ export function isReactRefreshBoundary(RefreshRuntime, moduleExports) {
|
|
|
9
9
|
let hasExports = false;
|
|
10
10
|
let areAllExportsComponents = true;
|
|
11
11
|
for (const key in moduleExports) {
|
|
12
|
-
if (
|
|
12
|
+
if (
|
|
13
|
+
key === "__esModule" ||
|
|
14
|
+
key === "metadata" ||
|
|
15
|
+
key === "revalidate" ||
|
|
16
|
+
key === "dynamic" ||
|
|
17
|
+
key === "dynamicParams" ||
|
|
18
|
+
key === "fetchCache" ||
|
|
19
|
+
key === "preferredRegion" ||
|
|
20
|
+
key === "runtime" ||
|
|
21
|
+
key === "maxDuration" ||
|
|
22
|
+
key === "generateStaticParams" ||
|
|
23
|
+
key === "generateMetadata" ||
|
|
24
|
+
key === "frontmatter" ||
|
|
25
|
+
key === "toc" ||
|
|
26
|
+
key === "headings"
|
|
27
|
+
) {
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
13
30
|
|
|
14
31
|
hasExports = true;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
32
|
+
let exportValue;
|
|
33
|
+
try {
|
|
34
|
+
exportValue = moduleExports[key];
|
|
35
|
+
} catch (e) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
19
38
|
if (!RefreshRuntime.isLikelyComponentType(exportValue)) {
|
|
20
39
|
areAllExportsComponents = false;
|
|
21
40
|
}
|
|
@@ -1,22 +1,29 @@
|
|
|
1
1
|
import RefreshRuntime from "/refresh.js";
|
|
2
2
|
import { isReactRefreshBoundary } from "./is-react-refresh-boundary";
|
|
3
3
|
|
|
4
|
+
const runtime = RefreshRuntime?.default || RefreshRuntime;
|
|
5
|
+
|
|
4
6
|
if (
|
|
5
7
|
typeof window !== "undefined" &&
|
|
6
8
|
!window.__REACT_REFRESH_RUNTIME_INSTALLED__
|
|
7
9
|
) {
|
|
8
|
-
|
|
9
|
-
window
|
|
10
|
-
window.$
|
|
10
|
+
runtime.injectIntoGlobalHook(window);
|
|
11
|
+
window.__reactRefreshRuntime = runtime;
|
|
12
|
+
window.$RefreshReg$ = (type, id) => {
|
|
13
|
+
runtime?.register(type, id);
|
|
14
|
+
};
|
|
15
|
+
window.$RefreshSig$ = runtime?.createSignatureFunctionForTransform
|
|
16
|
+
? runtime.createSignatureFunctionForTransform.bind(runtime)
|
|
17
|
+
: () => (type) => type;
|
|
11
18
|
window.__REACT_REFRESH_RUNTIME_INSTALLED__ = true;
|
|
12
19
|
|
|
13
20
|
let refreshTimeout;
|
|
14
|
-
window.performReactRefresh =
|
|
21
|
+
window.performReactRefresh = runtime.performReactRefresh;
|
|
15
22
|
window.__debouncePerformReactRefresh = () => {
|
|
16
23
|
clearTimeout(refreshTimeout);
|
|
17
24
|
refreshTimeout = setTimeout(() => {
|
|
18
25
|
try {
|
|
19
|
-
|
|
26
|
+
runtime.performReactRefresh();
|
|
20
27
|
} catch (err) {
|
|
21
28
|
console.warn("React Refresh failed:", err);
|
|
22
29
|
}
|
|
@@ -24,5 +31,5 @@ if (
|
|
|
24
31
|
};
|
|
25
32
|
|
|
26
33
|
window.__isReactRefreshBoundary = (moduleExports) =>
|
|
27
|
-
isReactRefreshBoundary(
|
|
34
|
+
isReactRefreshBoundary(runtime, moduleExports);
|
|
28
35
|
}
|
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
const frameworkEntries = new Set([
|
|
2
|
+
"main.js",
|
|
3
|
+
"runtime.js",
|
|
4
|
+
"refresh.js",
|
|
5
|
+
"serverFunctionProxy.js",
|
|
6
|
+
"dinouClientRedirect.js",
|
|
7
|
+
"dinouLink.js",
|
|
8
|
+
"dinouSlot.js",
|
|
9
|
+
"__hmr_client__.js",
|
|
10
|
+
"_commonjsHelpers.js",
|
|
11
|
+
]);
|
|
12
|
+
|
|
1
13
|
function reactRefreshWrapModules() {
|
|
2
14
|
return {
|
|
3
15
|
name: "react-refresh-wrap-modules",
|
|
@@ -5,35 +17,67 @@ function reactRefreshWrapModules() {
|
|
|
5
17
|
if (
|
|
6
18
|
!chunk ||
|
|
7
19
|
!/\.(jsx?|tsx?)$/.test(chunk.fileName) ||
|
|
20
|
+
frameworkEntries.has(chunk.fileName) ||
|
|
8
21
|
chunk.fileName.includes("refresh.js") ||
|
|
9
22
|
chunk.fileName.includes("runtime.js") ||
|
|
10
|
-
chunk.fileName.includes("_commonjsHelpers
|
|
23
|
+
chunk.fileName.includes("_commonjsHelpers")
|
|
11
24
|
) {
|
|
12
25
|
return null;
|
|
13
26
|
}
|
|
14
|
-
const safeId = JSON.stringify(chunk.fileName);
|
|
15
|
-
const wrappedCode = `
|
|
16
|
-
import RefreshRuntime from "/refresh.js";
|
|
17
27
|
|
|
28
|
+
// Only wrap user component chunks that contain actual app code (not third-party libraries)
|
|
29
|
+
const modulePaths = Object.keys(chunk.modules || {});
|
|
30
|
+
const hasUserCode = modulePaths.some(
|
|
31
|
+
(p) =>
|
|
32
|
+
!p.includes("node_modules") &&
|
|
33
|
+
!p.includes("dinou[\\/]core") &&
|
|
34
|
+
!p.includes("dinou[\\/]rollup") &&
|
|
35
|
+
!p.includes("dinou[\\/]esbuild") &&
|
|
36
|
+
!p.includes("dinou[\\/]webpack") &&
|
|
37
|
+
!p.includes("dinou/core") &&
|
|
38
|
+
!p.includes("dinou/rollup") &&
|
|
39
|
+
!p.includes("dinou/esbuild") &&
|
|
40
|
+
!p.includes("dinou/webpack")
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
if (!hasUserCode) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const urlId = "/" + chunk.fileName;
|
|
48
|
+
const safeId = JSON.stringify(urlId);
|
|
49
|
+
const wrappedCode = `
|
|
50
|
+
const RefreshRuntime = window.__reactRefreshRuntime;
|
|
51
|
+
const actualRuntime = RefreshRuntime?.default || RefreshRuntime;
|
|
18
52
|
let prevRefreshReg = window.$RefreshReg$;
|
|
19
53
|
let prevRefreshSig = window.$RefreshSig$;
|
|
20
54
|
|
|
21
55
|
window.$RefreshReg$ = (type, id) => {
|
|
22
|
-
|
|
56
|
+
const fullId = (id && id.includes('#')) ? id : (${safeId} + '#' + id);
|
|
57
|
+
actualRuntime?.register(type, fullId);
|
|
23
58
|
};
|
|
24
|
-
window.$RefreshSig$ =
|
|
59
|
+
window.$RefreshSig$ = (actualRuntime?.createSignatureFunctionForTransform)
|
|
60
|
+
? actualRuntime.createSignatureFunctionForTransform.bind(actualRuntime)
|
|
61
|
+
: (prevRefreshSig || (() => (type) => type));
|
|
62
|
+
|
|
63
|
+
if (!import.meta.hot) import.meta.hot = window.__hotContext?.(${safeId});
|
|
25
64
|
|
|
26
65
|
// --- original code ---
|
|
27
66
|
${code}
|
|
28
67
|
// --- end original code ---
|
|
29
68
|
|
|
30
|
-
window.$RefreshReg$ = prevRefreshReg;
|
|
31
|
-
window.$RefreshSig$ = prevRefreshSig;
|
|
32
|
-
|
|
33
69
|
if (import.meta.hot) {
|
|
34
|
-
import.meta.hot.accept()
|
|
35
|
-
|
|
70
|
+
import.meta.hot.accept(({ module }) => {
|
|
71
|
+
if (window.__isReactRefreshBoundary && window.__isReactRefreshBoundary(module)) {
|
|
72
|
+
window.__debouncePerformReactRefresh?.();
|
|
73
|
+
} else {
|
|
74
|
+
import.meta.hot.invalidate();
|
|
75
|
+
}
|
|
76
|
+
});
|
|
36
77
|
}
|
|
78
|
+
|
|
79
|
+
window.$RefreshReg$ = prevRefreshReg;
|
|
80
|
+
window.$RefreshSig$ = prevRefreshSig;
|
|
37
81
|
`;
|
|
38
82
|
|
|
39
83
|
return {
|
|
@@ -45,3 +89,4 @@ if (import.meta.hot) {
|
|
|
45
89
|
}
|
|
46
90
|
|
|
47
91
|
module.exports = reactRefreshWrapModules;
|
|
92
|
+
|
|
@@ -6,22 +6,40 @@ const { createServer } = require("node:http");
|
|
|
6
6
|
const changedIds = new Set();
|
|
7
7
|
const pendingUpdateUrls = new Set();
|
|
8
8
|
let needsFullReload = false;
|
|
9
|
+
let hasPendingCssUpdate = false;
|
|
10
|
+
|
|
11
|
+
function normalizePath(p) {
|
|
12
|
+
return path.resolve(p).replace(/\\/g, "/").toLowerCase();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let activeServer = null;
|
|
16
|
+
let activeHmrEngine = null;
|
|
17
|
+
|
|
9
18
|
function esmHmrPlugin() {
|
|
10
|
-
let hmrEngine;
|
|
11
|
-
let serverStarted = false;
|
|
19
|
+
let hmrEngine = activeHmrEngine;
|
|
12
20
|
|
|
13
21
|
return {
|
|
14
22
|
name: "esm-hmr",
|
|
15
23
|
|
|
16
24
|
buildStart() {
|
|
17
|
-
if (!
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
25
|
+
if (!activeHmrEngine) {
|
|
26
|
+
const hmrPort = Number(
|
|
27
|
+
process.env.HMR_PORT || (Number(process.env.PORT || 3000) + 1)
|
|
28
|
+
);
|
|
29
|
+
activeServer = createServer();
|
|
30
|
+
activeServer.on("error", (err) => {
|
|
31
|
+
if (err.code === "EADDRINUSE") {
|
|
32
|
+
console.warn(`⚠️ [Rollup HMR] Port ${hmrPort} already in use, reusing existing listener.`);
|
|
33
|
+
} else {
|
|
34
|
+
console.error("❌ [Rollup HMR Server Error]:", err);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
activeHmrEngine = new EsmHmrEngine({ server: activeServer });
|
|
38
|
+
activeServer.listen(hmrPort, () => {
|
|
39
|
+
// console.log(`[esm-hmr] WebSocket server listening on port ${hmrPort}`);
|
|
22
40
|
});
|
|
23
|
-
serverStarted = true;
|
|
24
41
|
}
|
|
42
|
+
hmrEngine = activeHmrEngine;
|
|
25
43
|
},
|
|
26
44
|
|
|
27
45
|
renderChunk(code, chunk) {
|
|
@@ -34,84 +52,194 @@ function esmHmrPlugin() {
|
|
|
34
52
|
return null;
|
|
35
53
|
}
|
|
36
54
|
|
|
37
|
-
const acceptsHmr = code.includes("import.meta.hot.accept");
|
|
38
55
|
const imports = Array.from(code.matchAll(/import\s+["'](.+?)["']/g)).map(
|
|
39
56
|
(m) => m[1]
|
|
40
57
|
);
|
|
41
58
|
const normalizedId = chunk.fileName;
|
|
42
|
-
|
|
59
|
+
const urlId = "/" + chunk.fileName;
|
|
60
|
+
hmrEngine?.setEntry(urlId, imports, true);
|
|
61
|
+
hmrEngine?.setEntry(normalizedId, imports, true);
|
|
43
62
|
|
|
44
63
|
const isClientEntry = normalizedId === "main.js";
|
|
45
64
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
// 🔥 Inject client HMR runtime if it's the entry
|
|
65
|
+
// Inject client HMR runtime if it's the entry
|
|
49
66
|
if (isClientEntry && !code.includes("/__hmr_client__.js")) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if (acceptsHmr) {
|
|
55
|
-
const safeId = JSON.stringify(normalizedId);
|
|
56
|
-
injectCode += `if (!import.meta.hot) import.meta.hot = window.__hotContext?.(${safeId});\n`;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (injectCode) {
|
|
60
|
-
code = injectCode + code;
|
|
67
|
+
return {
|
|
68
|
+
code: `import { createHotContext } from "/__hmr_client__.js";window.__hotContext = createHotContext;\n` + code,
|
|
69
|
+
map: null,
|
|
70
|
+
};
|
|
61
71
|
}
|
|
62
72
|
|
|
63
|
-
return
|
|
64
|
-
code,
|
|
65
|
-
map: null,
|
|
66
|
-
};
|
|
73
|
+
return null;
|
|
67
74
|
},
|
|
68
75
|
|
|
69
76
|
watchChange(id) {
|
|
70
|
-
changedIds.add(id);
|
|
77
|
+
changedIds.add(normalizePath(id));
|
|
71
78
|
},
|
|
72
79
|
|
|
73
80
|
generateBundle(options, bundle) {
|
|
74
81
|
const clientPath = path.resolve(__dirname, "./esm-hmr/client.js");
|
|
82
|
+
let clientSource = fs.readFileSync(clientPath, "utf-8");
|
|
83
|
+
const isDebug =
|
|
84
|
+
process.env.DINOU_DEBUG === "true" ||
|
|
85
|
+
process.env.DINOU_DEBUG === "1" ||
|
|
86
|
+
process.env.DEBUG === "true" ||
|
|
87
|
+
process.env.DEBUG === "1";
|
|
88
|
+
if (isDebug) {
|
|
89
|
+
clientSource = "window.__DINOU_DEBUG__ = true;\n" + clientSource;
|
|
90
|
+
}
|
|
75
91
|
this.emitFile({
|
|
76
92
|
type: "asset",
|
|
77
93
|
fileName: "__hmr_client__.js",
|
|
78
|
-
source:
|
|
94
|
+
source: clientSource,
|
|
79
95
|
});
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
96
|
+
|
|
97
|
+
if (changedIds.size > 0) {
|
|
98
|
+
hasPendingCssUpdate = Array.from(changedIds).some((id) => {
|
|
99
|
+
const lower = id.toLowerCase();
|
|
100
|
+
return lower.endsWith(".css") || lower.endsWith(".scss") || lower.endsWith(".less");
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
for (const [fileName, chunkInfo] of Object.entries(bundle)) {
|
|
104
|
+
if (fileName.endsWith(".css") || chunkInfo.type !== "chunk") {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
let isChangedByJs = false;
|
|
109
|
+
|
|
110
|
+
// 1. Check facadeModuleId
|
|
111
|
+
if (chunkInfo.facadeModuleId) {
|
|
112
|
+
const facadeNorm = normalizePath(chunkInfo.facadeModuleId.replace(/\?.*$/, ""));
|
|
113
|
+
if (changedIds.has(facadeNorm)) {
|
|
114
|
+
isChangedByJs = true;
|
|
90
115
|
}
|
|
91
116
|
}
|
|
117
|
+
|
|
118
|
+
// 2. Check modules in chunk
|
|
119
|
+
if (!isChangedByJs && chunkInfo.modules) {
|
|
120
|
+
isChangedByJs = Object.keys(chunkInfo.modules).some((modPath) => {
|
|
121
|
+
const norm = normalizePath(modPath.replace(/\?.*$/, ""));
|
|
122
|
+
const lower = norm.toLowerCase();
|
|
123
|
+
if (
|
|
124
|
+
(lower.endsWith(".css") || lower.endsWith(".scss") || lower.endsWith(".less")) &&
|
|
125
|
+
!lower.endsWith(".module.css")
|
|
126
|
+
) {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
return changedIds.has(norm);
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// 3. Fallback: match chunk filename with base name or relative path of changedId
|
|
134
|
+
if (!isChangedByJs) {
|
|
135
|
+
const chunkFileNameLower = fileName.toLowerCase().replace(/\.[jt]sx?$/, "");
|
|
136
|
+
for (const changedId of changedIds) {
|
|
137
|
+
const relClean = changedId
|
|
138
|
+
.replace(/^.*\/src\//, "")
|
|
139
|
+
.replace(/\.[jt]sx?$/, "")
|
|
140
|
+
.replace(/[^a-zA-Z0-9_-]/g, "_")
|
|
141
|
+
.toLowerCase();
|
|
142
|
+
if (relClean && chunkFileNameLower.includes(relClean)) {
|
|
143
|
+
isChangedByJs = true;
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
const baseName = path.basename(changedId).replace(/\.[jt]sx?$/, "").toLowerCase();
|
|
147
|
+
if (baseName.length > 2 && baseName !== "page" && baseName !== "layout" && baseName !== "index" && chunkFileNameLower.includes(baseName)) {
|
|
148
|
+
isChangedByJs = true;
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (isChangedByJs) {
|
|
155
|
+
const urlId = "/" + fileName;
|
|
156
|
+
pendingUpdateUrls.add(urlId);
|
|
157
|
+
}
|
|
92
158
|
}
|
|
93
159
|
}
|
|
94
160
|
},
|
|
95
|
-
closeBundle() {
|
|
96
|
-
if (changedIds.size === 0) return;
|
|
97
161
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
162
|
+
writeBundle(_options, _bundle) {
|
|
163
|
+
if (changedIds.size === 0 && pendingUpdateUrls.size === 0 && !hasPendingCssUpdate) return;
|
|
164
|
+
|
|
165
|
+
if (hasPendingCssUpdate) {
|
|
166
|
+
hmrEngine?.broadcastMessage({ type: "style-update", url: "/styles.css" });
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const timelineTime = () =>
|
|
170
|
+
new Date().toTimeString().slice(0, 8) +
|
|
171
|
+
"." +
|
|
172
|
+
String(Date.now() % 1000).padStart(3, "0");
|
|
173
|
+
const timelineRel = () =>
|
|
174
|
+
globalThis.__TIMELINE_T0__
|
|
175
|
+
? `[+${Date.now() - globalThis.__TIMELINE_T0__}ms]`
|
|
176
|
+
: ``;
|
|
177
|
+
|
|
178
|
+
const isDebug =
|
|
179
|
+
process.env.DINOU_DEBUG === "true" ||
|
|
180
|
+
process.env.DINOU_DEBUG === "1" ||
|
|
181
|
+
process.env.DEBUG === "true" ||
|
|
182
|
+
process.env.DEBUG === "1";
|
|
183
|
+
|
|
184
|
+
if (isDebug && changedIds.size > 0) {
|
|
185
|
+
console.log(
|
|
186
|
+
`⏱️ [TIMELINE ${timelineTime()}] ${timelineRel()} [HMR Rollup] Changed: [${Array.from(changedIds).join(", ")}] -> Chunks: [${Array.from(pendingUpdateUrls).join(", ")}]`
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (pendingUpdateUrls.size > 0 && !needsFullReload) {
|
|
102
191
|
for (const url of pendingUpdateUrls) {
|
|
103
|
-
|
|
104
|
-
|
|
192
|
+
if (isDebug) {
|
|
193
|
+
console.log(
|
|
194
|
+
`⏱️ [TIMELINE ${timelineTime()}] ${timelineRel()} ⚡ [HMR Broadcast] Sending update to browser: ${url}`
|
|
195
|
+
);
|
|
196
|
+
} else {
|
|
197
|
+
console.log(`⚡ [HMR] Updating client component: ${url}`);
|
|
198
|
+
}
|
|
199
|
+
hmrEngine?.broadcastMessage({ type: "update", url });
|
|
105
200
|
}
|
|
201
|
+
} else if (needsFullReload) {
|
|
202
|
+
if (isDebug) {
|
|
203
|
+
console.log(
|
|
204
|
+
`⏱️ [TIMELINE ${timelineTime()}] ${timelineRel()} ⚡ [HMR Broadcast] Full reload triggered`
|
|
205
|
+
);
|
|
206
|
+
} else {
|
|
207
|
+
console.log(`⚡ [HMR] Full reload triggered`);
|
|
208
|
+
}
|
|
209
|
+
hmrEngine?.broadcastMessage({ type: "reload" });
|
|
106
210
|
}
|
|
107
211
|
|
|
108
212
|
changedIds.clear();
|
|
109
213
|
pendingUpdateUrls.clear();
|
|
214
|
+
hasPendingCssUpdate = false;
|
|
110
215
|
needsFullReload = false;
|
|
111
216
|
},
|
|
217
|
+
|
|
218
|
+
closeWatcher() {
|
|
219
|
+
// Shared server stays open across restarts
|
|
220
|
+
},
|
|
112
221
|
};
|
|
113
222
|
}
|
|
114
223
|
|
|
224
|
+
function notifyFileChanged(absPath) {
|
|
225
|
+
if (absPath) {
|
|
226
|
+
changedIds.add(normalizePath(absPath));
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
115
230
|
module.exports = {
|
|
116
231
|
esmHmrPlugin,
|
|
232
|
+
getHmrEngine: () => activeHmrEngine,
|
|
233
|
+
notifyFileChanged,
|
|
234
|
+
closeHmrServer: () => {
|
|
235
|
+
if (activeServer) {
|
|
236
|
+
try {
|
|
237
|
+
activeServer.close();
|
|
238
|
+
} catch (e) {}
|
|
239
|
+
activeServer = null;
|
|
240
|
+
activeHmrEngine = null;
|
|
241
|
+
}
|
|
242
|
+
},
|
|
117
243
|
};
|
|
244
|
+
|
|
245
|
+
|
|
@@ -17,11 +17,15 @@ function dinouAssetPlugin({ include = regex } = {}) {
|
|
|
17
17
|
|
|
18
18
|
const fileName = `assets/${scoped}${ext}`;
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
fileName
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
const emitted = globalThis.__DINOU_EMITTED_ASSETS__ || (globalThis.__DINOU_EMITTED_ASSETS__ = new Set());
|
|
21
|
+
if (!emitted.has(fileName)) {
|
|
22
|
+
emitted.add(fileName);
|
|
23
|
+
this.emitFile({
|
|
24
|
+
type: "asset",
|
|
25
|
+
fileName,
|
|
26
|
+
source,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
25
29
|
|
|
26
30
|
return `export default '/assets/${scoped}${ext}';`;
|
|
27
31
|
},
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// dinou/rollup/rollup-plugins/rollup-plugin-memory.js
|
|
2
|
+
// Stores all bundled chunks, assets and sourcemaps in memory (globalThis.__DINOU_MEM_FILES__)
|
|
3
|
+
// and deletes them from Rollup's emit queue in dev mode to prevent massive disk writes.
|
|
4
|
+
|
|
5
|
+
const path = require("node:path");
|
|
6
|
+
|
|
7
|
+
function rollupMemoryPlugin() {
|
|
8
|
+
return {
|
|
9
|
+
name: "rollup-memory-plugin",
|
|
10
|
+
generateBundle(options, bundle) {
|
|
11
|
+
const isDev =
|
|
12
|
+
process.env.NODE_ENV !== "production" ||
|
|
13
|
+
process.env.DINOU_DEV === "true";
|
|
14
|
+
|
|
15
|
+
// Only acts in development mode. In production, Rollup writes to .dinou/dist3 normally.
|
|
16
|
+
if (!isDev) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const shouldWriteToDisk = process.env.DINOU_WRITE_TO_DISK === "true";
|
|
21
|
+
|
|
22
|
+
if (typeof globalThis !== "undefined") {
|
|
23
|
+
if (!globalThis.__DINOU_MEM_FILES__) {
|
|
24
|
+
globalThis.__DINOU_MEM_FILES__ = new Map();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
for (const [fileName, item] of Object.entries(bundle)) {
|
|
29
|
+
const normKey = fileName.replace(/\\/g, "/");
|
|
30
|
+
const raw = item.type === "asset" ? item.source : item.code;
|
|
31
|
+
const buf = Buffer.isBuffer(raw) ? raw : Buffer.from(raw || "");
|
|
32
|
+
|
|
33
|
+
if (typeof globalThis !== "undefined" && globalThis.__DINOU_MEM_FILES__) {
|
|
34
|
+
globalThis.__DINOU_MEM_FILES__.set(normKey, buf);
|
|
35
|
+
globalThis.__DINOU_MEM_FILES__.set("/" + normKey, buf);
|
|
36
|
+
const base = path.basename(normKey);
|
|
37
|
+
globalThis.__DINOU_MEM_FILES__.set(base, buf);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (item.map) {
|
|
41
|
+
const mapKey = `${normKey}.map`;
|
|
42
|
+
const mapRaw =
|
|
43
|
+
typeof item.map.toString === "function"
|
|
44
|
+
? item.map.toString()
|
|
45
|
+
: JSON.stringify(item.map);
|
|
46
|
+
const mapBuf = Buffer.from(mapRaw);
|
|
47
|
+
if (
|
|
48
|
+
typeof globalThis !== "undefined" &&
|
|
49
|
+
globalThis.__DINOU_MEM_FILES__
|
|
50
|
+
) {
|
|
51
|
+
globalThis.__DINOU_MEM_FILES__.set(mapKey, mapBuf);
|
|
52
|
+
globalThis.__DINOU_MEM_FILES__.set("/" + mapKey, mapBuf);
|
|
53
|
+
const baseMap = path.basename(mapKey);
|
|
54
|
+
globalThis.__DINOU_MEM_FILES__.set(baseMap, mapBuf);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (!shouldWriteToDisk) {
|
|
59
|
+
delete bundle[fileName];
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
module.exports = rollupMemoryPlugin;
|