@timber-js/app 0.2.0-alpha.152 → 0.2.0-alpha.154
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/_chunks/actions-8lJZYYGq.js +298 -0
- package/dist/_chunks/actions-8lJZYYGq.js.map +1 -0
- package/dist/_chunks/{cache-api-Co-yI-gP.js → cache-api-e1E4i3Vy.js} +3 -26
- package/dist/_chunks/cache-api-e1E4i3Vy.js.map +1 -0
- package/dist/_chunks/{cli-schema-sync-DJDdyEae.js → cli-schema-sync-ChsRzw8o.js} +2 -2
- package/dist/_chunks/{cli-schema-sync-DJDdyEae.js.map → cli-schema-sync-ChsRzw8o.js.map} +1 -1
- package/dist/_chunks/{cli-schema-sync-D_IhHEUW.js → cli-schema-sync-D4urWkeV.js} +1 -1
- package/dist/_chunks/{actions-a0RczDnB.js → logger-DvmCWhN9.js} +665 -274
- package/dist/_chunks/logger-DvmCWhN9.js.map +1 -0
- package/dist/_chunks/plugin-context-GfDWsdd2.js.map +1 -1
- package/dist/_chunks/{walkers-DvWDj453.js → walkers-DZuFKqFX.js} +2 -2
- package/dist/_chunks/{walkers-DvWDj453.js.map → walkers-DZuFKqFX.js.map} +1 -1
- package/dist/cache/index.js +1 -1
- package/dist/cli.js +1 -1
- package/dist/client/browser-dev.d.ts +3 -0
- package/dist/client/browser-dev.d.ts.map +1 -1
- package/dist/client/browser-entry/action-dispatch.d.ts.map +1 -1
- package/dist/config-types.d.ts +8 -0
- package/dist/config-types.d.ts.map +1 -1
- package/dist/config-validation.d.ts.map +1 -1
- package/dist/index.js +193 -48
- package/dist/index.js.map +1 -1
- package/dist/plugin-context.d.ts +9 -0
- package/dist/plugin-context.d.ts.map +1 -1
- package/dist/plugins/build-report.d.ts +13 -0
- package/dist/plugins/build-report.d.ts.map +1 -1
- package/dist/plugins/chunks.d.ts +11 -4
- package/dist/plugins/chunks.d.ts.map +1 -1
- package/dist/plugins/client-chunks.d.ts +23 -22
- package/dist/plugins/client-chunks.d.ts.map +1 -1
- package/dist/routing/index.js +2 -2
- package/dist/server/index.js +2 -2
- package/dist/server/internal.js +71 -4
- package/dist/server/internal.js.map +1 -1
- package/dist/server/logger.d.ts.map +1 -1
- package/dist/server/pipeline-metadata.d.ts.map +1 -1
- package/dist/server/pipeline-phases.d.ts.map +1 -1
- package/dist/server/pipeline.d.ts.map +1 -1
- package/dist/server/primitives.d.ts +8 -0
- package/dist/server/primitives.d.ts.map +1 -1
- package/dist/server/sitemap-handler.d.ts.map +1 -1
- package/dist/server/stream-utils.d.ts +11 -0
- package/dist/server/stream-utils.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/client/browser-dev.ts +3 -0
- package/src/client/browser-entry/action-dispatch.ts +14 -0
- package/src/config-types.ts +8 -0
- package/src/config-validation.ts +16 -0
- package/src/index.ts +2 -2
- package/src/plugin-context.ts +9 -0
- package/src/plugins/build-report.ts +105 -10
- package/src/plugins/chunks.ts +74 -5
- package/src/plugins/client-chunks.ts +73 -42
- package/src/server/logger.ts +5 -0
- package/src/server/pipeline-metadata.ts +1 -0
- package/src/server/pipeline-phases.ts +4 -1
- package/src/server/pipeline.ts +13 -0
- package/src/server/primitives.ts +29 -0
- package/src/server/sitemap-handler.ts +12 -3
- package/src/server/stream-utils.ts +73 -0
- package/dist/_chunks/actions-a0RczDnB.js.map +0 -1
- package/dist/_chunks/cache-api-Co-yI-gP.js.map +0 -1
- package/dist/_chunks/logger-CM0clugc.js +0 -645
- package/dist/_chunks/logger-CM0clugc.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/server/logger.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/server/logger.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline-metadata.d.ts","sourceRoot":"","sources":["../../src/server/pipeline-metadata.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAgBH;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CAC3C,SAAS,EAAE,OAAO,oBAAoB,EAAE,kBAAkB,GACzD,OAAO,CAAC,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"pipeline-metadata.d.ts","sourceRoot":"","sources":["../../src/server/pipeline-metadata.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAgBH;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CAC3C,SAAS,EAAE,OAAO,oBAAoB,EAAE,kBAAkB,GACzD,OAAO,CAAC,QAAQ,CAAC,CAanB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,KAAK,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC,GACD,MAAM,CAoBR;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,MAAM,CAMnE;AAED,qCAAqC;AACrC,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAO7C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline-phases.d.ts","sourceRoot":"","sources":["../../src/server/pipeline-phases.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAoBH,OAAO,EAA2C,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEpG,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC7E,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAKrF,UAAU,aAAa;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,mBAAmB,CAAC;CACpC;AAwBD;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,aAAa,EACvB,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,YAAY,CAAC,CAmBvB;AAID;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,UAAU,EACjB,eAAe,EAAE,OAAO,EACxB,oBAAoB,EAAE,OAAO,EAC7B,aAAa,EAAE,aAAa,GAC3B,OAAO,CAAC,YAAY,CAAC,CA6DvB;AAID;;;GAGG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,UAAU,EACjB,eAAe,EAAE,OAAO,EACxB,oBAAoB,EAAE,OAAO,EAC7B,EAAE,iBAAiB,EAAE,YAAY,EAAE,EAAE,aAAa,GACjD,OAAO,CAAC,YAAY,CAAC,CAkBvB;AAID;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,eAAe,CAAC,EAAE,OAAO,GACxB,OAAO,CAAC,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"pipeline-phases.d.ts","sourceRoot":"","sources":["../../src/server/pipeline-phases.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAoBH,OAAO,EAA2C,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEpG,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC7E,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAKrF,UAAU,aAAa;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,mBAAmB,CAAC;CACpC;AAwBD;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,aAAa,EACvB,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,YAAY,CAAC,CAmBvB;AAID;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,UAAU,EACjB,eAAe,EAAE,OAAO,EACxB,oBAAoB,EAAE,OAAO,EAC7B,aAAa,EAAE,aAAa,GAC3B,OAAO,CAAC,YAAY,CAAC,CA6DvB;AAID;;;GAGG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,UAAU,EACjB,eAAe,EAAE,OAAO,EACxB,oBAAoB,EAAE,OAAO,EAC7B,EAAE,iBAAiB,EAAE,YAAY,EAAE,EAAE,aAAa,GACjD,OAAO,CAAC,YAAY,CAAC,CAkBvB;AAID;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,eAAe,CAAC,EAAE,OAAO,GACxB,OAAO,CAAC,QAAQ,CAAC,CAwSnB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/server/pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/server/pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAa3D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAS9D;;;;;;;;GAQG;AACH,MAAM,WAAW,UAAU;IACzB,mDAAmD;IACnD,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,sEAAsE;IACtE,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IACjD;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IACrD,oEAAoE;IACpE,eAAe,EAAE,YAAY,EAAE,CAAC;CACjC;AAED,6DAA6D;AAC7D,MAAM,MAAM,YAAY,GAAG,CAAC,QAAQ,EAAE,MAAM,KAAK,UAAU,GAAG,IAAI,CAAC;AAEnE,sEAAsE;AACtE,MAAM,MAAM,oBAAoB,GAAG,CACjC,QAAQ,EAAE,MAAM,KACb,OAAO,oBAAoB,EAAE,kBAAkB,GAAG,IAAI,CAAC;AAE5D,iEAAiE;AACjE,MAAM,WAAW,mBAAmB;IAClC,iEAAiE;IACjE,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,6DAA6D;AAC7D,MAAM,MAAM,aAAa,GAAG,CAC1B,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,UAAU,EACjB,eAAe,EAAE,OAAO,EACxB,oBAAoB,EAAE,OAAO,EAC7B,YAAY,CAAC,EAAE,mBAAmB,KAC/B,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;AAElC,+DAA+D;AAC/D,MAAM,MAAM,iBAAiB,GAAG,CAC9B,KAAK,EAAE,UAAU,EACjB,GAAG,EAAE,OAAO,EACZ,eAAe,EAAE,OAAO,KACrB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAI1B;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,OAAO,CAAC;QAAE,OAAO,EAAE,WAAW,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC;AAEtE,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,KAAK,CAAC,EAAE,WAAW,GAAG,WAAW,CAAC;IAClC,qEAAqE;IACrE,UAAU,EAAE,YAAY,CAAC;IACzB,iGAAiG;IACjG,kBAAkB,CAAC,EAAE,oBAAoB,CAAC;IAC1C,kEAAkE;IAClE,MAAM,EAAE,aAAa,CAAC;IACtB,kEAAkE;IAClE,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,eAAe,EAAE,OAAO,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACzF,kFAAkF;IAClF,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B,gFAAgF;IAChF,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,yGAAyG;IACzG,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,OAAO,4BAA4B,EAAE,mBAAmB,EAAE,CAAC;IAClF;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,UAAU,GAAG,OAAO,GAAG,KAAK,CAAC;IAC5C;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IACpE;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAExD;;;;;;;;;;;;OAYG;IACH,uBAAuB,CAAC,EAAE,CACxB,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,MAAM,EACb,eAAe,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,KAAK,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;KAAE,CAAC,KACnF,IAAI,CAAC;IAEV;;;;;;;;;OASG;IACH,aAAa,CAAC,EAAE,OAAO,gCAAgC,EAAE,kBAAkB,CAAC;IAE5E;;;;;;;;;;OAUG;IACH,mBAAmB,CAAC,EAAE,CACpB,KAAK,EAAE,OAAO,EACd,GAAG,EAAE,OAAO,EACZ,eAAe,EAAE,OAAO,KACrB,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAClC;;;;;;;OAOG;IACH,kBAAkB,CAAC,EAAE,CACnB,IAAI,EAAE,UAAU,EAChB,GAAG,EAAE,OAAO,EACZ,eAAe,EAAE,OAAO;IACxB;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,UAAU,KACf,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CACnC;AAID;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,cAAc,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CA+K1F"}
|
|
@@ -70,6 +70,14 @@ export declare class RedirectSignal extends Error {
|
|
|
70
70
|
readonly status: number;
|
|
71
71
|
constructor(location: string, status: number);
|
|
72
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Returns true if the error is a framework control-flow signal (RedirectSignal
|
|
75
|
+
* or DenySignal) rather than a genuine application error. Works both for direct
|
|
76
|
+
* instances (RSC-side) and deserialized digest errors (SSR cross-boundary).
|
|
77
|
+
*
|
|
78
|
+
* See also: isFrameworkSignalError() in client/browser-dev.ts (client-only).
|
|
79
|
+
*/
|
|
80
|
+
export declare function isControlFlowSignal(error: unknown): boolean;
|
|
73
81
|
/**
|
|
74
82
|
* Options for redirect() — alternative to passing a bare status code.
|
|
75
83
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../../src/server/primitives.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../../src/server/primitives.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sitemap-handler.d.ts","sourceRoot":"","sources":["../../src/server/sitemap-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AASH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAKvD;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,WAAW,EACjB,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACrC,CAAC,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"sitemap-handler.d.ts","sourceRoot":"","sources":["../../src/server/sitemap-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AASH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAKvD;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,WAAW,EACjB,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACrC,CAAC,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC,GAAG,SAAS,CAyH9D"}
|
|
@@ -33,4 +33,15 @@ export interface TeeOptions {
|
|
|
33
33
|
* The returned streams are drop-in replacements for the native tee branches.
|
|
34
34
|
*/
|
|
35
35
|
export declare function teeWithErrorPropagation(stream: ReadableStream<Uint8Array>, options?: TeeOptions): [ReadableStream<Uint8Array>, ReadableStream<Uint8Array>];
|
|
36
|
+
/**
|
|
37
|
+
* Wrap a response body with stream-lifecycle timing instrumentation.
|
|
38
|
+
*
|
|
39
|
+
* Logs firstChunk, lastChunk, close, maxGap (largest inter-chunk gap),
|
|
40
|
+
* chunk count, and byte count on stream termination (clean close OR
|
|
41
|
+
* cancellation/disconnect). Gated behind `serverTiming: 'detailed'`.
|
|
42
|
+
*
|
|
43
|
+
* Uses a manual reader pump to guarantee logging on all termination
|
|
44
|
+
* paths — TransformStream.flush() is not called on cancellation.
|
|
45
|
+
*/
|
|
46
|
+
export declare function wrapResponseWithStreamTiming(body: ReadableStream<Uint8Array>, startTime: number): ReadableStream<Uint8Array>;
|
|
36
47
|
//# sourceMappingURL=stream-utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream-utils.d.ts","sourceRoot":"","sources":["../../src/server/stream-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,MAAM,WAAW,UAAU;IACzB;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,EAClC,OAAO,CAAC,EAAE,UAAU,GACnB,CAAC,cAAc,CAAC,UAAU,CAAC,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC,CAmK1D"}
|
|
1
|
+
{"version":3,"file":"stream-utils.d.ts","sourceRoot":"","sources":["../../src/server/stream-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,MAAM,WAAW,UAAU;IACzB;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,EAClC,OAAO,CAAC,EAAE,UAAU,GACnB,CAAC,cAAc,CAAC,UAAU,CAAC,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC,CAmK1D;AAED;;;;;;;;;GASG;AACH,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,cAAc,CAAC,UAAU,CAAC,EAChC,SAAS,EAAE,MAAM,GAChB,cAAc,CAAC,UAAU,CAAC,CA0D5B"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@timber-js/app",
|
|
3
|
-
"version": "0.2.0-alpha.
|
|
3
|
+
"version": "0.2.0-alpha.154",
|
|
4
4
|
"description": "Vite-native React framework built for Servers and Serverless Platforms — correct HTTP semantics, real status codes, pages that work without JavaScript",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare-workers",
|
|
@@ -116,10 +116,10 @@
|
|
|
116
116
|
},
|
|
117
117
|
"dependencies": {
|
|
118
118
|
"@opentelemetry/api": "^1.9.1",
|
|
119
|
-
"@opentelemetry/context-async-hooks": "^2.
|
|
120
|
-
"@opentelemetry/sdk-trace-base": "^2.
|
|
119
|
+
"@opentelemetry/context-async-hooks": "^2.8.0",
|
|
120
|
+
"@opentelemetry/sdk-trace-base": "^2.8.0",
|
|
121
121
|
"magic-string": "^0.30.21",
|
|
122
|
-
"nitro": "3.0.
|
|
122
|
+
"nitro": "3.0.260610-beta"
|
|
123
123
|
},
|
|
124
124
|
"peerDependencies": {
|
|
125
125
|
"@content-collections/core": "^0.14.0",
|
|
@@ -279,6 +279,9 @@ export function setupClientErrorForwarding(hot: Pick<HotInterface, 'send'>): voi
|
|
|
279
279
|
* (RedirectSignal, DenySignal). These must never surface as dev overlays —
|
|
280
280
|
* they are expected during navigation and are handled by the error boundary
|
|
281
281
|
* and router. Exported for tests.
|
|
282
|
+
*
|
|
283
|
+
* See also: isControlFlowSignal() in server/primitives.ts (server-side,
|
|
284
|
+
* handles both instanceof and digest detection).
|
|
282
285
|
*/
|
|
283
286
|
export function isFrameworkSignalError(error: unknown): boolean {
|
|
284
287
|
if (!error || typeof error !== 'object') return false;
|
|
@@ -66,6 +66,20 @@ export function setupServerActions(): void {
|
|
|
66
66
|
// instead of returning HTTP 302. Perform a client-side SPA navigation.
|
|
67
67
|
if (hasRedirect) {
|
|
68
68
|
const wrapper = decoded as { _redirect: string; _status: number };
|
|
69
|
+
|
|
70
|
+
// External redirects (e.g., OAuth flows via redirectExternal()) must
|
|
71
|
+
// use a full page navigation — the RSC router can only fetch same-origin
|
|
72
|
+
// payloads. On browsers with the Navigation API, navigation.navigate()
|
|
73
|
+
// happens to perform a real cross-origin navigation, but browsers
|
|
74
|
+
// without it (iPad Safari) would attempt an RSC fetch that fails on CORS.
|
|
75
|
+
const isExternal =
|
|
76
|
+
wrapper._redirect.startsWith('https://') || wrapper._redirect.startsWith('http://');
|
|
77
|
+
if (isExternal) {
|
|
78
|
+
setHardNavigating(true);
|
|
79
|
+
window.location.href = wrapper._redirect;
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
|
|
69
83
|
try {
|
|
70
84
|
const router = getRouter();
|
|
71
85
|
void router.navigate(wrapper._redirect);
|
package/src/config-types.ts
CHANGED
|
@@ -177,6 +177,14 @@ export interface TimberUserConfig {
|
|
|
177
177
|
* logging.
|
|
178
178
|
*/
|
|
179
179
|
serverTiming?: 'detailed' | 'total' | false;
|
|
180
|
+
/**
|
|
181
|
+
* Build-time performance budgets. When exceeded, the build report emits
|
|
182
|
+
* a warning (does not fail the build).
|
|
183
|
+
*/
|
|
184
|
+
budget?: {
|
|
185
|
+
/** Warn when any route's first-load JS (gzip) exceeds this many bytes. */
|
|
186
|
+
firstLoadJs?: number;
|
|
187
|
+
};
|
|
180
188
|
/**
|
|
181
189
|
* Override the app directory location. By default, timber auto-detects
|
|
182
190
|
* `app/` at the project root, falling back to `src/app/`.
|
package/src/config-validation.ts
CHANGED
|
@@ -49,6 +49,7 @@ const KNOWN_CONFIG_KEYS = {
|
|
|
49
49
|
sitemap: true,
|
|
50
50
|
buildDir: true,
|
|
51
51
|
topLoader: true,
|
|
52
|
+
budget: true,
|
|
52
53
|
} satisfies Record<keyof TimberUserConfig, true>;
|
|
53
54
|
|
|
54
55
|
const knownKeys = new Set<string>(Object.keys(KNOWN_CONFIG_KEYS));
|
|
@@ -180,6 +181,21 @@ export function validateConfig(config: TimberUserConfig): ConfigError[] {
|
|
|
180
181
|
}
|
|
181
182
|
}
|
|
182
183
|
|
|
184
|
+
// budget
|
|
185
|
+
if (config.budget != null && typeof config.budget === 'object') {
|
|
186
|
+
if (
|
|
187
|
+
config.budget.firstLoadJs !== undefined &&
|
|
188
|
+
(typeof config.budget.firstLoadJs !== 'number' || config.budget.firstLoadJs <= 0)
|
|
189
|
+
) {
|
|
190
|
+
errors.push({
|
|
191
|
+
field: 'budget.firstLoadJs',
|
|
192
|
+
message: `budget.firstLoadJs must be a positive number in bytes (got ${JSON.stringify(config.budget.firstLoadJs)}).`,
|
|
193
|
+
value: config.budget.firstLoadJs,
|
|
194
|
+
suggestion: 'Example: budget: { firstLoadJs: 150_000 } for a ~150 kB limit.',
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
183
199
|
for (const key of Object.keys(config)) {
|
|
184
200
|
if (!knownKeys.has(key)) {
|
|
185
201
|
errors.push({
|
package/src/index.ts
CHANGED
|
@@ -156,7 +156,7 @@ function createRscOptions(
|
|
|
156
156
|
// Layout-boundary grouping is the middle ground: components under the same
|
|
157
157
|
// layout segment share a chunk. See design/27-chunking-strategy.md, TIM-440, TIM-499.
|
|
158
158
|
clientChunks: (meta: { id: string; normalizedId: string; serverChunk: string }) =>
|
|
159
|
-
clientChunkGroup(meta, ctx.appDir, ctx.root),
|
|
159
|
+
clientChunkGroup(meta, ctx.appDir, ctx.root, ctx.sharedModuleFacades),
|
|
160
160
|
};
|
|
161
161
|
|
|
162
162
|
// Bound args encryption — AES-256-GCM authenticated encryption for
|
|
@@ -538,7 +538,7 @@ export function timber(config?: TimberUserConfig): PluginOption[] {
|
|
|
538
538
|
timberContent(ctx),
|
|
539
539
|
timberServerBundle(), // Bundle all deps in server environments for prod
|
|
540
540
|
timberCloudflareWasm(ctx), // Externalize WASM for Cloudflare Workers
|
|
541
|
-
timberChunks(),
|
|
541
|
+
timberChunks(ctx),
|
|
542
542
|
timberBuildReport(ctx), // Post-build: route table with bundle sizes
|
|
543
543
|
timberAdapterBuild(ctx), // Post-build: invoke adapter.buildOutput()
|
|
544
544
|
timberDevLogs(ctx), // Dev-only: forward server console.* to browser console
|
package/src/plugin-context.ts
CHANGED
|
@@ -94,6 +94,15 @@ export interface PluginContext {
|
|
|
94
94
|
* populate per-route modulepreload entries from clientReferenceDeps.
|
|
95
95
|
*/
|
|
96
96
|
routeClientRefKeys?: Map<string, Set<string>>;
|
|
97
|
+
/**
|
|
98
|
+
* Maps absolute module IDs of client references in non-facade RSC
|
|
99
|
+
* chunks to the absolute paths of their consuming facade modules.
|
|
100
|
+
* Built during the RSC `generateBundle` phase by timber-chunks,
|
|
101
|
+
* consumed by `clientChunkGroup` to reclassify `shared:` modules
|
|
102
|
+
* that are only used by a single route boundary.
|
|
103
|
+
* See design/27-chunking-strategy.md, TIM-1107.
|
|
104
|
+
*/
|
|
105
|
+
sharedModuleFacades?: Map<string, string[]>;
|
|
97
106
|
}
|
|
98
107
|
|
|
99
108
|
// ── App directory resolution ──────────────────────────────────────────────
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* Task: TIM-287
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
+
import { relative } from 'node:path';
|
|
16
17
|
import { gzipSync } from 'node:zlib';
|
|
17
18
|
import type { Plugin, Logger } from 'vite';
|
|
18
19
|
import type { PluginContext } from '../plugin-context.js';
|
|
@@ -160,6 +161,21 @@ export function buildRouteReport(entries: RouteEntry[], sharedSize: number): str
|
|
|
160
161
|
return lines;
|
|
161
162
|
}
|
|
162
163
|
|
|
164
|
+
/** Check route entries against a First-Load-JS budget and return warning lines. */
|
|
165
|
+
export function buildWarnings(entries: RouteEntry[], budget?: { firstLoadJs?: number }): string[] {
|
|
166
|
+
if (!budget?.firstLoadJs) return [];
|
|
167
|
+
const limit = budget.firstLoadJs;
|
|
168
|
+
const warnings: string[] = [];
|
|
169
|
+
for (const entry of entries) {
|
|
170
|
+
if (entry.firstLoadSize > limit) {
|
|
171
|
+
warnings.push(
|
|
172
|
+
`⚠ ${entry.path} first-load JS (${formatSize(entry.firstLoadSize)}) exceeds budget (${formatSize(limit)})`
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return warnings;
|
|
177
|
+
}
|
|
178
|
+
|
|
163
179
|
function pad(str: string, width: number, align: 'left' | 'right' = 'right'): string {
|
|
164
180
|
const gap = Math.max(0, width - stripAnsi(str).length);
|
|
165
181
|
return align === 'left' ? ' '.repeat(gap) + str : str + ' '.repeat(gap);
|
|
@@ -180,6 +196,7 @@ interface ChunkSize {
|
|
|
180
196
|
interface OutputChunkLike {
|
|
181
197
|
type: 'chunk' | 'asset';
|
|
182
198
|
fileName: string;
|
|
199
|
+
name?: string;
|
|
183
200
|
code?: string;
|
|
184
201
|
source?: string | Uint8Array;
|
|
185
202
|
modules?: Record<string, unknown>;
|
|
@@ -219,13 +236,62 @@ export function findChunkForFile(
|
|
|
219
236
|
return null;
|
|
220
237
|
}
|
|
221
238
|
|
|
239
|
+
// ─── Route → chunk group matching ────────────────────────────────────────
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Derive the expected client chunk group prefix for a route.
|
|
243
|
+
*
|
|
244
|
+
* Mirrors the `clientChunkGroup` logic: extract the first non-group segment
|
|
245
|
+
* from the route's file path under appDir. Routes at the root level or
|
|
246
|
+
* without a matching segment return null (their JS is in client-shared).
|
|
247
|
+
*/
|
|
248
|
+
function routeChunkGroupPrefix(entryFilePath: string, appDir: string, root: string): string | null {
|
|
249
|
+
const appPrefix = relative(root, appDir).replace(/\\/g, '/') + '/';
|
|
250
|
+
const relPath = relative(root, entryFilePath).replace(/\\/g, '/');
|
|
251
|
+
if (!relPath.startsWith(appPrefix)) return null;
|
|
252
|
+
|
|
253
|
+
const withinApp = relPath.slice(appPrefix.length);
|
|
254
|
+
const segments = withinApp.split('/');
|
|
255
|
+
for (const seg of segments) {
|
|
256
|
+
if (seg.includes('.')) break;
|
|
257
|
+
if (seg.startsWith('(') && seg.endsWith(')')) continue;
|
|
258
|
+
return `client-${seg}`;
|
|
259
|
+
}
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Find all client bundle chunks belonging to a chunk group.
|
|
265
|
+
*
|
|
266
|
+
* Uses the chunk's `name` property (set by Rolldown from the `clientChunks`
|
|
267
|
+
* callback's return value) for exact matching. The `name` is the group name
|
|
268
|
+
* itself (e.g. `client-docs`), not the hashed filename.
|
|
269
|
+
*/
|
|
270
|
+
export function findChunksForGroup(
|
|
271
|
+
groupName: string,
|
|
272
|
+
chunkSizes: Map<string, ChunkSize>,
|
|
273
|
+
bundle?: Record<string, OutputChunkLike>
|
|
274
|
+
): string[] {
|
|
275
|
+
if (!bundle) return [];
|
|
276
|
+
const matched: string[] = [];
|
|
277
|
+
for (const [fileName, item] of Object.entries(bundle)) {
|
|
278
|
+
if (item.type !== 'chunk') continue;
|
|
279
|
+
if (item.name === groupName && chunkSizes.has(fileName)) {
|
|
280
|
+
matched.push(fileName);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return matched;
|
|
284
|
+
}
|
|
285
|
+
|
|
222
286
|
// ─── Build route entries from collected data ──────────────────────────────
|
|
223
287
|
|
|
224
288
|
function buildEntries(
|
|
225
289
|
routeTree: RouteTree,
|
|
226
290
|
chunkSizes: Map<string, ChunkSize>,
|
|
227
291
|
bundle: Record<string, OutputChunkLike>,
|
|
228
|
-
outputMode: 'server' | 'static'
|
|
292
|
+
outputMode: 'server' | 'static',
|
|
293
|
+
appDir?: string,
|
|
294
|
+
root?: string
|
|
229
295
|
): { entries: RouteEntry[]; sharedGzip: number } {
|
|
230
296
|
const routeInfos = collectRoutes(routeTree);
|
|
231
297
|
|
|
@@ -233,7 +299,7 @@ function buildEntries(
|
|
|
233
299
|
let totalGzip = 0;
|
|
234
300
|
for (const s of chunkSizes.values()) totalGzip += s.gzip;
|
|
235
301
|
|
|
236
|
-
// Per-route sizes
|
|
302
|
+
// Per-route sizes. Track route-specific chunks to compute shared size.
|
|
237
303
|
const routeChunkFiles = new Set<string>();
|
|
238
304
|
const entries: RouteEntry[] = [];
|
|
239
305
|
|
|
@@ -242,14 +308,36 @@ function buildEntries(
|
|
|
242
308
|
let gzip = 0;
|
|
243
309
|
|
|
244
310
|
if (info.entryFilePath) {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
311
|
+
// Try chunk group matching first (works for server component routes
|
|
312
|
+
// whose client JS is in client-<segment> chunks, not in the route's
|
|
313
|
+
// own page.tsx chunk). Falls back to direct chunk lookup.
|
|
314
|
+
let matched = false;
|
|
315
|
+
if (appDir && root) {
|
|
316
|
+
const groupPrefix = routeChunkGroupPrefix(info.entryFilePath, appDir, root);
|
|
317
|
+
if (groupPrefix) {
|
|
318
|
+
const chunks = findChunksForGroup(groupPrefix, chunkSizes, bundle);
|
|
319
|
+
for (const chunk of chunks) {
|
|
320
|
+
const s = chunkSizes.get(chunk);
|
|
321
|
+
if (s) {
|
|
322
|
+
raw += s.raw;
|
|
323
|
+
gzip += s.gzip;
|
|
324
|
+
}
|
|
325
|
+
routeChunkFiles.add(chunk);
|
|
326
|
+
}
|
|
327
|
+
if (chunks.length > 0) matched = true;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
if (!matched) {
|
|
332
|
+
const chunk = findChunkForFile(info.entryFilePath, bundle);
|
|
333
|
+
if (chunk) {
|
|
334
|
+
const s = chunkSizes.get(chunk);
|
|
335
|
+
if (s) {
|
|
336
|
+
raw = s.raw;
|
|
337
|
+
gzip = s.gzip;
|
|
338
|
+
}
|
|
339
|
+
routeChunkFiles.add(chunk);
|
|
251
340
|
}
|
|
252
|
-
routeChunkFiles.add(chunk);
|
|
253
341
|
}
|
|
254
342
|
}
|
|
255
343
|
|
|
@@ -348,12 +436,19 @@ export function timberBuildReport(ctx: PluginContext): Plugin {
|
|
|
348
436
|
})),
|
|
349
437
|
sharedGzip: 0,
|
|
350
438
|
}
|
|
351
|
-
: buildEntries(ctx.routeTree, chunkSizes, clientBundle, outputMode);
|
|
439
|
+
: buildEntries(ctx.routeTree, chunkSizes, clientBundle, outputMode, ctx.appDir, ctx.root);
|
|
352
440
|
const elapsed = ((performance.now() - buildStart) / 1000).toFixed(2);
|
|
353
441
|
const lines = buildRouteReport(entries, sharedGzip);
|
|
354
442
|
|
|
355
443
|
logger.info('');
|
|
356
444
|
for (const line of lines) logger.info(line);
|
|
445
|
+
|
|
446
|
+
const warnings = buildWarnings(entries, ctx.config.budget);
|
|
447
|
+
if (warnings.length > 0) {
|
|
448
|
+
logger.info('');
|
|
449
|
+
for (const w of warnings) logger.warn(w);
|
|
450
|
+
}
|
|
451
|
+
|
|
357
452
|
logger.info('');
|
|
358
453
|
logger.info(
|
|
359
454
|
`✓ built ${entries.length} routes for all three environments (rsc, ssr, client) in ${elapsed}s`
|
package/src/plugins/chunks.ts
CHANGED
|
@@ -13,10 +13,16 @@
|
|
|
13
13
|
* - Per-route chunks (page/layout components, only when route-specific)
|
|
14
14
|
* - rolldown-runtime (Rolldown's own output, unavoidable)
|
|
15
15
|
*
|
|
16
|
+
* Additionally, this plugin builds a facade ancestry map during the RSC
|
|
17
|
+
* build so that `clientChunkGroup` can reclassify `shared:` client
|
|
18
|
+
* references that are only consumed by a single route boundary.
|
|
19
|
+
* See TIM-1107, design/27-chunking-strategy.md.
|
|
20
|
+
*
|
|
16
21
|
* Design docs: 27-chunking-strategy.md
|
|
17
22
|
*/
|
|
18
23
|
|
|
19
|
-
import type { Plugin } from 'vite';
|
|
24
|
+
import type { Plugin, Rollup } from 'vite';
|
|
25
|
+
import type { PluginContext } from '../plugin-context';
|
|
20
26
|
|
|
21
27
|
/**
|
|
22
28
|
* Check if a module is part of the timber framework runtime.
|
|
@@ -36,12 +42,71 @@ export function isTimberRuntime(id: string): boolean {
|
|
|
36
42
|
);
|
|
37
43
|
}
|
|
38
44
|
|
|
45
|
+
type OutputChunk = Rollup.OutputChunk;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Build a map from absolute module IDs in non-facade RSC chunks to the
|
|
49
|
+
* absolute facade module paths that transitively import them.
|
|
50
|
+
*
|
|
51
|
+
* Used by `clientChunkGroup` to reclassify `shared:` client references
|
|
52
|
+
* that are only consumed by a single route boundary (TIM-1107).
|
|
53
|
+
*/
|
|
54
|
+
function buildFacadeAncestryMap(bundle: Rollup.OutputBundle): Map<string, string[]> {
|
|
55
|
+
const chunks = new Map<string, OutputChunk>();
|
|
56
|
+
for (const [file, asset] of Object.entries(bundle)) {
|
|
57
|
+
if (asset.type === 'chunk') chunks.set(file, asset);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Reverse import graph: which chunks import this chunk file?
|
|
61
|
+
const importedBy = new Map<string, string[]>();
|
|
62
|
+
for (const [file, chunk] of chunks) {
|
|
63
|
+
for (const imp of chunk.imports) {
|
|
64
|
+
let parents = importedBy.get(imp);
|
|
65
|
+
if (!parents) {
|
|
66
|
+
parents = [];
|
|
67
|
+
importedBy.set(imp, parents);
|
|
68
|
+
}
|
|
69
|
+
parents.push(file);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Trace upward from a chunk to find all facade modules that consume it
|
|
74
|
+
function facadeAncestors(file: string, visited: Set<string>): string[] {
|
|
75
|
+
if (visited.has(file)) return [];
|
|
76
|
+
visited.add(file);
|
|
77
|
+
const chunk = chunks.get(file);
|
|
78
|
+
if (!chunk) return [];
|
|
79
|
+
if (chunk.facadeModuleId) return [chunk.facadeModuleId];
|
|
80
|
+
const parents = importedBy.get(file) ?? [];
|
|
81
|
+
const result: string[] = [];
|
|
82
|
+
for (const p of parents) {
|
|
83
|
+
for (const f of facadeAncestors(p, visited)) result.push(f);
|
|
84
|
+
}
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const moduleToFacades = new Map<string, string[]>();
|
|
89
|
+
for (const [file, chunk] of chunks) {
|
|
90
|
+
if (chunk.facadeModuleId) continue;
|
|
91
|
+
const facades = facadeAncestors(file, new Set());
|
|
92
|
+
if (facades.length === 0) continue;
|
|
93
|
+
// Deduplicate facades
|
|
94
|
+
const unique = [...new Set(facades)];
|
|
95
|
+
for (const modId of chunk.moduleIds) {
|
|
96
|
+
moduleToFacades.set(modId, unique);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return moduleToFacades;
|
|
101
|
+
}
|
|
102
|
+
|
|
39
103
|
/**
|
|
40
104
|
* Create the timber-chunks Vite plugin.
|
|
41
105
|
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
106
|
+
* Rolldown's default splitting produces the desired output (one main
|
|
107
|
+
* bundle + per-route chunks). This plugin's main job is building the
|
|
108
|
+
* facade ancestry map during the RSC build so `clientChunkGroup` can
|
|
109
|
+
* reclassify shared client references to their correct route boundary.
|
|
45
110
|
*
|
|
46
111
|
* NOTE: Ideally we'd use Rolldown's `format: 'app'` (module registry format)
|
|
47
112
|
* which guarantees single-copy module semantics like webpack/Turbopack.
|
|
@@ -51,8 +116,12 @@ export function isTimberRuntime(id: string): boolean {
|
|
|
51
116
|
*
|
|
52
117
|
* Design docs: 27-chunking-strategy.md
|
|
53
118
|
*/
|
|
54
|
-
export function timberChunks(): Plugin {
|
|
119
|
+
export function timberChunks(ctx: PluginContext): Plugin {
|
|
55
120
|
return {
|
|
56
121
|
name: 'timber-chunks',
|
|
122
|
+
generateBundle(_options, bundle) {
|
|
123
|
+
if (this.environment?.name !== 'rsc') return;
|
|
124
|
+
ctx.sharedModuleFacades = buildFacadeAncestryMap(bundle);
|
|
125
|
+
},
|
|
57
126
|
};
|
|
58
127
|
}
|