@foldkit/vite-plugin 0.26.1-canary.fe2701c2fa4b → 0.27.0-canary.49dc36ef672d

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 CHANGED
@@ -98,19 +98,20 @@ The standalone build plugin takes `foldkitBuild(serverEntry, { clientEntry, ...o
98
98
  Each module graph must load one Foldkit copy. The plugin configures Vite for that:
99
99
 
100
100
  - `resolve.dedupe` lists `foldkit`, `@foldkit/ui`, and `@foldkit/devtools`, each only when it resolves from the application root.
101
- - Server builds and the dev server's server render bundle those three packages, plus every installed package whose `dependencies` or `peerDependencies` include `foldkit` or an `@foldkit/*` package, such as `@foldkit/markdown`. In the dev server, these `ssr.noExternal` packages run through Vite's module runner instead of Node's own import. An explicit `ssr.external` entry still keeps a package external.
101
+ - In server builds and in every server environment of the dev server, the plugin bundles those three packages, plus every installed package whose `dependencies` or `peerDependencies` include `foldkit` or an `@foldkit/*` package, such as `@foldkit/markdown`. The plugin lists them in `resolve.noExternal`, which Vite applies to every environment, and in `ssr.noExternal`. In a Node server environment of the dev server, these packages run through Vite's module runner instead of Node's own import. An explicit `ssr.external` or `resolve.external` entry still keeps a package external.
102
102
  - The plugin finds these packages by crawling from the application's `package.json`. It follows the application's `dependencies` and `devDependencies`, then the `dependencies` of each package it bundles, plus the `devDependencies` of a bundled package that is a private workspace package.
103
+ - The plugin excludes `foldkit` from dependency pre-bundling in every environment, so the build id transform runs on it. It also pre-bundles the Effect entries Foldkit imports in every environment whose optimizer is enabled, for example a Cloudflare Worker environment, so Foldkit and the application share one Effect instance. Applications need no `optimizeDeps` settings for Foldkit.
103
104
 
104
- A package the crawl does not reach stays external. For example: a peer the application does not declare, or a package reached only through a package that does not depend on Foldkit. Such a package loads a second Foldkit copy from `node_modules` at runtime. Declare it in the application's `package.json`, or add it to `ssr.noExternal`:
105
+ A package the crawl does not reach stays external. For example: a peer the application does not declare, or a package reached only through a package that does not depend on Foldkit. Such a package loads a second Foldkit copy from `node_modules` at runtime. Declare it in the application's `package.json`, or add it to `resolve.noExternal`, which Vite applies to every environment:
105
106
 
106
107
  ```typescript
107
108
  export default defineConfig({
108
109
  plugins: [foldkit()],
109
- ssr: { noExternal: ['foldkit-component-library'] },
110
+ resolve: { noExternal: ['foldkit-component-library'] },
110
111
  })
111
112
  ```
112
113
 
113
- Vitest copies SSR `noExternal` into `server.deps.inline`. A Vitest config that includes `foldkit()` therefore also inlines the crawled packages in tests.
114
+ Vitest copies each environment's `resolve.noExternal` into `server.deps.inline`. A Vitest config that includes `foldkit()` therefore also inlines the crawled packages in tests.
114
115
 
115
116
  ## Completed build metadata
116
117
 
@@ -12,6 +12,6 @@ export declare const isFoldkitSingletonPackageSpecifier: (specifier: string) =>
12
12
  */
13
13
  export declare const crawlFoldkitPackages: (root: string, isBuild: boolean, viteUserConfig: UserConfig) => Promise<Readonly<{
14
14
  dedupe: Array<string>;
15
- ssrNoExternal: Array<string>;
15
+ noExternal: Array<string>;
16
16
  }>>;
