unhead 3.0.5 → 3.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/dist/plugins.d.mts +4 -31
- package/dist/plugins.d.ts +4 -31
- package/dist/plugins.mjs +35 -199
- package/dist/shared/unhead.Dl_lRDXb.d.mts +38 -0
- package/dist/shared/unhead.Dl_lRDXb.d.ts +38 -0
- package/dist/shared/unhead.ebqUBTt1.mjs +513 -0
- package/dist/stream/client.d.mts +22 -3
- package/dist/stream/client.d.ts +22 -3
- package/dist/stream/server.d.mts +6 -3
- package/dist/stream/server.d.ts +6 -3
- package/dist/stream/server.mjs +15 -4
- package/dist/stream/unplugin.d.mts +81 -0
- package/dist/stream/unplugin.d.ts +81 -0
- package/dist/stream/unplugin.mjs +166 -0
- package/dist/stream/vite.d.mts +19 -27
- package/dist/stream/vite.d.ts +19 -27
- package/dist/stream/vite.mjs +6 -78
- package/dist/validate.d.mts +236 -0
- package/dist/validate.d.ts +236 -0
- package/dist/validate.mjs +49 -0
- package/package.json +18 -3
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import * as unplugin from 'unplugin';
|
|
2
|
+
import { UnpluginOptions } from 'unplugin';
|
|
3
|
+
|
|
4
|
+
declare const VIRTUAL_CLIENT_ID = "virtual:@unhead/streaming-client";
|
|
5
|
+
declare const VIRTUAL_IIFE_ID = "virtual:@unhead/streaming-iife.js";
|
|
6
|
+
type Nonce = string | (() => string | undefined);
|
|
7
|
+
interface StreamingPluginOptions {
|
|
8
|
+
/** Framework package e.g. '@unhead/vue' */
|
|
9
|
+
framework: string;
|
|
10
|
+
/** Plugin name (optional, defaults to `${framework}:streaming`) */
|
|
11
|
+
name?: string;
|
|
12
|
+
/**
|
|
13
|
+
* File extension filter for transform hook, e.g. /\.vue$/. Optional;
|
|
14
|
+
* only required by frameworks whose client streaming support relies on
|
|
15
|
+
* source-level AST injection (React/Solid/Svelte). Vue does not use it.
|
|
16
|
+
*/
|
|
17
|
+
filter?: RegExp;
|
|
18
|
+
/** Transform handler called for files matching `filter`. */
|
|
19
|
+
transform?: (code: string, id: string, options?: {
|
|
20
|
+
ssr?: boolean;
|
|
21
|
+
}) => {
|
|
22
|
+
code: string;
|
|
23
|
+
map?: any;
|
|
24
|
+
} | null | undefined | void;
|
|
25
|
+
/**
|
|
26
|
+
* How to load the streaming client (vite-only, ignored on webpack/rspack/rollup where
|
|
27
|
+
* index.html injection isn't available; frameworks inject the iife themselves in SSR).
|
|
28
|
+
* - 'async' (default): Non-blocking external script. In dev served from a virtual
|
|
29
|
+
* module; in production emitted as a real asset chunk via `emitFile`.
|
|
30
|
+
* - 'inline': Inline the IIFE directly in HTML. Largest HTML, smallest TTFB,
|
|
31
|
+
* always safe in production. Recommended for streaming SSR.
|
|
32
|
+
* - 'module': ES module dynamic import of the client bootstrap. Vite rewrites the
|
|
33
|
+
* import path through its module graph so it survives production builds.
|
|
34
|
+
* @default 'async'
|
|
35
|
+
*/
|
|
36
|
+
mode?: 'async' | 'inline' | 'module';
|
|
37
|
+
/**
|
|
38
|
+
* CSP nonce forwarded on every injected `<script>` tag. Pass a string or a
|
|
39
|
+
* function returning a string (useful when the nonce rotates per request).
|
|
40
|
+
* Omit to inject without a nonce.
|
|
41
|
+
*/
|
|
42
|
+
nonce?: Nonce;
|
|
43
|
+
/**
|
|
44
|
+
* Stream key global name; must match `experimentalStreamKey` on the server
|
|
45
|
+
* head instance. Used by dev-mode warnings to detect when the server
|
|
46
|
+
* bootstrap script hasn't run (common misconfig).
|
|
47
|
+
* @default '__unhead__'
|
|
48
|
+
*/
|
|
49
|
+
streamKey?: string;
|
|
50
|
+
/**
|
|
51
|
+
* Emit a warning when the client IIFE runs but no server bootstrap queue
|
|
52
|
+
* has been installed (i.e. server didn't call `wrapStream` /
|
|
53
|
+
* `renderSSRHeadShell`). Dev-only.
|
|
54
|
+
* @default true in dev, false in prod
|
|
55
|
+
*/
|
|
56
|
+
warnOnMissingServerBootstrap?: boolean;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Builds the bundler-agnostic unplugin hook set for the streaming plugin. Exposed so
|
|
60
|
+
* framework wrappers (e.g. `@unhead/vue/bundler`) can bake in their own
|
|
61
|
+
* `framework`, `filter`, and `transform` while still using this factory
|
|
62
|
+
* to produce hooks that work across vite/webpack/rspack/rollup/esbuild via `createUnplugin`.
|
|
63
|
+
*
|
|
64
|
+
* SSR detection is bundler-specific:
|
|
65
|
+
* - vite build: `config.env.isSsrBuild`
|
|
66
|
+
* - vite dev (v6+ environments): `this.environment.name === 'ssr'` per-transform
|
|
67
|
+
* - webpack/rspack: `compiler.options.name === 'server'` or `target === 'node'`
|
|
68
|
+
*/
|
|
69
|
+
declare function buildStreamingPluginOptions(options: StreamingPluginOptions): UnpluginOptions;
|
|
70
|
+
/**
|
|
71
|
+
* Internal cross-bundler unplugin factory. Framework wrappers pick a single bundler's
|
|
72
|
+
* output (`.vite`, `.webpack`, `.rspack`, etc.) to expose via their own subpath export.
|
|
73
|
+
*
|
|
74
|
+
* Consumers should prefer the unified framework bundler entry (e.g.
|
|
75
|
+
* `@unhead/{vue,react,svelte,solid-js}/bundler`) rather than importing this
|
|
76
|
+
* directly.
|
|
77
|
+
*/
|
|
78
|
+
declare const createStreamingPlugin: unplugin.UnpluginInstance<StreamingPluginOptions, boolean>;
|
|
79
|
+
|
|
80
|
+
export { VIRTUAL_CLIENT_ID, VIRTUAL_IIFE_ID, buildStreamingPluginOptions, createStreamingPlugin };
|
|
81
|
+
export type { Nonce, StreamingPluginOptions };
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import * as unplugin from 'unplugin';
|
|
2
|
+
import { UnpluginOptions } from 'unplugin';
|
|
3
|
+
|
|
4
|
+
declare const VIRTUAL_CLIENT_ID = "virtual:@unhead/streaming-client";
|
|
5
|
+
declare const VIRTUAL_IIFE_ID = "virtual:@unhead/streaming-iife.js";
|
|
6
|
+
type Nonce = string | (() => string | undefined);
|
|
7
|
+
interface StreamingPluginOptions {
|
|
8
|
+
/** Framework package e.g. '@unhead/vue' */
|
|
9
|
+
framework: string;
|
|
10
|
+
/** Plugin name (optional, defaults to `${framework}:streaming`) */
|
|
11
|
+
name?: string;
|
|
12
|
+
/**
|
|
13
|
+
* File extension filter for transform hook, e.g. /\.vue$/. Optional;
|
|
14
|
+
* only required by frameworks whose client streaming support relies on
|
|
15
|
+
* source-level AST injection (React/Solid/Svelte). Vue does not use it.
|
|
16
|
+
*/
|
|
17
|
+
filter?: RegExp;
|
|
18
|
+
/** Transform handler called for files matching `filter`. */
|
|
19
|
+
transform?: (code: string, id: string, options?: {
|
|
20
|
+
ssr?: boolean;
|
|
21
|
+
}) => {
|
|
22
|
+
code: string;
|
|
23
|
+
map?: any;
|
|
24
|
+
} | null | undefined | void;
|
|
25
|
+
/**
|
|
26
|
+
* How to load the streaming client (vite-only, ignored on webpack/rspack/rollup where
|
|
27
|
+
* index.html injection isn't available; frameworks inject the iife themselves in SSR).
|
|
28
|
+
* - 'async' (default): Non-blocking external script. In dev served from a virtual
|
|
29
|
+
* module; in production emitted as a real asset chunk via `emitFile`.
|
|
30
|
+
* - 'inline': Inline the IIFE directly in HTML. Largest HTML, smallest TTFB,
|
|
31
|
+
* always safe in production. Recommended for streaming SSR.
|
|
32
|
+
* - 'module': ES module dynamic import of the client bootstrap. Vite rewrites the
|
|
33
|
+
* import path through its module graph so it survives production builds.
|
|
34
|
+
* @default 'async'
|
|
35
|
+
*/
|
|
36
|
+
mode?: 'async' | 'inline' | 'module';
|
|
37
|
+
/**
|
|
38
|
+
* CSP nonce forwarded on every injected `<script>` tag. Pass a string or a
|
|
39
|
+
* function returning a string (useful when the nonce rotates per request).
|
|
40
|
+
* Omit to inject without a nonce.
|
|
41
|
+
*/
|
|
42
|
+
nonce?: Nonce;
|
|
43
|
+
/**
|
|
44
|
+
* Stream key global name; must match `experimentalStreamKey` on the server
|
|
45
|
+
* head instance. Used by dev-mode warnings to detect when the server
|
|
46
|
+
* bootstrap script hasn't run (common misconfig).
|
|
47
|
+
* @default '__unhead__'
|
|
48
|
+
*/
|
|
49
|
+
streamKey?: string;
|
|
50
|
+
/**
|
|
51
|
+
* Emit a warning when the client IIFE runs but no server bootstrap queue
|
|
52
|
+
* has been installed (i.e. server didn't call `wrapStream` /
|
|
53
|
+
* `renderSSRHeadShell`). Dev-only.
|
|
54
|
+
* @default true in dev, false in prod
|
|
55
|
+
*/
|
|
56
|
+
warnOnMissingServerBootstrap?: boolean;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Builds the bundler-agnostic unplugin hook set for the streaming plugin. Exposed so
|
|
60
|
+
* framework wrappers (e.g. `@unhead/vue/bundler`) can bake in their own
|
|
61
|
+
* `framework`, `filter`, and `transform` while still using this factory
|
|
62
|
+
* to produce hooks that work across vite/webpack/rspack/rollup/esbuild via `createUnplugin`.
|
|
63
|
+
*
|
|
64
|
+
* SSR detection is bundler-specific:
|
|
65
|
+
* - vite build: `config.env.isSsrBuild`
|
|
66
|
+
* - vite dev (v6+ environments): `this.environment.name === 'ssr'` per-transform
|
|
67
|
+
* - webpack/rspack: `compiler.options.name === 'server'` or `target === 'node'`
|
|
68
|
+
*/
|
|
69
|
+
declare function buildStreamingPluginOptions(options: StreamingPluginOptions): UnpluginOptions;
|
|
70
|
+
/**
|
|
71
|
+
* Internal cross-bundler unplugin factory. Framework wrappers pick a single bundler's
|
|
72
|
+
* output (`.vite`, `.webpack`, `.rspack`, etc.) to expose via their own subpath export.
|
|
73
|
+
*
|
|
74
|
+
* Consumers should prefer the unified framework bundler entry (e.g.
|
|
75
|
+
* `@unhead/{vue,react,svelte,solid-js}/bundler`) rather than importing this
|
|
76
|
+
* directly.
|
|
77
|
+
*/
|
|
78
|
+
declare const createStreamingPlugin: unplugin.UnpluginInstance<StreamingPluginOptions, boolean>;
|
|
79
|
+
|
|
80
|
+
export { VIRTUAL_CLIENT_ID, VIRTUAL_IIFE_ID, buildStreamingPluginOptions, createStreamingPlugin };
|
|
81
|
+
export type { Nonce, StreamingPluginOptions };
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { createUnplugin } from 'unplugin';
|
|
2
|
+
|
|
3
|
+
const VIRTUAL_CLIENT_ID = "virtual:@unhead/streaming-client";
|
|
4
|
+
const VIRTUAL_IIFE_ID = "virtual:@unhead/streaming-iife.js";
|
|
5
|
+
const RESOLVED_ID = `\0${VIRTUAL_CLIENT_ID}`;
|
|
6
|
+
const RESOLVED_IIFE_ID = `\0${VIRTUAL_IIFE_ID}`;
|
|
7
|
+
const VIRTUAL_RE = /virtual:@unhead\/streaming/;
|
|
8
|
+
const RESOLVED_RE = /^\0virtual:@unhead\/streaming/;
|
|
9
|
+
let iifeCode;
|
|
10
|
+
let iifeCodeLoading;
|
|
11
|
+
async function loadIifeCode() {
|
|
12
|
+
if (iifeCode)
|
|
13
|
+
return;
|
|
14
|
+
iifeCodeLoading ||= import('unhead/stream/iife').then((mod) => {
|
|
15
|
+
iifeCode = mod.streamingIifeCode;
|
|
16
|
+
});
|
|
17
|
+
await iifeCodeLoading;
|
|
18
|
+
}
|
|
19
|
+
function resolveNonce(nonce) {
|
|
20
|
+
if (!nonce)
|
|
21
|
+
return void 0;
|
|
22
|
+
return typeof nonce === "function" ? nonce() : nonce;
|
|
23
|
+
}
|
|
24
|
+
function buildClientStub(framework, streamKey, warnOnMissing) {
|
|
25
|
+
const key = JSON.stringify(streamKey);
|
|
26
|
+
const warnBranch = warnOnMissing ? `else{console.warn('[unhead] streaming client loaded but window['+${key}+'] is undefined; did the server call wrapStream()/renderSSRHeadShell()?')}` : "";
|
|
27
|
+
return `import{createHead}from'${framework}/client'
|
|
28
|
+
const s=window[${key}];if(s){const q=s._q;s._q=[];const h=createHead({document});q.forEach(e=>h.push(e));s.push=e=>h.push(e);s._head=h}${warnBranch}`;
|
|
29
|
+
}
|
|
30
|
+
function buildStreamingPluginOptions(options) {
|
|
31
|
+
const {
|
|
32
|
+
framework,
|
|
33
|
+
name,
|
|
34
|
+
mode = "async",
|
|
35
|
+
nonce,
|
|
36
|
+
streamKey = "__unhead__",
|
|
37
|
+
warnOnMissingServerBootstrap
|
|
38
|
+
} = options;
|
|
39
|
+
const state = {
|
|
40
|
+
isBuild: false,
|
|
41
|
+
ssr: false
|
|
42
|
+
};
|
|
43
|
+
function isSSRCall(hookThis, opts) {
|
|
44
|
+
const envName = hookThis?.environment?.name;
|
|
45
|
+
return envName === "ssr" || envName === "server" || opts?.ssr === true || state.ssr;
|
|
46
|
+
}
|
|
47
|
+
function warnEnabled() {
|
|
48
|
+
return warnOnMissingServerBootstrap ?? !state.isBuild;
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
name: name ?? `${framework}:streaming`,
|
|
52
|
+
enforce: "pre",
|
|
53
|
+
async buildStart() {
|
|
54
|
+
await loadIifeCode();
|
|
55
|
+
if (mode === "async" && state.isBuild && typeof this.emitFile === "function") {
|
|
56
|
+
if (!iifeCode)
|
|
57
|
+
throw new Error("[unhead] Streaming IIFE not built. Run `pnpm build` in packages/unhead first.");
|
|
58
|
+
state.emittedIifeFileName = this.emitFile({
|
|
59
|
+
type: "asset",
|
|
60
|
+
name: "unhead-streaming.js",
|
|
61
|
+
source: iifeCode
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
resolveId: {
|
|
66
|
+
filter: { id: VIRTUAL_RE },
|
|
67
|
+
handler(id) {
|
|
68
|
+
if (id === VIRTUAL_CLIENT_ID || id === `/${VIRTUAL_CLIENT_ID}`)
|
|
69
|
+
return RESOLVED_ID;
|
|
70
|
+
if (id === VIRTUAL_IIFE_ID || id === `/${VIRTUAL_IIFE_ID}`)
|
|
71
|
+
return RESOLVED_IIFE_ID;
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
load: {
|
|
75
|
+
filter: { id: RESOLVED_RE },
|
|
76
|
+
handler(id, opts) {
|
|
77
|
+
const isSSR = isSSRCall(this, opts);
|
|
78
|
+
if (id === RESOLVED_ID) {
|
|
79
|
+
if (isSSR)
|
|
80
|
+
return { code: "export {}", moduleType: "js" };
|
|
81
|
+
return {
|
|
82
|
+
code: buildClientStub(framework, streamKey, warnEnabled()),
|
|
83
|
+
moduleType: "js"
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
if (id === RESOLVED_IIFE_ID) {
|
|
87
|
+
if (isSSR)
|
|
88
|
+
return { code: "", moduleType: "js" };
|
|
89
|
+
if (!iifeCode)
|
|
90
|
+
throw new Error("[unhead] Streaming IIFE not built. Run `pnpm build` in packages/unhead first.");
|
|
91
|
+
return { code: iifeCode, moduleType: "js" };
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
...options.transform && options.filter ? {
|
|
96
|
+
transform: {
|
|
97
|
+
filter: { id: options.filter },
|
|
98
|
+
handler(code, id, opts) {
|
|
99
|
+
return options.transform(code, id, { ssr: isSSRCall(this, opts) });
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
} : {},
|
|
103
|
+
webpack(compiler) {
|
|
104
|
+
const { name: n, target } = compiler.options;
|
|
105
|
+
if (n === "server" || target === "node" || target === "async-node")
|
|
106
|
+
state.ssr = true;
|
|
107
|
+
},
|
|
108
|
+
rspack(compiler) {
|
|
109
|
+
const { name: n, target } = compiler.options;
|
|
110
|
+
if (n === "server" || target === "node" || target === "async-node")
|
|
111
|
+
state.ssr = true;
|
|
112
|
+
},
|
|
113
|
+
vite: {
|
|
114
|
+
apply(_config, env) {
|
|
115
|
+
if (env.isSsrBuild)
|
|
116
|
+
state.ssr = true;
|
|
117
|
+
if (env.command === "build")
|
|
118
|
+
state.isBuild = true;
|
|
119
|
+
return true;
|
|
120
|
+
},
|
|
121
|
+
configResolved(config) {
|
|
122
|
+
if (config.command === "build")
|
|
123
|
+
state.isBuild = true;
|
|
124
|
+
},
|
|
125
|
+
transformIndexHtml: {
|
|
126
|
+
// `order: 'pre'` is separate from the plugin-level `enforce: 'pre'`:
|
|
127
|
+
// it runs this HTML transform before other non-pre HTML transforms
|
|
128
|
+
// so the virtual module `<script>` tags we inject go through the
|
|
129
|
+
// full Vite plugin pipeline (resolveId/load) and aren't stripped or
|
|
130
|
+
// rewritten by downstream HTML transforms.
|
|
131
|
+
order: "pre",
|
|
132
|
+
handler() {
|
|
133
|
+
const nonceValue = resolveNonce(nonce);
|
|
134
|
+
const nonceAttr = nonceValue ? { nonce: nonceValue } : {};
|
|
135
|
+
if (mode === "inline") {
|
|
136
|
+
if (!iifeCode)
|
|
137
|
+
throw new Error("[unhead] Streaming IIFE not built. Run `pnpm build` in packages/unhead first.");
|
|
138
|
+
return [{
|
|
139
|
+
tag: "script",
|
|
140
|
+
attrs: nonceAttr,
|
|
141
|
+
children: iifeCode,
|
|
142
|
+
injectTo: "head-prepend"
|
|
143
|
+
}];
|
|
144
|
+
}
|
|
145
|
+
if (mode === "async") {
|
|
146
|
+
const src = state.isBuild && state.emittedIifeFileName ? `/${state.emittedIifeFileName}` : `/${VIRTUAL_IIFE_ID}`;
|
|
147
|
+
return [{
|
|
148
|
+
tag: "script",
|
|
149
|
+
attrs: { ...nonceAttr, async: true, src },
|
|
150
|
+
injectTo: "head-prepend"
|
|
151
|
+
}];
|
|
152
|
+
}
|
|
153
|
+
return [{
|
|
154
|
+
tag: "script",
|
|
155
|
+
attrs: nonceAttr,
|
|
156
|
+
children: `import("/${VIRTUAL_CLIENT_ID}")`,
|
|
157
|
+
injectTo: "head-prepend"
|
|
158
|
+
}];
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
const createStreamingPlugin = createUnplugin(buildStreamingPluginOptions);
|
|
165
|
+
|
|
166
|
+
export { VIRTUAL_CLIENT_ID, VIRTUAL_IIFE_ID, buildStreamingPluginOptions, createStreamingPlugin };
|
package/dist/stream/vite.d.mts
CHANGED
|
@@ -1,31 +1,23 @@
|
|
|
1
1
|
import { Plugin } from 'vite';
|
|
2
|
+
import { StreamingPluginOptions } from './unplugin.mjs';
|
|
3
|
+
export { VIRTUAL_CLIENT_ID, VIRTUAL_IIFE_ID, buildStreamingPluginOptions } from './unplugin.mjs';
|
|
4
|
+
import 'unplugin';
|
|
2
5
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
} | null | undefined | void;
|
|
19
|
-
/**
|
|
20
|
-
* How to load the streaming client:
|
|
21
|
-
* - 'async': Load as async script (non-blocking, may have brief queue delay)
|
|
22
|
-
* - 'inline': Inline the IIFE directly in HTML (larger HTML, but immediate execution)
|
|
23
|
-
* - 'module': Use ES module import (original behavior, waits for bundle)
|
|
24
|
-
* @default 'async'
|
|
25
|
-
*/
|
|
26
|
-
mode?: 'async' | 'inline' | 'module';
|
|
27
|
-
}
|
|
6
|
+
/**
|
|
7
|
+
* @deprecated Import from `unhead/stream/unplugin` instead and call `.vite(options)`
|
|
8
|
+
* on the returned unplugin instance. The `unhead/stream/vite` subpath will be
|
|
9
|
+
* removed in a future major release.
|
|
10
|
+
*
|
|
11
|
+
* ```ts
|
|
12
|
+
* // Before
|
|
13
|
+
* import { createStreamingPlugin } from 'unhead/stream/vite'
|
|
14
|
+
* const plugin = createStreamingPlugin({ framework, filter, transform })
|
|
15
|
+
*
|
|
16
|
+
* // After
|
|
17
|
+
* import { createStreamingPlugin } from 'unhead/stream/unplugin'
|
|
18
|
+
* const plugin = createStreamingPlugin.vite({ framework, filter, transform })
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
28
21
|
declare function createStreamingPlugin(options: StreamingPluginOptions): Plugin;
|
|
29
22
|
|
|
30
|
-
export {
|
|
31
|
-
export type { StreamingPluginOptions };
|
|
23
|
+
export { StreamingPluginOptions, createStreamingPlugin };
|
package/dist/stream/vite.d.ts
CHANGED
|
@@ -1,31 +1,23 @@
|
|
|
1
1
|
import { Plugin } from 'vite';
|
|
2
|
+
import { StreamingPluginOptions } from './unplugin.js';
|
|
3
|
+
export { VIRTUAL_CLIENT_ID, VIRTUAL_IIFE_ID, buildStreamingPluginOptions } from './unplugin.js';
|
|
4
|
+
import 'unplugin';
|
|
2
5
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
} | null | undefined | void;
|
|
19
|
-
/**
|
|
20
|
-
* How to load the streaming client:
|
|
21
|
-
* - 'async': Load as async script (non-blocking, may have brief queue delay)
|
|
22
|
-
* - 'inline': Inline the IIFE directly in HTML (larger HTML, but immediate execution)
|
|
23
|
-
* - 'module': Use ES module import (original behavior, waits for bundle)
|
|
24
|
-
* @default 'async'
|
|
25
|
-
*/
|
|
26
|
-
mode?: 'async' | 'inline' | 'module';
|
|
27
|
-
}
|
|
6
|
+
/**
|
|
7
|
+
* @deprecated Import from `unhead/stream/unplugin` instead and call `.vite(options)`
|
|
8
|
+
* on the returned unplugin instance. The `unhead/stream/vite` subpath will be
|
|
9
|
+
* removed in a future major release.
|
|
10
|
+
*
|
|
11
|
+
* ```ts
|
|
12
|
+
* // Before
|
|
13
|
+
* import { createStreamingPlugin } from 'unhead/stream/vite'
|
|
14
|
+
* const plugin = createStreamingPlugin({ framework, filter, transform })
|
|
15
|
+
*
|
|
16
|
+
* // After
|
|
17
|
+
* import { createStreamingPlugin } from 'unhead/stream/unplugin'
|
|
18
|
+
* const plugin = createStreamingPlugin.vite({ framework, filter, transform })
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
28
21
|
declare function createStreamingPlugin(options: StreamingPluginOptions): Plugin;
|
|
29
22
|
|
|
30
|
-
export {
|
|
31
|
-
export type { StreamingPluginOptions };
|
|
23
|
+
export { StreamingPluginOptions, createStreamingPlugin };
|
package/dist/stream/vite.mjs
CHANGED
|
@@ -1,81 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const VIRTUAL_RE = /virtual:@unhead\/streaming/;
|
|
6
|
-
const RESOLVED_RE = /^\0virtual:@unhead\/streaming/;
|
|
7
|
-
let iifeCode;
|
|
8
|
-
let iifeCodeLoaded = false;
|
|
1
|
+
import { createStreamingPlugin as createStreamingPlugin$1 } from './unplugin.mjs';
|
|
2
|
+
export { VIRTUAL_CLIENT_ID, VIRTUAL_IIFE_ID, buildStreamingPluginOptions } from './unplugin.mjs';
|
|
3
|
+
import 'unplugin';
|
|
4
|
+
|
|
9
5
|
function createStreamingPlugin(options) {
|
|
10
|
-
|
|
11
|
-
return {
|
|
12
|
-
name: name ?? `${framework}:streaming`,
|
|
13
|
-
enforce: "pre",
|
|
14
|
-
async configResolved() {
|
|
15
|
-
if (!iifeCodeLoaded) {
|
|
16
|
-
iifeCodeLoaded = true;
|
|
17
|
-
const mod = await import('unhead/stream/iife');
|
|
18
|
-
iifeCode = mod.streamingIifeCode;
|
|
19
|
-
}
|
|
20
|
-
},
|
|
21
|
-
resolveId: {
|
|
22
|
-
filter: { id: VIRTUAL_RE },
|
|
23
|
-
handler(id) {
|
|
24
|
-
if (id === VIRTUAL_CLIENT_ID || id === `/${VIRTUAL_CLIENT_ID}`)
|
|
25
|
-
return RESOLVED_ID;
|
|
26
|
-
if (id === VIRTUAL_IIFE_ID || id === `/${VIRTUAL_IIFE_ID}`)
|
|
27
|
-
return RESOLVED_IIFE_ID;
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
load: {
|
|
31
|
-
filter: { id: RESOLVED_RE },
|
|
32
|
-
handler(id, opts) {
|
|
33
|
-
if (id === RESOLVED_ID) {
|
|
34
|
-
if (opts?.ssr)
|
|
35
|
-
return { code: "export {}", moduleType: "js" };
|
|
36
|
-
return {
|
|
37
|
-
code: `import{createHead}from'${framework}/client'
|
|
38
|
-
const s=window.__unhead__;if(s){const q=s._q;s._q=[];const h=createHead({document});q.forEach(e=>h.push(e));s.push=e=>h.push(e);s._head=h}`,
|
|
39
|
-
moduleType: "js"
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
if (id === RESOLVED_IIFE_ID) {
|
|
43
|
-
if (opts?.ssr)
|
|
44
|
-
return { code: "", moduleType: "js" };
|
|
45
|
-
if (!iifeCode)
|
|
46
|
-
throw new Error("[unhead] Streaming IIFE not built. Run `pnpm build` in packages/unhead first.");
|
|
47
|
-
return { code: iifeCode, moduleType: "js" };
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
|
-
transformIndexHtml() {
|
|
52
|
-
if (mode === "inline") {
|
|
53
|
-
if (!iifeCode)
|
|
54
|
-
throw new Error("[unhead] Streaming IIFE not built. Run `pnpm build` in packages/unhead first.");
|
|
55
|
-
return [{
|
|
56
|
-
tag: "script",
|
|
57
|
-
children: iifeCode,
|
|
58
|
-
injectTo: "head-prepend"
|
|
59
|
-
}];
|
|
60
|
-
}
|
|
61
|
-
if (mode === "async") {
|
|
62
|
-
return [{
|
|
63
|
-
tag: "script",
|
|
64
|
-
attrs: { async: true, src: `/${VIRTUAL_IIFE_ID}` },
|
|
65
|
-
injectTo: "head-prepend"
|
|
66
|
-
}];
|
|
67
|
-
}
|
|
68
|
-
return [{
|
|
69
|
-
tag: "script",
|
|
70
|
-
children: `import("/${VIRTUAL_CLIENT_ID}")`,
|
|
71
|
-
injectTo: "head-prepend"
|
|
72
|
-
}];
|
|
73
|
-
},
|
|
74
|
-
transform: {
|
|
75
|
-
filter: { id: options.filter },
|
|
76
|
-
handler: options.transform
|
|
77
|
-
}
|
|
78
|
-
};
|
|
6
|
+
return createStreamingPlugin$1.vite(options);
|
|
79
7
|
}
|
|
80
8
|
|
|
81
|
-
export {
|
|
9
|
+
export { createStreamingPlugin };
|