react-client 1.0.18 → 1.0.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/commands/dev.js
CHANGED
|
@@ -25,7 +25,7 @@ async function dev() {
|
|
|
25
25
|
const cacheDir = path_1.default.join(appRoot, '.react-client', 'deps');
|
|
26
26
|
const pkgFile = path_1.default.join(appRoot, 'package.json');
|
|
27
27
|
await fs_extra_1.default.ensureDir(cacheDir);
|
|
28
|
-
// Detect entry
|
|
28
|
+
// Detect entry file
|
|
29
29
|
const possibleEntries = ['src/main.tsx', 'src/main.jsx'];
|
|
30
30
|
const entry = possibleEntries.map((p) => path_1.default.join(appRoot, p)).find((p) => fs_extra_1.default.existsSync(p));
|
|
31
31
|
if (!entry) {
|
|
@@ -33,7 +33,7 @@ async function dev() {
|
|
|
33
33
|
process.exit(1);
|
|
34
34
|
}
|
|
35
35
|
const indexHtml = path_1.default.join(appRoot, 'index.html');
|
|
36
|
-
// Detect port
|
|
36
|
+
// Detect open port
|
|
37
37
|
const availablePort = await (0, detect_port_1.default)(defaultPort);
|
|
38
38
|
const port = availablePort;
|
|
39
39
|
if (availablePort !== defaultPort) {
|
|
@@ -60,7 +60,7 @@ async function dev() {
|
|
|
60
60
|
});
|
|
61
61
|
console.log(chalk_1.default.green('✅ react-refresh installed successfully.'));
|
|
62
62
|
}
|
|
63
|
-
//
|
|
63
|
+
// --- Plugins
|
|
64
64
|
const corePlugins = [
|
|
65
65
|
{
|
|
66
66
|
name: 'css-hmr',
|
|
@@ -81,26 +81,38 @@ async function dev() {
|
|
|
81
81
|
];
|
|
82
82
|
const userPlugins = Array.isArray(userConfig.plugins) ? userConfig.plugins : [];
|
|
83
83
|
const plugins = [...corePlugins, ...userPlugins];
|
|
84
|
-
// Connect app
|
|
85
84
|
const app = (0, connect_1.default)();
|
|
86
85
|
const transformCache = new Map();
|
|
87
|
-
// 🧠
|
|
88
|
-
async function
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
86
|
+
// 🧠 Deep dependency graph analyzer
|
|
87
|
+
async function analyzeGraph(file, seen = new Set()) {
|
|
88
|
+
if (seen.has(file))
|
|
89
|
+
return seen;
|
|
90
|
+
seen.add(file);
|
|
91
|
+
const code = await fs_extra_1.default.readFile(file, 'utf8');
|
|
92
|
+
const matches = [
|
|
93
|
+
...code.matchAll(/\bfrom\s+['"]([^'".\/][^'"]*)['"]/g),
|
|
94
|
+
...code.matchAll(/\bimport\(['"]([^'".\/][^'"]*)['"]\)/g),
|
|
93
95
|
];
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
96
|
+
for (const m of matches) {
|
|
97
|
+
const dep = m[1];
|
|
98
|
+
if (!dep || dep.startsWith('.') || dep.startsWith('/'))
|
|
99
|
+
continue;
|
|
100
|
+
try {
|
|
101
|
+
const resolved = require.resolve(dep, { paths: [appRoot] });
|
|
102
|
+
await analyzeGraph(resolved, seen);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
seen.add(dep); // bare dependency
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return seen;
|
|
97
109
|
}
|
|
98
|
-
// 📦 Smart prebundle cache
|
|
110
|
+
// 📦 Smart prebundle cache (parallelized)
|
|
99
111
|
async function prebundleDeps(deps) {
|
|
100
|
-
if (!deps.
|
|
112
|
+
if (!deps.size)
|
|
101
113
|
return;
|
|
102
114
|
const cached = (await fs_extra_1.default.readdir(cacheDir)).map((f) => f.replace('.js', ''));
|
|
103
|
-
const missing = deps.filter((d) => !cached.includes(d));
|
|
115
|
+
const missing = [...deps].filter((d) => !cached.includes(d));
|
|
104
116
|
if (!missing.length) {
|
|
105
117
|
console.log(chalk_1.default.green('✅ All dependencies already prebundled.'));
|
|
106
118
|
return;
|
|
@@ -127,16 +139,16 @@ async function dev() {
|
|
|
127
139
|
}
|
|
128
140
|
}));
|
|
129
141
|
}
|
|
130
|
-
// 🧩
|
|
142
|
+
// 🧩 Prewarm Graph
|
|
143
|
+
const deps = await analyzeGraph(entry);
|
|
144
|
+
await prebundleDeps(deps);
|
|
145
|
+
// Auto rebuild on package.json change
|
|
131
146
|
chokidar_1.default.watch(pkgFile).on('change', async () => {
|
|
132
|
-
console.log(chalk_1.default.yellow('📦
|
|
133
|
-
const
|
|
134
|
-
await prebundleDeps(
|
|
147
|
+
console.log(chalk_1.default.yellow('📦 package.json changed — rebuilding prebundle cache...'));
|
|
148
|
+
const newDeps = await analyzeGraph(entry);
|
|
149
|
+
await prebundleDeps(newDeps);
|
|
135
150
|
});
|
|
136
|
-
//
|
|
137
|
-
const initialDeps = await analyzeImports(entry);
|
|
138
|
-
await prebundleDeps(initialDeps);
|
|
139
|
-
// --- Serve prebundled / node_modules
|
|
151
|
+
// --- Serve /@modules/
|
|
140
152
|
app.use('/@modules/', async (req, res, next) => {
|
|
141
153
|
const id = req.url?.replace(/^\/(@modules\/)?/, '');
|
|
142
154
|
if (!id)
|
|
@@ -149,7 +161,7 @@ async function dev() {
|
|
|
149
161
|
}
|
|
150
162
|
let entryPath = null;
|
|
151
163
|
try {
|
|
152
|
-
entryPath = require.resolve(id, { paths: [
|
|
164
|
+
entryPath = require.resolve(id, { paths: [appRoot] });
|
|
153
165
|
}
|
|
154
166
|
catch {
|
|
155
167
|
if (id === 'react')
|
|
@@ -168,12 +180,19 @@ async function dev() {
|
|
|
168
180
|
write: false,
|
|
169
181
|
});
|
|
170
182
|
let code = result.outputFiles[0].text;
|
|
171
|
-
//
|
|
183
|
+
// 🩹 Fixed react-dom/client shim (no duplicate export)
|
|
172
184
|
if (id === 'react-dom/client') {
|
|
173
185
|
code += `
|
|
186
|
+
// React Client auto-shim for React 18+
|
|
174
187
|
import * as ReactDOMClient from '/@modules/react-dom';
|
|
175
|
-
|
|
176
|
-
|
|
188
|
+
if (!('createRoot' in ReactDOMClient) && ReactDOMClient.default) {
|
|
189
|
+
Object.assign(ReactDOMClient, ReactDOMClient.default);
|
|
190
|
+
}
|
|
191
|
+
export const createRoot =
|
|
192
|
+
ReactDOMClient.createRoot ||
|
|
193
|
+
ReactDOMClient.default?.createRoot ||
|
|
194
|
+
(() => { throw new Error('ReactDOM.createRoot not found'); });
|
|
195
|
+
export default ReactDOMClient;
|
|
177
196
|
`;
|
|
178
197
|
}
|
|
179
198
|
await fs_extra_1.default.writeFile(cacheFile, code, 'utf8');
|
|
@@ -187,7 +206,7 @@ async function dev() {
|
|
|
187
206
|
res.end(`// Failed to resolve module ${id}: ${e.message}`);
|
|
188
207
|
}
|
|
189
208
|
});
|
|
190
|
-
// --- Serve src files
|
|
209
|
+
// --- Serve /src files dynamically
|
|
191
210
|
app.use(async (req, res, next) => {
|
|
192
211
|
if (!req.url || (!req.url.startsWith('/src/') && !req.url.endsWith('.css')))
|
|
193
212
|
return next();
|
|
@@ -204,6 +223,7 @@ async function dev() {
|
|
|
204
223
|
return next();
|
|
205
224
|
try {
|
|
206
225
|
let code = await fs_extra_1.default.readFile(filePath, 'utf8');
|
|
226
|
+
// Rewrite bare imports → /@modules/*
|
|
207
227
|
code = code
|
|
208
228
|
.replace(/\bfrom\s+['"]([^'".\/][^'"]*)['"]/g, (_match, dep) => `from "/@modules/${dep}"`)
|
|
209
229
|
.replace(/\bimport\(['"]([^'".\/][^'"]*)['"]\)/g, (_match, dep) => `import("/@modules/${dep}")`);
|
|
@@ -234,7 +254,7 @@ async function dev() {
|
|
|
234
254
|
res.end(`// Error: ${e.message}`);
|
|
235
255
|
}
|
|
236
256
|
});
|
|
237
|
-
// --- index.html + overlay
|
|
257
|
+
// --- Serve index.html + overlay + HMR
|
|
238
258
|
app.use(async (req, res, next) => {
|
|
239
259
|
if (req.url !== '/' && req.url !== '/index.html')
|
|
240
260
|
return next();
|
|
@@ -16,10 +16,8 @@ class BroadcastManager {
|
|
|
16
16
|
this.wss = new ws_1.WebSocketServer({ server });
|
|
17
17
|
this.wss.on('connection', (ws) => {
|
|
18
18
|
this.clients.add(ws);
|
|
19
|
-
console.log(chalk_1.default.gray('🔌 Client connected'));
|
|
20
19
|
ws.on('close', () => {
|
|
21
20
|
this.clients.delete(ws);
|
|
22
|
-
console.log(chalk_1.default.gray('❎ Client disconnected'));
|
|
23
21
|
});
|
|
24
22
|
ws.on('error', (err) => {
|
|
25
23
|
console.error(chalk_1.default.red('⚠️ WebSocket error:'), err.message);
|