17
17
  //# sourceMappingURL=foldkitPackages.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"foldkitPackages.d.ts","sourceRoot":"","sources":["../src/foldkitPackages.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,UAAU,EAA0B,MAAM,MAAM,CAAA;AAS9D;;;;GAIG;AACH,eAAO,MAAM,kCAAkC,cAClC,MAAM,KAChB,OAKA,CAAA;AA8CH;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,SACzB,MAAM,WACH,OAAO,kBACA,UAAU,KACzB,OAAO,CACR,QAAQ,CAAC;IAAE,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAAC,aAAa,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;CAAE,CAAC,CAqClE,CAAA"}
1
+ {"version":3,"file":"foldkitPackages.d.ts","sourceRoot":"","sources":["../src/foldkitPackages.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,UAAU,EAA0B,MAAM,MAAM,CAAA;AAS9D;;;;GAIG;AACH,eAAO,MAAM,kCAAkC,cAClC,MAAM,KAChB,OAKA,CAAA;AA8CH;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,SACzB,MAAM,WACH,OAAO,kBACA,UAAU,KACzB,OAAO,CAAC,QAAQ,CAAC;IAAE,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAAC,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;CAAE,CAAC,CAoCxE,CAAA"}
@@ -58,11 +58,11 @@ export const crawlFoldkitPackages = async (root, isBuild, viteUserConfig) => {
58
58
  viteUserConfig,
59
59
  isSemiFrameworkPkgByJson: dependsOnFoldkit,
60
60
  });
