odoro 1.0.9 → 2.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/README.md +94 -0
- package/client.d.ts +90 -16
- package/dist/build-XJIP4GNT.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-DF67LADH.js +735 -0
- package/dist/{chunk-LHZGX5ML.js → chunk-HS7NGZLM.js} +307 -196
- package/dist/chunk-LIKVHWB4.js +231 -0
- package/dist/chunk-QOVBLN7A.js +241 -0
- package/dist/chunk-RTWJ5GFB.js +729 -0
- package/dist/chunk-TONYIKCN.js +57 -0
- package/dist/cli.d.ts +12 -13
- package/dist/cli.js +86 -63
- package/dist/{commands-AHMXBWQQ.js → commands-GYA7NTCX.js} +124 -124
- package/dist/commands-UOWN3IK4.js +181 -0
- package/dist/{create-CYVSVDAD.js → create-B2TLV6XI.js} +198 -160
- package/dist/index.d.ts +603 -151
- package/dist/index.js +6 -6
- package/dist/{package-EIDLKAA6.js → package-3ZJOEXM4.js} +6 -5
- package/dist/preview-3IRG7MHV.js +4 -0
- package/dist/registry/index.d.ts +75 -76
- package/dist/registry/index.js +1 -1
- package/dist/{server-4UGN3SFS.js → server-ZB3P3EGS.js} +3 -3
- package/package.json +6 -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-3SZIN6VG.js +0 -64
- package/dist/chunk-DL3NPC4H.js +0 -113
- package/dist/chunk-TQUJ3MFS.js +0 -268
- package/dist/chunk-ZVL7EXJO.js +0 -66
- package/dist/commands-4JRBD55Z.js +0 -245
- 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 -66
- 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 -66
package/dist/index.d.ts
CHANGED
|
@@ -1,110 +1,305 @@
|
|
|
1
|
+
import { Plugin, BuildResult } from 'esbuild';
|
|
2
|
+
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
|
-
*
|
|
5
|
+
* Engine plugins.
|
|
6
|
+
*
|
|
7
|
+
* ## Why such a small surface
|
|
8
|
+
*
|
|
9
|
+
* A plugin system is a compatibility promise: everything it exposes will have
|
|
10
|
+
* to be honoured. This one exposes only what a project really needs —
|
|
11
|
+
* transform code, transform the document, add a route to the server — and
|
|
12
|
+
* leaves an escape hatch towards the bundler for the rest.
|
|
3
13
|
*
|
|
4
|
-
*
|
|
5
|
-
* donc etre ecrit en TypeScript et utiliser toute la puissance du langage,
|
|
6
|
-
* sans etape de build prealable.
|
|
14
|
+
* Three hooks can be replaced; thirty get dragged along.
|
|
7
15
|
*
|
|
8
16
|
* @module
|
|
9
17
|
*/
|
|
10
|
-
|
|
18
|
+
|
|
19
|
+
/** What a plugin knows about the transformation under way. */
|
|
20
|
+
interface TransformContext {
|
|
21
|
+
/** Absolute path of the transformed file. */
|
|
22
|
+
readonly id: string;
|
|
23
|
+
/** True during development, false in a production build. */
|
|
24
|
+
readonly dev: boolean;
|
|
25
|
+
/** True during a server render (prerendering). */
|
|
26
|
+
readonly ssr: boolean;
|
|
27
|
+
}
|
|
28
|
+
/** What a plugin knows about the document it transforms. */
|
|
29
|
+
interface HtmlContext {
|
|
30
|
+
/** True during development. */
|
|
31
|
+
readonly dev: boolean;
|
|
32
|
+
/** Route being rendered, during a prerender; `/` otherwise. */
|
|
33
|
+
readonly route: string;
|
|
34
|
+
}
|
|
35
|
+
/** A request middleware, added to the development server. */
|
|
36
|
+
type Middleware = (request: IncomingMessage, response: ServerResponse, next: () => void) => void | Promise<void>;
|
|
37
|
+
/** What a plugin receives to hook into the server. */
|
|
38
|
+
interface ServerContext {
|
|
39
|
+
/** Adds a middleware, called before the engine handles the request. */
|
|
40
|
+
use(middleware: Middleware): void;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* A plugin.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* import { defineConfig, type OdoroPlugin } from 'odoro'
|
|
47
|
+
*
|
|
48
|
+
* const stamped: OdoroPlugin = {
|
|
49
|
+
* name: 'stamped',
|
|
50
|
+
* transformIndexHtml: (html) =>
|
|
51
|
+
* html.replace('</head>', `<meta name="build" content="${Date.now()}"></head>`),
|
|
52
|
+
* }
|
|
53
|
+
*
|
|
54
|
+
* export default defineConfig({ plugins: [stamped] })
|
|
55
|
+
*/
|
|
56
|
+
interface OdoroPlugin {
|
|
57
|
+
/** Plugin name, shown in error messages. */
|
|
58
|
+
readonly name: string;
|
|
59
|
+
/**
|
|
60
|
+
* Transforms the code of a source file before it is compiled.
|
|
61
|
+
*
|
|
62
|
+
* Returning `null` or `undefined` leaves the file untouched — that is what to
|
|
63
|
+
* do for everything the plugin is not concerned with, and it is cheaper than
|
|
64
|
+
* returning the unchanged code.
|
|
65
|
+
*/
|
|
66
|
+
transform?(code: string, context: TransformContext): string | null | undefined | Promise<string | null | undefined>;
|
|
67
|
+
/** Transforms the HTML document before it is served or written. */
|
|
68
|
+
transformIndexHtml?(html: string, context: HtmlContext): string | Promise<string>;
|
|
69
|
+
/** Hooks middlewares into the development server. */
|
|
70
|
+
configureServer?(context: ServerContext): void | Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Bundler plugins, for what the hooks above do not cover.
|
|
73
|
+
*
|
|
74
|
+
* This is the escape hatch: it grants access to full resolution and loading,
|
|
75
|
+
* at the price of coupling to the bundler.
|
|
76
|
+
*/
|
|
77
|
+
readonly esbuild?: readonly Plugin[];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Configuration of the Odoro engine.
|
|
82
|
+
*
|
|
83
|
+
* The `odoro.config.ts` file is compiled on the fly then imported: it can
|
|
84
|
+
* therefore be written in TypeScript and use the full power of the language,
|
|
85
|
+
* with no prior build step.
|
|
86
|
+
*
|
|
87
|
+
* @module
|
|
88
|
+
*/
|
|
89
|
+
|
|
90
|
+
/** Certificate of an HTTPS development server. */
|
|
91
|
+
interface HttpsConfig {
|
|
92
|
+
/** Path to the certificate, relative to the project root. */
|
|
93
|
+
cert: string;
|
|
94
|
+
/** Path to the private key, relative to the project root. */
|
|
95
|
+
key: string;
|
|
96
|
+
}
|
|
97
|
+
/** Development server settings. */
|
|
11
98
|
interface ServerConfig {
|
|
12
|
-
/** Port
|
|
99
|
+
/** Port to listen on. @defaultValue 5180 */
|
|
13
100
|
port?: number;
|
|
14
|
-
/** Interface
|
|
101
|
+
/** Interface to listen on. @defaultValue 'localhost' */
|
|
15
102
|
host?: string;
|
|
16
103
|
/**
|
|
17
|
-
*
|
|
104
|
+
* Request forwarding, from path prefix to target origin.
|
|
18
105
|
*
|
|
19
106
|
* @example
|
|
20
107
|
* { '/api': 'http://localhost:3001' }
|
|
21
108
|
*/
|
|
22
109
|
proxy?: Record<string, string>;
|
|
110
|
+
/**
|
|
111
|
+
* Serves over HTTPS, with the given certificate.
|
|
112
|
+
*
|
|
113
|
+
* Required as soon as an interface demands a secure origin: camera,
|
|
114
|
+
* microphone, clipboard, service worker.
|
|
115
|
+
*/
|
|
116
|
+
https?: HttpsConfig;
|
|
117
|
+
/**
|
|
118
|
+
* Fails if the requested port is taken, instead of sliding to the next one.
|
|
119
|
+
*
|
|
120
|
+
* @defaultValue false
|
|
121
|
+
*/
|
|
122
|
+
strictPort?: boolean;
|
|
123
|
+
/** Opens the browser on startup. @defaultValue false */
|
|
124
|
+
open?: boolean;
|
|
125
|
+
}
|
|
126
|
+
/** Prerendering settings. */
|
|
127
|
+
interface PrerenderConfig {
|
|
128
|
+
/**
|
|
129
|
+
* The routes rendered at build time.
|
|
130
|
+
*
|
|
131
|
+
* When empty, the ones the server entry exports under the name `routes` are
|
|
132
|
+
* taken.
|
|
133
|
+
*/
|
|
134
|
+
routes?: readonly string[];
|
|
135
|
+
/**
|
|
136
|
+
* Server entry, relative to the root.
|
|
137
|
+
*
|
|
138
|
+
* @defaultValue 'src/entry-server.tsx'
|
|
139
|
+
*/
|
|
140
|
+
entry?: string;
|
|
23
141
|
}
|
|
24
|
-
/**
|
|
142
|
+
/** Production build settings. */
|
|
25
143
|
interface BuildConfig {
|
|
26
|
-
/**
|
|
144
|
+
/** Output directory, relative to the root. @defaultValue 'dist' */
|
|
27
145
|
outDir?: string;
|
|
28
|
-
/**
|
|
146
|
+
/** Minifies the produced code. @defaultValue true */
|
|
29
147
|
minify?: boolean;
|
|
30
|
-
/**
|
|
148
|
+
/** Emits source maps. @defaultValue true */
|
|
31
149
|
sourcemap?: boolean;
|
|
32
|
-
/**
|
|
150
|
+
/** Build target. @defaultValue 'es2022' */
|
|
33
151
|
target?: string;
|
|
34
152
|
/**
|
|
35
|
-
*
|
|
153
|
+
* Removes from the stylesheet the utility classes nothing uses.
|
|
36
154
|
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
155
|
+
* The library ships a pre-generated stylesheet holding them all; a given
|
|
156
|
+
* application uses a fraction of it. Pruning reads the **produced** code —
|
|
157
|
+
* so the library components as much as the application source — and keeps
|
|
158
|
+
* only what is reachable.
|
|
41
159
|
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
160
|
+
* A class assembled at runtime (`o-text-${color}`) exists nowhere in its
|
|
161
|
+
* final form and will disappear: declaring it in `safelist` is the only way
|
|
162
|
+
* to keep it.
|
|
45
163
|
*
|
|
46
164
|
* @defaultValue true
|
|
47
165
|
*/
|
|
48
|
-
|
|
166
|
+
prune?: boolean;
|
|
49
167
|
/**
|
|
50
|
-
*
|
|
168
|
+
* The classes kept no matter what, despite pruning.
|
|
51
169
|
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
170
|
+
* A string keeps one class; a regular expression keeps every class it
|
|
171
|
+
* matches.
|
|
54
172
|
*
|
|
55
173
|
* @example
|
|
56
174
|
* { safelist: [/^o-text-/, 'o-animate-spin'] }
|
|
57
175
|
*/
|
|
58
176
|
safelist?: readonly (string | RegExp)[];
|
|
177
|
+
/**
|
|
178
|
+
* Writes `manifest.json` next to the produced files.
|
|
179
|
+
*
|
|
180
|
+
* It gives, for each entry, the hashed file, its stylesheets and its chunks.
|
|
181
|
+
* That is what a server reads to place the tags itself, when the project
|
|
182
|
+
* document does not carry them.
|
|
183
|
+
*
|
|
184
|
+
* @defaultValue true
|
|
185
|
+
*/
|
|
186
|
+
manifest?: boolean;
|
|
187
|
+
/**
|
|
188
|
+
* Declares the shared chunks as `modulepreload` in the document.
|
|
189
|
+
*
|
|
190
|
+
* Without it, the browser only discovers a chunk after reading the module
|
|
191
|
+
* that imports it: as many round trips as there are levels of depth, on the
|
|
192
|
+
* critical path.
|
|
193
|
+
*
|
|
194
|
+
* @defaultValue true
|
|
195
|
+
*/
|
|
196
|
+
preload?: boolean;
|
|
197
|
+
/**
|
|
198
|
+
* Renders the routes to HTML at build time.
|
|
199
|
+
*
|
|
200
|
+
* `true` takes the defaults; an array gives the routes; the object form
|
|
201
|
+
* allows naming another entry point.
|
|
202
|
+
*
|
|
203
|
+
* @defaultValue false
|
|
204
|
+
*
|
|
205
|
+
* @example
|
|
206
|
+
* { prerender: ['/', '/about'] }
|
|
207
|
+
*/
|
|
208
|
+
prerender?: boolean | readonly string[] | PrerenderConfig;
|
|
59
209
|
}
|
|
60
|
-
/** Configuration
|
|
210
|
+
/** Configuration of an Odoro project. */
|
|
61
211
|
interface OdoroConfig {
|
|
62
|
-
/**
|
|
212
|
+
/** Project root. @defaultValue the current directory */
|
|
63
213
|
root?: string;
|
|
64
|
-
/**
|
|
214
|
+
/** Prefix of public URLs. @defaultValue '/' */
|
|
65
215
|
base?: string;
|
|
66
|
-
/**
|
|
216
|
+
/** Directory of files copied as is. @defaultValue 'public' */
|
|
67
217
|
publicDir?: string;
|
|
68
|
-
/**
|
|
218
|
+
/** Development server settings. */
|
|
69
219
|
server?: ServerConfig;
|
|
70
|
-
/**
|
|
220
|
+
/** Production build settings. */
|
|
71
221
|
build?: BuildConfig;
|
|
72
222
|
/**
|
|
73
|
-
*
|
|
223
|
+
* Import path aliases, from prefix to a path relative to the root.
|
|
74
224
|
*
|
|
75
225
|
* @example
|
|
76
226
|
* { '@': 'src' }
|
|
77
227
|
*/
|
|
78
228
|
alias?: Record<string, string>;
|
|
79
|
-
/**
|
|
229
|
+
/** Textual replacements applied at build time. */
|
|
80
230
|
define?: Record<string, string>;
|
|
81
231
|
/**
|
|
82
|
-
*
|
|
232
|
+
* Prefix of the environment variables exposed to the client through
|
|
83
233
|
* `import.meta.env`.
|
|
84
234
|
*
|
|
85
235
|
* @defaultValue 'ODORO_'
|
|
86
236
|
*/
|
|
87
237
|
envPrefix?: string;
|
|
238
|
+
/**
|
|
239
|
+
* Directory where the `.env` files are looked up.
|
|
240
|
+
*
|
|
241
|
+
* @defaultValue the project root
|
|
242
|
+
*/
|
|
243
|
+
envDir?: string;
|
|
244
|
+
/**
|
|
245
|
+
* Build mode: it chooses the `.env` files read and feeds
|
|
246
|
+
* `import.meta.env.MODE`.
|
|
247
|
+
*
|
|
248
|
+
* @defaultValue 'development' for `dev`, 'production' for `build`
|
|
249
|
+
*/
|
|
250
|
+
mode?: string;
|
|
251
|
+
/** Plugins applied to the build and to the server. */
|
|
252
|
+
plugins?: readonly OdoroPlugin[];
|
|
253
|
+
}
|
|
254
|
+
/** Prerendering, once resolved. */
|
|
255
|
+
interface ResolvedPrerender {
|
|
256
|
+
/** Routes to render; when empty, those of the server entry. */
|
|
257
|
+
readonly routes: readonly string[];
|
|
258
|
+
/** Absolute path of the server entry. */
|
|
259
|
+
readonly entry: string;
|
|
88
260
|
}
|
|
89
|
-
/**
|
|
261
|
+
/** Production build, once resolved. */
|
|
262
|
+
interface ResolvedBuild {
|
|
263
|
+
readonly outDir: string;
|
|
264
|
+
readonly minify: boolean;
|
|
265
|
+
readonly sourcemap: boolean;
|
|
266
|
+
readonly target: string;
|
|
267
|
+
readonly prune: boolean;
|
|
268
|
+
readonly safelist: readonly (string | RegExp)[];
|
|
269
|
+
readonly manifest: boolean;
|
|
270
|
+
readonly preload: boolean;
|
|
271
|
+
/** `undefined` when prerendering is not requested. */
|
|
272
|
+
readonly prerender: ResolvedPrerender | undefined;
|
|
273
|
+
}
|
|
274
|
+
/** Configuration once the default values are applied. */
|
|
90
275
|
interface ResolvedConfig {
|
|
91
276
|
readonly root: string;
|
|
92
277
|
readonly base: string;
|
|
93
278
|
readonly publicDir: string;
|
|
94
279
|
readonly outDir: string;
|
|
95
|
-
readonly server: Required<Omit<ServerConfig, 'proxy'>> & {
|
|
280
|
+
readonly server: Required<Omit<ServerConfig, 'proxy' | 'https'>> & {
|
|
96
281
|
proxy: Record<string, string>;
|
|
282
|
+
https: HttpsConfig | undefined;
|
|
97
283
|
};
|
|
98
|
-
readonly build:
|
|
284
|
+
readonly build: ResolvedBuild;
|
|
99
285
|
readonly alias: Record<string, string>;
|
|
100
286
|
readonly define: Record<string, string>;
|
|
101
287
|
readonly envPrefix: string;
|
|
102
|
-
|
|
288
|
+
readonly envDir: string;
|
|
289
|
+
/** Mode retained. */
|
|
290
|
+
readonly mode: string;
|
|
291
|
+
/** Every variable read, prefixed or not. Never leaves the machine. */
|
|
292
|
+
readonly env: Readonly<Record<string, string>>;
|
|
293
|
+
/** What the client code reads in `import.meta.env`. */
|
|
294
|
+
readonly envClient: Readonly<Record<string, string | boolean>>;
|
|
295
|
+
/** Plugins declared by the project. */
|
|
296
|
+
readonly plugins: readonly OdoroPlugin[];
|
|
297
|
+
/** Path of the configuration file actually loaded, if there is one. */
|
|
103
298
|
readonly configFile: string | undefined;
|
|
104
299
|
}
|
|
105
300
|
/**
|
|
106
|
-
*
|
|
107
|
-
*
|
|
301
|
+
* Identity on the configuration, present only for typing and completion in
|
|
302
|
+
* `odoro.config.ts`.
|
|
108
303
|
*
|
|
109
304
|
* @example
|
|
110
305
|
* import { defineConfig } from 'odoro'
|
|
@@ -115,38 +310,290 @@ interface ResolvedConfig {
|
|
|
115
310
|
*/
|
|
116
311
|
declare function defineConfig(config: OdoroConfig): OdoroConfig;
|
|
117
312
|
/**
|
|
118
|
-
*
|
|
313
|
+
* Loads the configuration of a project and applies the default values.
|
|
119
314
|
*
|
|
120
|
-
* @param root
|
|
121
|
-
* @param overrides
|
|
315
|
+
* @param root Project root.
|
|
316
|
+
* @param overrides Settings coming from the command line, which take priority.
|
|
317
|
+
* @param defaultMode Mode retained when neither the command line nor the
|
|
318
|
+
* configuration file names one.
|
|
122
319
|
*
|
|
123
320
|
* @example
|
|
124
321
|
* const config = await loadConfig(process.cwd(), { server: { port: 4000 } })
|
|
125
322
|
*/
|
|
126
|
-
declare function loadConfig(root: string, overrides?: OdoroConfig): Promise<ResolvedConfig>;
|
|
323
|
+
declare function loadConfig(root: string, overrides?: OdoroConfig, defaultMode?: string): Promise<ResolvedConfig>;
|
|
127
324
|
|
|
325
|
+
/** What loading produced. */
|
|
326
|
+
interface LoadedEnv {
|
|
327
|
+
/** Every value read, prefixed or not. */
|
|
328
|
+
readonly all: Record<string, string>;
|
|
329
|
+
/** The only values exposed to the client, the prefixed ones. */
|
|
330
|
+
readonly client: Record<string, string>;
|
|
331
|
+
/** The files actually read, in order. */
|
|
332
|
+
readonly files: readonly string[];
|
|
333
|
+
}
|
|
128
334
|
/**
|
|
129
|
-
*
|
|
335
|
+
* Loads the environment files of a project.
|
|
336
|
+
*
|
|
337
|
+
* ## What wins, and why
|
|
338
|
+
*
|
|
339
|
+
* A variable already present in the process environment is **never** overwritten
|
|
340
|
+
* by a file. That is the only rule that makes a deployment predictable: a `.env`
|
|
341
|
+
* versioned by mistake must not take precedence over the value the host
|
|
342
|
+
* injects.
|
|
130
343
|
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
344
|
+
* ## What goes to the browser
|
|
345
|
+
*
|
|
346
|
+
* The prefix alone. A variable without the prefix stays readable by the command
|
|
347
|
+
* — a database token, a server API key — and does not leave the machine:
|
|
348
|
+
* everything that enters `import.meta.env` ends up in clear text in the
|
|
349
|
+
* published bundle, and nothing catches it afterwards.
|
|
350
|
+
*
|
|
351
|
+
* @param directory Directory where the files are looked up.
|
|
352
|
+
* @param mode Build mode (`development`, `production`, or your own).
|
|
353
|
+
* @param prefix Prefix of the variables exposed to the client.
|
|
354
|
+
*
|
|
355
|
+
* @example
|
|
356
|
+
* const env = await loadEnv('/project', 'production', 'ODORO_')
|
|
357
|
+
* env.client // { ODORO_API: 'https://api.odoro.dev' }
|
|
358
|
+
*/
|
|
359
|
+
declare function loadEnv(directory: string, mode: string, prefix: string): Promise<LoadedEnv>;
|
|
360
|
+
/**
|
|
361
|
+
* Assembles the values the client code reads in `import.meta.env`.
|
|
362
|
+
*
|
|
363
|
+
* @example
|
|
364
|
+
* clientEnv({ ODORO_API: 'x' }, 'production', '/')
|
|
365
|
+
* // { MODE: 'production', DEV: false, PROD: true, BASE_URL: '/', ODORO_API: 'x' }
|
|
366
|
+
*/
|
|
367
|
+
declare function clientEnv(variables: Readonly<Record<string, string>>, mode: string, base: string): Record<string, string | boolean>;
|
|
368
|
+
|
|
369
|
+
/** What the transformation produced. */
|
|
370
|
+
interface Resolution {
|
|
371
|
+
/** Transformed code. */
|
|
372
|
+
readonly code: string;
|
|
373
|
+
/** Files reached, as absolute paths. */
|
|
374
|
+
readonly files: readonly string[];
|
|
375
|
+
}
|
|
376
|
+
/** Tells whether some code uses import by pattern. */
|
|
377
|
+
declare function hasGlob(code: string): boolean;
|
|
378
|
+
/**
|
|
379
|
+
* Replaces the calls to `import.meta.glob` by tables of static imports.
|
|
380
|
+
*
|
|
381
|
+
* @param code Source of the module.
|
|
382
|
+
* @param file Absolute path of the module.
|
|
383
|
+
* @param projectRoot Project root, for patterns starting with `/`.
|
|
384
|
+
* @returns The transformed code, or `undefined` if nothing changed.
|
|
385
|
+
*
|
|
386
|
+
* @example
|
|
387
|
+
* transformGlob("const p = import.meta.glob('./pages/*.tsx')", file, root)
|
|
388
|
+
* // const p = {"./pages/index.tsx": () => import("./pages/index.tsx")}
|
|
389
|
+
*/
|
|
390
|
+
declare function transformGlob(code: string, file: string, projectRoot: string): Resolution | undefined;
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* The build manifest, and the preloading it enables.
|
|
394
|
+
*
|
|
395
|
+
* ## Two needs, a single reading
|
|
396
|
+
*
|
|
397
|
+
* The bundler report knows everything: which file comes from which source,
|
|
398
|
+
* which stylesheet goes with which script, which chunk is shared by which
|
|
399
|
+
* modules. It is written in a format of its own, and it disappears at the end
|
|
400
|
+
* of the build.
|
|
401
|
+
*
|
|
402
|
+
* Two things depend on it. A server that places the tags itself — because the
|
|
403
|
+
* document is rendered elsewhere, by a template engine or by the back end —
|
|
404
|
+
* needs to know what to point at; that is `manifest.json`. And the browser
|
|
405
|
+
* gains from knowing the chunks **before** having read the module that imports
|
|
406
|
+
* them; that is preloading.
|
|
135
407
|
*
|
|
136
408
|
* @module
|
|
137
409
|
*/
|
|
138
410
|
|
|
139
|
-
/**
|
|
411
|
+
/** What the manifest says about a produced file. */
|
|
412
|
+
interface ManifestEntry {
|
|
413
|
+
/** Path of the produced file, relative to the output directory. */
|
|
414
|
+
readonly file: string;
|
|
415
|
+
/** Source it comes from, relative to the root. Absent for a chunk. */
|
|
416
|
+
readonly src?: string;
|
|
417
|
+
/** True when it is an entry of the document. */
|
|
418
|
+
readonly isEntry?: boolean;
|
|
419
|
+
/** Stylesheets to place alongside it. */
|
|
420
|
+
readonly css?: readonly string[];
|
|
421
|
+
/** Chunks it imports statically, by their key in the manifest. */
|
|
422
|
+
readonly imports?: readonly string[];
|
|
423
|
+
/** Chunks it imports on demand. */
|
|
424
|
+
readonly dynamicImports?: readonly string[];
|
|
425
|
+
}
|
|
426
|
+
/** The whole manifest. */
|
|
427
|
+
type Manifest = Readonly<Record<string, ManifestEntry>>;
|
|
428
|
+
/** What is needed to read the report. */
|
|
429
|
+
interface Context {
|
|
430
|
+
/** Project root — the paths of the report are relative to it. */
|
|
431
|
+
readonly root: string;
|
|
432
|
+
/** Directory where the produced files are written. */
|
|
433
|
+
readonly assetsDir: string;
|
|
434
|
+
/**
|
|
435
|
+
* The entries of the document, as absolute paths.
|
|
436
|
+
*
|
|
437
|
+
* ## Why they have to be given
|
|
438
|
+
*
|
|
439
|
+
* The report assigns an `entryPoint` to every module that **opens a chunk** —
|
|
440
|
+
* so to every module imported on demand, which splitting isolates by
|
|
441
|
+
* construction. Taking those for document entries would make a server place
|
|
442
|
+
* one `<script>` tag per lazy page: everything would be loaded up front, and
|
|
443
|
+
* splitting would have served no purpose.
|
|
444
|
+
*
|
|
445
|
+
* Only the document knows which ones are its own.
|
|
446
|
+
*/
|
|
447
|
+
readonly entries?: readonly string[];
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* Builds the manifest from the build report.
|
|
451
|
+
*
|
|
452
|
+
* The keys are the **sources** for the entries — that is the name a server
|
|
453
|
+
* looks them up under, `src/main.tsx` and not `main-A1B2.js`, which it cannot
|
|
454
|
+
* guess — and the produced file for the chunks, which have no single source.
|
|
455
|
+
*
|
|
456
|
+
* @example
|
|
457
|
+
* const manifest = buildManifest(result, { root, assetsDir })
|
|
458
|
+
* manifest['src/main.tsx'].file // 'main-A1B2.js'
|
|
459
|
+
*/
|
|
460
|
+
declare function buildManifest(result: BuildResult<{
|
|
461
|
+
metafile: true;
|
|
462
|
+
}>, context: Context): Manifest;
|
|
463
|
+
/**
|
|
464
|
+
* The chunks to preload for a given entry.
|
|
465
|
+
*
|
|
466
|
+
* ## Why the transitive ones count
|
|
467
|
+
*
|
|
468
|
+
* The browser discovers a chunk by reading the module that imports it. A chunk
|
|
469
|
+
* imported by a chunk therefore only appears on the third round trip — one per
|
|
470
|
+
* level of depth, each on the critical path, and splitting multiplies them by
|
|
471
|
+
* construction.
|
|
472
|
+
*
|
|
473
|
+
* Declaring them all up front puts them in flight at the same time.
|
|
474
|
+
*
|
|
475
|
+
* ## What is not in there
|
|
476
|
+
*
|
|
477
|
+
* The imports on demand. Those are the ones deliberately deferred — a page the
|
|
478
|
+
* visitor may never open. Preloading them would cancel the splitting while
|
|
479
|
+
* keeping its cost.
|
|
480
|
+
*
|
|
481
|
+
* @param entry The produced file for the entry, as the report names it.
|
|
482
|
+
* @returns The files to preload, relative to the produced files directory.
|
|
483
|
+
*/
|
|
484
|
+
declare function chunksFor(result: BuildResult<{
|
|
485
|
+
metafile: true;
|
|
486
|
+
}>, entry: string, context: Context): string[];
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* Suffixed imports, on the build side: `?worker`, `?raw`, `?url`.
|
|
490
|
+
*
|
|
491
|
+
* @module
|
|
492
|
+
*/
|
|
493
|
+
|
|
494
|
+
/** What changes between the client build and the prerender. */
|
|
495
|
+
interface AssetOptions {
|
|
496
|
+
/**
|
|
497
|
+
* Receives the paths of the files written **outside** the main build — those
|
|
498
|
+
* of the workers. Without it, they would appear in no summary: the report of
|
|
499
|
+
* the main build does not know them, and a hundred-kilobyte bundle would land
|
|
500
|
+
* in the output directory without anything announcing it.
|
|
501
|
+
*/
|
|
502
|
+
readonly outputs: Set<string>;
|
|
503
|
+
/**
|
|
504
|
+
* True during the prerender.
|
|
505
|
+
*
|
|
506
|
+
* It builds nothing new: everything has already been produced for the client,
|
|
507
|
+
* and doing it again would drop a second copy of each asset, under another
|
|
508
|
+
* hash.
|
|
509
|
+
*/
|
|
510
|
+
readonly ssr?: boolean;
|
|
511
|
+
/**
|
|
512
|
+
* The public addresses already assigned, from the source file to its URL.
|
|
513
|
+
*
|
|
514
|
+
* ## Why they must be the same
|
|
515
|
+
*
|
|
516
|
+
* An image written in the prerendered HTML and the same image loaded by the
|
|
517
|
+
* script must point to the same place. Letting the prerender recompute the
|
|
518
|
+
* address would produce two hashes for a single file: one exists, the other
|
|
519
|
+
* does not, and the prerendered page would show a broken image until
|
|
520
|
+
* hydration replaced it — that is, precisely in front of the people the
|
|
521
|
+
* prerender is for.
|
|
522
|
+
*/
|
|
523
|
+
readonly urls?: ReadonlyMap<string, string>;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/**
|
|
527
|
+
* Prerendering: the routes become HTML at build time.
|
|
528
|
+
*
|
|
529
|
+
* ## Why this is the missing piece
|
|
530
|
+
*
|
|
531
|
+
* A single-page application ships an empty document and a script. A visitor
|
|
532
|
+
* does not see it — the script runs in a few dozen milliseconds — but a robot
|
|
533
|
+
* does: a search engine that does not run the script, a link preview that reads
|
|
534
|
+
* only the tags of the document, a screen reader that starts before hydration.
|
|
535
|
+
* For them, a marketing site published as a single page is a blank page.
|
|
536
|
+
*
|
|
537
|
+
* ## Why at build time, and not on demand
|
|
538
|
+
*
|
|
539
|
+
* Rendering on every request would require a Node process in production, hence
|
|
540
|
+
* a host that keeps one, hence monitoring, memory, a restart. Rendering at
|
|
541
|
+
* build time produces files: the site stays served by any static server, and
|
|
542
|
+
* prerendering costs nothing after the build.
|
|
543
|
+
*
|
|
544
|
+
* The price is that the routes must be known up front. That is the case of a
|
|
545
|
+
* marketing site, which is what this command serves.
|
|
546
|
+
*
|
|
547
|
+
* @module
|
|
548
|
+
*/
|
|
549
|
+
|
|
550
|
+
/** What a server entry may return. */
|
|
551
|
+
type RouteRender = string | {
|
|
552
|
+
/** The HTML placed in the application container. */
|
|
553
|
+
html: string;
|
|
554
|
+
/** Tags added to `<head>` — title, description, preview. */
|
|
555
|
+
head?: string;
|
|
556
|
+
};
|
|
557
|
+
/** What the prerender produced. */
|
|
558
|
+
interface PrerenderOutput {
|
|
559
|
+
/** The files written, relative to the output directory. */
|
|
560
|
+
readonly pages: readonly string[];
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* Renders the configured routes and writes one document per route.
|
|
564
|
+
*
|
|
565
|
+
* @param config Resolved configuration of the project.
|
|
566
|
+
* @param document The document already rewritten towards the hashed files.
|
|
567
|
+
* @param assets The addresses the client build assigned, so that the rendered
|
|
568
|
+
* HTML points at the same files.
|
|
569
|
+
*
|
|
570
|
+
* @example
|
|
571
|
+
* await prerender(config, html)
|
|
572
|
+
*/
|
|
573
|
+
declare function prerender(config: ResolvedConfig, document: string, assets?: AssetOptions): Promise<PrerenderOutput>;
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* Development server.
|
|
577
|
+
*
|
|
578
|
+
* No prior build: the browser asks for the modules one by one, as native
|
|
579
|
+
* modules, and each is compiled on demand then cached. The start time therefore
|
|
580
|
+
* does not depend on the size of the project, only on the depth of the first
|
|
581
|
+
* screen.
|
|
582
|
+
*
|
|
583
|
+
* @module
|
|
584
|
+
*/
|
|
585
|
+
|
|
586
|
+
/** Running development server. */
|
|
140
587
|
interface DevServer {
|
|
141
|
-
/**
|
|
588
|
+
/** Address to open in a browser. */
|
|
142
589
|
readonly url: string;
|
|
143
|
-
/**
|
|
590
|
+
/** Stops the server and releases the resources. */
|
|
144
591
|
close(): Promise<void>;
|
|
145
592
|
}
|
|
146
593
|
/**
|
|
147
|
-
*
|
|
594
|
+
* Starts the development server.
|
|
148
595
|
*
|
|
149
|
-
* @param config
|
|
596
|
+
* @param config Resolved configuration of the project.
|
|
150
597
|
*
|
|
151
598
|
* @example
|
|
152
599
|
* const server = await startDevServer(await loadConfig(process.cwd()))
|
|
@@ -155,66 +602,73 @@ interface DevServer {
|
|
|
155
602
|
declare function startDevServer(config: ResolvedConfig): Promise<DevServer>;
|
|
156
603
|
|
|
157
604
|
/**
|
|
158
|
-
*
|
|
605
|
+
* Production build.
|
|
159
606
|
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
* fichiers empreintes.
|
|
607
|
+
* The HTML document is the starting point: its module script tags designate the
|
|
608
|
+
* entries, and it is rewritten at the end to point at the hashed files.
|
|
163
609
|
*
|
|
164
610
|
* @module
|
|
165
611
|
*/
|
|
166
612
|
|
|
167
|
-
/**
|
|
613
|
+
/** A file produced by the build. */
|
|
168
614
|
interface BuiltFile {
|
|
169
|
-
/**
|
|
615
|
+
/** Path relative to the output directory. */
|
|
170
616
|
readonly path: string;
|
|
171
|
-
/**
|
|
617
|
+
/** Size in bytes. */
|
|
172
618
|
readonly bytes: number;
|
|
619
|
+
/**
|
|
620
|
+
* Size once compressed, for text files.
|
|
621
|
+
*
|
|
622
|
+
* That is the one that counts: no server ships uncompressed JavaScript.
|
|
623
|
+
* Announcing the raw bytes makes every bundle look three times heavier than
|
|
624
|
+
* it arrives, and makes any trade-off on weight wrong.
|
|
625
|
+
*/
|
|
626
|
+
readonly gzip?: number;
|
|
173
627
|
}
|
|
174
|
-
/**
|
|
628
|
+
/** Result of a production build. */
|
|
175
629
|
interface BuildOutput {
|
|
176
|
-
/**
|
|
630
|
+
/** Output directory. */
|
|
177
631
|
readonly outDir: string;
|
|
178
|
-
/**
|
|
632
|
+
/** Files produced, from largest to smallest. */
|
|
179
633
|
readonly files: readonly BuiltFile[];
|
|
180
|
-
/**
|
|
634
|
+
/** Total duration, in milliseconds. */
|
|
181
635
|
readonly elapsed: number;
|
|
182
636
|
}
|
|
183
637
|
/**
|
|
184
|
-
*
|
|
638
|
+
* Builds a project for production.
|
|
185
639
|
*
|
|
186
|
-
* @param config
|
|
640
|
+
* @param config Resolved configuration of the project.
|
|
187
641
|
*
|
|
188
642
|
* @example
|
|
189
643
|
* const output = await buildProject(await loadConfig(process.cwd()))
|
|
190
644
|
*/
|
|
191
645
|
declare function buildProject(config: ResolvedConfig): Promise<BuildOutput>;
|
|
192
|
-
/**
|
|
646
|
+
/** Prints the summary of a build. */
|
|
193
647
|
declare function reportBuild(output: BuildOutput, root: string): void;
|
|
194
648
|
|
|
195
649
|
/**
|
|
196
|
-
*
|
|
650
|
+
* Preview server for the production build.
|
|
197
651
|
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
*
|
|
652
|
+
* It builds nothing: it serves the output directory as it is, with the same
|
|
653
|
+
* single-page application fallback a static host uses. This is the last safety
|
|
654
|
+
* net before a deployment.
|
|
201
655
|
*
|
|
202
656
|
* @module
|
|
203
657
|
*/
|
|
204
658
|
|
|
205
|
-
/**
|
|
659
|
+
/** Running preview server. */
|
|
206
660
|
interface PreviewServer {
|
|
207
|
-
/**
|
|
661
|
+
/** Address to open in a browser. */
|
|
208
662
|
readonly url: string;
|
|
209
|
-
/**
|
|
663
|
+
/** Stops the server. */
|
|
210
664
|
close(): Promise<void>;
|
|
211
665
|
}
|
|
212
666
|
/**
|
|
213
|
-
*
|
|
667
|
+
* Starts the preview server.
|
|
214
668
|
*
|
|
215
|
-
* @param config
|
|
216
|
-
* @param port Port
|
|
217
|
-
*
|
|
669
|
+
* @param config Resolved configuration of the project.
|
|
670
|
+
* @param port Port to listen on. By default, the development server port plus
|
|
671
|
+
* one, so that both can run.
|
|
218
672
|
*
|
|
219
673
|
* @example
|
|
220
674
|
* const preview = await startPreviewServer(config)
|
|
@@ -222,158 +676,156 @@ interface PreviewServer {
|
|
|
222
676
|
declare function startPreviewServer(config: ResolvedConfig, port?: number): Promise<PreviewServer>;
|
|
223
677
|
|
|
224
678
|
/**
|
|
225
|
-
*
|
|
679
|
+
* Graph of the served modules.
|
|
226
680
|
*
|
|
227
|
-
*
|
|
228
|
-
*
|
|
681
|
+
* It answers a single question, but the most important one in hot development:
|
|
682
|
+
* when this file changes, what has to be reloaded?
|
|
229
683
|
*
|
|
230
684
|
* @module
|
|
231
685
|
*/
|
|
232
|
-
/**
|
|
686
|
+
/** A module known to the server. */
|
|
233
687
|
interface ModuleNode {
|
|
234
|
-
/**
|
|
688
|
+
/** Absolute path of the file. */
|
|
235
689
|
readonly file: string;
|
|
236
|
-
/** URL
|
|
690
|
+
/** URL the module is served under. */
|
|
237
691
|
readonly url: string;
|
|
238
|
-
/** Modules
|
|
692
|
+
/** Modules that import this one. */
|
|
239
693
|
readonly importers: Set<string>;
|
|
240
|
-
/** Modules
|
|
694
|
+
/** Modules imported by this one. */
|
|
241
695
|
readonly imported: Set<string>;
|
|
242
696
|
/**
|
|
243
|
-
* `true`
|
|
697
|
+
* `true` when the module declares that it accepts its own updates through
|
|
244
698
|
* `import.meta.hot.accept()`.
|
|
245
699
|
*/
|
|
246
700
|
selfAccepting: boolean;
|
|
247
|
-
/**
|
|
701
|
+
/** Transformed code, or `undefined` when the module must be rebuilt. */
|
|
248
702
|
code: string | undefined;
|
|
249
|
-
/**
|
|
703
|
+
/** Timestamp of the last invalidation, used to break the cache. */
|
|
250
704
|
timestamp: number;
|
|
251
705
|
}
|
|
252
706
|
/**
|
|
253
|
-
*
|
|
707
|
+
* Detects whether a source declares that it accepts its own updates.
|
|
254
708
|
*
|
|
255
|
-
*
|
|
256
|
-
*
|
|
257
|
-
*
|
|
258
|
-
*
|
|
709
|
+
* The analysis is deliberately textual. A full syntactic analysis would be
|
|
710
|
+
* safer, but `import.meta.hot.accept` is too distinctive a formula to appear by
|
|
711
|
+
* accident, and the cost of a false positive is limited to an update where a
|
|
712
|
+
* reload would have been enough.
|
|
259
713
|
*
|
|
260
714
|
* @example
|
|
261
715
|
* detectSelfAccepting('import.meta.hot?.accept()') // true
|
|
262
716
|
*/
|
|
263
717
|
declare function detectSelfAccepting(source: string): boolean;
|
|
264
|
-
/**
|
|
718
|
+
/** Graph of the modules and of their import relations. */
|
|
265
719
|
declare class ModuleGraph {
|
|
266
720
|
private readonly nodes;
|
|
267
|
-
/**
|
|
721
|
+
/** Gets a module, or creates it when it is unknown. */
|
|
268
722
|
ensure(file: string, url: string): ModuleNode;
|
|
269
|
-
/**
|
|
723
|
+
/** Gets a module already known. */
|
|
270
724
|
get(file: string): ModuleNode | undefined;
|
|
271
|
-
/**
|
|
725
|
+
/** Number of known modules. */
|
|
272
726
|
get size(): number;
|
|
273
727
|
/**
|
|
274
|
-
*
|
|
275
|
-
*
|
|
728
|
+
* Replaces the dependency list of a module, keeping the reverse relations up
|
|
729
|
+
* to date.
|
|
276
730
|
*/
|
|
277
731
|
setDependencies(file: string, dependencies: readonly string[]): void;
|
|
278
732
|
/**
|
|
279
|
-
*
|
|
280
|
-
*
|
|
733
|
+
* Invalidates a module and climbs the chain of its importers until it finds,
|
|
734
|
+
* on every branch, a module that accepts updates.
|
|
281
735
|
*
|
|
282
|
-
* @returns
|
|
283
|
-
*
|
|
736
|
+
* @returns The modules to reload on the client side. An empty array means
|
|
737
|
+
* that no boundary accepts the update: the page must be reloaded.
|
|
284
738
|
*
|
|
285
739
|
* @example
|
|
286
|
-
* const boundaries = graph.invalidate('/
|
|
740
|
+
* const boundaries = graph.invalidate('/project/src/App.css')
|
|
287
741
|
*/
|
|
288
742
|
invalidate(file: string): ModuleNode[];
|
|
289
|
-
/**
|
|
743
|
+
/** Forgets every module. */
|
|
290
744
|
clear(): void;
|
|
291
745
|
}
|
|
292
746
|
|
|
293
747
|
/**
|
|
294
|
-
* Transformation
|
|
748
|
+
* Transformation of the modules served in development.
|
|
295
749
|
*
|
|
296
|
-
*
|
|
297
|
-
*
|
|
298
|
-
*
|
|
299
|
-
*
|
|
750
|
+
* The browser can read neither TypeScript, nor JSX, nor bare import specifiers
|
|
751
|
+
* (`import React from 'react'`). Every requested module is therefore compiled
|
|
752
|
+
* on the fly and its imports are rewritten into URLs the server knows how to
|
|
753
|
+
* resolve.
|
|
300
754
|
*
|
|
301
|
-
*
|
|
302
|
-
*
|
|
303
|
-
*
|
|
304
|
-
*
|
|
305
|
-
*
|
|
306
|
-
* complete.
|
|
755
|
+
* The rewriting is not done with regular expressions — a string containing the
|
|
756
|
+
* word `import` would be enough to defeat it. We lean on the resolver of the
|
|
757
|
+
* bundler itself: every import is resolved then **marked external**, so that
|
|
758
|
+
* nothing is inlined but all the paths come out rewritten, with the same
|
|
759
|
+
* accuracy as a full build.
|
|
307
760
|
*
|
|
308
761
|
* @module
|
|
309
762
|
*/
|
|
310
763
|
|
|
311
764
|
/**
|
|
312
|
-
*
|
|
765
|
+
* Compiled file name matching a dependency specifier.
|
|
313
766
|
*
|
|
314
|
-
*
|
|
315
|
-
*
|
|
316
|
-
* `import './chunk-X.js'`
|
|
317
|
-
*
|
|
767
|
+
* The name is **flattened**: that is what makes the served URL free of any
|
|
768
|
+
* directory segment. A module served under `/@deps/react-dom/client` would
|
|
769
|
+
* resolve its own `import './chunk-X.js'` to `/@deps/react-dom/chunk-X.js`,
|
|
770
|
+
* whereas the chunk is dropped at the root of the cache.
|
|
318
771
|
*
|
|
319
772
|
* @example
|
|
320
773
|
* depFileName('react-dom/client') // 'react-dom_client.js'
|
|
321
|
-
* depFileName('@scope/
|
|
774
|
+
* depFileName('@scope/package') // 'scope_package.js'
|
|
322
775
|
*/
|
|
323
776
|
declare function depFileName(specifier: string): string;
|
|
324
777
|
|
|
325
778
|
/**
|
|
326
|
-
*
|
|
779
|
+
* Prebundling of the dependencies.
|
|
327
780
|
*
|
|
328
|
-
*
|
|
781
|
+
* Two reasons make it indispensable, and not optional:
|
|
329
782
|
*
|
|
330
|
-
* 1.
|
|
331
|
-
*
|
|
332
|
-
* 2.
|
|
333
|
-
*
|
|
783
|
+
* 1. many packages are still distributed only as CommonJS modules, which the
|
|
784
|
+
* browser cannot load;
|
|
785
|
+
* 2. a dependency split into hundreds of small files would trigger as many
|
|
786
|
+
* requests on the first load.
|
|
334
787
|
*
|
|
335
|
-
*
|
|
336
|
-
*
|
|
337
|
-
*
|
|
338
|
-
*
|
|
339
|
-
*
|
|
340
|
-
* partage, et l'instance reste unique.
|
|
788
|
+
* The trap lies elsewhere: if `react` and `react-dom/client` were bundled
|
|
789
|
+
* separately, each would carry its own copy of React. Two instances of React in
|
|
790
|
+
* the same page break hooks and contexts, with baffling symptoms. Every
|
|
791
|
+
* specifier is therefore **bundled in a single pass**, with splitting: the
|
|
792
|
+
* common code ends up in a shared chunk, and the instance stays unique.
|
|
341
793
|
*
|
|
342
794
|
* @module
|
|
343
795
|
*/
|
|
344
796
|
|
|
345
|
-
/**
|
|
797
|
+
/** Result of the prebundling. */
|
|
346
798
|
interface OptimizedDeps {
|
|
347
|
-
/**
|
|
799
|
+
/** Directory holding the bundled modules. */
|
|
348
800
|
readonly directory: string;
|
|
349
|
-
/**
|
|
801
|
+
/** Specifiers available. */
|
|
350
802
|
readonly specifiers: readonly string[];
|
|
351
|
-
/** `true`
|
|
803
|
+
/** `true` when a build actually took place. */
|
|
352
804
|
readonly rebuilt: boolean;
|
|
353
805
|
}
|
|
354
806
|
/**
|
|
355
|
-
*
|
|
356
|
-
*
|
|
807
|
+
* Walks the project code looking for the dependencies actually imported,
|
|
808
|
+
* transitively.
|
|
357
809
|
*
|
|
358
|
-
*
|
|
359
|
-
* application
|
|
810
|
+
* Relying on the `dependencies` field of the manifest would not be enough: an
|
|
811
|
+
* application imports `react-dom/client`, never plain `react-dom`.
|
|
360
812
|
*
|
|
361
|
-
* @param entries
|
|
813
|
+
* @param entries Entry points of the project, as absolute paths.
|
|
362
814
|
*
|
|
363
815
|
* @example
|
|
364
|
-
* const specifiers = await scanDependencies(config, ['/
|
|
816
|
+
* const specifiers = await scanDependencies(config, ['/project/src/main.tsx'])
|
|
365
817
|
*/
|
|
366
818
|
declare function scanDependencies(config: ResolvedConfig, entries: readonly string[]): Promise<string[]>;
|
|
367
819
|
/**
|
|
368
|
-
*
|
|
820
|
+
* Bundles a set of specifiers in a single pass.
|
|
369
821
|
*
|
|
370
|
-
* @param config
|
|
371
|
-
* @param specifiers
|
|
372
|
-
* @param force
|
|
822
|
+
* @param config Resolved configuration of the project.
|
|
823
|
+
* @param specifiers Specifiers to bundle.
|
|
824
|
+
* @param force Rebuilds even when the cache looks valid.
|
|
373
825
|
*
|
|
374
826
|
* @example
|
|
375
827
|
* const deps = await optimizeDeps(config, ['react', 'react-dom/client'])
|
|
376
828
|
*/
|
|
377
829
|
declare function optimizeDeps(config: ResolvedConfig, specifiers: readonly string[], force?: boolean): Promise<OptimizedDeps>;
|
|
378
830
|
|
|
379
|
-
export { type BuildConfig, type BuildOutput, type BuiltFile, type DevServer, ModuleGraph, type ModuleNode, type OdoroConfig, type OptimizedDeps, type PreviewServer, type ResolvedConfig, type ServerConfig, buildProject, defineConfig, depFileName, detectSelfAccepting, loadConfig, optimizeDeps, reportBuild, scanDependencies, startDevServer, startPreviewServer };
|
|
831
|
+
export { type BuildConfig, type BuildOutput, type BuiltFile, type DevServer, type HtmlContext, type HttpsConfig, type LoadedEnv, type Manifest, type ManifestEntry, type Middleware, ModuleGraph, type ModuleNode, type OdoroConfig, type OdoroPlugin, type OptimizedDeps, type PrerenderConfig, type PrerenderOutput, type PreviewServer, type ResolvedBuild, type ResolvedConfig, type ResolvedPrerender, type RouteRender, type ServerConfig, type ServerContext, type TransformContext, buildManifest, buildProject, chunksFor, clientEnv, defineConfig, depFileName, detectSelfAccepting, hasGlob, loadConfig, loadEnv, optimizeDeps, prerender, reportBuild, scanDependencies, startDevServer, startPreviewServer, transformGlob };
|