odoro 1.0.8 → 2.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/README.md +94 -0
- package/client.d.ts +90 -16
- package/dist/build-LZAUDJST.js +5 -0
- package/dist/{chunk-34RGOZFA.js → chunk-4D56Z7G3.js} +49 -50
- package/dist/{chunk-JMEHF3KN.js → chunk-7ZB5MAM6.js} +4 -4
- package/dist/{chunk-LHZGX5ML.js → chunk-OMHEQVIW.js} +295 -160
- package/dist/{chunk-3SZIN6VG.js → chunk-P3DJITWE.js} +10 -10
- package/dist/{chunk-ZVL7EXJO.js → chunk-PRWVZ2SM.js} +22 -14
- package/dist/chunk-Q2KCMTB5.js +741 -0
- package/dist/chunk-QOVBLN7A.js +241 -0
- package/dist/chunk-WWTDEV4Y.js +604 -0
- package/dist/cli.d.ts +12 -13
- package/dist/cli.js +84 -63
- package/dist/{commands-4JRBD55Z.js → commands-EUGVLQWL.js} +44 -45
- package/dist/{commands-AHMXBWQQ.js → commands-GYA7NTCX.js} +124 -124
- package/dist/{create-CDKS7KZ3.js → create-QX5LEWMS.js} +158 -154
- package/dist/index.d.ts +603 -151
- package/dist/index.js +6 -6
- package/dist/{package-NBP5NDX6.js → package-T4Z7OBOH.js} +5 -5
- package/dist/preview-P4WY5GEY.js +4 -0
- package/dist/registry/index.d.ts +75 -76
- package/dist/registry/index.js +1 -1
- package/dist/{server-4UGN3SFS.js → server-2WP562EV.js} +3 -3
- package/package.json +5 -5
- package/templates/react-ts/README.md +71 -35
- package/templates/react-ts/_env.example +9 -0
- package/templates/react-ts/_variants/with-engine/src/background.tsx +118 -0
- package/templates/react-ts/_variants/without-libs/src/App.tsx +380 -0
- package/templates/react-ts/_variants/without-libs/src/background.tsx +24 -0
- package/templates/react-ts/_variants/without-libs/src/entry-server.tsx +39 -0
- package/templates/react-ts/_variants/without-libs/src/main.tsx +26 -0
- package/templates/{react-ts-server/_variantes/sans-libs/client → react-ts/_variants/without-libs}/src/styles.css +137 -137
- package/templates/react-ts/{_variantes/sans-routeur → _variants/without-router}/src/App.tsx +141 -141
- package/templates/react-ts/_variants/without-router/src/entry-server.tsx +39 -0
- package/templates/react-ts/index.html +4 -4
- package/templates/react-ts/odoro.config.ts +5 -0
- package/templates/react-ts/src/App.tsx +219 -209
- package/templates/react-ts/src/background.tsx +66 -0
- package/templates/react-ts/src/entry-server.tsx +85 -0
- package/templates/react-ts/src/main.tsx +13 -4
- package/templates/react-ts/src/router.tsx +65 -45
- package/templates/react-ts/src/styles.css +5 -5
- package/templates/react-ts-server/Dockerfile +9 -9
- package/templates/react-ts-server/README.md +97 -45
- package/templates/react-ts-server/_env.example +31 -33
- package/templates/react-ts-server/_variants/with-engine/client/src/background.tsx +118 -0
- package/templates/react-ts-server/_variants/without-libs/client/src/App.tsx +380 -0
- package/templates/react-ts-server/_variants/without-libs/client/src/background.tsx +24 -0
- package/templates/react-ts-server/_variants/without-libs/client/src/entry-server.tsx +39 -0
- package/templates/react-ts-server/_variants/without-libs/client/src/main.tsx +26 -0
- package/templates/{react-ts/_variantes/sans-libs → react-ts-server/_variants/without-libs/client}/src/styles.css +137 -137
- package/templates/react-ts-server/{_variantes/sans-routeur → _variants/without-router}/client/src/App.tsx +141 -141
- package/templates/react-ts-server/_variants/without-router/client/src/entry-server.tsx +39 -0
- package/templates/react-ts-server/client/index.html +4 -4
- package/templates/react-ts-server/client/src/App.tsx +228 -210
- package/templates/react-ts-server/client/src/account.tsx +267 -0
- package/templates/react-ts-server/client/src/auth.tsx +139 -0
- package/templates/react-ts-server/client/src/background.tsx +66 -0
- package/templates/react-ts-server/client/src/entry-server.tsx +92 -0
- package/templates/react-ts-server/client/src/main.tsx +17 -5
- package/templates/react-ts-server/client/src/router.tsx +77 -45
- package/templates/react-ts-server/client/src/styles.css +5 -5
- package/templates/react-ts-server/odoro.config.ts +7 -4
- package/templates/react-ts-server/package.json +2 -0
- package/templates/react-ts-server/scripts/dev.mjs +14 -14
- package/templates/react-ts-server/server/src/main.ts +119 -45
- package/templates/react-ts-server/server/src/modules/auth/index.ts +238 -0
- package/templates/react-ts-server/server/src/modules/auth/password.ts +122 -0
- package/templates/react-ts-server/server/src/modules/auth/store.ts +193 -0
- package/templates/react-ts-server/server/src/modules/health/index.ts +45 -46
- package/dist/build-JFQHODAT.js +0 -5
- package/dist/chunk-22KJTV2R.js +0 -380
- package/dist/chunk-DL3NPC4H.js +0 -113
- package/dist/chunk-TQUJ3MFS.js +0 -268
- package/dist/preview-7DKEAQOQ.js +0 -4
- package/templates/react-ts/_variantes/avec-moteur/src/fond.tsx +0 -118
- package/templates/react-ts/_variantes/sans-libs/src/App.tsx +0 -382
- package/templates/react-ts/_variantes/sans-libs/src/fond.tsx +0 -23
- package/templates/react-ts/_variantes/sans-libs/src/main.tsx +0 -17
- package/templates/react-ts/src/fond.tsx +0 -42
- package/templates/react-ts-server/_variantes/avec-moteur/client/src/fond.tsx +0 -118
- package/templates/react-ts-server/_variantes/sans-libs/client/src/App.tsx +0 -382
- package/templates/react-ts-server/_variantes/sans-libs/client/src/fond.tsx +0 -23
- package/templates/react-ts-server/_variantes/sans-libs/client/src/main.tsx +0 -17
- package/templates/react-ts-server/client/src/fond.tsx +0 -42
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { depFileName, INTERNAL_PREFIX,
|
|
3
|
-
import { info,
|
|
2
|
+
import { sourcePlugin, depFileName, SOURCE_EXTENSIONS, listen, openBrowser, INTERNAL_PREFIX, applyAlias, readSuffix, hasExtension, STYLE_EXTENSIONS, ASSET_EXTENSIONS, isBareSpecifier, DEPS_PREFIX, urlToFile, wantsStylesheet, wrapAsset, isAssetRequest, wrapJson, transformHtmlWith, textModule, urlModule, workerModule, fileToUrl, wrapStyle, transformModule } from './chunk-WWTDEV4Y.js';
|
|
3
|
+
import { info, warn, success, duration, colors, error } from './chunk-7ZB5MAM6.js';
|
|
4
4
|
import { existsSync, readFileSync, statSync, watch, createReadStream } from 'fs';
|
|
5
5
|
import { readFile, rm, mkdir, writeFile } from 'fs/promises';
|
|
6
6
|
import { createServer, request } from 'http';
|
|
7
|
+
import { createServer as createServer$1 } from 'https';
|
|
7
8
|
import { join, dirname, resolve, extname } from 'path';
|
|
8
9
|
import { createRequire } from 'module';
|
|
9
10
|
import { pathToFileURL, fileURLToPath } from 'url';
|
|
@@ -12,37 +13,90 @@ import { build } from 'esbuild';
|
|
|
12
13
|
import { transformAsync } from '@babel/core';
|
|
13
14
|
import reactRefreshPlugin from 'react-refresh/babel';
|
|
14
15
|
|
|
15
|
-
var
|
|
16
|
-
var
|
|
17
|
-
function
|
|
18
|
-
if (
|
|
19
|
-
if (typeof
|
|
20
|
-
return
|
|
16
|
+
var PACKAGE = "@odoro-cli/libs";
|
|
17
|
+
var SUBPATH = "./generator";
|
|
18
|
+
function fileFor(entry) {
|
|
19
|
+
if (entry === void 0) return void 0;
|
|
20
|
+
if (typeof entry === "string") return entry;
|
|
21
|
+
return entry.import ?? entry.default;
|
|
21
22
|
}
|
|
22
|
-
async function
|
|
23
|
+
async function cssProviderFor(root) {
|
|
23
24
|
try {
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
if (
|
|
30
|
-
const module_ = await import(pathToFileURL(resolve(
|
|
31
|
-
if (typeof module_.
|
|
25
|
+
const require_ = createRequire(join(root, "package.json"));
|
|
26
|
+
const manifest = require_.resolve(`${PACKAGE}/package.json`);
|
|
27
|
+
const directory = dirname(manifest);
|
|
28
|
+
const content = JSON.parse(await readFile(manifest, "utf8"));
|
|
29
|
+
const relativePath = fileFor(content.exports?.[SUBPATH]);
|
|
30
|
+
if (relativePath === void 0) return void 0;
|
|
31
|
+
const module_ = await import(pathToFileURL(resolve(directory, relativePath)).href);
|
|
32
|
+
if (typeof module_.renderUtilitiesFor !== "function") return void 0;
|
|
32
33
|
const generate = module_.generate;
|
|
33
34
|
return {
|
|
34
|
-
|
|
35
|
-
// `generate`
|
|
36
|
-
//
|
|
37
|
-
//
|
|
35
|
+
renderUtilitiesFor: module_.renderUtilitiesFor,
|
|
36
|
+
// `generate` enumerates the classes of the current tier. Absent from an
|
|
37
|
+
// older package: the field then stays undefined, and development falls
|
|
38
|
+
// back on the stylesheet as it ships.
|
|
38
39
|
...typeof generate === "function" ? {
|
|
39
|
-
|
|
40
|
+
knownClasses: () => new Set(generate("core").classNames)
|
|
40
41
|
} : {}
|
|
41
42
|
};
|
|
42
43
|
} catch {
|
|
43
44
|
return void 0;
|
|
44
45
|
}
|
|
45
46
|
}
|
|
47
|
+
var IMPORT = /@import\s+(?:url\(\s*)?(['"])([^'"]+)\1\s*\)?\s*([^;]*);/g;
|
|
48
|
+
var URL_VALUE = /url\(\s*(['"]?)([^'")]+)\1\s*\)/g;
|
|
49
|
+
function isExternal(address) {
|
|
50
|
+
return address.startsWith("data:") || address.startsWith("http:") || address.startsWith("https:") || address.startsWith("//") || address.startsWith("#");
|
|
51
|
+
}
|
|
52
|
+
function resolveReference(reference, from) {
|
|
53
|
+
if (reference.startsWith("/")) return void 0;
|
|
54
|
+
if (isBareSpecifier(reference)) {
|
|
55
|
+
try {
|
|
56
|
+
return createRequire(from).resolve(reference);
|
|
57
|
+
} catch {
|
|
58
|
+
return void 0;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const path = resolve(dirname(from), reference);
|
|
62
|
+
return existsSync(path) ? path : void 0;
|
|
63
|
+
}
|
|
64
|
+
async function assembleStylesheet(file, root) {
|
|
65
|
+
const files = [];
|
|
66
|
+
const seen = /* @__PURE__ */ new Set();
|
|
67
|
+
const read = async (path) => {
|
|
68
|
+
if (seen.has(path)) return "";
|
|
69
|
+
seen.add(path);
|
|
70
|
+
files.push(path);
|
|
71
|
+
const source = await readFile(path, "utf8");
|
|
72
|
+
const pieces = [];
|
|
73
|
+
let cursor = 0;
|
|
74
|
+
for (const found of source.matchAll(IMPORT)) {
|
|
75
|
+
const reference = found[2];
|
|
76
|
+
const conditions = (found[3] ?? "").trim();
|
|
77
|
+
if (reference === void 0) continue;
|
|
78
|
+
pieces.push(source.slice(cursor, found.index));
|
|
79
|
+
cursor = found.index + found[0].length;
|
|
80
|
+
const target = isExternal(reference) ? void 0 : resolveReference(reference, path);
|
|
81
|
+
if (target === void 0) {
|
|
82
|
+
pieces.push(found[0]);
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const content = await read(target);
|
|
86
|
+
pieces.push(conditions === "" ? content : `@media ${conditions} {
|
|
87
|
+
${content}
|
|
88
|
+
}`);
|
|
89
|
+
}
|
|
90
|
+
pieces.push(source.slice(cursor));
|
|
91
|
+
return pieces.join("").replace(URL_VALUE, (whole, quote, address) => {
|
|
92
|
+
if (isExternal(address) || address.startsWith("/")) return whole;
|
|
93
|
+
const target = resolveReference(address, path);
|
|
94
|
+
if (target === void 0) return whole;
|
|
95
|
+
return `url(${quote}${fileToUrl(target, root)}${quote})`;
|
|
96
|
+
});
|
|
97
|
+
};
|
|
98
|
+
return { css: await read(file), files };
|
|
99
|
+
}
|
|
46
100
|
|
|
47
101
|
// src/dev/client.ts
|
|
48
102
|
var HMR_STREAM_PATH = "/@odoro/hmr";
|
|
@@ -50,23 +104,23 @@ var HMR_CLIENT_PATH = "/@odoro/client";
|
|
|
50
104
|
var HMR_CLIENT_SOURCE = String.raw`
|
|
51
105
|
const OVERLAY_ID = 'odoro-error-overlay'
|
|
52
106
|
|
|
53
|
-
/**
|
|
107
|
+
/** Hot contexts, by module URL. */
|
|
54
108
|
const contexts = new Map()
|
|
55
109
|
|
|
56
110
|
/**
|
|
57
|
-
*
|
|
111
|
+
* Creates the context exposed to a module through import.meta.hot.
|
|
58
112
|
* @param {string} url
|
|
59
113
|
*/
|
|
60
114
|
export function createHotContext(url) {
|
|
61
115
|
const existing = contexts.get(url)
|
|
62
116
|
if (existing) {
|
|
63
|
-
//
|
|
64
|
-
//
|
|
117
|
+
// Reload of the same module: the callbacks of the previous version are run
|
|
118
|
+
// then forgotten.
|
|
65
119
|
for (const callback of existing.disposers) {
|
|
66
120
|
try {
|
|
67
121
|
callback(existing.data)
|
|
68
122
|
} catch (cause) {
|
|
69
|
-
console.error('[odoro]
|
|
123
|
+
console.error('[odoro] cleanup failed for', url, cause)
|
|
70
124
|
}
|
|
71
125
|
}
|
|
72
126
|
existing.disposers = []
|
|
@@ -96,7 +150,7 @@ export function createHotContext(url) {
|
|
|
96
150
|
}
|
|
97
151
|
|
|
98
152
|
/**
|
|
99
|
-
*
|
|
153
|
+
* Reloads a module and notifies those that accept it.
|
|
100
154
|
* @param {string} url
|
|
101
155
|
* @param {number} timestamp
|
|
102
156
|
*/
|
|
@@ -111,20 +165,20 @@ async function applyUpdate(url, timestamp) {
|
|
|
111
165
|
try {
|
|
112
166
|
const module = await import(url + (url.includes('?') ? '&' : '?') + 't=' + timestamp)
|
|
113
167
|
for (const accept of acceptors) accept(module)
|
|
114
|
-
console.log('[odoro]
|
|
168
|
+
console.log('[odoro] updated', url)
|
|
115
169
|
} catch (cause) {
|
|
116
|
-
console.error('[odoro]
|
|
170
|
+
console.error('[odoro] update failed for', url, cause)
|
|
117
171
|
location.reload()
|
|
118
172
|
}
|
|
119
173
|
}
|
|
120
174
|
|
|
121
|
-
/**
|
|
175
|
+
/** Removes the error overlay when it is displayed. */
|
|
122
176
|
function clearOverlay() {
|
|
123
177
|
document.getElementById(OVERLAY_ID)?.remove()
|
|
124
178
|
}
|
|
125
179
|
|
|
126
180
|
/**
|
|
127
|
-
*
|
|
181
|
+
* Displays a build error on top of the page.
|
|
128
182
|
* @param {string} message
|
|
129
183
|
* @param {string | undefined} file
|
|
130
184
|
*/
|
|
@@ -146,14 +200,14 @@ function showOverlay(message, file) {
|
|
|
146
200
|
].join(';')
|
|
147
201
|
|
|
148
202
|
const title = document.createElement('div')
|
|
149
|
-
title.textContent = file ? '
|
|
203
|
+
title.textContent = file ? 'Build error — ' + file : 'Build error'
|
|
150
204
|
title.style.cssText = 'font-weight:700;margin-bottom:1rem;color:#ff9d9d'
|
|
151
205
|
|
|
152
206
|
const body = document.createElement('div')
|
|
153
207
|
body.textContent = message
|
|
154
208
|
|
|
155
209
|
const hint = document.createElement('div')
|
|
156
|
-
hint.textContent = '
|
|
210
|
+
hint.textContent = 'Fix the file: this overlay will disappear on its own.'
|
|
157
211
|
hint.style.cssText = 'margin-top:1.5rem;opacity:0.6'
|
|
158
212
|
|
|
159
213
|
overlay.append(title, body, hint)
|
|
@@ -167,7 +221,7 @@ source.addEventListener('message', (event) => {
|
|
|
167
221
|
|
|
168
222
|
switch (payload.type) {
|
|
169
223
|
case 'connected':
|
|
170
|
-
console.log('[odoro]
|
|
224
|
+
console.log('[odoro] hot reloading connected')
|
|
171
225
|
break
|
|
172
226
|
case 'update':
|
|
173
227
|
clearOverlay()
|
|
@@ -187,9 +241,9 @@ source.addEventListener('message', (event) => {
|
|
|
187
241
|
})
|
|
188
242
|
|
|
189
243
|
source.addEventListener('error', () => {
|
|
190
|
-
// EventSource
|
|
244
|
+
// EventSource reconnects on its own; we only report a prolonged loss.
|
|
191
245
|
if (source.readyState === EventSource.CLOSED) {
|
|
192
|
-
console.warn('[odoro]
|
|
246
|
+
console.warn('[odoro] hot reloading connection lost')
|
|
193
247
|
}
|
|
194
248
|
})
|
|
195
249
|
`.replace("__HMR_STREAM_PATH__", HMR_STREAM_PATH);
|
|
@@ -307,6 +361,9 @@ function collectBareImports(config, found) {
|
|
|
307
361
|
builder.onResolve({ filter: /.*/ }, (args) => {
|
|
308
362
|
if (args.kind === "entry-point") return null;
|
|
309
363
|
const aliased = applyAlias(args.path, config);
|
|
364
|
+
if (readSuffix(aliased) !== void 0) {
|
|
365
|
+
return { path: aliased, external: true };
|
|
366
|
+
}
|
|
310
367
|
if (hasExtension(aliased, STYLE_EXTENSIONS) || hasExtension(aliased, ASSET_EXTENSIONS)) {
|
|
311
368
|
return { path: aliased, external: true };
|
|
312
369
|
}
|
|
@@ -330,29 +387,36 @@ async function scanDependencies(config, entries) {
|
|
|
330
387
|
logLevel: "silent",
|
|
331
388
|
absWorkingDir: config.root,
|
|
332
389
|
jsx: "automatic",
|
|
333
|
-
//
|
|
334
|
-
//
|
|
335
|
-
// `react/jsx-dev-runtime`,
|
|
390
|
+
// The server compiles with the development JSX: without this setting, the
|
|
391
|
+
// scan would look for `react/jsx-runtime` where the browser will ask for
|
|
392
|
+
// `react/jsx-dev-runtime`, and the dependency would be missing.
|
|
336
393
|
jsxDev: true,
|
|
337
|
-
|
|
394
|
+
// The same pass as the build one: a module reached by a pattern is a module
|
|
395
|
+
// of the project, and its dependencies must be prebundled like the others.
|
|
396
|
+
// Without that, a page loaded only through `import.meta.glob` would ask at
|
|
397
|
+
// runtime for a dependency the cache does not hold.
|
|
398
|
+
plugins: [
|
|
399
|
+
collectBareImports(config, found),
|
|
400
|
+
sourcePlugin({ root: config.root, plugins: config.plugins, dev: true })
|
|
401
|
+
]
|
|
338
402
|
});
|
|
339
403
|
return [...found].sort();
|
|
340
404
|
}
|
|
341
405
|
async function optimizeDeps(config, specifiers, force = false) {
|
|
342
406
|
try {
|
|
343
|
-
return await
|
|
407
|
+
return await buildDeps(config, specifiers, force);
|
|
344
408
|
} catch (cause) {
|
|
345
|
-
if (!
|
|
346
|
-
await new Promise((
|
|
347
|
-
return
|
|
409
|
+
if (!isRaceError(cause)) throw cause;
|
|
410
|
+
await new Promise((next) => setTimeout(next, RACE_DELAY));
|
|
411
|
+
return buildDeps(config, specifiers, force);
|
|
348
412
|
}
|
|
349
413
|
}
|
|
350
|
-
var
|
|
351
|
-
function
|
|
414
|
+
var RACE_DELAY = 400;
|
|
415
|
+
function isRaceError(cause) {
|
|
352
416
|
const code = cause?.code;
|
|
353
417
|
return code === "ENOENT" || code === "EPERM" || code === "EBUSY";
|
|
354
418
|
}
|
|
355
|
-
async function
|
|
419
|
+
async function buildDeps(config, specifiers, force) {
|
|
356
420
|
const directory = join(config.root, "node_modules", ".odoro", "deps");
|
|
357
421
|
const sorted = [...specifiers].sort();
|
|
358
422
|
const hash = createHash("sha256").update(JSON.stringify(sorted)).update(await lockfileFingerprint(config.root)).update(entriesFingerprint(config.root, sorted)).update(engineVersion()).digest("hex").slice(0, 16);
|
|
@@ -381,9 +445,9 @@ async function compilerDeps(config, specifiers, force) {
|
|
|
381
445
|
entryPoints.push({ in: proxy, out });
|
|
382
446
|
}
|
|
383
447
|
await build({
|
|
384
|
-
//
|
|
385
|
-
//
|
|
386
|
-
//
|
|
448
|
+
// The output names are imposed: a specifier with a subpath would
|
|
449
|
+
// otherwise produce a directory tree, and two different packages could
|
|
450
|
+
// fight over the same file name.
|
|
387
451
|
entryPoints,
|
|
388
452
|
bundle: true,
|
|
389
453
|
format: "esm",
|
|
@@ -412,7 +476,7 @@ function engineVersion() {
|
|
|
412
476
|
try {
|
|
413
477
|
const parsed = JSON.parse(readFileSync(manifest, "utf8"));
|
|
414
478
|
if (parsed.name === "odoro") {
|
|
415
|
-
cachedVersion = parsed.version ?? "
|
|
479
|
+
cachedVersion = parsed.version ?? "unknown";
|
|
416
480
|
return cachedVersion;
|
|
417
481
|
}
|
|
418
482
|
} catch {
|
|
@@ -423,7 +487,7 @@ function engineVersion() {
|
|
|
423
487
|
if (parent === directory) break;
|
|
424
488
|
directory = parent;
|
|
425
489
|
}
|
|
426
|
-
cachedVersion = "
|
|
490
|
+
cachedVersion = "unknown";
|
|
427
491
|
return cachedVersion;
|
|
428
492
|
}
|
|
429
493
|
function entriesFingerprint(root, specifiers) {
|
|
@@ -449,13 +513,13 @@ function packageFingerprint(name, resolver) {
|
|
|
449
513
|
try {
|
|
450
514
|
manifestPath = resolver.resolve(`${name}/package.json`);
|
|
451
515
|
} catch {
|
|
452
|
-
return "
|
|
516
|
+
return "not-found";
|
|
453
517
|
}
|
|
454
518
|
let manifest;
|
|
455
519
|
try {
|
|
456
520
|
manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
457
521
|
} catch {
|
|
458
|
-
return "
|
|
522
|
+
return "unreadable";
|
|
459
523
|
}
|
|
460
524
|
const directory = dirname(manifestPath);
|
|
461
525
|
const targets = /* @__PURE__ */ new Set();
|
|
@@ -491,7 +555,7 @@ async function lockfileFingerprint(root) {
|
|
|
491
555
|
if (!existsSync(file)) continue;
|
|
492
556
|
return createHash("sha256").update(await readFile(file)).digest("hex");
|
|
493
557
|
}
|
|
494
|
-
return "
|
|
558
|
+
return "no-lockfile";
|
|
495
559
|
}
|
|
496
560
|
|
|
497
561
|
// src/dev/graph.ts
|
|
@@ -500,7 +564,7 @@ function detectSelfAccepting(source) {
|
|
|
500
564
|
}
|
|
501
565
|
var ModuleGraph = class {
|
|
502
566
|
nodes = /* @__PURE__ */ new Map();
|
|
503
|
-
/**
|
|
567
|
+
/** Gets a module, or creates it when it is unknown. */
|
|
504
568
|
ensure(file, url) {
|
|
505
569
|
const existing = this.nodes.get(file);
|
|
506
570
|
if (existing !== void 0) return existing;
|
|
@@ -516,17 +580,17 @@ var ModuleGraph = class {
|
|
|
516
580
|
this.nodes.set(file, node);
|
|
517
581
|
return node;
|
|
518
582
|
}
|
|
519
|
-
/**
|
|
583
|
+
/** Gets a module already known. */
|
|
520
584
|
get(file) {
|
|
521
585
|
return this.nodes.get(file);
|
|
522
586
|
}
|
|
523
|
-
/**
|
|
587
|
+
/** Number of known modules. */
|
|
524
588
|
get size() {
|
|
525
589
|
return this.nodes.size;
|
|
526
590
|
}
|
|
527
591
|
/**
|
|
528
|
-
*
|
|
529
|
-
*
|
|
592
|
+
* Replaces the dependency list of a module, keeping the reverse relations up
|
|
593
|
+
* to date.
|
|
530
594
|
*/
|
|
531
595
|
setDependencies(file, dependencies) {
|
|
532
596
|
const node = this.nodes.get(file);
|
|
@@ -544,14 +608,14 @@ var ModuleGraph = class {
|
|
|
544
608
|
}
|
|
545
609
|
}
|
|
546
610
|
/**
|
|
547
|
-
*
|
|
548
|
-
*
|
|
611
|
+
* Invalidates a module and climbs the chain of its importers until it finds,
|
|
612
|
+
* on every branch, a module that accepts updates.
|
|
549
613
|
*
|
|
550
|
-
* @returns
|
|
551
|
-
*
|
|
614
|
+
* @returns The modules to reload on the client side. An empty array means
|
|
615
|
+
* that no boundary accepts the update: the page must be reloaded.
|
|
552
616
|
*
|
|
553
617
|
* @example
|
|
554
|
-
* const boundaries = graph.invalidate('/
|
|
618
|
+
* const boundaries = graph.invalidate('/project/src/App.css')
|
|
555
619
|
*/
|
|
556
620
|
invalidate(file) {
|
|
557
621
|
const boundaries = [];
|
|
@@ -577,7 +641,7 @@ var ModuleGraph = class {
|
|
|
577
641
|
};
|
|
578
642
|
return walk(file) ? boundaries : [];
|
|
579
643
|
}
|
|
580
|
-
/**
|
|
644
|
+
/** Forgets every module. */
|
|
581
645
|
clear() {
|
|
582
646
|
this.nodes.clear();
|
|
583
647
|
}
|
|
@@ -594,22 +658,22 @@ async function applyReactRefresh(code, file) {
|
|
|
594
658
|
filename: file,
|
|
595
659
|
babelrc: false,
|
|
596
660
|
configFile: false,
|
|
597
|
-
//
|
|
598
|
-
//
|
|
599
|
-
// code
|
|
661
|
+
// The source map produced by the previous build is picked up and merged:
|
|
662
|
+
// without that, the line numbers in the debugger would designate the
|
|
663
|
+
// instrumented code rather than the source.
|
|
600
664
|
//
|
|
601
|
-
// `true`
|
|
602
|
-
// —
|
|
603
|
-
//
|
|
604
|
-
//
|
|
665
|
+
// `true` asks Babel to read the inline map of the received code. It accepts
|
|
666
|
+
// it — checked: the source picked up is indeed the original file — but the
|
|
667
|
+
// 7.x types only describe the object form. The annotation is incomplete,
|
|
668
|
+
// not the value.
|
|
605
669
|
inputSourceMap: true,
|
|
606
670
|
sourceMaps: "inline",
|
|
607
|
-
// `skipEnvCheck`
|
|
608
|
-
//
|
|
609
|
-
// point
|
|
610
|
-
//
|
|
611
|
-
//
|
|
612
|
-
//
|
|
671
|
+
// `skipEnvCheck` lifts a guard meant for global configurations, which
|
|
672
|
+
// refuses the transformation outside NODE_ENV=development. Here it is the
|
|
673
|
+
// point of application that enforces the rule: this function is only called
|
|
674
|
+
// by the development server, never by the production build. Without it, a
|
|
675
|
+
// `NODE_ENV=production odoro dev` — or a test suite — would fail instead of
|
|
676
|
+
// simply instrumenting.
|
|
613
677
|
plugins: [[reactRefreshPlugin, { skipEnvCheck: true }]],
|
|
614
678
|
parserOpts: { sourceType: "module" }
|
|
615
679
|
});
|
|
@@ -635,8 +699,8 @@ void import(import.meta.url).then((__odoroCurrent) => {
|
|
|
635
699
|
__odoroRefresh.registerExports(${JSON.stringify(id)}, __odoroCurrent)
|
|
636
700
|
import.meta.hot?.accept((__odoroNext) => {
|
|
637
701
|
if (!__odoroNext) return
|
|
638
|
-
const
|
|
639
|
-
if (
|
|
702
|
+
const refusal = __odoroRefresh.checkBoundary(__odoroCurrent, __odoroNext)
|
|
703
|
+
if (refusal !== null) import.meta.hot.invalidate(refusal)
|
|
640
704
|
else {
|
|
641
705
|
__odoroRefresh.registerExports(${JSON.stringify(id)}, __odoroNext)
|
|
642
706
|
__odoroRefresh.enqueueUpdate()
|
|
@@ -647,12 +711,12 @@ void import(import.meta.url).then((__odoroCurrent) => {
|
|
|
647
711
|
}
|
|
648
712
|
var REFRESH_RUNTIME_SOURCE = `import runtime from 'react-refresh/runtime'
|
|
649
713
|
|
|
650
|
-
//
|
|
651
|
-
//
|
|
714
|
+
// The hook must be installed **before** React is loaded: it is through it that
|
|
715
|
+
// React reports the components it renders.
|
|
652
716
|
runtime.injectIntoGlobalHook(window)
|
|
653
717
|
|
|
654
|
-
//
|
|
655
|
-
//
|
|
718
|
+
// Neutral values: an uninstrumented module must be able to evaluate without
|
|
719
|
+
// those functions really existing.
|
|
656
720
|
window.$RefreshReg$ = () => {}
|
|
657
721
|
window.$RefreshSig$ = () => (type) => type
|
|
658
722
|
|
|
@@ -660,11 +724,10 @@ export const register = runtime.register
|
|
|
660
724
|
export const createSignature = runtime.createSignatureFunctionForTransform
|
|
661
725
|
|
|
662
726
|
/**
|
|
663
|
-
*
|
|
727
|
+
* Registers the exports of a module that look like components.
|
|
664
728
|
*
|
|
665
|
-
*
|
|
666
|
-
* module
|
|
667
|
-
* pas.
|
|
729
|
+
* Registering by export name completes the one placed in the body of the
|
|
730
|
+
* module: a component re-exported from another file would not appear there.
|
|
668
731
|
*/
|
|
669
732
|
export function registerExports(id, exports) {
|
|
670
733
|
for (const key of Object.keys(exports)) {
|
|
@@ -676,29 +739,29 @@ export function registerExports(id, exports) {
|
|
|
676
739
|
}
|
|
677
740
|
|
|
678
741
|
/**
|
|
679
|
-
*
|
|
742
|
+
* Checks that a module can be replaced hot.
|
|
680
743
|
*
|
|
681
|
-
* @returns null
|
|
744
|
+
* @returns null when the replacement is safe, otherwise the reason for refusal.
|
|
682
745
|
*/
|
|
683
746
|
export function checkBoundary(previous, next) {
|
|
684
747
|
const before = Object.keys(previous)
|
|
685
748
|
const after = Object.keys(next)
|
|
686
749
|
|
|
687
|
-
if (after.length === 0) return '
|
|
750
|
+
if (after.length === 0) return 'the module no longer exports anything'
|
|
688
751
|
|
|
689
752
|
for (const key of after) {
|
|
690
|
-
if (!before.includes(key)) return '
|
|
753
|
+
if (!before.includes(key)) return 'new export: ' + key
|
|
691
754
|
}
|
|
692
755
|
for (const key of before) {
|
|
693
|
-
if (!after.includes(key)) return 'export
|
|
756
|
+
if (!after.includes(key)) return 'export removed: ' + key
|
|
694
757
|
}
|
|
695
758
|
|
|
696
759
|
for (const key of after) {
|
|
697
760
|
const value = next[key]
|
|
698
761
|
if (runtime.isLikelyComponentType(value)) continue
|
|
699
|
-
//
|
|
700
|
-
//
|
|
701
|
-
if (previous[key] !== value) return '
|
|
762
|
+
// An export that is not a component can only be kept when it has not
|
|
763
|
+
// changed: otherwise its consumers would keep the old value.
|
|
764
|
+
if (previous[key] !== value) return 'non-component export changed: ' + key
|
|
702
765
|
}
|
|
703
766
|
|
|
704
767
|
return null
|
|
@@ -707,7 +770,7 @@ export function checkBoundary(previous, next) {
|
|
|
707
770
|
let planned
|
|
708
771
|
const DEBOUNCE = 16
|
|
709
772
|
|
|
710
|
-
/**
|
|
773
|
+
/** Groups the updates of a same burst into a single refresh. */
|
|
711
774
|
export function enqueueUpdate() {
|
|
712
775
|
clearTimeout(planned)
|
|
713
776
|
planned = setTimeout(() => {
|
|
@@ -740,7 +803,7 @@ async function bundleRefreshRuntime() {
|
|
|
740
803
|
}
|
|
741
804
|
|
|
742
805
|
// src/dev/server.ts
|
|
743
|
-
var
|
|
806
|
+
var UTILITIES_PATH = `${INTERNAL_PREFIX}utilities.css`;
|
|
744
807
|
var MIME = {
|
|
745
808
|
".html": "text/html; charset=utf-8",
|
|
746
809
|
".js": "text/javascript; charset=utf-8",
|
|
@@ -767,17 +830,26 @@ var SCRIPT_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mjs"];
|
|
|
767
830
|
function cleanUrl(url) {
|
|
768
831
|
return (url.split("?")[0] ?? url).split("#")[0] ?? url;
|
|
769
832
|
}
|
|
770
|
-
function
|
|
771
|
-
const
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
BASE_URL: config.base
|
|
776
|
-
};
|
|
777
|
-
for (const [key, value] of Object.entries(process.env)) {
|
|
778
|
-
if (key.startsWith(config.envPrefix) && value !== void 0) env[key] = value;
|
|
833
|
+
function suffixOf(url) {
|
|
834
|
+
const query = url.split("?")[1];
|
|
835
|
+
if (query === void 0) return void 0;
|
|
836
|
+
for (const name of ["worker", "raw", "url"]) {
|
|
837
|
+
if (query.split("&").includes(name)) return name;
|
|
779
838
|
}
|
|
780
|
-
return
|
|
839
|
+
return void 0;
|
|
840
|
+
}
|
|
841
|
+
function chain(middlewares, request_, response, done) {
|
|
842
|
+
let index = 0;
|
|
843
|
+
const next = () => {
|
|
844
|
+
const middleware = middlewares[index];
|
|
845
|
+
index += 1;
|
|
846
|
+
if (middleware === void 0) {
|
|
847
|
+
done();
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
850
|
+
void (async () => middleware(request_, response, next))();
|
|
851
|
+
};
|
|
852
|
+
next();
|
|
781
853
|
}
|
|
782
854
|
function extractEntries(html, root) {
|
|
783
855
|
const entries = [];
|
|
@@ -790,11 +862,11 @@ function extractEntries(html, root) {
|
|
|
790
862
|
}
|
|
791
863
|
return entries;
|
|
792
864
|
}
|
|
793
|
-
function injectClient(html,
|
|
865
|
+
function injectClient(html, utilities = false) {
|
|
794
866
|
const tags = [
|
|
795
|
-
//
|
|
796
|
-
//
|
|
797
|
-
...
|
|
867
|
+
// The stylesheet comes before everything else: the base and the application
|
|
868
|
+
// styles, imported afterwards, must be able to override it.
|
|
869
|
+
...utilities ? [`<link rel="stylesheet" href="${UTILITIES_PATH}">`] : [],
|
|
798
870
|
REFRESH_HTML_TAG,
|
|
799
871
|
`<script type="module" src="${HMR_CLIENT_PATH}"></script>`
|
|
800
872
|
].join("\n ");
|
|
@@ -806,25 +878,37 @@ ${html}`;
|
|
|
806
878
|
async function startDevServer(config) {
|
|
807
879
|
const started = Date.now();
|
|
808
880
|
const graph = new ModuleGraph();
|
|
809
|
-
const env =
|
|
881
|
+
const env = config.envClient;
|
|
810
882
|
const clients = /* @__PURE__ */ new Set();
|
|
883
|
+
const middlewares = [];
|
|
884
|
+
for (const plugin of config.plugins) {
|
|
885
|
+
await plugin.configureServer?.({
|
|
886
|
+
use: (middleware) => middlewares.push(middleware)
|
|
887
|
+
});
|
|
888
|
+
}
|
|
811
889
|
const indexFile = join(config.root, "index.html");
|
|
812
890
|
if (!existsSync(indexFile)) {
|
|
813
|
-
throw new Error(`[odoro]
|
|
891
|
+
throw new Error(`[odoro] No "index.html" at the project root (${config.root}).`);
|
|
814
892
|
}
|
|
815
893
|
const refreshRuntime = await bundleRefreshRuntime();
|
|
816
|
-
const
|
|
817
|
-
const
|
|
818
|
-
if (
|
|
894
|
+
const provider = await cssProviderFor(config.root);
|
|
895
|
+
const utilities = provider?.knownClasses === void 0 ? void 0 : provider.renderUtilitiesFor(provider.knownClasses());
|
|
896
|
+
if (utilities !== void 0) {
|
|
897
|
+
info(`development utilities: ${String(Math.round(utilities.length / 1024))} kB`);
|
|
898
|
+
}
|
|
899
|
+
const exposed = Object.keys(config.envClient).filter(
|
|
900
|
+
(key) => key.startsWith(config.envPrefix)
|
|
901
|
+
);
|
|
902
|
+
if (exposed.length > 0) {
|
|
819
903
|
info(
|
|
820
|
-
|
|
904
|
+
`${String(exposed.length)} variable${exposed.length > 1 ? "s" : ""} exposed to the client: ${exposed.join(", ")}`
|
|
821
905
|
);
|
|
822
906
|
}
|
|
823
907
|
const entries = extractEntries(await readFile(indexFile, "utf8"), config.root);
|
|
824
908
|
const specifiers = await scanDependencies(config, entries);
|
|
825
909
|
const deps = await optimizeDeps(config, specifiers);
|
|
826
910
|
if (deps.rebuilt && specifiers.length > 0) {
|
|
827
|
-
info(`${specifiers.length}
|
|
911
|
+
info(`${specifiers.length} dependencies prebundled`);
|
|
828
912
|
}
|
|
829
913
|
const broadcast = (message) => {
|
|
830
914
|
const payload = `data: ${JSON.stringify(message)}
|
|
@@ -863,7 +947,7 @@ async function startDevServer(config) {
|
|
|
863
947
|
send(response, node.code, MIME[".js"]);
|
|
864
948
|
};
|
|
865
949
|
const serveStyle = async (response, file, direct) => {
|
|
866
|
-
const css = await
|
|
950
|
+
const { css, files } = await assembleStylesheet(file, config.root);
|
|
867
951
|
if (direct) {
|
|
868
952
|
send(response, css, MIME[".css"]);
|
|
869
953
|
return;
|
|
@@ -872,13 +956,37 @@ async function startDevServer(config) {
|
|
|
872
956
|
const node = graph.ensure(file, url2);
|
|
873
957
|
node.selfAccepting = true;
|
|
874
958
|
node.code = hotPreamble(url2) + wrapStyle(url2, css);
|
|
959
|
+
const imported = files.filter((one) => one !== file);
|
|
960
|
+
if (imported.length > 0) {
|
|
961
|
+
graph.setDependencies(file, imported);
|
|
962
|
+
for (const one of imported) {
|
|
963
|
+
const dependency = graph.ensure(one, fileToUrl(one, config.root));
|
|
964
|
+
dependency.importers.add(file);
|
|
965
|
+
dependency.selfAccepting = false;
|
|
966
|
+
}
|
|
967
|
+
}
|
|
875
968
|
send(response, node.code, MIME[".js"]);
|
|
876
969
|
};
|
|
877
|
-
const
|
|
878
|
-
if (
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
970
|
+
const serveSuffixed = async (response, file, path, suffix) => {
|
|
971
|
+
if (suffix === "raw") {
|
|
972
|
+
send(
|
|
973
|
+
response,
|
|
974
|
+
textModule(await readFile(file, "utf8")),
|
|
975
|
+
MIME[".js"]
|
|
976
|
+
);
|
|
977
|
+
return;
|
|
978
|
+
}
|
|
979
|
+
if (suffix === "url") {
|
|
980
|
+
send(response, urlModule(path), MIME[".js"]);
|
|
981
|
+
return;
|
|
982
|
+
}
|
|
983
|
+
send(response, workerModule(path), MIME[".js"]);
|
|
984
|
+
};
|
|
985
|
+
const directoryIndex = (directory) => {
|
|
986
|
+
if (!existsSync(directory) || !statSync(directory).isDirectory()) return void 0;
|
|
987
|
+
for (const name of ["index.html", "index.md"]) {
|
|
988
|
+
const candidate = join(directory, name);
|
|
989
|
+
if (existsSync(candidate) && statSync(candidate).isFile()) return candidate;
|
|
882
990
|
}
|
|
883
991
|
return void 0;
|
|
884
992
|
};
|
|
@@ -887,13 +995,14 @@ async function startDevServer(config) {
|
|
|
887
995
|
response.writeHead(200, { "Content-Type": type, "Cache-Control": "no-cache" });
|
|
888
996
|
createReadStream(file).pipe(response);
|
|
889
997
|
};
|
|
890
|
-
const serveHtml = async (response) => {
|
|
998
|
+
const serveHtml = async (response, route = "/") => {
|
|
891
999
|
const html = await readFile(indexFile, "utf8");
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
injectClient(html,
|
|
895
|
-
|
|
1000
|
+
const rendered = await transformHtmlWith(
|
|
1001
|
+
config.plugins,
|
|
1002
|
+
injectClient(html, utilities !== void 0),
|
|
1003
|
+
{ dev: true, route }
|
|
896
1004
|
);
|
|
1005
|
+
send(response, rendered, MIME[".html"]);
|
|
897
1006
|
};
|
|
898
1007
|
const forward = (incoming, response, target) => {
|
|
899
1008
|
const url2 = new URL(incoming.url ?? "/", target);
|
|
@@ -912,12 +1021,12 @@ async function startDevServer(config) {
|
|
|
912
1021
|
}
|
|
913
1022
|
);
|
|
914
1023
|
proxied.on("error", (cause) => {
|
|
915
|
-
warn(`proxy
|
|
916
|
-
send(response, `Proxy
|
|
1024
|
+
warn(`proxy unavailable: ${target}`);
|
|
1025
|
+
send(response, `Proxy unavailable: ${String(cause)}`, "text/plain", 502);
|
|
917
1026
|
});
|
|
918
1027
|
incoming.pipe(proxied);
|
|
919
1028
|
};
|
|
920
|
-
const
|
|
1029
|
+
const handle = (incoming, response) => {
|
|
921
1030
|
void (async () => {
|
|
922
1031
|
const url2 = incoming.url ?? "/";
|
|
923
1032
|
const path = cleanUrl(url2);
|
|
@@ -932,12 +1041,12 @@ async function startDevServer(config) {
|
|
|
932
1041
|
send(response, refreshRuntime, MIME[".js"] ?? "text/javascript");
|
|
933
1042
|
return;
|
|
934
1043
|
}
|
|
935
|
-
if (path ===
|
|
936
|
-
if (
|
|
937
|
-
send(response, "
|
|
1044
|
+
if (path === UTILITIES_PATH) {
|
|
1045
|
+
if (utilities === void 0) {
|
|
1046
|
+
send(response, "Not found", "text/plain", 404);
|
|
938
1047
|
return;
|
|
939
1048
|
}
|
|
940
|
-
send(response,
|
|
1049
|
+
send(response, utilities, MIME[".css"] ?? "text/css");
|
|
941
1050
|
return;
|
|
942
1051
|
}
|
|
943
1052
|
if (path === HMR_CLIENT_PATH) {
|
|
@@ -969,7 +1078,7 @@ async function startDevServer(config) {
|
|
|
969
1078
|
send(
|
|
970
1079
|
response,
|
|
971
1080
|
`throw new Error(${JSON.stringify(
|
|
972
|
-
`[odoro]
|
|
1081
|
+
`[odoro] Dependency not prebundled: "${specifier}". Restart the server.`
|
|
973
1082
|
)})`,
|
|
974
1083
|
MIME[".js"] ?? "text/javascript"
|
|
975
1084
|
);
|
|
@@ -980,13 +1089,18 @@ async function startDevServer(config) {
|
|
|
980
1089
|
return;
|
|
981
1090
|
}
|
|
982
1091
|
if (path.startsWith(INTERNAL_PREFIX)) {
|
|
983
|
-
send(response, "
|
|
1092
|
+
send(response, "Not found", "text/plain", 404);
|
|
984
1093
|
return;
|
|
985
1094
|
}
|
|
986
1095
|
const file = urlToFile(path, config.root);
|
|
987
1096
|
if (existsSync(file) && statSync(file).isFile()) {
|
|
1097
|
+
const suffix = suffixOf(url2);
|
|
1098
|
+
if (suffix !== void 0) {
|
|
1099
|
+
await serveSuffixed(response, file, path, suffix);
|
|
1100
|
+
return;
|
|
1101
|
+
}
|
|
988
1102
|
if (hasExtension(path, STYLE_EXTENSIONS)) {
|
|
989
|
-
await serveStyle(response, file,
|
|
1103
|
+
await serveStyle(response, file, wantsStylesheet(incoming.headers, url2));
|
|
990
1104
|
return;
|
|
991
1105
|
}
|
|
992
1106
|
if (hasExtension(path, ASSET_EXTENSIONS)) {
|
|
@@ -1002,7 +1116,7 @@ async function startDevServer(config) {
|
|
|
1002
1116
|
return;
|
|
1003
1117
|
}
|
|
1004
1118
|
if (hasExtension(path, [".json"])) {
|
|
1005
|
-
if (
|
|
1119
|
+
if (isAssetRequest(incoming.headers) || url2.includes("?import")) {
|
|
1006
1120
|
const json = await readFile(file, "utf8");
|
|
1007
1121
|
send(response, wrapJson(json), MIME[".js"] ?? "text/javascript");
|
|
1008
1122
|
} else {
|
|
@@ -1018,24 +1132,40 @@ async function startDevServer(config) {
|
|
|
1018
1132
|
serveFile(response, publicFile);
|
|
1019
1133
|
return;
|
|
1020
1134
|
}
|
|
1021
|
-
const index =
|
|
1135
|
+
const index = directoryIndex(publicFile);
|
|
1022
1136
|
if (index !== void 0) {
|
|
1023
1137
|
serveFile(response, index);
|
|
1024
1138
|
return;
|
|
1025
1139
|
}
|
|
1026
|
-
if (!extname(path) && !
|
|
1027
|
-
await serveHtml(response);
|
|
1140
|
+
if (!extname(path) && !isAssetRequest(incoming.headers)) {
|
|
1141
|
+
await serveHtml(response, path);
|
|
1028
1142
|
return;
|
|
1029
1143
|
}
|
|
1030
|
-
send(response, "
|
|
1144
|
+
send(response, "Not found", "text/plain", 404);
|
|
1031
1145
|
} catch (cause) {
|
|
1032
1146
|
const message = cause instanceof Error ? cause.message : String(cause);
|
|
1033
|
-
error(`
|
|
1147
|
+
error(`failed to handle ${path}`, cause);
|
|
1034
1148
|
broadcast({ type: "error", message, file: path });
|
|
1035
|
-
send(response, `
|
|
1149
|
+
send(response, `Error: ${message}`, "text/plain", 500);
|
|
1036
1150
|
}
|
|
1037
1151
|
})();
|
|
1038
|
-
}
|
|
1152
|
+
};
|
|
1153
|
+
const listener = (incoming, response) => {
|
|
1154
|
+
if (middlewares.length === 0) {
|
|
1155
|
+
handle(incoming, response);
|
|
1156
|
+
return;
|
|
1157
|
+
}
|
|
1158
|
+
chain(middlewares, incoming, response, () => {
|
|
1159
|
+
handle(incoming, response);
|
|
1160
|
+
});
|
|
1161
|
+
};
|
|
1162
|
+
const server = config.server.https === void 0 ? createServer(listener) : createServer$1(
|
|
1163
|
+
{
|
|
1164
|
+
cert: readFileSync(resolve(config.root, config.server.https.cert)),
|
|
1165
|
+
key: readFileSync(resolve(config.root, config.server.https.key))
|
|
1166
|
+
},
|
|
1167
|
+
listener
|
|
1168
|
+
);
|
|
1039
1169
|
let pending;
|
|
1040
1170
|
const changed = /* @__PURE__ */ new Set();
|
|
1041
1171
|
const watcher = watch(config.root, { recursive: true }, (_event, filename) => {
|
|
@@ -1071,23 +1201,28 @@ async function startDevServer(config) {
|
|
|
1071
1201
|
}
|
|
1072
1202
|
}
|
|
1073
1203
|
if (reload) {
|
|
1074
|
-
info("
|
|
1204
|
+
info("page reload");
|
|
1075
1205
|
broadcast({ type: "full-reload" });
|
|
1076
1206
|
} else if (updates.length > 0) {
|
|
1077
|
-
info(
|
|
1078
|
-
`mise a jour a chaud : ${updates.map((update) => update.url).join(", ")}`
|
|
1079
|
-
);
|
|
1207
|
+
info(`hot update: ${updates.map((update) => update.url).join(", ")}`);
|
|
1080
1208
|
broadcast({ type: "update", updates });
|
|
1081
1209
|
}
|
|
1082
1210
|
}, 40);
|
|
1083
1211
|
});
|
|
1084
|
-
const { port,
|
|
1085
|
-
|
|
1086
|
-
|
|
1212
|
+
const { port, requested } = await listen(
|
|
1213
|
+
server,
|
|
1214
|
+
config.server.port,
|
|
1215
|
+
config.server.host,
|
|
1216
|
+
config.server.strictPort ? 1 : void 0
|
|
1217
|
+
);
|
|
1218
|
+
if (requested !== void 0) {
|
|
1219
|
+
warn(`port ${String(requested)} in use \u2014 server listening on ${String(port)}`);
|
|
1087
1220
|
}
|
|
1088
|
-
const
|
|
1089
|
-
|
|
1221
|
+
const protocol = config.server.https === void 0 ? "http" : "https";
|
|
1222
|
+
const url = `${protocol}://${config.server.host}:${String(port)}${config.base}`;
|
|
1223
|
+
success(`ready in ${duration(Date.now() - started)}`);
|
|
1090
1224
|
info(` ${colors.cyan(url)}`);
|
|
1225
|
+
if (config.server.open) openBrowser(url);
|
|
1091
1226
|
return {
|
|
1092
1227
|
url,
|
|
1093
1228
|
async close() {
|
|
@@ -1101,4 +1236,4 @@ async function startDevServer(config) {
|
|
|
1101
1236
|
};
|
|
1102
1237
|
}
|
|
1103
1238
|
|
|
1104
|
-
export { ModuleGraph, detectSelfAccepting, extractEntries,
|
|
1239
|
+
export { ModuleGraph, cssProviderFor, detectSelfAccepting, extractEntries, injectClient, optimizeDeps, scanDependencies, startDevServer };
|