@ecopages/react 0.2.0-alpha.9 → 0.2.1-beta.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/README.md +30 -13
- package/package.json +23 -12
- package/src/eco-embed.d.ts +11 -0
- package/src/eco-embed.js +11 -0
- package/src/react-hmr-strategy.d.ts +102 -18
- package/src/react-hmr-strategy.js +427 -50
- package/src/react-renderer.d.ts +100 -92
- package/src/react-renderer.js +356 -340
- package/src/react.constants.d.ts +1 -0
- package/src/react.constants.js +4 -0
- package/src/react.plugin.d.ts +25 -107
- package/src/react.plugin.js +109 -61
- package/src/react.types.d.ts +88 -0
- package/src/react.types.js +0 -0
- package/src/router-adapter.d.ts +7 -14
- package/src/runtime/use-sync-external-store-with-selector.d.ts +3 -0
- package/src/runtime/use-sync-external-store-with-selector.js +56 -0
- package/src/services/pages-index.d.ts +64 -0
- package/src/services/pages-index.js +73 -0
- package/src/services/react-bundle.service.d.ts +24 -9
- package/src/services/react-bundle.service.js +35 -24
- package/src/services/react-hmr-page-metadata-cache.d.ts +10 -1
- package/src/services/react-hmr-page-metadata-cache.js +18 -2
- package/src/services/react-hydration-asset.service.d.ts +28 -19
- package/src/services/react-hydration-asset.service.js +83 -64
- package/src/services/react-mdx-config-dependency.service.d.ts +36 -0
- package/src/services/react-mdx-config-dependency.service.js +122 -0
- package/src/services/react-page-module.service.d.ts +8 -3
- package/src/services/react-page-module.service.js +33 -26
- package/src/services/react-page-payload.service.d.ts +46 -0
- package/src/services/react-page-payload.service.js +67 -0
- package/src/services/react-runtime-bundle.service.d.ts +9 -2
- package/src/services/react-runtime-bundle.service.js +77 -16
- package/src/utils/client-graph-boundary-cache.d.ts +108 -0
- package/src/utils/client-graph-boundary-cache.js +116 -0
- package/src/utils/client-graph-boundary-plugin.d.ts +13 -5
- package/src/utils/client-graph-boundary-plugin.js +63 -5
- package/src/utils/component-config-traversal.d.ts +36 -0
- package/src/utils/component-config-traversal.js +54 -0
- package/src/utils/declared-modules.d.ts +1 -1
- package/src/utils/declared-modules.js +7 -16
- package/src/utils/dynamic.test.browser.d.ts +1 -0
- package/src/utils/dynamic.test.browser.js +33 -0
- package/src/utils/hydration-scripts.d.ts +9 -5
- package/src/utils/hydration-scripts.js +119 -34
- package/src/utils/hydration-scripts.test.browser.d.ts +1 -0
- package/src/utils/hydration-scripts.test.browser.js +198 -0
- package/src/utils/react-dom-runtime-interop-plugin.d.ts +1 -1
- package/src/utils/react-dom-runtime-interop-plugin.js +9 -0
- package/src/utils/react-mdx-loader-plugin.d.ts +1 -1
- package/src/utils/{react-runtime-specifier-map.d.ts → react-runtime-alias-map.d.ts} +3 -1
- package/src/utils/react-runtime-alias-map.js +90 -0
- package/CHANGELOG.md +0 -27
- package/src/react-hmr-strategy.ts +0 -386
- package/src/react-renderer.ts +0 -803
- package/src/react.plugin.ts +0 -276
- package/src/router-adapter.ts +0 -95
- package/src/services/react-bundle.service.ts +0 -108
- package/src/services/react-hmr-page-metadata-cache.ts +0 -24
- package/src/services/react-hydration-asset.service.ts +0 -263
- package/src/services/react-page-module.service.ts +0 -224
- package/src/services/react-runtime-bundle.service.ts +0 -172
- package/src/utils/client-graph-boundary-plugin.ts +0 -831
- package/src/utils/client-only.ts +0 -27
- package/src/utils/declared-modules.ts +0 -99
- package/src/utils/dynamic.ts +0 -27
- package/src/utils/hmr-scripts.ts +0 -47
- package/src/utils/html-boundary.ts +0 -66
- package/src/utils/hydration-scripts.ts +0 -459
- package/src/utils/reachability-analyzer.ts +0 -593
- package/src/utils/react-dom-runtime-interop-plugin.ts +0 -33
- package/src/utils/react-mdx-loader-plugin.ts +0 -63
- package/src/utils/react-runtime-specifier-map.js +0 -37
- package/src/utils/react-runtime-specifier-map.ts +0 -45
- package/src/utils/use-sync-external-store-shim-plugin.d.ts +0 -5
- package/src/utils/use-sync-external-store-shim-plugin.js +0 -41
- package/src/utils/use-sync-external-store-shim-plugin.ts +0 -45
package/README.md
CHANGED
|
@@ -5,7 +5,8 @@ First-class integration for [React 19](https://react.dev/) in Ecopages. This plu
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
|
|
8
|
+
bun add @ecopages/react react react-dom
|
|
9
|
+
bun add -d @types/react @types/react-dom
|
|
9
10
|
```
|
|
10
11
|
|
|
11
12
|
## Usage
|
|
@@ -26,15 +27,15 @@ export default config;
|
|
|
26
27
|
|
|
27
28
|
## Component-Level Islands
|
|
28
29
|
|
|
29
|
-
|
|
30
|
+
For component-level islands, Ecopages React uses this contract:
|
|
30
31
|
|
|
31
32
|
- SSR output preserves the authored DOM structure (no unnecessary wrapper elements).
|
|
32
33
|
- A stable `data-eco-component-id` attribute is attached to the component SSR root.
|
|
33
|
-
- The client
|
|
34
|
+
- The island runtime replaces the SSR host with a dedicated client-owned container and mounts it with `createRoot()`. Full-page hydration paths use `hydrateRoot()`.
|
|
34
35
|
|
|
35
36
|
> [!TIP]
|
|
36
37
|
> **Full React SPA Routing:**
|
|
37
|
-
> If you are building full React pages and want client-side navigation (SPA), use [@ecopages/react-router](
|
|
38
|
+
> If you are building full React pages and want client-side navigation (SPA), use [@ecopages/react-router](../../react-router/README.md) and pass it to the react plugin: `reactPlugin({ router: ecoRouter() })`.
|
|
38
39
|
|
|
39
40
|
## MDX Support
|
|
40
41
|
|
|
@@ -60,6 +61,22 @@ const config = await new ConfigBuilder()
|
|
|
60
61
|
export default config;
|
|
61
62
|
```
|
|
62
63
|
|
|
64
|
+
## Mixed Rendering
|
|
65
|
+
|
|
66
|
+
The React integration can participate in mixed-renderer apps in three ways:
|
|
67
|
+
|
|
68
|
+
- React can own the page or view directly.
|
|
69
|
+
- React can render nested foreign subtrees inside pages owned by another integration.
|
|
70
|
+
- React can render through non-React page, layout, or document shells when those shell components return strings.
|
|
71
|
+
|
|
72
|
+
When a non-React render pass reaches a React-owned foreign child, Ecopages hands that foreign subtree back to the React renderer. When React renders through a non-React shell, that shell must serialize to HTML so React can insert the result into the final response without escaping it.
|
|
73
|
+
|
|
74
|
+
Important:
|
|
75
|
+
|
|
76
|
+
- Components that may render foreign children must declare those children in `config.dependencies.components`.
|
|
77
|
+
- Ecopages validates mixed-renderer ownership from declared dependencies during render preparation. It does not infer every foreign subtree from rendered HTML alone.
|
|
78
|
+
- React still keeps its own child transport and hydration rules for React-owned subtrees.
|
|
79
|
+
|
|
63
80
|
## Server and Client Graph Contract
|
|
64
81
|
|
|
65
82
|
The React integration supports Node.js modules and server-only code **only on the server execution graph**.
|
|
@@ -99,7 +116,7 @@ The client bundle keeps:
|
|
|
99
116
|
- The page component render path.
|
|
100
117
|
- Client-safe component dependencies reachable from render.
|
|
101
118
|
- Layout wiring needed for hydration.
|
|
102
|
-
- Router runtime state needed by [@ecopages/react-router](
|
|
119
|
+
- Router runtime state needed by [@ecopages/react-router](../../react-router/README.md) when SPA mode is enabled.
|
|
103
120
|
|
|
104
121
|
The client bundle removes or excludes:
|
|
105
122
|
|
|
@@ -114,7 +131,7 @@ Important:
|
|
|
114
131
|
|
|
115
132
|
### AST Pipeline Order
|
|
116
133
|
|
|
117
|
-
The browser-bound transform in [
|
|
134
|
+
The browser-bound transform in [src/utils/client-graph-boundary-plugin.ts](src/utils/client-graph-boundary-plugin.ts) follows this order:
|
|
118
135
|
|
|
119
136
|
1. Parse the module and build a reachability view of the client render graph.
|
|
120
137
|
2. Remove imports that are not allowed or not reachable from the client graph.
|
|
@@ -149,7 +166,7 @@ The fix is to strip server-only `eco.page(...)` options after import pruning, wh
|
|
|
149
166
|
|
|
150
167
|
The browser must not receive arbitrary request-scoped data.
|
|
151
168
|
|
|
152
|
-
The React renderer in [
|
|
169
|
+
The React renderer in [src/react-renderer.ts](src/react-renderer.ts) serializes only the top-level `locals` keys explicitly declared by `Page.requires`. If a page does not declare `requires`, no `locals` are serialized for hydration.
|
|
153
170
|
|
|
154
171
|
Example:
|
|
155
172
|
|
|
@@ -174,8 +191,8 @@ Hydration must rebuild the same tree the server rendered.
|
|
|
174
191
|
|
|
175
192
|
That applies to both:
|
|
176
193
|
|
|
177
|
-
- non-router hydration scripts in [
|
|
178
|
-
- router-backed hydration in [
|
|
194
|
+
- non-router hydration scripts in [src/utils/hydration-scripts.ts](src/utils/hydration-scripts.ts)
|
|
195
|
+
- router-backed hydration in [../../react-router/src/router.ts](../../react-router/src/router.ts)
|
|
179
196
|
|
|
180
197
|
If the page render receives `locals` on the server and the layout also depends on those values, the client must pass the same serialized `locals` into the layout during hydration. Otherwise React will detect a mismatch.
|
|
181
198
|
|
|
@@ -183,9 +200,9 @@ If the page render receives `locals` on the server and the layout also depends o
|
|
|
183
200
|
|
|
184
201
|
The main regression coverage lives in:
|
|
185
202
|
|
|
186
|
-
- [
|
|
187
|
-
- [
|
|
188
|
-
- [
|
|
189
|
-
- [
|
|
203
|
+
- [src/utils/client-graph-boundary-plugin.test.ts](src/utils/client-graph-boundary-plugin.test.ts): verifies server-only `eco.page(...)` options are stripped from browser bundles.
|
|
204
|
+
- [src/react-renderer.locals.test.ts](src/react-renderer.locals.test.ts): verifies only declared `requires` keys are serialized into hydration payloads.
|
|
205
|
+
- [src/utils/hydration-scripts.test.ts](src/utils/hydration-scripts.test.ts): verifies non-router hydration passes serialized `locals` into layouts.
|
|
206
|
+
- [../../react-router/test/hmr-reload.test.browser.ts](../../react-router/test/hmr-reload.test.browser.ts): verifies router-backed layout hydration receives `locals` with `persistLayouts` both enabled and disabled.
|
|
190
207
|
|
|
191
208
|
If you change the AST transform or hydration flow, update the corresponding tests in the same change.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ecopages/react",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1-beta.0",
|
|
4
4
|
"description": "React integration for Ecopages",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ecopages",
|
|
@@ -16,6 +16,10 @@
|
|
|
16
16
|
"default": "./src/react.plugin.js",
|
|
17
17
|
"types": "./src/react.plugin.d.ts"
|
|
18
18
|
},
|
|
19
|
+
"./eco-embed": {
|
|
20
|
+
"default": "./src/eco-embed.js",
|
|
21
|
+
"types": "./src/eco-embed.d.ts"
|
|
22
|
+
},
|
|
19
23
|
"./declarations": {
|
|
20
24
|
"types": "./src/declarations.d.ts"
|
|
21
25
|
},
|
|
@@ -27,10 +31,18 @@
|
|
|
27
31
|
"types": "./src/utils/client-only.d.ts",
|
|
28
32
|
"default": "./src/utils/client-only.js"
|
|
29
33
|
},
|
|
34
|
+
"./runtime/use-sync-external-store-with-selector": {
|
|
35
|
+
"types": "./src/runtime/use-sync-external-store-with-selector.d.ts",
|
|
36
|
+
"default": "./src/runtime/use-sync-external-store-with-selector.js"
|
|
37
|
+
},
|
|
30
38
|
"./router-adapter": {
|
|
31
39
|
"types": "./src/router-adapter.d.ts",
|
|
32
40
|
"default": "./src/router-adapter.js"
|
|
33
41
|
},
|
|
42
|
+
"./eco-embed.ts": {
|
|
43
|
+
"default": "./src/eco-embed.js",
|
|
44
|
+
"types": "./src/eco-embed.d.ts"
|
|
45
|
+
},
|
|
34
46
|
"./declarations.ts": {
|
|
35
47
|
"types": "./src/declarations.d.ts"
|
|
36
48
|
},
|
|
@@ -42,6 +54,10 @@
|
|
|
42
54
|
"types": "./src/utils/client-only.d.ts",
|
|
43
55
|
"default": "./src/utils/client-only.js"
|
|
44
56
|
},
|
|
57
|
+
"./runtime/use-sync-external-store-with-selector.ts": {
|
|
58
|
+
"types": "./src/runtime/use-sync-external-store-with-selector.d.ts",
|
|
59
|
+
"default": "./src/runtime/use-sync-external-store-with-selector.js"
|
|
60
|
+
},
|
|
45
61
|
"./router-adapter.ts": {
|
|
46
62
|
"types": "./src/router-adapter.d.ts",
|
|
47
63
|
"default": "./src/router-adapter.js"
|
|
@@ -53,24 +69,19 @@
|
|
|
53
69
|
"directory": "packages/integrations/react"
|
|
54
70
|
},
|
|
55
71
|
"peerDependencies": {
|
|
56
|
-
"@ecopages/core": "0.2.
|
|
72
|
+
"@ecopages/core": "0.2.1-beta.0",
|
|
57
73
|
"@types/react": "^19",
|
|
58
74
|
"@types/react-dom": "^19",
|
|
59
75
|
"react": "^19",
|
|
60
76
|
"react-dom": "^19"
|
|
61
77
|
},
|
|
62
78
|
"dependencies": {
|
|
63
|
-
"@ecopages/file-system": "0.2.
|
|
64
|
-
"@ecopages/logger": "
|
|
65
|
-
"@mdx-js/
|
|
66
|
-
"
|
|
67
|
-
"oxc-
|
|
68
|
-
"oxc-transform": "^0.114.0",
|
|
79
|
+
"@ecopages/file-system": "0.2.1-beta.0",
|
|
80
|
+
"@ecopages/logger": "^0.2.3",
|
|
81
|
+
"@mdx-js/mdx": "^3.1.1",
|
|
82
|
+
"oxc-parser": "^0.124.0",
|
|
83
|
+
"oxc-transform": "^0.124.0",
|
|
69
84
|
"source-map": "^0.7.6",
|
|
70
85
|
"vfile": "^6.0.3"
|
|
71
|
-
},
|
|
72
|
-
"overrides": {
|
|
73
|
-
"react": "^19",
|
|
74
|
-
"react-dom": "^19"
|
|
75
86
|
}
|
|
76
87
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { EcoComponent, EcoEmbedProps as CoreEcoEmbedProps } from '@ecopages/core';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
/**
|
|
4
|
+
* Props for the React-owned `EcoEmbed` adapter.
|
|
5
|
+
*/
|
|
6
|
+
export type EcoEmbedProps<TComponent extends EcoComponent> = CoreEcoEmbedProps<TComponent>;
|
|
7
|
+
/**
|
|
8
|
+
* Renders a foreign or same-integration eco component from a React JSX file
|
|
9
|
+
* without forcing inline mixed-JSX authoring.
|
|
10
|
+
*/
|
|
11
|
+
export declare function EcoEmbed<TComponent extends EcoComponent>({ component, props, children, }: EcoEmbedProps<TComponent>): ReactNode;
|
package/src/eco-embed.js
ADDED
|
@@ -6,10 +6,28 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @module
|
|
8
8
|
*/
|
|
9
|
-
import { HmrStrategy,
|
|
9
|
+
import { HmrStrategy, type HmrAction } from '@ecopages/core/hmr/hmr-strategy';
|
|
10
|
+
import type { BrowserRuntimeManifest } from '@ecopages/core/build/browser-runtime-manifest';
|
|
10
11
|
import type { DefaultHmrContext } from '@ecopages/core';
|
|
11
12
|
import type { CompileOptions } from '@mdx-js/mdx';
|
|
13
|
+
import { ClientGraphBoundaryCache } from './utils/client-graph-boundary-cache.js';
|
|
12
14
|
import type { ReactHmrPageMetadataCache } from './services/react-hmr-page-metadata-cache.js';
|
|
15
|
+
export interface ReactHmrStrategyOptions {
|
|
16
|
+
context: DefaultHmrContext;
|
|
17
|
+
pageMetadataCache: ReactHmrPageMetadataCache;
|
|
18
|
+
runtimeManifest: BrowserRuntimeManifest;
|
|
19
|
+
mdxCompilerOptions?: CompileOptions;
|
|
20
|
+
ownedTemplateExtensions?: string[];
|
|
21
|
+
allTemplateExtensions?: string[];
|
|
22
|
+
explicitGraphEnabled?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Per-app cache for client-graph-boundary transform results. Owned by
|
|
25
|
+
* the React plugin for the app's lifetime. When omitted, the strategy
|
|
26
|
+
* uses a fresh in-memory cache that does not persist across HMR
|
|
27
|
+
* rebuilds.
|
|
28
|
+
*/
|
|
29
|
+
clientGraphBoundaryCache?: ClientGraphBoundaryCache;
|
|
30
|
+
}
|
|
13
31
|
/**
|
|
14
32
|
* Strategy for handling React component HMR updates.
|
|
15
33
|
*
|
|
@@ -39,17 +57,20 @@ import type { ReactHmrPageMetadataCache } from './services/react-hmr-page-metada
|
|
|
39
57
|
* ```typescript
|
|
40
58
|
* const context = {
|
|
41
59
|
* getWatchedFiles: () => watchedFilesMap,
|
|
42
|
-
* getSpecifierMap: () => specifierMap,
|
|
43
60
|
* getDistDir: () => '/path/to/dist/_hmr',
|
|
44
61
|
* getPlugins: () => [],
|
|
45
62
|
* getSrcDir: () => '/path/to/src',
|
|
46
63
|
* getLayoutsDir: () => '/path/to/src/layouts'
|
|
47
64
|
* };
|
|
48
|
-
* const strategy = new ReactHmrStrategy(
|
|
65
|
+
* const strategy = new ReactHmrStrategy({
|
|
66
|
+
* context,
|
|
67
|
+
* pageMetadataCache,
|
|
68
|
+
* runtimeManifest
|
|
69
|
+
* });
|
|
49
70
|
* ```
|
|
50
71
|
*/
|
|
51
72
|
export declare class ReactHmrStrategy extends HmrStrategy {
|
|
52
|
-
readonly type
|
|
73
|
+
readonly type: 100;
|
|
53
74
|
private mdxCompilerOptions?;
|
|
54
75
|
private readonly ownedTemplateExtensions;
|
|
55
76
|
private readonly allTemplateExtensions;
|
|
@@ -57,25 +78,24 @@ export declare class ReactHmrStrategy extends HmrStrategy {
|
|
|
57
78
|
/**
|
|
58
79
|
* Creates a new React HMR strategy instance.
|
|
59
80
|
*
|
|
60
|
-
* @param
|
|
61
|
-
* and the layouts directory for detecting layout file changes that require full
|
|
62
|
-
* page reloads instead of module-level HMR updates.
|
|
63
|
-
* @param pageMetadataCache - React-only cache of declared browser modules discovered during
|
|
64
|
-
* server rendering. This avoids re-importing unchanged page modules
|
|
65
|
-
* during save-time Fast Refresh rebuilds.
|
|
66
|
-
* @param mdxCompilerOptions - Optional MDX compiler options for processing .mdx files
|
|
67
|
-
* @param explicitGraphEnabled - Enables explicit graph mode for React HMR bundling.
|
|
68
|
-
* In explicit mode, HMR builds omit AST server-only stripping plugins in React paths.
|
|
81
|
+
* @param options - React HMR runtime services and behavior flags.
|
|
69
82
|
*/
|
|
70
83
|
private context;
|
|
71
84
|
private pageMetadataCache;
|
|
72
85
|
private explicitGraphEnabled;
|
|
73
|
-
|
|
86
|
+
private readonly runtimeManifest;
|
|
87
|
+
private readonly clientGraphBoundaryCache;
|
|
88
|
+
private readonly pagesIndex;
|
|
89
|
+
constructor(options: ReactHmrStrategyOptions);
|
|
74
90
|
/**
|
|
75
91
|
* Returns build plugins for React HMR bundling.
|
|
76
92
|
*
|
|
77
93
|
* Includes the client graph boundary plugin to prevent undeclared imports
|
|
78
94
|
* (including `node:*`) from breaking the browser bundle.
|
|
95
|
+
*
|
|
96
|
+
* @remarks
|
|
97
|
+
* HMR builds receive the React runtime manifest and rewrite manifest-owned
|
|
98
|
+
* runtime imports to concrete asset URLs before module resolution.
|
|
79
99
|
*/
|
|
80
100
|
private getBuildPlugins;
|
|
81
101
|
private isReactEntrypoint;
|
|
@@ -89,11 +109,22 @@ export declare class ReactHmrStrategy extends HmrStrategy {
|
|
|
89
109
|
*/
|
|
90
110
|
private isRouteTemplate;
|
|
91
111
|
private resolveTemplateExtension;
|
|
112
|
+
private ownsWatchedEntrypoint;
|
|
113
|
+
private configContainsFile;
|
|
114
|
+
private pageModuleRequiresLayoutRefresh;
|
|
115
|
+
private hasLayoutOwnedDependencyTarget;
|
|
92
116
|
/**
|
|
93
117
|
* Determines if the file is a React/MDX entrypoint that's registered for HMR.
|
|
94
118
|
*
|
|
119
|
+
* Uses a three-way decision strategy for selective invalidation:
|
|
120
|
+
* 1. If the file is a watched entrypoint, check if React owns it
|
|
121
|
+
* 2. If the file is a dependency of watched entrypoints (via dependency graph),
|
|
122
|
+
* check if any affected entrypoints are React-owned. Returns false if hits
|
|
123
|
+
* exist but none are owned (prevents unnecessary rebuilds).
|
|
124
|
+
* 3. Otherwise, check if the file itself is a React entrypoint template
|
|
125
|
+
*
|
|
95
126
|
* @param filePath - Absolute path to the changed file
|
|
96
|
-
* @returns True if this
|
|
127
|
+
* @returns True if this file should trigger React HMR rebuilds
|
|
97
128
|
*/
|
|
98
129
|
matches(filePath: string): boolean;
|
|
99
130
|
/**
|
|
@@ -108,13 +139,33 @@ export declare class ReactHmrStrategy extends HmrStrategy {
|
|
|
108
139
|
* @returns True if the file is in the layouts directory
|
|
109
140
|
*/
|
|
110
141
|
private isLayoutFile;
|
|
142
|
+
private isPageEntrypoint;
|
|
143
|
+
private getEntrypointOutput;
|
|
144
|
+
private getRolldownEntryKey;
|
|
145
|
+
private getTempFileBasename;
|
|
146
|
+
private collectReactPageBuildTargets;
|
|
147
|
+
/**
|
|
148
|
+
* Expands one HMR request into the full React page build cohort when needed.
|
|
149
|
+
*
|
|
150
|
+
* @remarks
|
|
151
|
+
* Page and layout changes need one shared rebuild pass so sibling routes keep
|
|
152
|
+
* a consistent client module graph. Non-page changes that do not touch a page
|
|
153
|
+
* cohort can stay scoped to the originally requested targets.
|
|
154
|
+
*/
|
|
155
|
+
private resolveBuildTargets;
|
|
156
|
+
private partitionBuildTargets;
|
|
111
157
|
/**
|
|
112
|
-
* Processes a React file change by rebuilding
|
|
158
|
+
* Processes a React file change by rebuilding affected React entrypoints.
|
|
159
|
+
*
|
|
160
|
+
* Uses a three-way decision strategy for selective invalidation:
|
|
161
|
+
* 1. Changed file is a watched entrypoint: rebuild only that entrypoint
|
|
162
|
+
* 2. Dependency graph has hits: rebuild only affected React-owned entrypoints.
|
|
163
|
+
* If hits exist but none map to React-owned entrypoints, return 'none' to
|
|
164
|
+
* prevent unnecessary rebuilds.
|
|
165
|
+
* 3. Dependency graph miss: fall back to rebuilding all watched entrypoints
|
|
113
166
|
*
|
|
114
167
|
* For layout files, broadcasts a 'layout-update' event to trigger full page reload.
|
|
115
168
|
* For regular components/pages, broadcasts 'update' events for module-level HMR.
|
|
116
|
-
* When a page entrypoint is first registered, only that entrypoint is built.
|
|
117
|
-
* Subsequent file updates rebuild all watched React entrypoints as usual.
|
|
118
169
|
*
|
|
119
170
|
* @param _filePath - Absolute path to the changed file
|
|
120
171
|
* @returns Action to broadcast update events (layout-update for layouts, update for components)
|
|
@@ -123,16 +174,49 @@ export declare class ReactHmrStrategy extends HmrStrategy {
|
|
|
123
174
|
/**
|
|
124
175
|
* Bundles a single React/MDX entrypoint with HMR support.
|
|
125
176
|
*
|
|
177
|
+
* After successful bundling, populates the entrypoint dependency graph with
|
|
178
|
+
* the build's dependency metadata. This enables selective invalidation on
|
|
179
|
+
* subsequent file changes, so only entrypoints affected by a changed
|
|
180
|
+
* dependency are rebuilt.
|
|
181
|
+
*
|
|
126
182
|
* @param entrypointPath - Absolute path to the source file
|
|
127
183
|
* @param outputUrl - URL path for the bundled file
|
|
128
184
|
* @returns True if bundling was successful
|
|
129
185
|
*/
|
|
130
186
|
private bundleReactEntrypoint;
|
|
187
|
+
/**
|
|
188
|
+
* Bundles multiple React/MDX entrypoints in a single build pass.
|
|
189
|
+
*
|
|
190
|
+
* Uses code splitting to share common dependencies across entrypoints.
|
|
191
|
+
* After successful bundling, populates the entrypoint dependency graph with
|
|
192
|
+
* the build's dependency metadata for selective invalidation.
|
|
193
|
+
*
|
|
194
|
+
* @param entrypoints - Array of entrypoint paths and their output URLs
|
|
195
|
+
* @returns Array of output URLs that were successfully built
|
|
196
|
+
*/
|
|
197
|
+
private bundleReactEntrypoints;
|
|
198
|
+
private resolveTempOutputPath;
|
|
199
|
+
/**
|
|
200
|
+
* Clears stale HMR output from a directory before a rebuild.
|
|
201
|
+
*
|
|
202
|
+
* Only removes:
|
|
203
|
+
* - `*.tmp.js` files (the per-build bundler output the strategy owns)
|
|
204
|
+
* - the `chunks/` subdirectory (the bundler's splitting target)
|
|
205
|
+
*
|
|
206
|
+
* The HMR runtime script (`_hmr_runtime.js`) and any user-authored
|
|
207
|
+
* assets in the outdir are preserved. This is the minimal set of
|
|
208
|
+
* files that, if left from a previous build, can cause the bundler
|
|
209
|
+
* to emit `ENOENT` for chunk references that point to entrypoints
|
|
210
|
+
* whose hash has since changed.
|
|
211
|
+
*/
|
|
212
|
+
private clearHmrOutdir;
|
|
131
213
|
/**
|
|
132
214
|
* Encodes dynamic route segments (brackets) in file paths.
|
|
133
215
|
* Converts `[slug]` to `_slug_` to avoid filesystem issues.
|
|
134
216
|
*/
|
|
135
217
|
private encodeDynamicSegments;
|
|
218
|
+
private rewriteChunkImportUrls;
|
|
219
|
+
private isMissingTempOutputError;
|
|
136
220
|
/**
|
|
137
221
|
* Processes bundled output and injects the React HMR handler.
|
|
138
222
|
* Writes to temp file first, then renames atomically to avoid conflicts.
|