@foldkit/vite-plugin 0.20.2 → 0.21.0-canary.ba0d6f141325
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 +3 -3
- package/dist/build.d.ts +16 -13
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +73 -12
- package/dist/index.d.ts +14 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +25 -19
- package/dist/ssr.d.ts +6 -0
- package/dist/ssr.d.ts.map +1 -1
- package/dist/ssr.js +5 -5
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @foldkit/vite-plugin
|
|
2
2
|
|
|
3
|
-
Vite plugin for Foldkit: view identity branding for the differ, plus
|
|
3
|
+
Vite plugin for Foldkit: view identity branding for the differ, plus state-preserving live reload.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -34,7 +34,7 @@ This plugin supplies that identity. At build time, in dev and production alike,
|
|
|
34
34
|
|
|
35
35
|
Foldkit core modules are never instrumented, and functions that never return vnodes are wrapped inertly. Builds without this plugin fall back to positional matching plus keys, where branch points need hand-written keys.
|
|
36
36
|
|
|
37
|
-
##
|
|
37
|
+
## State-preserving live reload
|
|
38
38
|
|
|
39
39
|
When you save a file during development, the plugin:
|
|
40
40
|
|
|
@@ -51,7 +51,7 @@ The plugin uses Vite's WebSocket connection to communicate between the dev serve
|
|
|
51
51
|
- **On file change**: The browser sends the current Model to the Vite server for preservation.
|
|
52
52
|
- **On reload**: The browser requests the preserved Model from the server and initializes the Foldkit Runtime with it.
|
|
53
53
|
|
|
54
|
-
The Model survives
|
|
54
|
+
The Model survives development reloads but clears on a manual browser refresh, so a refresh still resets the application.
|
|
55
55
|
|
|
56
56
|
## Server rendering dev host
|
|
57
57
|
|
package/dist/build.d.ts
CHANGED
|
@@ -23,26 +23,24 @@ export type FoldkitPrerenderOptions = Readonly<{
|
|
|
23
23
|
}>;
|
|
24
24
|
/** How `vite build` builds a server entry and what it generates from it. */
|
|
25
25
|
export type FoldkitBuildOptions = Readonly<{
|
|
26
|
-
/**
|
|
27
|
-
* The module the server build starts from. Defaults to the `serverEntry`
|
|
28
|
-
* itself, which is what a generated site wants. Point it at a host module
|
|
29
|
-
* when the deployment serves requests through one, such as an HTTP server or
|
|
30
|
-
* a Worker that imports the entry and calls `renderPage`.
|
|
31
|
-
*
|
|
32
|
-
* A build that also generates pages needs `renderPage` and, unless the paths
|
|
33
|
-
* are configured here, `prerenderPaths` on whichever module this names.
|
|
34
|
-
*/
|
|
35
|
-
entry?: string;
|
|
36
26
|
/** Where the browser build is written. */
|
|
37
27
|
clientOutDir?: string;
|
|
38
28
|
/** Where the server build is written. */
|
|
39
29
|
serverOutDir?: string;
|
|
30
|
+
/**
|
|
31
|
+
* The `id` of the empty container in `index.html` the fetch handler
|
|
32
|
+
* replaces. Defaults to `'root'`. The aggregate plugin copies
|
|
33
|
+
* `ssr.containerId` here.
|
|
34
|
+
*/
|
|
35
|
+
containerId?: string;
|
|
40
36
|
/**
|
|
41
37
|
* Generate static HTML for a set of URLs after both builds. `true` takes the
|
|
42
38
|
* paths from the entry's `prerenderPaths` export.
|
|
43
39
|
*/
|
|
44
40
|
prerender?: boolean | FoldkitPrerenderOptions;
|
|
45
41
|
}>;
|
|
42
|
+
/** Vite module id of the fetch handler Foldkit emits as the server entry. */
|
|
43
|
+
export declare const FOLDKIT_FETCH_MODULE_ID = "virtual:foldkit/fetch";
|
|
46
44
|
/**
|
|
47
45
|
* What the build produced, written beside the server bundle for whatever
|
|
48
46
|
* deploys it.
|
|
@@ -73,6 +71,11 @@ export declare const FoldkitBuildManifest: Schema.Struct<{
|
|
|
73
71
|
readonly serverEntry: Schema.String;
|
|
74
72
|
/** Every path this build generated a page for, in the order it generated. */
|
|
75
73
|
readonly prerendered: Schema.$Array<Schema.String>;
|
|
74
|
+
/**
|
|
75
|
+
* How a request-time host should run the server entry. Always `'fetch'`:
|
|
76
|
+
* the entry is a Web `fetch` handler, not a Node process.
|
|
77
|
+
*/
|
|
78
|
+
readonly host: Schema.optional<Schema.Literals<readonly ["fetch"]>>;
|
|
76
79
|
}>;
|
|
77
80
|
/**
|
|
78
81
|
* What the build produced, written beside the server bundle for whatever
|
|
@@ -96,14 +99,14 @@ export declare const renderTargetFor: (clientDirectory: string, path: string, or
|
|
|
96
99
|
file: string;
|
|
97
100
|
}>;
|
|
98
101
|
/**
|
|
99
|
-
* Builds
|
|
100
|
-
* HTML from
|
|
102
|
+
* Builds a Web `fetch` handler alongside the browser build, and generates
|
|
103
|
+
* static HTML from the server entry, inside one `vite build`.
|
|
101
104
|
*
|
|
102
105
|
* Vite drives both environments and every host plugin composes with them, so a
|
|
103
106
|
* deployment target that runs `vite build` gets the whole application rather
|
|
104
107
|
* than the browser half. The generated pages take their template from the
|
|
105
108
|
* browser build's own output, so generating twice over one build produces the
|
|
106
|
-
* same pages.
|
|
109
|
+
* same pages. The server bundle's default export is `{ fetch }`.
|
|
107
110
|
*/
|
|
108
111
|
export declare const foldkitBuild: (serverEntry: string, options?: FoldkitBuildOptions) => Plugin;
|
|
109
112
|
//# sourceMappingURL=build.d.ts.map
|
package/dist/build.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,MAAM,EAAE,MAAM,QAAQ,CAAA;AAGtC,OAAO,
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,MAAM,EAAE,MAAM,QAAQ,CAAA;AAGtC,OAAO,QAA8B,MAAM,WAAW,CAAA;AAEtD,OAAO,KAAK,EAGV,MAAM,EAEP,MAAM,MAAM,CAAA;AAEb,mEAAmE;AACnE,MAAM,MAAM,uBAAuB,GAAG,QAAQ,CAAC;IAC7C;;;OAGG;IACH,KAAK,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IAC7B;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,CAAC,CAAA;AAEF,4EAA4E;AAC5E,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC;IACzC,0CAA0C;IAC1C,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,yCAAyC;IACzC,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,GAAG,uBAAuB,CAAA;CAC9C,CAAC,CAAA;AAEF,6EAA6E;AAC7E,eAAO,MAAM,uBAAuB,0BAA0B,CAAA;AAE9D;;;;;;;;;;GAUG;AACH,eAAO,MAAM,oBAAoB;IAC/B;;;;OAIG;;IAEH;;;;OAIG;;IAEH,+EAA+E;;IAE/E,2DAA2D;;IAE3D,6EAA6E;;IAE7E;;;OAGG;;EAEH,CAAA;AAEF;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,oBAAoB,GAAG,OAAO,oBAAoB,CAAC,IAAI,CAAA;AAcnE,eAAO,MAAM,YAAY,SACjB,MAAM,aACD,MAAM,YACR,OAAO,QAAQ,KACvB,MAQF,CAAA;AAwFD,eAAO,MAAM,eAAe,oBACT,MAAM,QACjB,MAAM,UACJ,MAAM,YACL,OAAO,QAAQ,KACvB,QAAQ,CAAC;IAAE,GAAG,EAAE,GAAG,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CA0CrC,CAAA;AA4GD;;;;;;;;;GASG;AACH,eAAO,MAAM,YAAY,gBACV,MAAM,YACV,mBAAmB,KAC3B,MAoOF,CAAA"}
|
package/dist/build.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { Array, Schema } from 'effect';
|
|
2
2
|
import { mkdir, writeFile } from 'node:fs/promises';
|
|
3
|
-
import nodePath, {
|
|
3
|
+
import nodePath, { dirname, resolve } from 'node:path';
|
|
4
4
|
import { pathToFileURL } from 'node:url';
|
|
5
|
+
/** Vite module id of the fetch handler Foldkit emits as the server entry. */
|
|
6
|
+
export const FOLDKIT_FETCH_MODULE_ID = 'virtual:foldkit/fetch';
|
|
5
7
|
/**
|
|
6
8
|
* What the build produced, written beside the server bundle for whatever
|
|
7
9
|
* deploys it.
|
|
@@ -32,6 +34,11 @@ export const FoldkitBuildManifest = Schema.Struct({
|
|
|
32
34
|
serverEntry: Schema.String,
|
|
33
35
|
/** Every path this build generated a page for, in the order it generated. */
|
|
34
36
|
prerendered: Schema.Array(Schema.String),
|
|
37
|
+
/**
|
|
38
|
+
* How a request-time host should run the server entry. Always `'fetch'`:
|
|
39
|
+
* the entry is a Web `fetch` handler, not a Node process.
|
|
40
|
+
*/
|
|
41
|
+
host: Schema.optional(Schema.Literals(['fetch'])),
|
|
35
42
|
});
|
|
36
43
|
const MANIFEST_SCHEMA_VERSION = 1;
|
|
37
44
|
// Relative and POSIX so the manifest describes a layout rather than this
|
|
@@ -55,10 +62,8 @@ const MANIFEST_FILE_NAME = 'foldkit.build.json';
|
|
|
55
62
|
const DEFAULT_CLIENT_OUT_DIR = 'dist/client';
|
|
56
63
|
const DEFAULT_SERVER_OUT_DIR = 'dist/server';
|
|
57
64
|
const DEFAULT_PRERENDER_ORIGIN = 'http://localhost';
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
// keeps starting the same file.
|
|
61
|
-
const serverChunkName = (entry) => basename(entry, extname(entry));
|
|
65
|
+
const FETCH_CHUNK_NAME = 'fetch';
|
|
66
|
+
const RESOLVED_FETCH_MODULE_ID = `\0${FOLDKIT_FETCH_MODULE_ID}`;
|
|
62
67
|
// The chunk built from the configured entry, by name rather than by position.
|
|
63
68
|
//
|
|
64
69
|
// An SSR environment can carry more than one input, and prerendering imports
|
|
@@ -177,21 +182,55 @@ const captures = (() => {
|
|
|
177
182
|
registry[CAPTURES] = fresh;
|
|
178
183
|
return fresh;
|
|
179
184
|
})();
|
|
185
|
+
const fetchModuleSource = (serverEntry, template, containerId) => {
|
|
186
|
+
const containerLiteral = containerId === undefined ? 'undefined' : JSON.stringify(containerId);
|
|
187
|
+
// NOTE: `export *` re-exports whatever the application entry actually names,
|
|
188
|
+
// so a missing `prerenderPaths` is absent rather than a Vite undefined-import
|
|
189
|
+
// warning.
|
|
190
|
+
return `${[
|
|
191
|
+
`import { handleRequest } from 'foldkit/experimental/server'`,
|
|
192
|
+
`import * as server from ${JSON.stringify(serverEntry)}`,
|
|
193
|
+
`export * from ${JSON.stringify(serverEntry)}`,
|
|
194
|
+
`const template = ${JSON.stringify(template)}`,
|
|
195
|
+
`const containerId = ${containerLiteral}`,
|
|
196
|
+
`export default {`,
|
|
197
|
+
` fetch(request) {`,
|
|
198
|
+
` return handleRequest(request, {`,
|
|
199
|
+
` renderPage: server.renderPage,`,
|
|
200
|
+
` template,`,
|
|
201
|
+
` containerId,`,
|
|
202
|
+
` })`,
|
|
203
|
+
` },`,
|
|
204
|
+
`}`,
|
|
205
|
+
``,
|
|
206
|
+
].join('\n')}`;
|
|
207
|
+
};
|
|
208
|
+
// The template is what the browser build emitted in this same `vite build`,
|
|
209
|
+
// never a file on disk: `dist/client/index.html` could only be the previous
|
|
210
|
+
// build's shell with its old asset hashes, and the source `index.html` still
|
|
211
|
+
// names `/src/entry.ts`. Either would bundle into a handler that serves a
|
|
212
|
+
// page which cannot hydrate, from a build that reported success.
|
|
213
|
+
const templateForFetchModule = (capturedTemplate) => {
|
|
214
|
+
if (capturedTemplate === undefined) {
|
|
215
|
+
throw new Error('[foldkit] the browser build has not emitted index.html, so the fetch handler has no template to render into. Build the "client" environment before "ssr", and give the client an HTML entry.');
|
|
216
|
+
}
|
|
217
|
+
return capturedTemplate;
|
|
218
|
+
};
|
|
180
219
|
/**
|
|
181
|
-
* Builds
|
|
182
|
-
* HTML from
|
|
220
|
+
* Builds a Web `fetch` handler alongside the browser build, and generates
|
|
221
|
+
* static HTML from the server entry, inside one `vite build`.
|
|
183
222
|
*
|
|
184
223
|
* Vite drives both environments and every host plugin composes with them, so a
|
|
185
224
|
* deployment target that runs `vite build` gets the whole application rather
|
|
186
225
|
* than the browser half. The generated pages take their template from the
|
|
187
226
|
* browser build's own output, so generating twice over one build produces the
|
|
188
|
-
* same pages.
|
|
227
|
+
* same pages. The server bundle's default export is `{ fetch }`.
|
|
189
228
|
*/
|
|
190
229
|
export const foldkitBuild = (serverEntry, options = {}) => {
|
|
191
|
-
const entry = options.entry ?? serverEntry;
|
|
192
230
|
const clientOutDir = options.clientOutDir ?? DEFAULT_CLIENT_OUT_DIR;
|
|
193
231
|
const serverOutDir = options.serverOutDir ?? DEFAULT_SERVER_OUT_DIR;
|
|
194
232
|
const prerender = prerenderOptionsFrom(options.prerender ?? false);
|
|
233
|
+
const containerId = prerender?.containerId ?? options.containerId;
|
|
195
234
|
// Prerendering imports the server bundle and runs it in the build process,
|
|
196
235
|
// with the build's own privileges. That module is the application's own code
|
|
197
236
|
// and its dependencies, built from the configured entry, and is trusted on
|
|
@@ -235,6 +274,7 @@ export const foldkitBuild = (serverEntry, options = {}) => {
|
|
|
235
274
|
server: manifestPath(builder.config.root, serverOutDir),
|
|
236
275
|
serverEntry: entryFileName,
|
|
237
276
|
prerendered,
|
|
277
|
+
host: 'fetch',
|
|
238
278
|
});
|
|
239
279
|
await writeFile(resolve(serverDirectory, MANIFEST_FILE_NAME), `${JSON.stringify(manifest, undefined, 2)}\n`);
|
|
240
280
|
builder.config.logger.info(` wrote ${MANIFEST_FILE_NAME}`);
|
|
@@ -247,7 +287,7 @@ export const foldkitBuild = (serverEntry, options = {}) => {
|
|
|
247
287
|
// describes is what lets the finalizing instance read what the others
|
|
248
288
|
// emitted, and what lets finalization work whether this plugin orchestrates
|
|
249
289
|
// the environments or a host does.
|
|
250
|
-
const key = [clientOutDir, serverOutDir,
|
|
290
|
+
const key = [clientOutDir, serverOutDir, serverEntry].join('\u0000');
|
|
251
291
|
const captured = (root) => {
|
|
252
292
|
const existing = captures.get(`${root}\u0000${key}`);
|
|
253
293
|
if (existing !== undefined) {
|
|
@@ -277,6 +317,25 @@ export const foldkitBuild = (serverEntry, options = {}) => {
|
|
|
277
317
|
return {
|
|
278
318
|
name: 'foldkit:build',
|
|
279
319
|
apply: 'build',
|
|
320
|
+
api: {
|
|
321
|
+
host: 'fetch',
|
|
322
|
+
serverEntry,
|
|
323
|
+
fetchModuleId: FOLDKIT_FETCH_MODULE_ID,
|
|
324
|
+
},
|
|
325
|
+
resolveId(id) {
|
|
326
|
+
if (id === FOLDKIT_FETCH_MODULE_ID) {
|
|
327
|
+
return RESOLVED_FETCH_MODULE_ID;
|
|
328
|
+
}
|
|
329
|
+
return undefined;
|
|
330
|
+
},
|
|
331
|
+
load(id) {
|
|
332
|
+
if (id !== RESOLVED_FETCH_MODULE_ID) {
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
const state = captured(this.environment.config.root);
|
|
336
|
+
const template = templateForFetchModule(state.template);
|
|
337
|
+
return fetchModuleSource(serverEntry, template, containerId);
|
|
338
|
+
},
|
|
280
339
|
// NOTE: `writeBundle` rather than `generateBundle`: Vite's own HTML plugin
|
|
281
340
|
// emits `index.html` from a `generateBundle` hook of its own, and hook
|
|
282
341
|
// order between plugins decides whether that asset exists yet. By
|
|
@@ -292,7 +351,7 @@ export const foldkitBuild = (serverEntry, options = {}) => {
|
|
|
292
351
|
return;
|
|
293
352
|
}
|
|
294
353
|
if (this.environment.name === 'ssr') {
|
|
295
|
-
state.serverEntryFile = serverEntryFile(outputs,
|
|
354
|
+
state.serverEntryFile = serverEntryFile(outputs, FETCH_CHUNK_NAME);
|
|
296
355
|
}
|
|
297
356
|
},
|
|
298
357
|
config: userConfig => {
|
|
@@ -303,7 +362,9 @@ export const foldkitBuild = (serverEntry, options = {}) => {
|
|
|
303
362
|
build: {
|
|
304
363
|
ssr: true,
|
|
305
364
|
outDir: serverOutDir,
|
|
306
|
-
rollupOptions: {
|
|
365
|
+
rollupOptions: {
|
|
366
|
+
input: { [FETCH_CHUNK_NAME]: FOLDKIT_FETCH_MODULE_ID },
|
|
367
|
+
},
|
|
307
368
|
},
|
|
308
369
|
};
|
|
309
370
|
// NOTE: a host framework that orchestrates its own environments owns
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { Plugin } from 'vite';
|
|
|
2
2
|
import { type FoldkitBuildOptions } from './build.js';
|
|
3
3
|
import { type FoldkitSsrOptions } from './ssr.js';
|
|
4
4
|
export { type BrandDistResult, brandDistDirectory } from './brandDist.js';
|
|
5
|
-
export { FoldkitBuildManifest, type FoldkitBuildOptions, type FoldkitPrerenderOptions, foldkitBuild, } from './build.js';
|
|
5
|
+
export { FOLDKIT_FETCH_MODULE_ID, FoldkitBuildManifest, type FoldkitBuildOptions, type FoldkitPrerenderOptions, foldkitBuild, } from './build.js';
|
|
6
6
|
export { type FoldkitSsrOptions, foldkitSsr } from './ssr.js';
|
|
7
7
|
export { type ViewIdentityTransformResult, foldkitViewIdentity, transformViewIdentity, } from './viewIdentity.js';
|
|
8
8
|
/** Options for the `foldkit` Vite plugin. */
|
|
@@ -15,19 +15,22 @@ export type FoldkitPluginOptions = Readonly<{
|
|
|
15
15
|
*/
|
|
16
16
|
devToolsMcpPort?: number;
|
|
17
17
|
/**
|
|
18
|
-
* Serve server-rendered pages from the Vite dev server
|
|
19
|
-
*
|
|
20
|
-
* `
|
|
21
|
-
*
|
|
18
|
+
* Serve server-rendered pages from the Vite dev server, and, with
|
|
19
|
+
* `ssr.build`, emit a Web `fetch` handler as the server bundle. When
|
|
20
|
+
* set, `vite` passes HTML navigations that fall through Vite, plus
|
|
21
|
+
* non-GET requests, to `renderPage` from the module at
|
|
22
|
+
* `ssr.serverEntry`. When `undefined` (the default), the dev server
|
|
23
|
+
* serves the client entry only.
|
|
22
24
|
*/
|
|
23
|
-
ssr?: Omit<FoldkitSsrOptions, 'buildId'> & Readonly<{
|
|
25
|
+
ssr?: Omit<FoldkitSsrOptions, 'buildId' | 'quietStandDown'> & Readonly<{
|
|
24
26
|
/**
|
|
25
|
-
* Build
|
|
26
|
-
* HTML from
|
|
27
|
-
*
|
|
27
|
+
* Build a Web `fetch` handler alongside the browser build, and generate
|
|
28
|
+
* static HTML from the server entry, inside this project's own
|
|
29
|
+
* `vite build`. The handler is the server bundle: Node and Workers
|
|
30
|
+
* both run it. `true` builds it with the default output directories
|
|
31
|
+
* and generates nothing.
|
|
28
32
|
*
|
|
29
|
-
* When this is absent, `vite build` builds the browser bundle only
|
|
30
|
-
* the server build is a separate command the deployment runs itself.
|
|
33
|
+
* When this is absent, `vite build` builds the browser bundle only.
|
|
31
34
|
*/
|
|
32
35
|
build?: boolean | FoldkitBuildOptions;
|
|
33
36
|
}>;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAmCA,OAAO,KAAK,EACV,MAAM,EAIP,MAAM,MAAM,CAAA;AAGb,OAAO,EAAE,KAAK,mBAAmB,EAAgB,MAAM,YAAY,CAAA;AAGnE,OAAO,EAAE,KAAK,iBAAiB,EAAc,MAAM,UAAU,CAAA;AAG7D,OAAO,EAAE,KAAK,eAAe,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AACzE,OAAO,EACL,oBAAoB,EACpB,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC5B,YAAY,GACb,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,KAAK,iBAAiB,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAC7D,OAAO,EACL,KAAK,2BAA2B,EAChC,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,mBAAmB,CAAA;AAE1B,6CAA6C;AAC7C,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC;IAC1C;;;;;OAKG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAmCA,OAAO,KAAK,EACV,MAAM,EAIP,MAAM,MAAM,CAAA;AAGb,OAAO,EAAE,KAAK,mBAAmB,EAAgB,MAAM,YAAY,CAAA;AAGnE,OAAO,EAAE,KAAK,iBAAiB,EAAc,MAAM,UAAU,CAAA;AAG7D,OAAO,EAAE,KAAK,eAAe,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AACzE,OAAO,EACL,uBAAuB,EACvB,oBAAoB,EACpB,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC5B,YAAY,GACb,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,KAAK,iBAAiB,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAC7D,OAAO,EACL,KAAK,2BAA2B,EAChC,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,mBAAmB,CAAA;AAE1B,6CAA6C;AAC7C,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC;IAC1C;;;;;OAKG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB;;;;;;;OAOG;IACH,GAAG,CAAC,EAAE,IAAI,CAAC,iBAAiB,EAAE,SAAS,GAAG,gBAAgB,CAAC,GACzD,QAAQ,CAAC;QACP;;;;;;;;WAQG;QACH,KAAK,CAAC,EAAE,OAAO,GAAG,mBAAmB,CAAA;KACtC,CAAC,CAAA;IACJ;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAC,CAAA;AAonBF,eAAO,MAAM,OAAO,aAAa,oBAAoB,KAAQ,KAAK,CAAC,MAAM,CAuFxE,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Array, Console, Data, Duration, Effect, Exit, Fiber, HashMap, HashSet, Match, Option, Predicate, Queue, Ref, Schedule, Schema, Stream, pipe, } from 'effect';
|
|
2
2
|
import { Event as DevToolsEvent, EventFrame, RequestFrame, Response, ResponseFrame, } from 'foldkit/devtools-protocol';
|
|
3
|
-
import { PreserveModelMessage, RequestModelMessage, RestoreModelMessage, } from 'foldkit/
|
|
3
|
+
import { PreserveModelMessage, RequestModelMessage, RestoreModelMessage, } from 'foldkit/model-preservation';
|
|
4
4
|
import { createRequire } from 'node:module';
|
|
5
5
|
import { resolve } from 'node:path';
|
|
6
6
|
import { WebSocketServer } from 'ws';
|
|
@@ -10,7 +10,7 @@ import { devToolsOverlayPlugin } from './devToolsOverlay.js';
|
|
|
10
10
|
import { foldkitSsr } from './ssr.js';
|
|
11
11
|
import { foldkitViewIdentity } from './viewIdentity.js';
|
|
12
12
|
export { brandDistDirectory } from './brandDist.js';
|
|
13
|
-
export { FoldkitBuildManifest, foldkitBuild, } from './build.js';
|
|
13
|
+
export { FOLDKIT_FETCH_MODULE_ID, FoldkitBuildManifest, foldkitBuild, } from './build.js';
|
|
14
14
|
export { foldkitSsr } from './ssr.js';
|
|
15
15
|
export { foldkitViewIdentity, transformViewIdentity, } from './viewIdentity.js';
|
|
16
16
|
// NOTE: Vite's dep optimizer scans the consumer's source for `effect`
|
|
@@ -41,6 +41,7 @@ const FORCE_INCLUDED_EFFECT_NAMESPACES = [
|
|
|
41
41
|
'effect/HashMap',
|
|
42
42
|
'effect/HashSet',
|
|
43
43
|
'effect/Layer',
|
|
44
|
+
'effect/Logger',
|
|
44
45
|
'effect/Match',
|
|
45
46
|
'effect/Number',
|
|
46
47
|
'effect/Option',
|
|
@@ -114,26 +115,26 @@ const makeState = Effect.gen(function* () {
|
|
|
114
115
|
const encodeResponseFrameJson = Schema.encodeUnknownSync(Schema.fromJsonString(ResponseFrame));
|
|
115
116
|
// HANDLERS
|
|
116
117
|
const handlePreserveModelReceived = (state, payload) => Exit.match(Schema.decodeUnknownExit(PreserveModelMessage)(payload), {
|
|
117
|
-
onFailure: error => Console.warn('[foldkit:
|
|
118
|
-
onSuccess: ({ id, model,
|
|
119
|
-
const existingFlag = Option.exists(HashMap.get(current, id), ({
|
|
118
|
+
onFailure: error => Console.warn('[foldkit:preserve] failed to decode preserve-model payload', error),
|
|
119
|
+
onSuccess: ({ id, model, isReloadFlush }) => Ref.update(state.preservedModels, current => {
|
|
120
|
+
const existingFlag = Option.exists(HashMap.get(current, id), ({ isReloadFlush }) => isReloadFlush);
|
|
120
121
|
const entry = {
|
|
121
122
|
model,
|
|
122
|
-
|
|
123
|
+
isReloadFlush: isReloadFlush === true || existingFlag,
|
|
123
124
|
};
|
|
124
125
|
return HashMap.set(current, id, entry);
|
|
125
126
|
}),
|
|
126
127
|
});
|
|
127
128
|
const handleRequestModelReceived = (server, state, payload) => Exit.match(Schema.decodeUnknownExit(RequestModelMessage)(payload), {
|
|
128
|
-
onFailure: error => Console.warn('[foldkit:
|
|
129
|
+
onFailure: error => Console.warn('[foldkit:preserve] failed to decode request-model payload', error),
|
|
129
130
|
onSuccess: ({ id }) => Effect.gen(function* () {
|
|
130
131
|
const current = yield* Ref.get(state.preservedModels);
|
|
131
132
|
const sendRestore = (model) => Effect.sync(() => server.ws.send('foldkit:restore-model', Schema.encodeUnknownSync(RestoreModelMessage)(RestoreModelMessage.make({ id, model }))));
|
|
132
133
|
yield* Option.match(HashMap.get(current, id), {
|
|
133
134
|
onNone: () => sendRestore(undefined),
|
|
134
135
|
onSome: entry => {
|
|
135
|
-
if (entry.
|
|
136
|
-
const served = { ...entry,
|
|
136
|
+
if (entry.isReloadFlush) {
|
|
137
|
+
const served = { ...entry, isReloadFlush: false };
|
|
137
138
|
return Ref.update(state.preservedModels, HashMap.set(id, served)).pipe(Effect.flatMap(() => sendRestore(entry.model)));
|
|
138
139
|
}
|
|
139
140
|
return Ref.update(state.preservedModels, HashMap.remove(id)).pipe(Effect.flatMap(() => sendRestore(undefined)));
|
|
@@ -141,7 +142,7 @@ const handleRequestModelReceived = (server, state, payload) => Exit.match(Schema
|
|
|
141
142
|
});
|
|
142
143
|
}),
|
|
143
144
|
});
|
|
144
|
-
const handleHotUpdateFired = (state) => Ref.update(state.preservedModels, current => HashMap.map(current, entry => ({ ...entry,
|
|
145
|
+
const handleHotUpdateFired = (state) => Ref.update(state.preservedModels, current => HashMap.map(current, entry => ({ ...entry, isReloadFlush: true })));
|
|
145
146
|
const handleBrowserEventFrameReceived = (state, data, client) => Exit.match(Schema.decodeUnknownExit(EventFrame)(data), {
|
|
146
147
|
onFailure: error => Console.warn('[foldkit:devTools] failed to decode browser event frame', error),
|
|
147
148
|
onSuccess: frame => DevToolsEvent.match(frame.event, {
|
|
@@ -315,7 +316,7 @@ const main = (server, events, options) => Effect.gen(function* () {
|
|
|
315
316
|
};
|
|
316
317
|
yield* registerViteWsHandlers(server, state, enqueue);
|
|
317
318
|
// NOTE: Forked rather than awaited because binding the relay can retry for
|
|
318
|
-
// seconds.
|
|
319
|
+
// seconds. Model preservation is independent of the relay, and the runtime
|
|
319
320
|
// gives up on its boot-time model request in well under a second, so
|
|
320
321
|
// sequencing the dispatch loop behind the bind would cost model
|
|
321
322
|
// preservation whenever the port is contended.
|
|
@@ -327,8 +328,8 @@ const main = (server, events, options) => Effect.gen(function* () {
|
|
|
327
328
|
// PLUGIN ENTRY
|
|
328
329
|
/**
|
|
329
330
|
* Foldkit's Vite plugin set: the view-identity branding transform and
|
|
330
|
-
* DevTools overlay injection (dev and build), plus
|
|
331
|
-
*
|
|
331
|
+
* DevTools overlay injection (dev and build), plus Model preservation across
|
|
332
|
+
* reloads and the optional DevTools MCP relay (dev only). Returned as
|
|
332
333
|
* an array; Vite flattens nested plugin arrays, so `plugins: [foldkit()]`
|
|
333
334
|
* keeps working.
|
|
334
335
|
*/
|
|
@@ -337,15 +338,19 @@ const main = (server, events, options) => Effect.gen(function* () {
|
|
|
337
338
|
// that needs them to differ still can.
|
|
338
339
|
const withContainerId = (build, containerId) => {
|
|
339
340
|
const options = build === true ? {} : build;
|
|
340
|
-
if (containerId === undefined
|
|
341
|
+
if (containerId === undefined) {
|
|
341
342
|
return options;
|
|
342
343
|
}
|
|
344
|
+
const withContainer = { ...options, containerId };
|
|
345
|
+
if (options.prerender === undefined) {
|
|
346
|
+
return withContainer;
|
|
347
|
+
}
|
|
343
348
|
const prerender = options.prerender === true ? {} : options.prerender;
|
|
344
349
|
if (prerender === false) {
|
|
345
|
-
return
|
|
350
|
+
return withContainer;
|
|
346
351
|
}
|
|
347
352
|
return {
|
|
348
|
-
...
|
|
353
|
+
...withContainer,
|
|
349
354
|
prerender: { containerId, ...prerender },
|
|
350
355
|
};
|
|
351
356
|
};
|
|
@@ -366,8 +371,8 @@ export const foldkit = (options = {}) => {
|
|
|
366
371
|
return Fiber.interrupt(fiber);
|
|
367
372
|
}
|
|
368
373
|
});
|
|
369
|
-
const
|
|
370
|
-
name: 'foldkit
|
|
374
|
+
const reloadPlugin = {
|
|
375
|
+
name: 'foldkit',
|
|
371
376
|
apply: 'serve',
|
|
372
377
|
config: userConfig => ({
|
|
373
378
|
optimizeDeps: {
|
|
@@ -401,7 +406,7 @@ export const foldkit = (options = {}) => {
|
|
|
401
406
|
foldkitBuildToken(options.buildId),
|
|
402
407
|
foldkitViewIdentity(),
|
|
403
408
|
devToolsOverlayPlugin(),
|
|
404
|
-
|
|
409
|
+
reloadPlugin,
|
|
405
410
|
];
|
|
406
411
|
if (options.ssr === undefined) {
|
|
407
412
|
return shared;
|
|
@@ -410,6 +415,7 @@ export const foldkit = (options = {}) => {
|
|
|
410
415
|
const servePages = foldkitSsr({
|
|
411
416
|
...ssr,
|
|
412
417
|
...(options.buildId === undefined ? {} : { buildId: options.buildId }),
|
|
418
|
+
quietStandDown: build !== undefined && build !== false,
|
|
413
419
|
});
|
|
414
420
|
if (build === undefined || build === false) {
|
|
415
421
|
return [...shared, servePages];
|
package/dist/ssr.d.ts
CHANGED
|
@@ -36,6 +36,12 @@ export type FoldkitSsrOptions = Readonly<{
|
|
|
36
36
|
* The value is public in rendered HTML, so it must not be a secret.
|
|
37
37
|
*/
|
|
38
38
|
buildId?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Skip the stand-down warning when the `ssr` environment is not runnable.
|
|
41
|
+
* The aggregate plugin sets this when `ssr.build` is on, because production
|
|
42
|
+
* still needs `serverEntry` and the host is supposed to serve.
|
|
43
|
+
*/
|
|
44
|
+
quietStandDown?: boolean;
|
|
39
45
|
}>;
|
|
40
46
|
/**
|
|
41
47
|
* Serves server-rendered pages from the Vite dev server.
|
package/dist/ssr.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ssr.d.ts","sourceRoot":"","sources":["../src/ssr.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAGV,MAAM,EAGP,MAAM,MAAM,CAAA;AAIb,0EAA0E;AAC1E,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC;IACvC;;;;;OAKG;IACH,WAAW,EAAE,MAAM,CAAA;IACnB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"ssr.d.ts","sourceRoot":"","sources":["../src/ssr.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAGV,MAAM,EAGP,MAAM,MAAM,CAAA;AAIb,0EAA0E;AAC1E,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC;IACvC;;;;;OAKG;IACH,WAAW,EAAE,MAAM,CAAA;IACnB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB,CAAC,CAAA;AAwsBF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,UAAU,YAAa,iBAAiB,KAAG,MAgEvD,CAAA"}
|
package/dist/ssr.js
CHANGED
|
@@ -497,11 +497,11 @@ export const foldkitSsr = (options) => {
|
|
|
497
497
|
// bindings the deployed entry holds, while the deployment it is standing
|
|
498
498
|
// in for renders in workerd.
|
|
499
499
|
if (!isRunnable(server.environments.ssr)) {
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
500
|
+
if (options.quietStandDown !== true) {
|
|
501
|
+
server.config.logger.warn('[foldkit] the "ssr" environment is not runnable, so another plugin owns' +
|
|
502
|
+
" server-side execution. Dev-time rendering through Foldkit's Vite" +
|
|
503
|
+
' middleware is off; page requests go to that host.');
|
|
504
|
+
}
|
|
505
505
|
return;
|
|
506
506
|
}
|
|
507
507
|
const requestUrls = new WeakMap();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@foldkit/vite-plugin",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Vite plugin for Foldkit
|
|
3
|
+
"version": "0.21.0-canary.ba0d6f141325",
|
|
4
|
+
"description": "Vite plugin for Foldkit with state-preserving live reload",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"module": "./dist/index.js",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
],
|
|
18
18
|
"peerDependencies": {
|
|
19
19
|
"effect": "4.0.0-rc.112",
|
|
20
|
-
"foldkit": "
|
|
20
|
+
"foldkit": "0.159.0-canary.ba0d6f141325",
|
|
21
21
|
"vite": "^7.0.0 || ^8.0.0"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
@@ -34,14 +34,14 @@
|
|
|
34
34
|
"vite": "^8.2.2",
|
|
35
35
|
"vite7": "npm:vite@^7.3.6",
|
|
36
36
|
"vitest": "^4.1.11",
|
|
37
|
-
"foldkit": "0.
|
|
37
|
+
"foldkit": "0.159.0-canary.ba0d6f141325"
|
|
38
38
|
},
|
|
39
39
|
"keywords": [
|
|
40
40
|
"vite",
|
|
41
41
|
"vite-plugin",
|
|
42
42
|
"foldkit",
|
|
43
|
-
"
|
|
44
|
-
"
|
|
43
|
+
"live-reload",
|
|
44
|
+
"state-preservation"
|
|
45
45
|
],
|
|
46
46
|
"author": "Devin Jameson",
|
|
47
47
|
"license": "MIT",
|