@adonisjs/vite 5.1.0 → 6.0.0-next.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.
@@ -0,0 +1,630 @@
1
+ import { n as makeAttributes, r as uniqBy } from "./utils-CdZpa_tV.js";
2
+ import { join } from "node:path";
3
+ import string from "@poppinss/utils/string";
4
+ import { existsSync, readFileSync } from "node:fs";
5
+ import { pathToFileURL } from "node:url";
6
+ //#region src/server_modules/dev_module_runner.ts
7
+ /**
8
+ * Hosts the Vite `ModuleRunner` used to evaluate server-side modules in
9
+ * development mode.
10
+ *
11
+ * Owns a single shared runner across all `loadServerModule` calls, and
12
+ * detects Vite dev server restarts (which replace `server.environments.ssr`
13
+ * with a fresh instance) so the stale runner is closed and recreated.
14
+ */
15
+ var DevModuleRunner = class {
16
+ /**
17
+ * Shared module runner. Lazy-created on first import.
18
+ */
19
+ #runner;
20
+ /**
21
+ * Reference to the SSR environment the current runner was created from.
22
+ * When Vite restarts the dev server, `server.environments.ssr` is
23
+ * replaced — we use this reference to detect that and recreate.
24
+ */
25
+ #ssrEnvironment;
26
+ /**
27
+ * Factory provided by the orchestrator to lazily create the runner.
28
+ * Indirection keeps this class decoupled from how the runner is built.
29
+ */
30
+ #createRunner;
31
+ constructor(createRunner) {
32
+ this.#createRunner = createRunner;
33
+ }
34
+ /**
35
+ * Imports a module through the runner. Recreates the runner if the
36
+ * dev server's SSR environment was swapped underneath us.
37
+ */
38
+ async import(server, entry, opts) {
39
+ const currentSsrEnv = server.environments.ssr;
40
+ if (this.#ssrEnvironment !== currentSsrEnv) {
41
+ if (this.#runner) await this.#runner.close();
42
+ this.#runner = void 0;
43
+ this.#ssrEnvironment = currentSsrEnv;
44
+ }
45
+ this.#runner ??= await this.#createRunner();
46
+ if (opts.fresh) this.#runner.clearCache();
47
+ return this.#runner.import(entry);
48
+ }
49
+ /**
50
+ * Closes the runner, if any. Safe to call when no runner has been
51
+ * created yet.
52
+ */
53
+ async close() {
54
+ if (this.#runner) {
55
+ await this.#runner.close();
56
+ this.#runner = void 0;
57
+ this.#ssrEnvironment = void 0;
58
+ }
59
+ }
60
+ };
61
+ //#endregion
62
+ //#region src/server_modules/bundled_module_resolver.ts
63
+ /**
64
+ * Resolves and imports server-side modules from the production SSR build.
65
+ *
66
+ * In production there is no Vite dev server — entrypoints declared as
67
+ * `serverEntrypoints` are pre-built into `<buildDirectory>/server` and
68
+ * recorded in `<buildDirectory>/server/.vite/manifest.json`. The
69
+ * resolver reads that manifest to map an entry source path to the
70
+ * emitted bundle file, then imports it through Node's native `import()`.
71
+ *
72
+ * Imports are cached per entry so repeated calls reuse the same module
73
+ * instance and side-effects only run once.
74
+ */
75
+ var BundledModuleResolver = class {
76
+ /**
77
+ * Absolute path to `<buildDirectory>/server`.
78
+ */
79
+ #serverDir;
80
+ /**
81
+ * Cache of in-flight or resolved module imports, keyed by entry.
82
+ * Stores the promise so concurrent callers share the same import.
83
+ */
84
+ #cache = /* @__PURE__ */ new Map();
85
+ /**
86
+ * Lazily-loaded manifest contents. Loaded once on first import call.
87
+ */
88
+ #manifest;
89
+ constructor(buildDirectory) {
90
+ this.#serverDir = join(buildDirectory, "server");
91
+ }
92
+ async import(entry) {
93
+ let pending = this.#cache.get(entry);
94
+ if (!pending) {
95
+ const chunk = this.#readManifest()[entry];
96
+ if (!chunk) throw new Error(`Cannot loadServerModule("${entry}"): no chunk for this entry in the SSR manifest. Make sure the entry is declared in serverEntrypoints and the application has been rebuilt.`);
97
+ pending = import(pathToFileURL(join(this.#serverDir, chunk.file)).href);
98
+ this.#cache.set(entry, pending);
99
+ }
100
+ return pending;
101
+ }
102
+ #readManifest() {
103
+ if (this.#manifest) return this.#manifest;
104
+ const manifestPath = join(this.#serverDir, ".vite/manifest.json");
105
+ if (!existsSync(manifestPath)) throw new Error(`SSR manifest not found at ${manifestPath}. Build the application with at least one declared serverEntrypoint before loading server modules.`);
106
+ this.#manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
107
+ return this.#manifest;
108
+ }
109
+ };
110
+ //#endregion
111
+ //#region src/server_modules/server_module_loader.ts
112
+ /**
113
+ * Public entry point for loading server-side modules processed by Vite.
114
+ *
115
+ * Picks between two collaborators based on whether the Vite dev server
116
+ * is running:
117
+ *
118
+ * - In development, delegates to {@link DevModuleRunner} which evaluates
119
+ * the entry through Vite's `ModuleRunner`, with HMR-driven cache
120
+ * invalidation.
121
+ * - In production, delegates to {@link BundledModuleResolver} which
122
+ * imports the pre-built bundle from disk.
123
+ *
124
+ * Entry strings are passed through verbatim to mirror how client
125
+ * `entrypoints` are handled — the caller is responsible for using the
126
+ * exact string declared in `serverEntrypoints`.
127
+ */
128
+ var ServerModuleLoader = class {
129
+ #getDevServer;
130
+ #devRunner;
131
+ #bundled;
132
+ constructor(getDevServer, buildDirectory, createRunner) {
133
+ this.#getDevServer = getDevServer;
134
+ this.#devRunner = new DevModuleRunner(createRunner);
135
+ this.#bundled = new BundledModuleResolver(buildDirectory);
136
+ }
137
+ async load(entry, opts = {}) {
138
+ const server = this.#getDevServer();
139
+ if (server) return this.#devRunner.import(server, entry, opts);
140
+ return this.#bundled.import(entry);
141
+ }
142
+ async close() {
143
+ await this.#devRunner.close();
144
+ }
145
+ };
146
+ //#endregion
147
+ //#region src/vite.ts
148
+ const STYLE_FILE_REGEX = /\.(css|less|sass|scss|styl|stylus|pcss|postcss)($|\?)/;
149
+ /**
150
+ * Vite class exposes the APIs to generate tags and URLs for
151
+ * assets processed using vite.
152
+ */
153
+ var Vite = class {
154
+ /**
155
+ * We cache the manifest file content in production
156
+ * to avoid reading the file multiple times
157
+ */
158
+ #manifestCache;
159
+ #options;
160
+ #devServer;
161
+ /**
162
+ * Loads server-side TypeScript modules through Vite. Picks between
163
+ * the dev `ModuleRunner` and the production SSR bundle automatically.
164
+ */
165
+ #serverModuleLoader;
166
+ /**
167
+ * Indicates whether the Vite manifest file exists on disk
168
+ */
169
+ hasManifestFile;
170
+ get useDevServer() {
171
+ return !!this.#devServer;
172
+ }
173
+ /**
174
+ * Creates a new Vite instance for managing asset compilation and serving
175
+ *
176
+ * @param options - Configuration options for Vite integration
177
+ *
178
+ * @example
179
+ * const vite = new Vite({
180
+ * buildDirectory: 'build',
181
+ * assetsUrl: '/assets',
182
+ * manifestFile: 'build/manifest.json'
183
+ * })
184
+ */
185
+ constructor(options) {
186
+ this.#options = options;
187
+ this.#options.assetsUrl = (this.#options.assetsUrl || "/").replace(/\/$/, "");
188
+ this.hasManifestFile = existsSync(this.#options.manifestFile);
189
+ this.#serverModuleLoader = new ServerModuleLoader(() => this.#devServer, this.#options.buildDirectory, () => this.createModuleRunner());
190
+ }
191
+ /**
192
+ * Reads the file contents as JSON
193
+ */
194
+ #readFileAsJSON(filePath) {
195
+ return JSON.parse(readFileSync(filePath, "utf-8"));
196
+ }
197
+ /**
198
+ * Generates a JSON element with a custom toString implementation
199
+ */
200
+ #generateElement(element) {
201
+ return {
202
+ ...element,
203
+ toString() {
204
+ const attributes = `${makeAttributes(element.attributes)}`;
205
+ if (element.tag === "link") return `<${element.tag} ${attributes}/>`;
206
+ return `<${element.tag} ${attributes}>${element.children.join("\n")}</${element.tag}>`;
207
+ }
208
+ };
209
+ }
210
+ /**
211
+ * Returns the script needed for the HMR working with Vite
212
+ */
213
+ #getViteHmrScript(attributes) {
214
+ return this.#generateElement({
215
+ tag: "script",
216
+ attributes: {
217
+ type: "module",
218
+ src: "/@vite/client",
219
+ ...attributes
220
+ },
221
+ children: []
222
+ });
223
+ }
224
+ /**
225
+ * Check if the given path is a CSS path
226
+ */
227
+ #isCssPath(path) {
228
+ return path.match(STYLE_FILE_REGEX) !== null;
229
+ }
230
+ /**
231
+ * If the module is a style module
232
+ */
233
+ #isStyleModule(mod) {
234
+ if (this.#isCssPath(mod.url) || mod.id && /\?vue&type=style/.test(mod.id)) return true;
235
+ return false;
236
+ }
237
+ /**
238
+ * Unwrap attributes from the user defined function or return
239
+ * the attributes as it is
240
+ */
241
+ #unwrapAttributes(src, url, attributes) {
242
+ if (typeof attributes === "function") return attributes({
243
+ src,
244
+ url
245
+ });
246
+ return attributes;
247
+ }
248
+ /**
249
+ * Create a style tag for the given path
250
+ */
251
+ #makeStyleTag(src, url, attributes) {
252
+ const customAttributes = this.#unwrapAttributes(src, url, this.#options?.styleAttributes);
253
+ return this.#generateElement({
254
+ tag: "link",
255
+ attributes: {
256
+ rel: "stylesheet",
257
+ ...customAttributes,
258
+ ...attributes,
259
+ href: url
260
+ }
261
+ });
262
+ }
263
+ /**
264
+ * Create a script tag for the given path
265
+ */
266
+ #makeScriptTag(src, url, attributes) {
267
+ const customAttributes = this.#unwrapAttributes(src, url, this.#options?.scriptAttributes);
268
+ return this.#generateElement({
269
+ tag: "script",
270
+ attributes: {
271
+ type: "module",
272
+ ...customAttributes,
273
+ ...attributes,
274
+ src: url
275
+ },
276
+ children: []
277
+ });
278
+ }
279
+ /**
280
+ * Generate an asset URL for a given asset path
281
+ */
282
+ #generateAssetUrl(path) {
283
+ return `${this.#options.assetsUrl}/${path}`;
284
+ }
285
+ /**
286
+ * Generate a HTML tag for the given asset
287
+ */
288
+ #generateTag(asset, attributes) {
289
+ let url = "";
290
+ if (this.useDevServer) url = `/${asset}`;
291
+ else url = this.#generateAssetUrl(asset);
292
+ if (this.#isCssPath(asset)) return this.#makeStyleTag(asset, url, attributes);
293
+ return this.#makeScriptTag(asset, url, attributes);
294
+ }
295
+ /**
296
+ * Collect CSS files from the module graph recursively
297
+ */
298
+ #collectCss(mod, styleUrls, visitedModules, importer) {
299
+ if (!mod.url) return;
300
+ /**
301
+ * Prevent visiting the same module twice
302
+ */
303
+ if (visitedModules.has(mod.url)) return;
304
+ visitedModules.add(mod.url);
305
+ if (this.#isStyleModule(mod) && (!importer || !this.#isStyleModule(importer))) if (mod.url.startsWith("/")) styleUrls.add(mod.url);
306
+ else if (mod.url.startsWith("\0")) styleUrls.add(`/@id/__x00__${mod.url.substring(1)}`);
307
+ else styleUrls.add(`/@id/${mod.url}`);
308
+ mod.importedModules.forEach((dep) => this.#collectCss(dep, styleUrls, visitedModules, mod));
309
+ }
310
+ /**
311
+ * Generate style and script tags for the given entrypoints
312
+ * Also adds the @vite/client script
313
+ */
314
+ async #generateEntryPointsTagsForDevMode(entryPoints, attributes) {
315
+ const server = this.getDevServer();
316
+ const tags = entryPoints.map((entrypoint) => this.#generateTag(entrypoint, attributes));
317
+ const jsEntrypoints = entryPoints.filter((entrypoint) => !this.#isCssPath(entrypoint));
318
+ /**
319
+ * If the client module graph is empty, that means we didn't execute the
320
+ * entrypoint yet : we just started the AdonisJS dev server. So let's
321
+ * execute the entrypoints to populate the client module graph.
322
+ *
323
+ * Use the per-environment client graph instead of the backward-compat
324
+ * `server.moduleGraph` union (client + ssr). Otherwise an SSR runner
325
+ * (e.g. @adonisjs/inertia rendering before @vite()) populates the ssr
326
+ * graph, the union check returns non-empty, the client warmup is
327
+ * skipped, and no <link rel="stylesheet"> tags are emitted.
328
+ */
329
+ if (server?.environments.client.moduleGraph.idToModuleMap.size === 0) await Promise.allSettled(jsEntrypoints.map((entrypoint) => server.warmupRequest(`/${entrypoint}`)));
330
+ /**
331
+ * We need to collect the CSS files imported by the entrypoints
332
+ * Otherwise, we gonna have a FOUC each time we full reload the page
333
+ */
334
+ const preloadUrls = /* @__PURE__ */ new Set();
335
+ const visitedModules = /* @__PURE__ */ new Set();
336
+ const cssTagsElement = /* @__PURE__ */ new Set();
337
+ /**
338
+ * Let's search for the CSS files by browsing the module graph
339
+ * generated by Vite.
340
+ */
341
+ for (const entryPoint of jsEntrypoints) {
342
+ const filePath = join(server.config.root, entryPoint);
343
+ const entryMod = server.environments.client.moduleGraph.getModuleById(string.toUnixSlash(filePath));
344
+ if (entryMod) this.#collectCss(entryMod, preloadUrls, visitedModules);
345
+ }
346
+ Array.from(preloadUrls).map((href) => this.#generateElement({
347
+ tag: "link",
348
+ attributes: {
349
+ rel: "stylesheet",
350
+ href
351
+ }
352
+ })).forEach((element) => cssTagsElement.add(element));
353
+ const viteHmr = this.#getViteHmrScript(attributes);
354
+ return [...cssTagsElement, viteHmr].concat(tags).sort((tag) => tag.tag === "link" ? -1 : 1);
355
+ }
356
+ /**
357
+ * Get a chunk from the manifest file for a given file name
358
+ */
359
+ #chunk(manifest, entrypoint) {
360
+ const chunk = manifest[entrypoint];
361
+ if (!chunk) throw new Error(`Cannot find "${entrypoint}" chunk in the manifest file`);
362
+ return chunk;
363
+ }
364
+ /**
365
+ * Get a list of chunks for a given filename
366
+ */
367
+ #chunksByFile(manifest, file) {
368
+ return Object.entries(manifest).filter(([, chunk]) => chunk.file === file).map(([_, chunk]) => chunk);
369
+ }
370
+ /**
371
+ * Generate preload tag for a given url
372
+ */
373
+ #makePreloadTagForUrl(url) {
374
+ const attributes = this.#isCssPath(url) ? {
375
+ rel: "preload",
376
+ as: "style",
377
+ href: url
378
+ } : {
379
+ rel: "modulepreload",
380
+ href: url
381
+ };
382
+ return this.#generateElement({
383
+ tag: "link",
384
+ attributes
385
+ });
386
+ }
387
+ /**
388
+ * Generate style and script tags for the given entrypoints
389
+ * using the manifest file
390
+ */
391
+ #generateEntryPointsTagsWithManifest(entryPoints, attributes) {
392
+ const manifest = this.manifest();
393
+ const tags = [];
394
+ const preloads = [];
395
+ for (const entryPoint of entryPoints) {
396
+ /**
397
+ * 1. We generate tags + modulepreload for the entrypoint
398
+ */
399
+ const chunk = this.#chunk(manifest, entryPoint);
400
+ preloads.push({ path: this.#generateAssetUrl(chunk.file) });
401
+ tags.push({
402
+ path: chunk.file,
403
+ tag: this.#generateTag(chunk.file, {
404
+ ...attributes,
405
+ integrity: chunk.integrity
406
+ })
407
+ });
408
+ /**
409
+ * 2. We go through the CSS files that are imported by the entrypoint
410
+ * and generate tags + preload for them
411
+ */
412
+ for (const css of chunk.css || []) {
413
+ preloads.push({ path: this.#generateAssetUrl(css) });
414
+ tags.push({
415
+ path: css,
416
+ tag: this.#generateTag(css)
417
+ });
418
+ }
419
+ /**
420
+ * 3. We go through every import of the entrypoint and generate preload
421
+ */
422
+ for (const importNode of chunk.imports || []) {
423
+ preloads.push({ path: this.#generateAssetUrl(manifest[importNode].file) });
424
+ /**
425
+ * 4. Finally, we generate tags + preload for the CSS files imported by the import
426
+ * of the entrypoint
427
+ */
428
+ for (const css of manifest[importNode].css || []) {
429
+ const subChunk = this.#chunksByFile(manifest, css);
430
+ preloads.push({ path: this.#generateAssetUrl(css) });
431
+ tags.push({
432
+ path: this.#generateAssetUrl(css),
433
+ tag: this.#generateTag(css, {
434
+ ...attributes,
435
+ integrity: subChunk[0]?.integrity
436
+ })
437
+ });
438
+ }
439
+ }
440
+ }
441
+ /**
442
+ * And finally, we return the preloads + script and link tags
443
+ */
444
+ return uniqBy(preloads, "path").sort((preload) => this.#isCssPath(preload.path) ? -1 : 1).map((preload) => this.#makePreloadTagForUrl(preload.path)).concat(tags.map(({ tag }) => tag));
445
+ }
446
+ /**
447
+ * Generate HTML tags (script and link) for the specified entry points
448
+ *
449
+ * In development mode, includes HMR script and dynamically discovers CSS files.
450
+ * In production mode, uses the manifest file to generate optimized tags with preloading.
451
+ *
452
+ * @param entryPoints - Single entry point or array of entry points to generate tags for
453
+ * @param attributes - Additional HTML attributes to apply to the generated tags
454
+ *
455
+ * @example
456
+ * // Generate tags for a single entry point
457
+ * const tags = await vite.generateEntryPointsTags('app.js')
458
+ *
459
+ * @example
460
+ * // Generate tags for multiple entry points with custom attributes
461
+ * const tags = await vite.generateEntryPointsTags(
462
+ * ['app.js', 'admin.js'],
463
+ * { defer: true }
464
+ * )
465
+ */
466
+ async generateEntryPointsTags(entryPoints, attributes) {
467
+ entryPoints = Array.isArray(entryPoints) ? entryPoints : [entryPoints];
468
+ if (this.useDevServer) return this.#generateEntryPointsTagsForDevMode(entryPoints, attributes);
469
+ return this.#generateEntryPointsTagsWithManifest(entryPoints, attributes);
470
+ }
471
+ /**
472
+ * Returns the base URL for serving static assets
473
+ *
474
+ * @example
475
+ * const url = vite.assetsUrl()
476
+ * // Returns: '/assets' or '/build' depending on configuration
477
+ */
478
+ assetsUrl() {
479
+ return this.#options.assetsUrl;
480
+ }
481
+ /**
482
+ * Returns the full URL path to a specific asset file
483
+ *
484
+ * In development mode, returns the asset path with leading slash.
485
+ * In production mode, uses the manifest file to return the versioned/hashed asset URL.
486
+ *
487
+ * @param asset - The relative path to the asset file
488
+ *
489
+ * @example
490
+ * const path = vite.assetPath('images/logo.png')
491
+ * // Dev: '/images/logo.png'
492
+ * // Prod: '/assets/images/logo-abc123.png'
493
+ */
494
+ assetPath(asset) {
495
+ if (this.useDevServer) return `/${asset}`;
496
+ const chunk = this.#chunk(this.manifest(), asset);
497
+ return this.#generateAssetUrl(chunk.file);
498
+ }
499
+ /**
500
+ * Returns the parsed Vite manifest file contents
501
+ *
502
+ * The manifest file contains information about compiled assets including
503
+ * file paths, integrity hashes, and import dependencies.
504
+ *
505
+ * @throws Will throw an exception when running in development mode
506
+ *
507
+ * @example
508
+ * const manifest = vite.manifest()
509
+ * console.log(manifest['app.js'].file) // 'assets/app-abc123.js'
510
+ */
511
+ manifest() {
512
+ if (this.useDevServer) throw new Error("Cannot read the manifest file when running in dev mode");
513
+ if (!this.hasManifestFile) throw new Error("Missing manifest file. Make sure to first create a build");
514
+ if (!this.#manifestCache) this.#manifestCache = this.#readFileAsJSON(this.#options.manifestFile);
515
+ return this.#manifestCache;
516
+ }
517
+ /**
518
+ * Creates and initializes the Vite development server
519
+ *
520
+ * Lazy loads Vite APIs to avoid importing them in production.
521
+ * The server runs in middleware mode and is configured for custom app integration.
522
+ *
523
+ * @param options - Additional Vite configuration options to merge with defaults
524
+ *
525
+ * @example
526
+ * await vite.createDevServer({
527
+ * root: './src',
528
+ * server: { port: 3000 }
529
+ * })
530
+ */
531
+ async createDevServer(options) {
532
+ const { createServer } = await import("vite");
533
+ const hmrPort = Number(process.env.VITE_HMR_PORT);
534
+ /**
535
+ * We do not await the server creation since it will
536
+ * slow down the boot process of AdonisJS
537
+ */
538
+ this.#devServer = await createServer({
539
+ server: {
540
+ middlewareMode: true,
541
+ ...hmrPort && !Number.isNaN(hmrPort) ? { hmr: { port: hmrPort } } : {}
542
+ },
543
+ appType: "custom",
544
+ ...options
545
+ });
546
+ }
547
+ /**
548
+ * Creates a server-side module runner for executing modules in Node.js context
549
+ *
550
+ * Only available in development mode as it requires the Vite dev server.
551
+ * Useful for server-side rendering and module transformation.
552
+ *
553
+ * @param options - Configuration options for the module runner
554
+ *
555
+ * @example
556
+ * const runner = await vite.createModuleRunner({
557
+ * hmr: { port: 24678 }
558
+ * })
559
+ * const mod = await runner.import('./app.js')
560
+ */
561
+ async createModuleRunner(options = {}) {
562
+ const { createServerModuleRunner } = await import("vite");
563
+ return createServerModuleRunner(this.#devServer.environments.ssr, options);
564
+ }
565
+ loadServerModule(entry, opts) {
566
+ return this.#serverModuleLoader.load(entry, opts);
567
+ }
568
+ /**
569
+ * Gracefully stops the Vite development server
570
+ *
571
+ * Waits for the server creation promise to complete before closing.
572
+ *
573
+ * @example
574
+ * await vite.stopDevServer()
575
+ */
576
+ async stopDevServer() {
577
+ await this.#serverModuleLoader.close();
578
+ await this.#devServer?.close();
579
+ }
580
+ /**
581
+ * Returns the Vite development server instance
582
+ *
583
+ * Only available in development mode after calling createDevServer().
584
+ * Returns undefined in production or if the server hasn't been created yet.
585
+ *
586
+ * @example
587
+ * const server = vite.getDevServer()
588
+ * if (server) {
589
+ * console.log('Dev server is running on', server.config.server.port)
590
+ * }
591
+ */
592
+ getDevServer() {
593
+ return this.#devServer;
594
+ }
595
+ /**
596
+ * Generates the React Hot Module Replacement (HMR) script for development
597
+ *
598
+ * Only returns a script element in development mode. In production mode,
599
+ * returns null since HMR is not needed.
600
+ *
601
+ * @param attributes - Additional HTML attributes to apply to the script tag
602
+ *
603
+ * @example
604
+ * const hmrScript = vite.getReactHmrScript({ async: true })
605
+ * if (hmrScript) {
606
+ * console.log(hmrScript.toString()) // <script type="module" async>...<\/script>
607
+ * }
608
+ */
609
+ getReactHmrScript(attributes) {
610
+ if (!this.useDevServer) return null;
611
+ return this.#generateElement({
612
+ tag: "script",
613
+ attributes: {
614
+ type: "module",
615
+ ...attributes
616
+ },
617
+ children: [
618
+ "",
619
+ `import RefreshRuntime from '/@react-refresh'`,
620
+ `RefreshRuntime.injectIntoGlobalHook(window)`,
621
+ `window.$RefreshReg$ = () => {}`,
622
+ `window.$RefreshSig$ = () => (type) => type`,
623
+ `window.__vite_plugin_react_preamble_installed__ = true`,
624
+ ""
625
+ ]
626
+ });
627
+ }
628
+ };
629
+ //#endregion
630
+ export { Vite as t };
@@ -0,0 +1,72 @@
1
+ //#region src/vite_middleware.ts
2
+ /**
3
+ * Middleware for proxying requests between AdonisJS and Vite development server
4
+ *
5
+ * Since Vite dev server is integrated within the AdonisJS process, this
6
+ * middleware is used to proxy the requests to it.
7
+ *
8
+ * Some of the requests are directly handled by the Vite dev server,
9
+ * like the one for the assets, while others are passed down to the
10
+ * AdonisJS server.
11
+ */
12
+ var ViteMiddleware = class {
13
+ #devServer;
14
+ /**
15
+ * Creates a new ViteMiddleware instance
16
+ *
17
+ * @param vite - The Vite instance containing the dev server
18
+ *
19
+ * @example
20
+ * const middleware = new ViteMiddleware(viteInstance)
21
+ */
22
+ constructor(vite) {
23
+ this.vite = vite;
24
+ this.#devServer = this.vite.getDevServer();
25
+ }
26
+ /**
27
+ * Handles HTTP requests by proxying them to the Vite dev server when appropriate
28
+ *
29
+ * @param request - The HTTP request object from AdonisJS context
30
+ * @param response - The HTTP response object from AdonisJS context
31
+ * @param next - Function to call the next middleware in the chain
32
+ *
33
+ * @example
34
+ * await middleware.handle(ctx, next)
35
+ */
36
+ async handle({ request, response }, next) {
37
+ if (!this.#devServer) return next();
38
+ return new Promise((resolve, reject) => {
39
+ function done(error) {
40
+ response.response.removeListener("finish", done);
41
+ if (error) reject(error);
42
+ else resolve();
43
+ }
44
+ /**
45
+ * When vite handles the request, we will resolve this promise after the
46
+ * response is sent.
47
+ */
48
+ response.response.addListener("finish", done);
49
+ /**
50
+ * Even if the request is not handled by Vite, we will relay headers
51
+ * to Node.js.
52
+ */
53
+ response.relayHeaders();
54
+ this.#devServer.middlewares.handle(request.request, response.response, async () => {
55
+ /**
56
+ * This callback is invoked when Vite does not handle the request. In that
57
+ * case, we will call next and resolve this promise. Also we remove the
58
+ * unneeded "finish" listener
59
+ */
60
+ response.response.removeListener("finish", done);
61
+ try {
62
+ await next();
63
+ done();
64
+ } catch (error) {
65
+ done(error);
66
+ }
67
+ });
68
+ });
69
+ }
70
+ };
71
+ //#endregion
72
+ export { ViteMiddleware as t };