dinou 6.1.0 → 7.0.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 +99 -0
- package/README.md +9461 -1080
- package/cli.js +392 -169
- 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 +309 -157
- 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 +172 -95
- package/dinou/core/handler.js +2296 -0
- package/dinou/core/http-adapter.js +115 -0
- package/dinou/core/import-module.js +83 -53
- package/dinou/core/layout-functions.js +181 -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 +207 -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 +133 -15
- package/dinou/core/request-context.js +47 -13
- package/dinou/core/resolve-module-ppr.js +32 -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 +17 -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 +173 -94
- package/package.json +110 -107
- 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
|
@@ -1,25 +1,81 @@
|
|
|
1
1
|
// plugins-esbuild/esm-hmr-plugin.mjs
|
|
2
2
|
import fs from "node:fs/promises";
|
|
3
|
+
import fsSync from "node:fs";
|
|
3
4
|
import path from "node:path";
|
|
4
|
-
import {
|
|
5
|
+
import { transform } from "@swc/core";
|
|
5
6
|
import { createServer } from "node:http";
|
|
6
7
|
import { EsmHmrEngine } from "./esm-hmr/server.js";
|
|
7
8
|
import { fileURLToPath } from "node:url";
|
|
8
9
|
import write from "../helpers-esbuild/write.mjs";
|
|
9
10
|
import normalizePath from "../helpers-esbuild/normalize-path.mjs";
|
|
11
|
+
import stripNamespace from "../helpers-esbuild/strip-namespace.mjs";
|
|
10
12
|
|
|
11
13
|
const norm = (p) => path.resolve(p).replace(/\\/g, "/");
|
|
14
|
+
const normKey = (p) => {
|
|
15
|
+
if (!p) return "";
|
|
16
|
+
let s = path.resolve(p).replace(/\\/g, "/");
|
|
17
|
+
if (process.platform === "win32") {
|
|
18
|
+
s = s.replace(/^([a-zA-Z]):/, (_, d) => d.toLowerCase() + ":");
|
|
19
|
+
}
|
|
20
|
+
return s;
|
|
21
|
+
};
|
|
22
|
+
|
|
12
23
|
let serverStarted = false;
|
|
13
24
|
|
|
25
|
+
const swcGlobalCache = new Map();
|
|
26
|
+
let swcCacheLoaded = false;
|
|
27
|
+
let swcCacheDirty = false;
|
|
28
|
+
|
|
29
|
+
function getSwcCachePath() {
|
|
30
|
+
const dir = path.resolve(process.cwd(), ".dinou/cache");
|
|
31
|
+
return { dir, file: path.join(dir, "swc-dev-cache.json") };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function loadSwcCache() {
|
|
35
|
+
if (swcCacheLoaded) return;
|
|
36
|
+
swcCacheLoaded = true;
|
|
37
|
+
try {
|
|
38
|
+
const { file } = getSwcCachePath();
|
|
39
|
+
if (fsSync.existsSync(file)) {
|
|
40
|
+
const parsed = JSON.parse(fsSync.readFileSync(file, "utf8"));
|
|
41
|
+
for (const [k, v] of Object.entries(parsed)) {
|
|
42
|
+
swcGlobalCache.set(k, v);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
} catch (e) {}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function saveSwcCache() {
|
|
49
|
+
if (!swcCacheDirty) return;
|
|
50
|
+
swcCacheDirty = false;
|
|
51
|
+
try {
|
|
52
|
+
const { dir, file } = getSwcCachePath();
|
|
53
|
+
if (!fsSync.existsSync(dir)) {
|
|
54
|
+
fsSync.mkdirSync(dir, { recursive: true });
|
|
55
|
+
}
|
|
56
|
+
const data = {};
|
|
57
|
+
for (const [k, v] of swcGlobalCache.entries()) {
|
|
58
|
+
data[k] = v;
|
|
59
|
+
}
|
|
60
|
+
await fs.writeFile(file, JSON.stringify(data), "utf8");
|
|
61
|
+
} catch (e) {}
|
|
62
|
+
}
|
|
63
|
+
|
|
14
64
|
export default function esmHmrPlugin({
|
|
15
65
|
entryNames = ["main", "error"],
|
|
16
66
|
changedIds,
|
|
17
67
|
hmrEngine,
|
|
68
|
+
hmrPort,
|
|
18
69
|
} = {}) {
|
|
70
|
+
const port = hmrPort || Number(process.env.HMR_PORT || (Number(process.env.PORT || 3000) + 1));
|
|
71
|
+
|
|
19
72
|
return {
|
|
20
73
|
name: "esm-hmr",
|
|
21
74
|
|
|
22
75
|
setup(build) {
|
|
76
|
+
let isInitialBuild = true;
|
|
77
|
+
let swcTotalTime = 0;
|
|
78
|
+
let swcCount = 0;
|
|
23
79
|
const outdir = build.initialOptions.outdir || ".dinou/public";
|
|
24
80
|
const entryPoints = build.initialOptions.entryPoints;
|
|
25
81
|
|
|
@@ -29,94 +85,69 @@ export default function esmHmrPlugin({
|
|
|
29
85
|
|
|
30
86
|
if (!serverStarted) {
|
|
31
87
|
const server = createServer();
|
|
88
|
+
server.on("error", (err) => {
|
|
89
|
+
if (err.code === "EADDRINUSE") {
|
|
90
|
+
console.warn(`⚠️ [esm-hmr] Port ${port} already in use. HMR may be affected if another server is running.`);
|
|
91
|
+
} else {
|
|
92
|
+
console.error("❌ [esm-hmr] Server error:", err);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
32
95
|
hmrEngine.value = new EsmHmrEngine({ server });
|
|
33
|
-
server
|
|
34
|
-
|
|
96
|
+
hmrEngine.value.server = server;
|
|
97
|
+
server.listen(port, () => {
|
|
98
|
+
// console.log(`[esm-hmr] WebSocket server listening on port ${port}`);
|
|
35
99
|
});
|
|
36
100
|
serverStarted = true;
|
|
37
101
|
}
|
|
38
102
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const entryPath = entryPoints?.[entryName];
|
|
42
|
-
if (!entryPath) return;
|
|
43
|
-
|
|
44
|
-
const absPath = path.resolve(entryPath);
|
|
45
|
-
entryAbsPaths.push(absPath);
|
|
46
|
-
entrySources.push(await fs.readFile(absPath, "utf8"));
|
|
47
|
-
entryOutputNames.push(entryName + ".js");
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
build.onLoad({ filter: /.*/ }, async (args) => {
|
|
52
|
-
const abs = path.resolve(args.path);
|
|
103
|
+
const rootEntryMap = new Map();
|
|
104
|
+
let entryPointsSet = null;
|
|
53
105
|
|
|
54
|
-
|
|
106
|
+
let onLoadCount = 0;
|
|
107
|
+
let onLoadTime = 0;
|
|
55
108
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
109
|
+
build.onStart(async () => {
|
|
110
|
+
swcTotalTime = 0;
|
|
111
|
+
swcCount = 0;
|
|
112
|
+
onLoadCount = 0;
|
|
113
|
+
onLoadTime = 0;
|
|
114
|
+
if (!entryPointsSet) {
|
|
115
|
+
entryPointsSet = new Set(
|
|
116
|
+
Object.values(entryPoints || {}).map((val) => normKey(path.resolve(val)))
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
if (rootEntryMap.size === 0) {
|
|
120
|
+
for (const entryName of entryNames) {
|
|
121
|
+
const entryPath = entryPoints?.[entryName];
|
|
122
|
+
if (!entryPath) continue;
|
|
61
123
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
// IMPORTANT: We return RAW 'source' + injection.
|
|
70
|
-
// Without passing through Babel/SWC to prevent $RefreshSig$ from breaking initialization.
|
|
71
|
-
return {
|
|
72
|
-
contents: injectCode + source,
|
|
73
|
-
loader: "jsx",
|
|
74
|
-
};
|
|
124
|
+
const absPath = path.resolve(entryPath);
|
|
125
|
+
const source = await fs.readFile(absPath, "utf8");
|
|
126
|
+
entryAbsPaths.push(absPath);
|
|
127
|
+
entrySources.push(source);
|
|
128
|
+
entryOutputNames.push(entryName + ".js");
|
|
129
|
+
rootEntryMap.set(normKey(absPath), source);
|
|
75
130
|
}
|
|
76
|
-
return null;
|
|
77
131
|
}
|
|
132
|
+
});
|
|
78
133
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const
|
|
82
|
-
(val) => norm(path.resolve(val)) === absNorm,
|
|
83
|
-
);
|
|
134
|
+
build.onLoad({ filter: /[/\\]client\.[jt]sx?$/i }, async (args) => {
|
|
135
|
+
const abs = path.resolve(args.path);
|
|
136
|
+
const absNorm = normKey(abs);
|
|
84
137
|
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
const { code } = transformSync(source, {
|
|
91
|
-
filename: abs,
|
|
92
|
-
jsc: {
|
|
93
|
-
parser: {
|
|
94
|
-
syntax: "typescript",
|
|
95
|
-
tsx: true,
|
|
96
|
-
dynamicImport: true,
|
|
97
|
-
},
|
|
98
|
-
target: "es2022",
|
|
99
|
-
transform: {
|
|
100
|
-
react: {
|
|
101
|
-
refresh: true,
|
|
102
|
-
development: true,
|
|
103
|
-
runtime: "automatic",
|
|
104
|
-
},
|
|
105
|
-
},
|
|
106
|
-
},
|
|
107
|
-
});
|
|
138
|
+
// Check if it is a ROOT Entry (client.jsx)
|
|
139
|
+
const rootSource = rootEntryMap.get(absNorm);
|
|
140
|
+
if (rootSource) {
|
|
141
|
+
let injectCode = `import { createHotContext } from "/__hmr_client__.js";\n`;
|
|
142
|
+
injectCode += `window.__hotContext = createHotContext;\n`;
|
|
108
143
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
console.error("SWC Error:", e);
|
|
115
|
-
return null;
|
|
116
|
-
}
|
|
144
|
+
return {
|
|
145
|
+
contents: injectCode + rootSource,
|
|
146
|
+
loader: "jsx",
|
|
147
|
+
watchFiles: [abs],
|
|
148
|
+
};
|
|
117
149
|
}
|
|
118
150
|
|
|
119
|
-
// CASE C: It is not an entry point (libraries, internal helpers, node_modules...)
|
|
120
151
|
return null;
|
|
121
152
|
});
|
|
122
153
|
|
|
@@ -126,7 +157,15 @@ export default function esmHmrPlugin({
|
|
|
126
157
|
path.dirname(fileURLToPath(import.meta.url)),
|
|
127
158
|
"./esm-hmr/client.mjs",
|
|
128
159
|
);
|
|
129
|
-
|
|
160
|
+
let clientCode = await fs.readFile(clientPath, "utf8");
|
|
161
|
+
const isDebug =
|
|
162
|
+
process.env.DINOU_DEBUG === "true" ||
|
|
163
|
+
process.env.DINOU_DEBUG === "1" ||
|
|
164
|
+
process.env.DEBUG === "true" ||
|
|
165
|
+
process.env.DEBUG === "1";
|
|
166
|
+
if (isDebug) {
|
|
167
|
+
clientCode = `window.__DINOU_DEBUG__ = true;\n` + clientCode;
|
|
168
|
+
}
|
|
130
169
|
const assetPath = path.join(outdir, "__hmr_client__.js");
|
|
131
170
|
result.outputFiles.push({
|
|
132
171
|
path: assetPath,
|
|
@@ -135,6 +174,7 @@ export default function esmHmrPlugin({
|
|
|
135
174
|
});
|
|
136
175
|
|
|
137
176
|
build.onEnd(async (result) => {
|
|
177
|
+
const tWrap0 = Date.now();
|
|
138
178
|
if (!result.metafile) {
|
|
139
179
|
// console.warn(
|
|
140
180
|
// "[hmr-plugin] Metafile is missing. Enable 'metafile: true'"
|
|
@@ -144,15 +184,17 @@ export default function esmHmrPlugin({
|
|
|
144
184
|
const bundleFiles = Object.keys(result.metafile.outputs);
|
|
145
185
|
const normalizeRel = (p) => p.replace(/\\/g, "/");
|
|
146
186
|
|
|
187
|
+
const outputFilesByRelPath = new Map();
|
|
188
|
+
for (const f of result.outputFiles) {
|
|
189
|
+
outputFilesByRelPath.set(normalizeRel(path.relative(process.cwd(), f.path)), f);
|
|
190
|
+
}
|
|
191
|
+
|
|
147
192
|
for (const bF of bundleFiles) {
|
|
148
193
|
if (!bF.endsWith(".js")) {
|
|
149
194
|
continue;
|
|
150
195
|
}
|
|
151
196
|
const relPath = normalizeRel(bF);
|
|
152
|
-
const outputFile =
|
|
153
|
-
(f) =>
|
|
154
|
-
normalizeRel(path.relative(process.cwd(), f.path)) === relPath,
|
|
155
|
-
);
|
|
197
|
+
const outputFile = outputFilesByRelPath.get(relPath);
|
|
156
198
|
if (!outputFile) continue;
|
|
157
199
|
const baseName = path.basename(bF, ".js");
|
|
158
200
|
|
|
@@ -160,27 +202,47 @@ export default function esmHmrPlugin({
|
|
|
160
202
|
const outfile_basename = path.basename(outfile);
|
|
161
203
|
const urlId = "/" + outfile_basename;
|
|
162
204
|
const safeId = JSON.stringify(urlId);
|
|
163
|
-
const frameworkEntries = [
|
|
205
|
+
const frameworkEntries = new Set([
|
|
164
206
|
"main.js",
|
|
165
|
-
"error.js",
|
|
166
207
|
"serverFunctionProxy.js",
|
|
167
208
|
"runtime.js",
|
|
168
209
|
"react-refresh-entry.js",
|
|
169
|
-
];
|
|
170
|
-
if (frameworkEntries.
|
|
210
|
+
]);
|
|
211
|
+
if (frameworkEntries.has(outfile_basename)) continue;
|
|
212
|
+
|
|
213
|
+
// Only wrap user component chunks that contain actual app code (not third-party libraries/vendor)
|
|
214
|
+
const outputInfo = result.metafile.outputs[bF];
|
|
215
|
+
const inputFiles = Object.keys(outputInfo?.inputs || {});
|
|
216
|
+
const hasUserCode = inputFiles.some(
|
|
217
|
+
(f) =>
|
|
218
|
+
!f.includes("node_modules") &&
|
|
219
|
+
!f.includes("/dinou/core/") &&
|
|
220
|
+
!f.includes("\\dinou\\core\\") &&
|
|
221
|
+
/\.(jsx?|tsx?)$/.test(f)
|
|
222
|
+
);
|
|
223
|
+
if (!hasUserCode) continue;
|
|
224
|
+
|
|
171
225
|
const source = new TextDecoder().decode(outputFile.contents);
|
|
226
|
+
if (source.includes("__reactRefreshRuntime")) {
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
172
229
|
|
|
173
230
|
const imports = Array.from(
|
|
174
231
|
source.matchAll(/import\s+["'](.+?)["']/g),
|
|
175
232
|
).map((m) => m[1]);
|
|
176
233
|
|
|
177
|
-
hmrEngine.value
|
|
234
|
+
if (hmrEngine.value) {
|
|
235
|
+
hmrEngine.value.setEntry(urlId, imports, true);
|
|
236
|
+
const acceptedEntry = hmrEngine.value.getEntry(urlId, true);
|
|
237
|
+
if (acceptedEntry) acceptedEntry.isHmrAccepted = true;
|
|
238
|
+
}
|
|
178
239
|
const wrappedCode = `
|
|
179
240
|
const RefreshRuntime = window.__reactRefreshRuntime;
|
|
180
241
|
let prevRefreshReg = window.$RefreshReg$;
|
|
181
242
|
let prevRefreshSig = window.$RefreshSig$;
|
|
182
243
|
window.$RefreshReg$ = (type, id) => {
|
|
183
|
-
|
|
244
|
+
const fullId = (id && id.includes('#')) ? id : (${safeId} + '#' + id);
|
|
245
|
+
RefreshRuntime.register(type, fullId);
|
|
184
246
|
};
|
|
185
247
|
window.$RefreshSig$ = RefreshRuntime?.createSignatureFunctionForTransform;
|
|
186
248
|
if (!import.meta.hot) import.meta.hot = window.__hotContext?.(${safeId});
|
|
@@ -200,49 +262,124 @@ export default function esmHmrPlugin({
|
|
|
200
262
|
window.$RefreshReg$ = prevRefreshReg;
|
|
201
263
|
window.$RefreshSig$ = prevRefreshSig;
|
|
202
264
|
`;
|
|
203
|
-
|
|
265
|
+
const encodedWrapped = new TextEncoder().encode(wrappedCode);
|
|
266
|
+
outputFile.contents = encodedWrapped;
|
|
204
267
|
}
|
|
268
|
+
globalThis.__DINOU_WRAP_TIME__ = Date.now() - tWrap0;
|
|
205
269
|
});
|
|
206
270
|
|
|
207
271
|
build.onEnd(write);
|
|
208
272
|
|
|
209
273
|
build.onEnd(async (result) => {
|
|
274
|
+
const tBroadcast0 = Date.now();
|
|
275
|
+
if (!globalThis.__DINOU_SWC_TIME__) {
|
|
276
|
+
globalThis.__DINOU_SWC_TIME__ = swcTotalTime;
|
|
277
|
+
globalThis.__DINOU_SWC_COUNT__ = swcCount;
|
|
278
|
+
}
|
|
279
|
+
if (isInitialBuild) {
|
|
280
|
+
isInitialBuild = false;
|
|
281
|
+
changedIds?.clear();
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
|
|
210
285
|
if (!result.metafile) {
|
|
211
|
-
// console.warn(
|
|
212
|
-
// "[hmr-plugin] Metafile is missing. Enable 'metafile: true'"
|
|
213
|
-
// );
|
|
214
286
|
return;
|
|
215
287
|
}
|
|
216
288
|
|
|
217
289
|
if (changedIds.size === 0) return;
|
|
290
|
+
|
|
291
|
+
// If only CSS files were modified, styles are updated via style-update in cssProcessorPlugin.
|
|
292
|
+
// Do NOT trigger full reload or JS component updates.
|
|
293
|
+
const isCssOnly = Array.from(changedIds).every((id) => {
|
|
294
|
+
const lower = id.toLowerCase();
|
|
295
|
+
return (
|
|
296
|
+
(lower.endsWith(".css") || lower.endsWith(".scss") || lower.endsWith(".less")) &&
|
|
297
|
+
!lower.endsWith(".module.css")
|
|
298
|
+
);
|
|
299
|
+
});
|
|
300
|
+
if (isCssOnly) {
|
|
301
|
+
changedIds.clear();
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
|
|
218
305
|
const bundleFiles = Object.keys(result.metafile.outputs);
|
|
219
306
|
const pendingUpdateUrls = new Set();
|
|
220
307
|
let needsFullReload = false;
|
|
308
|
+
|
|
309
|
+
const frameworkEntries = new Set([
|
|
310
|
+
"main.js",
|
|
311
|
+
"serverFunctionProxy.js",
|
|
312
|
+
"runtime.js",
|
|
313
|
+
"react-refresh-entry.js",
|
|
314
|
+
]);
|
|
315
|
+
|
|
221
316
|
for (const fileName of bundleFiles) {
|
|
317
|
+
// Only inspect actual JavaScript output chunks (skip sourcemaps, css, images, etc.)
|
|
318
|
+
if (!fileName.endsWith(".js") || fileName.endsWith(".js.map")) {
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
const baseName = path.basename(fileName);
|
|
322
|
+
if (frameworkEntries.has(baseName)) {
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
|
|
222
326
|
const chunk = result.metafile.outputs[fileName];
|
|
223
327
|
const modules = Object.keys(chunk?.inputs ?? {});
|
|
224
328
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
329
|
+
const isChangedByModule = modules.some((modulePath) => {
|
|
330
|
+
const cleanPath = stripNamespace(modulePath);
|
|
331
|
+
const norm = normKey(cleanPath);
|
|
332
|
+
const lower = norm.toLowerCase();
|
|
333
|
+
if (
|
|
334
|
+
(lower.endsWith(".css") || lower.endsWith(".scss") || lower.endsWith(".less")) &&
|
|
335
|
+
!lower.endsWith(".module.css")
|
|
336
|
+
) {
|
|
337
|
+
return false;
|
|
338
|
+
}
|
|
339
|
+
return changedIds.has(norm);
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
if (isChangedByModule) {
|
|
343
|
+
const url = "/" + path.relative(outdir, fileName).replace(/\\/g, "/");
|
|
344
|
+
const baseNameUrl = "/" + baseName;
|
|
345
|
+
const entry = hmrEngine.value.getEntry(url) || hmrEngine.value.getEntry(baseNameUrl);
|
|
346
|
+
if (entry?.isHmrAccepted) {
|
|
347
|
+
pendingUpdateUrls.add(baseNameUrl);
|
|
348
|
+
} else {
|
|
349
|
+
needsFullReload = true;
|
|
234
350
|
}
|
|
235
351
|
}
|
|
236
352
|
}
|
|
237
353
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
354
|
+
const timelineTime = () => new Date().toTimeString().slice(0, 8) + "." + String(Date.now() % 1000).padStart(3, "0");
|
|
355
|
+
const timelineRel = () => globalThis.__TIMELINE_T0__ ? `[+${Date.now() - globalThis.__TIMELINE_T0__}ms]` : ``;
|
|
356
|
+
|
|
357
|
+
const isDebug =
|
|
358
|
+
process.env.DINOU_DEBUG === "true" ||
|
|
359
|
+
process.env.DINOU_DEBUG === "1" ||
|
|
360
|
+
process.env.DEBUG === "true" ||
|
|
361
|
+
process.env.DEBUG === "1";
|
|
362
|
+
|
|
363
|
+
if (pendingUpdateUrls.size > 0 && !needsFullReload) {
|
|
241
364
|
for (const url of pendingUpdateUrls) {
|
|
365
|
+
if (isDebug) {
|
|
366
|
+
console.log(`⏱️ [TIMELINE ${timelineTime()}] ${timelineRel()} ⚡ [HMR Broadcast] Sending update to browser: ${url}`);
|
|
367
|
+
} else {
|
|
368
|
+
console.log(`⚡ [HMR] Updating client component: ${url}`);
|
|
369
|
+
}
|
|
242
370
|
hmrEngine.value.broadcastMessage({ type: "update", url });
|
|
243
371
|
}
|
|
372
|
+
} else if (needsFullReload) {
|
|
373
|
+
if (isDebug) {
|
|
374
|
+
console.log(`⏱️ [TIMELINE ${timelineTime()}] ${timelineRel()} ⚡ [HMR Broadcast] Full reload triggered (needsFullReload: ${needsFullReload})`);
|
|
375
|
+
} else {
|
|
376
|
+
console.log(`⚡ [HMR] Full reload triggered`);
|
|
377
|
+
}
|
|
378
|
+
hmrEngine.value.broadcastMessage({ type: "reload" });
|
|
244
379
|
}
|
|
380
|
+
saveSwcCache().catch(() => {});
|
|
245
381
|
changedIds.clear();
|
|
382
|
+
globalThis.__DINOU_BROADCAST_TIME__ = Date.now() - tBroadcast0;
|
|
246
383
|
});
|
|
247
384
|
},
|
|
248
385
|
};
|
|
@@ -9,12 +9,26 @@ 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
|
-
const desc = Object.getOwnPropertyDescriptor(moduleExports, key);
|
|
16
|
-
if (desc && desc.get) return false;
|
|
17
|
-
|
|
18
32
|
const exportValue = moduleExports[key];
|
|
19
33
|
if (!RefreshRuntime.isLikelyComponentType(exportValue)) {
|
|
20
34
|
areAllExportsComponents = false;
|