61
- const ssrNoExternal = Array.dedupe([
61
+ const noExternal = Array.dedupe([
62
62
  ...FOLDKIT_SINGLETON_PACKAGES,
63
63
  ...crawl.ssr.noExternal,
64
64
  ]);
65
65
  const maybeResolvableSingletons = await Promise.all(Array.map(FOLDKIT_SINGLETON_PACKAGES, async (packageName) => pipe(await findDepPkgJsonPath(packageName, crawlRoot), Option.fromUndefinedOr, Option.as(packageName))));
66
66
  const dedupe = Array.getSomes(maybeResolvableSingletons);
67
- return { dedupe, ssrNoExternal };
67
+ return { dedupe, noExternal };
68
68
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA6CA,OAAO,KAAK,EAEV,MAAM,EAIP,MAAM,MAAM,CAAA;AAOb,OAAO,EAAE,KAAK,mBAAmB,EAAgB,MAAM,YAAY,CAAA;AAKnE,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,oBAAoB,EACpB,KAAK,eAAe,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;;;;;;;;OAQG;IACH,eAAe,CAAC,EAAE,MAAM,GAAG,KAAK,CAAA;IAChC;;;;;;;OAOG;IACH,GAAG,CAAC,EAAE,IAAI,CACR,iBAAiB,EACjB,SAAS,GAAG,gBAAgB,GAAG,aAAa,GAAG,aAAa,CAC7D,GACC,CACI,QAAQ,CAAC;QACP,kFAAkF;QAClF,WAAW,EAAE,MAAM,CAAA;QACnB,WAAW,CAAC,EAAE,KAAK,CAAA;QACnB;;;;;;;;WAQG;QACH,KAAK,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC,mBAAmB,EAAE,aAAa,CAAC,CAAA;KAC3D,CAAC,GACF,QAAQ,CAAC;QACP,kEAAkE;QAClE,WAAW,CAAC,EAAE,KAAK,CAAA;QACnB,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,KAAK,CAAC,EAAE,KAAK,CAAA;KACd,CAAC,CACL,CAAA;IACH;;;;;;;;;;;;;;;;OAgBG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAC,CAAA;AA64BF,eAAO,MAAM,OAAO,aAAa,oBAAoB,KAAQ,KAAK,CAAC,MAAM,CAuIxE,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA6CA,OAAO,KAAK,EAGV,MAAM,EAIP,MAAM,MAAM,CAAA;AAOb,OAAO,EAAE,KAAK,mBAAmB,EAAgB,MAAM,YAAY,CAAA;AAKnE,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,oBAAoB,EACpB,KAAK,eAAe,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;;;;;;;;OAQG;IACH,eAAe,CAAC,EAAE,MAAM,GAAG,KAAK,CAAA;IAChC;;;;;;;OAOG;IACH,GAAG,CAAC,EAAE,IAAI,CACR,iBAAiB,EACjB,SAAS,GAAG,gBAAgB,GAAG,aAAa,GAAG,aAAa,CAC7D,GACC,CACI,QAAQ,CAAC;QACP,kFAAkF;QAClF,WAAW,EAAE,MAAM,CAAA;QACnB,WAAW,CAAC,EAAE,KAAK,CAAA;QACnB;;;;;;;;WAQG;QACH,KAAK,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC,mBAAmB,EAAE,aAAa,CAAC,CAAA;KAC3D,CAAC,GACF,QAAQ,CAAC;QACP,kEAAkE;QAClE,WAAW,CAAC,EAAE,KAAK,CAAA;QACnB,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,KAAK,CAAC,EAAE,KAAK,CAAA;KACd,CAAC,CACL,CAAA;IACH;;;;;;;;;;;;;;;;OAgBG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAC,CAAA;AA86BF,eAAO,MAAM,OAAO,aAAa,oBAAoB,KAAQ,KAAK,CAAC,MAAM,CA+IxE,CAAA"}
package/dist/index.js CHANGED
@@ -19,12 +19,12 @@ export { FOLDKIT_FETCH_MODULE_ID, FoldkitBuildManifest, FoldkitBuildMetadata, fo
19
19
  export { foldkitSsr } from './ssr.js';
20
20
  export { foldkitViewIdentity, transformViewIdentity, } from './viewIdentity.js';
21
21
  // NOTE: Vite does not scan imports through `foldkit` because the plugin
22
- // excludes the package from optimization. A consumer can import only Effect
23
- // subpaths while Foldkit's compiled distribution imports the bare barrel, so
24
- // include both the barrel and every top-level namespace Foldkit imports. This
25
- // keeps them in one optimized dependency graph. Over-inclusion is harmless;
26
- // under-inclusion is the bug. `scripts/check-effect-prebundle.ts` keeps the
27
- // entries in sync with Foldkit's source and runs in `pnpm check`.
22
+ // excludes the package from optimization in every environment. A consumer can
23
+ // import only Effect subpaths while Foldkit's compiled distribution imports the
24
+ // bare barrel, so include both the barrel and every top-level namespace Foldkit
25
+ // imports. This keeps them in one optimized dependency graph. Over-inclusion is
26
+ // harmless; under-inclusion is the bug. `scripts/check-effect-prebundle.ts`
27
+ // keeps the entries in sync with Foldkit's source and runs in `pnpm check`.
28
28
  const FORCE_INCLUDED_EFFECT_ENTRIES = [
29
29
  'effect',
30
30
  'effect/Array',
@@ -70,6 +70,16 @@ const FORCE_INCLUDED_EFFECT_ENTRIES = [
70
70
  'effect/SubscriptionRef',
71
71
  'effect/Types',
72
72
  ];
73
+ // NOTE: Adding includes to an environment whose optimizer is otherwise disabled
74
+ // turns on Vite's explicit optimizer, which would pre-bundle Effect in Vite's
75
+ // default Node `ssr` environment.
76
+ const shouldForceEffectEntries = (name, config) => {
77
+ const consumer = config.consumer ?? (name === 'client' ? 'client' : 'server');
78
+ const isClientEnvironment = consumer === 'client';
79
+ const isDiscoveryEnabled = config.optimizeDeps?.noDiscovery === false;
80
+ const isExplicitOptimizationEnabled = Array.isArrayNonEmpty(config.optimizeDeps?.include ?? []);
81
+ return (isClientEnvironment || isDiscoveryEnabled || isExplicitOptimizationEnabled);
82
+ };
73
83
  const Event = Data.taggedEnum();
74
84
  const makeState = Effect.gen(function* () {
75
85
  const preservedModels = yield* Ref.make(HashMap.empty());
@@ -87,6 +97,8 @@ const makeState = Effect.gen(function* () {
87
97
  return state;
88
98
  });
89
99
  const encodeResponseFrameJson = Schema.encodeUnknownSync(Schema.fromJsonString(ResponseFrame));
100
+ class WebSocketSendFailed extends Data.TaggedError('WebSocketSendFailed') {
101
+ }
90
102
  // HANDLERS
91
103
  const handlePreserveModelReceived = (state, payload) => Exit.match(Schema.decodeUnknownExit(PreserveModelMessage)(payload), {
92
104
  onFailure: error => Console.warn('[foldkit:preserve] failed to decode preserve-model payload', error),
@@ -103,7 +115,14 @@ const handleRequestModelReceived = (server, state, payload) => Exit.match(Schema
103
115
  onFailure: error => Console.warn('[foldkit:preserve] failed to decode request-model payload', error),
104
116
  onSuccess: ({ id }) => Effect.gen(function* () {
105
117
  const current = yield* Ref.get(state.preservedModels);
106
- const sendRestore = (model) => Effect.sync(() => server.ws.send('foldkit:restore-model', Schema.encodeUnknownSync(RestoreModelMessage)(RestoreModelMessage.make({ id, model }))));
118
+ const sendRestore = (model) => Effect.gen(function* () {
119
+ const frame = RestoreModelMessage.make({ id, model });
120
+ const encoded = yield* Schema.encodeEffect(RestoreModelMessage)(frame);
121
+ yield* Effect.try({
122
+ try: () => server.ws.send('foldkit:restore-model', encoded),
123
+ catch: cause => new WebSocketSendFailed({ cause }),
124
+ });
125
+ }).pipe(Effect.catch(error => Console.warn('[foldkit:preserve] failed to send restore-model payload', error)));
107
126
  yield* Option.match(HashMap.get(current, id), {
108
127
  onNone: () => sendRestore(undefined),
109
128
  onSome: entry => {
@@ -175,7 +194,7 @@ const handleMcpClientDisconnected = (state, client) => Effect.gen(function* () {
175
194
  const remaining = HashSet.size(yield* Ref.get(state.mcpClients));
176
195
  yield* Console.log(`[foldkit:devTools] MCP client disconnected (${remaining} remaining)`);
177
196
  });
178
- const handleMcpRequestReceived = (server, state, client, raw) => Exit.match(Schema.decodeUnknownExit(Schema.fromJsonString(RequestFrame))(raw), {
197
+ const handleMcpRequestReceived = (server, state, client, raw) => Exit.match(Schema.decodeExit(Schema.fromJsonString(RequestFrame))(raw), {
179
198
  onFailure: error => Console.warn('[foldkit:devTools] failed to decode MCP request frame', error),
180
199
  onSuccess: frame => Match.value(frame.request).pipe(Match.tag('RequestListRuntimes', () => replyListRuntimes(state, client, frame.id)), Match.orElse(() => forwardRequestToBrowsers(server, frame))),
181
200
  });
@@ -191,7 +210,13 @@ const replyListRuntimes = (state, client, requestId) => Effect.gen(function* ()
191
210
  }
192
211
  });
193
212
  });
194
- const forwardRequestToBrowsers = (server, frame) => Effect.sync(() => server.ws.send('foldkit:devTools:request', Schema.encodeUnknownSync(RequestFrame)(frame)));
213
+ const forwardRequestToBrowsers = (server, frame) => Effect.gen(function* () {
214
+ const encoded = yield* Schema.encodeEffect(RequestFrame)(frame);
215
+ yield* Effect.try({
216
+ try: () => server.ws.send('foldkit:devTools:request', encoded),
217
+ catch: cause => new WebSocketSendFailed({ cause }),
218
+ });
219
+ }).pipe(Effect.catch(error => Console.warn('[foldkit:devTools] failed to send request frame', error)));
195
220
  // EVENT DISPATCH
196
221
  const dispatchEvent = (server, state, event) => Match.value(event).pipe(Match.tagsExhaustive({
197
222
  PreserveModelReceived: ({ payload }) => handlePreserveModelReceived(state, payload),
@@ -492,11 +517,15 @@ export const foldkit = (options = {}) => {
492
517
  const reloadPlugin = {
493
518
  name: 'foldkit',
494
519
  apply: 'serve',
495
- config: () => ({
496
- optimizeDeps: {
497
- include: [...FORCE_INCLUDED_EFFECT_ENTRIES],
498
- },
499
- }),
520
+ // NOTE: The `post` order runs this hook after every default-order
521
+ // `configEnvironment` hook, so the predicate sees discovery or includes
522
+ // that another plugin turns on there.
523
+ configEnvironment: {
524
+ order: 'post',
525
+ handler: (name, config) => shouldForceEffectEntries(name, config)
526
+ ? { optimizeDeps: { include: [...FORCE_INCLUDED_EFFECT_ENTRIES] } }
527
+ : undefined,
528
+ },
500
529
  configureServer: server => {
501
530
  const events = Effect.runSync(Queue.unbounded());
502
531
  // NOTE: The default ConfigProvider snapshots the environment. Create a
@@ -526,24 +555,27 @@ export const foldkit = (options = {}) => {
526
555
  config: async (userConfig, { command }) => {
527
556
  const foldkitPackages = await crawlFoldkitPackages(userConfig.root ?? process.cwd(), command === 'build', userConfig);
528
557
  return {
529
- optimizeDeps: {
530
- exclude: ['foldkit'],
531
- },
532
558
  resolve: {
533
559
  dedupe: foldkitPackages.dedupe,
560
+ noExternal: foldkitPackages.noExternal,
534
561
  },
535
562
  ssr: {
536
- noExternal: foldkitPackages.ssrNoExternal,
563
+ noExternal: foldkitPackages.noExternal,
537
564
  },
538
565
  environments: {
539
566
  ssr: {
540
567
  resolve: {
541
- noExternal: foldkitPackages.ssrNoExternal,
568
+ noExternal: foldkitPackages.noExternal,
542
569
  },
543
570
  },
544
571
  },
545
572
  };
546
573
  },
574
+ configEnvironment: () => ({
575
+ optimizeDeps: {
576
+ exclude: ['foldkit'],
577
+ },
578
+ }),
547
579
  };
548
580
  const shared = [
549
581
  resolutionPlugin,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@foldkit/vite-plugin",
3
- "version": "0.26.1-canary.fe2701c2fa4b",
3
+ "version": "0.27.0-canary.49dc36ef672d",
4
4
  "description": "Vite plugin for Foldkit with state-preserving live reload",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -17,7 +17,7 @@
17
17
  ],
18
18
  "peerDependencies": {
19
19
  "effect": "4.0.0",
20
- "foldkit": "0.166.0-canary.fe2701c2fa4b",
20
+ "foldkit": "0.167.0-canary.49dc36ef672d",
21
21
  "vite": "^8.0.0"
22
22
  },
23
23
  "dependencies": {
@@ -32,13 +32,13 @@
32
32
  "@types/ws": "^8.18.1",
33
33
  "@vitejs/plugin-basic-ssl": "^2.3.0",
34
34
  "effect": "4.0.0",
35
+ "foldkit": "0.167.0-canary.49dc36ef672d",
35
36
  "happy-dom": "^20.14.5",
36
37
  "rimraf": "^6.1.3",
37
38
  "typescript": "^7.0.2",
38
39
  "vite": "^8.3.1",
39
40
  "vite-host": "npm:vite@8.2.1",
40
- "vitest": "^4.1.11",
41
- "foldkit": "0.166.0-canary.fe2701c2fa4b"
41
+ "vitest": "^4.1.11"
42
42
  },
43
43
  "keywords": [
44
44
  "vite",