@octanejs/vite-plugin 0.1.11 → 0.1.13
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/package.json +9 -9
- package/src/client-assets.js +14 -3
- package/src/index.js +65 -8
- package/types/index.d.ts +9 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@octanejs/vite-plugin",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.13",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -46,18 +46,18 @@
|
|
|
46
46
|
}
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@ripple-ts/adapter": "^0.3.
|
|
50
|
-
"@octanejs/app-core": "0.0.
|
|
49
|
+
"@ripple-ts/adapter": "^0.3.108",
|
|
50
|
+
"@octanejs/app-core": "0.0.9"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
53
53
|
"vite": "^8.0.16",
|
|
54
|
-
"octane": "0.1.
|
|
54
|
+
"octane": "0.1.13"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
|
-
"@types/node": "^24.3
|
|
58
|
-
"playwright": "^1.61.
|
|
59
|
-
"type-fest": "^5.
|
|
60
|
-
"vite": "^8.
|
|
61
|
-
"octane": "0.1.
|
|
57
|
+
"@types/node": "^24.13.3",
|
|
58
|
+
"playwright": "^1.61.1",
|
|
59
|
+
"type-fest": "^5.8.0",
|
|
60
|
+
"vite": "^8.1.5",
|
|
61
|
+
"octane": "0.1.13"
|
|
62
62
|
}
|
|
63
63
|
}
|
package/src/client-assets.js
CHANGED
|
@@ -32,9 +32,14 @@ function isDeferredHydrationId(id) {
|
|
|
32
32
|
*
|
|
33
33
|
* @param {Record<string, ViteManifestEntry>} manifest
|
|
34
34
|
* @param {string[]} moduleIds
|
|
35
|
+
* @param {Record<string, string>} [entryFiles]
|
|
35
36
|
* @returns {Record<string, { js: string, css: string[] }>}
|
|
36
37
|
*/
|
|
37
|
-
export function createClientAssetMap(manifest, moduleIds) {
|
|
38
|
+
export function createClientAssetMap(manifest, moduleIds, entryFiles = {}) {
|
|
39
|
+
const manifestKeysByFile = new Map(
|
|
40
|
+
Object.entries(manifest).map(([key, entry]) => [entry.file, key]),
|
|
41
|
+
);
|
|
42
|
+
|
|
38
43
|
/**
|
|
39
44
|
* @param {string} key
|
|
40
45
|
* @param {boolean} deferredHydrationBranch
|
|
@@ -69,9 +74,15 @@ export function createClientAssetMap(manifest, moduleIds) {
|
|
|
69
74
|
const assets = {};
|
|
70
75
|
for (const moduleId of moduleIds) {
|
|
71
76
|
// Vite manifest keys are root-relative without the leading slash.
|
|
72
|
-
const
|
|
77
|
+
const sourceKey = moduleId.startsWith('/') ? moduleId.slice(1) : moduleId;
|
|
78
|
+
// A route module that is also statically imported can become a shared
|
|
79
|
+
// non-facade chunk. Vite keys that manifest entry by generated chunk name,
|
|
80
|
+
// so use the Rollup-observed output file to recover the graph root.
|
|
81
|
+
const manifestKey = manifest[sourceKey]
|
|
82
|
+
? sourceKey
|
|
83
|
+
: manifestKeysByFile.get(entryFiles[moduleId]);
|
|
84
|
+
if (!manifestKey) continue;
|
|
73
85
|
const entry = manifest[manifestKey];
|
|
74
|
-
if (!entry) continue;
|
|
75
86
|
assets[moduleId] = {
|
|
76
87
|
js: entry.file,
|
|
77
88
|
css: [...new Set(collectCss(manifestKey, false, new Set()))],
|
package/src/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @ts-check
|
|
2
|
-
/** @import {Plugin, RenderBuiltAssetUrl, ResolvedConfig, ViteDevServer, UserConfig} from 'vite' */
|
|
2
|
+
/** @import {ModulePreloadOptions, Plugin, RenderBuiltAssetUrl, ResolvedConfig, ViteDevServer, UserConfig} from 'vite' */
|
|
3
3
|
/** @import {LoadedOctaneConfig, OctaneConfigOptions, ResolvedOctaneConfig, RenderRoute} from '@octanejs/vite-plugin' */
|
|
4
4
|
|
|
5
5
|
import fs from 'node:fs';
|
|
@@ -210,9 +210,9 @@ function collect_hydrate_module_paths(config) {
|
|
|
210
210
|
* build is redirected to `{outDir}/client` with a manifest, the hydrate entry
|
|
211
211
|
* is injected into index.html (so Vite bundles + hashes it), and closeBundle
|
|
212
212
|
* runs a second, `ssr: true` build of a generated server entry to
|
|
213
|
-
* `{outDir}/server/entry.js
|
|
214
|
-
*
|
|
215
|
-
*
|
|
213
|
+
* `{outDir}/server/entry.js`. Node-target adapters get the existing bootable
|
|
214
|
+
* `handler`/`nodeHandler` module; webworker-target adapters get an importable
|
|
215
|
+
* `createWebWorkerHandler` factory for their deployment wrapper.
|
|
216
216
|
*
|
|
217
217
|
* @param {{ hmr?: boolean, profile?: boolean, exclude?: string[], requireDirective?: boolean, renderers?: import('@octanejs/app-core').ExperimentalRendererConfigOptions }} [inlineOptions]
|
|
218
218
|
* @returns {Plugin[]}
|
|
@@ -243,6 +243,8 @@ export function octane(inlineOptions = {}) {
|
|
|
243
243
|
let buildOctaneConfig = null;
|
|
244
244
|
/** @type {string[]} Module paths the generated client entry maps statically (build only) */
|
|
245
245
|
let staticEntries = [];
|
|
246
|
+
/** @type {Record<string, string>} Static module path → emitted client chunk file */
|
|
247
|
+
let staticEntryFiles = Object.create(null);
|
|
246
248
|
/** @type {Set<string>} Vite-root paths of modules containing `module server` */
|
|
247
249
|
const serverModuleModules = new Set();
|
|
248
250
|
|
|
@@ -328,6 +330,25 @@ export function octane(inlineOptions = {}) {
|
|
|
328
330
|
if (buildOctaneConfig.build.target !== undefined) {
|
|
329
331
|
buildConfig.target = buildOctaneConfig.build.target;
|
|
330
332
|
}
|
|
333
|
+
const userModulePreload = userConfig.build?.modulePreload;
|
|
334
|
+
if (userModulePreload === false) {
|
|
335
|
+
buildConfig.modulePreload = false;
|
|
336
|
+
} else {
|
|
337
|
+
/** @type {ModulePreloadOptions} */
|
|
338
|
+
const modulePreload =
|
|
339
|
+
typeof userModulePreload === 'object' ? { ...userModulePreload } : {};
|
|
340
|
+
const userResolveDependencies = modulePreload.resolveDependencies;
|
|
341
|
+
modulePreload.resolveDependencies = (filename, dependencies, context) => {
|
|
342
|
+
// Vite 8.1 emits entry dependency hints after the entry script.
|
|
343
|
+
// A script that installs <base> in between can redirect those
|
|
344
|
+
// root-relative requests off-origin. Static imports discover the
|
|
345
|
+
// same dependencies safely from the entry module URL, so omit only
|
|
346
|
+
// the redundant HTML hints; retain JS dynamic-import preloading.
|
|
347
|
+
if (context.hostType === 'html') return [];
|
|
348
|
+
return userResolveDependencies?.(filename, dependencies, context) ?? dependencies;
|
|
349
|
+
};
|
|
350
|
+
buildConfig.modulePreload = modulePreload;
|
|
351
|
+
}
|
|
331
352
|
const userRenderBuiltUrl = userConfig.experimental?.renderBuiltUrl;
|
|
332
353
|
/** @type {RenderBuiltAssetUrl} */
|
|
333
354
|
const renderBuiltUrl = (filename, context) => {
|
|
@@ -367,6 +388,28 @@ export function octane(inlineOptions = {}) {
|
|
|
367
388
|
if (!isBuild || isSSRBuild || !has_route_config(buildOctaneConfig)) return;
|
|
368
389
|
serverModuleModules.clear();
|
|
369
390
|
staticEntries = collect_hydrate_module_paths(buildOctaneConfig);
|
|
391
|
+
staticEntryFiles = Object.create(null);
|
|
392
|
+
},
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Preserve the source-to-file relation that Vite's manifest cannot express
|
|
396
|
+
* when Rolldown promotes a dynamic route entry into a shared chunk.
|
|
397
|
+
*/
|
|
398
|
+
generateBundle(_options, bundle) {
|
|
399
|
+
if (!isBuild || isSSRBuild || !has_route_config(buildOctaneConfig)) return;
|
|
400
|
+
const entryByModuleId = new Map(
|
|
401
|
+
staticEntries.map((moduleId) => {
|
|
402
|
+
const file = path.resolve(root, moduleId.startsWith('/') ? `.${moduleId}` : moduleId);
|
|
403
|
+
return [file.split(path.sep).join('/'), moduleId];
|
|
404
|
+
}),
|
|
405
|
+
);
|
|
406
|
+
for (const output of Object.values(bundle)) {
|
|
407
|
+
if (output.type !== 'chunk') continue;
|
|
408
|
+
for (const moduleId of output.moduleIds) {
|
|
409
|
+
const entryId = entryByModuleId.get(moduleId.split(path.sep).join('/'));
|
|
410
|
+
if (entryId !== undefined) staticEntryFiles[entryId] = output.fileName;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
370
413
|
},
|
|
371
414
|
|
|
372
415
|
async configResolved(resolvedConfig) {
|
|
@@ -670,6 +713,7 @@ export function octane(inlineOptions = {}) {
|
|
|
670
713
|
async closeBundle() {
|
|
671
714
|
if (!isBuild || isSSRBuild || !has_route_config(buildOctaneConfig)) return;
|
|
672
715
|
const cfg = /** @type {ResolvedOctaneConfig} */ (buildOctaneConfig);
|
|
716
|
+
const webWorkerServer = cfg.adapter?.serverTarget === 'webworker';
|
|
673
717
|
|
|
674
718
|
console.log('[@octanejs/vite-plugin] Client build done. Building the server bundle…');
|
|
675
719
|
|
|
@@ -692,7 +736,7 @@ export function octane(inlineOptions = {}) {
|
|
|
692
736
|
);
|
|
693
737
|
}
|
|
694
738
|
|
|
695
|
-
const clientAssetMap = createClientAssetMap(clientManifest, staticEntries);
|
|
739
|
+
const clientAssetMap = createClientAssetMap(clientManifest, staticEntries, staticEntryFiles);
|
|
696
740
|
|
|
697
741
|
// The manifest was only needed here; leaving .vite/ in dist/client would
|
|
698
742
|
// publish source file paths through the static server.
|
|
@@ -712,9 +756,11 @@ export function octane(inlineOptions = {}) {
|
|
|
712
756
|
rootBoundary: cfg.rootBoundary,
|
|
713
757
|
rpcModulePaths: [...serverModuleModules],
|
|
714
758
|
clientAssetMap,
|
|
759
|
+
...(webWorkerServer ? { mode: 'webworker' } : null),
|
|
715
760
|
// The virtual entry has no filesystem importer, so resolve app-core
|
|
716
761
|
// from this package before handing source to Vite. This also works
|
|
717
762
|
// when app-core is nested under the plugin by a package manager.
|
|
763
|
+
configModuleId: requireFromPlugin.resolve('@octanejs/app-core/config'),
|
|
718
764
|
productionModuleId: requireFromPlugin.resolve('@octanejs/app-core/production'),
|
|
719
765
|
nodeModuleId: requireFromPlugin.resolve('@octanejs/app-core/node'),
|
|
720
766
|
}),
|
|
@@ -739,6 +785,10 @@ export function octane(inlineOptions = {}) {
|
|
|
739
785
|
await viteBuild({
|
|
740
786
|
root,
|
|
741
787
|
appType: 'custom',
|
|
788
|
+
// Vite deliberately preserves process.env references in SSR/library
|
|
789
|
+
// output. Pin build intent here so Rollup can remove Octane's complete
|
|
790
|
+
// development error table even when the server bundle is not minified.
|
|
791
|
+
define: { 'process.env.NODE_ENV': JSON.stringify('production') },
|
|
742
792
|
plugins: [virtualEntryPlugin],
|
|
743
793
|
resolve: {
|
|
744
794
|
alias: [
|
|
@@ -760,6 +810,10 @@ export function octane(inlineOptions = {}) {
|
|
|
760
810
|
minify: cfg.build.minify ?? false,
|
|
761
811
|
rollupOptions: {
|
|
762
812
|
input: VIRTUAL_SERVER_ENTRY_ID,
|
|
813
|
+
// Cloudflare's nodejs_compat exposes `node:` modules directly.
|
|
814
|
+
// Preserve application imports as well as Octane's current runtime
|
|
815
|
+
// dependencies instead of replacing them with browser shims.
|
|
816
|
+
...(webWorkerServer ? { external: [/^node:/] } : null),
|
|
763
817
|
output: {
|
|
764
818
|
entryFileNames: ENTRY_FILENAME,
|
|
765
819
|
format: 'esm',
|
|
@@ -767,6 +821,7 @@ export function octane(inlineOptions = {}) {
|
|
|
767
821
|
},
|
|
768
822
|
},
|
|
769
823
|
ssr: {
|
|
824
|
+
...(webWorkerServer ? { target: 'webworker' } : null),
|
|
770
825
|
// Self-contained server bundle: everything except node builtins is
|
|
771
826
|
// bundled, so dist/server deploys without node_modules. 'vite'
|
|
772
827
|
// stays external as a guard — nothing should reach it (the facade
|
|
@@ -784,9 +839,11 @@ export function octane(inlineOptions = {}) {
|
|
|
784
839
|
}
|
|
785
840
|
|
|
786
841
|
console.log(`[@octanejs/vite-plugin] Server build complete: ${path.join(outDir, 'server')}`);
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
842
|
+
if (!webWorkerServer) {
|
|
843
|
+
console.log(
|
|
844
|
+
`[@octanejs/vite-plugin] Start with: node ${outDir}/server/${ENTRY_FILENAME} (or octane-preview)`,
|
|
845
|
+
);
|
|
846
|
+
}
|
|
790
847
|
|
|
791
848
|
// ------------------------------------------------------------------
|
|
792
849
|
// Deploy adapter (SvelteKit-style): with both bundles on disk, let the
|
package/types/index.d.ts
CHANGED
|
@@ -23,13 +23,15 @@ export interface OctanePluginOptions {
|
|
|
23
23
|
*/
|
|
24
24
|
exclude?: string[];
|
|
25
25
|
/**
|
|
26
|
-
* Mixed-toolchain ownership gate: when `true`,
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
26
|
+
* Mixed-toolchain ownership gate: when `true`, a project `.tsrx` is
|
|
27
|
+
* Octane's by extension, and a project `.tsx` (full compile) or plain
|
|
28
|
+
* `.ts`/`.js` (hook slotting) is Octane's only when it opens with a
|
|
29
|
+
* leading `@jsxImportSource octane` pragma comment (any registered
|
|
30
|
+
* renderer's intrinsics module also counts). A pragma naming a
|
|
31
|
+
* foreign source (e.g. `react`) does not claim the file. Unmarked
|
|
32
|
+
* project modules pass through to the host framework's own pipeline
|
|
33
|
+
* (e.g. React's JSX transform). Installed and linked packages keep
|
|
34
|
+
* their Octane package-manifest decision.
|
|
33
35
|
* @default false
|
|
34
36
|
*/
|
|
35
37
|
requireDirective?: boolean;
|