@ripple-ts/vite-plugin 0.3.81 → 0.3.82
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/CHANGELOG.md +18 -0
- package/package.json +4 -4
- package/src/index.js +1 -2
- package/src/project-codegen.js +24 -13
- package/tests/project-codegen.test.js +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @ripple-ts/vite-plugin
|
|
2
2
|
|
|
3
|
+
## 0.3.82
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`67f3794`](https://github.com/Ripple-TS/ripple/commit/67f3794d2f1ffd55dd23a47327d925d9a76a4171)
|
|
8
|
+
Thanks [@leonidaz](https://github.com/leonidaz)! - Compose `RenderRoute` layouts
|
|
9
|
+
during client hydration. The generated client entry hydrated the bare page
|
|
10
|
+
component, so a route's `layout` only existed in the server-rendered HTML: the
|
|
11
|
+
layout component never ran in the browser, its CSS was missing from the client
|
|
12
|
+
graph, and once the SSR style block was removed after hydration the layout's
|
|
13
|
+
styles disappeared (visible as a flash of unstyled content). The client entry
|
|
14
|
+
now loads the layout module and wraps the page the same way the server does, and
|
|
15
|
+
layout entries are included in the client build's static route imports so their
|
|
16
|
+
CSS is bundled.
|
|
17
|
+
- Updated dependencies []:
|
|
18
|
+
- @tsrx/ripple@0.1.30
|
|
19
|
+
- @ripple-ts/adapter@0.3.82
|
|
20
|
+
|
|
3
21
|
## 0.3.81
|
|
4
22
|
|
|
5
23
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "Vite plugin for Ripple",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Dominic Gannaway",
|
|
6
|
-
"version": "0.3.
|
|
6
|
+
"version": "0.3.82",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"module": "src/index.js",
|
|
9
9
|
"main": "src/index.js",
|
|
@@ -32,14 +32,14 @@
|
|
|
32
32
|
"url": "https://github.com/Ripple-TS/ripple/issues"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@ripple
|
|
36
|
-
"@
|
|
35
|
+
"@tsrx/ripple": "0.1.30",
|
|
36
|
+
"@ripple-ts/adapter": "0.3.82"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@types/node": "^24.3.0",
|
|
40
40
|
"type-fest": "^5.6.0",
|
|
41
41
|
"vite": "^8.0.12",
|
|
42
|
-
"ripple": "0.3.
|
|
42
|
+
"ripple": "0.3.82"
|
|
43
43
|
},
|
|
44
44
|
"publishConfig": {
|
|
45
45
|
"access": "public"
|
package/src/index.js
CHANGED
|
@@ -529,8 +529,7 @@ export function ripple(inlineOptions = {}) {
|
|
|
529
529
|
|
|
530
530
|
renderRouteEntries = loadedRippleConfig.router.routes
|
|
531
531
|
.filter((/** @type {Route} */ r) => r.type === 'render')
|
|
532
|
-
.
|
|
533
|
-
.map(get_route_entry_path)
|
|
532
|
+
.flatMap((/** @type {RenderRoute} */ r) => [get_route_entry_path(r.entry), r.layout])
|
|
534
533
|
.filter((entry) => typeof entry === 'string');
|
|
535
534
|
|
|
536
535
|
// Deduplicate entries (multiple routes can share the same component)
|
package/src/project-codegen.js
CHANGED
|
@@ -106,33 +106,44 @@ async function resolveRouteComponent(data) {
|
|
|
106
106
|
if (!entryPath) return null;
|
|
107
107
|
|
|
108
108
|
const loadModule = routeModules[entryPath] ?? (() => import(/* @vite-ignore */ entryPath));
|
|
109
|
-
|
|
109
|
+
const Component = getComponentExport(await loadModule(), exportName);
|
|
110
|
+
if (!Component) return null;
|
|
111
|
+
|
|
112
|
+
// Load the route layout so hydration sees the same component tree as the
|
|
113
|
+
// server render and the layout's CSS is part of the client graph.
|
|
114
|
+
const layoutPath = typeof route?.layout === 'string' ? route.layout : undefined;
|
|
115
|
+
if (layoutPath) {
|
|
116
|
+
const loadLayout = routeModules[layoutPath] ?? (() => import(/* @vite-ignore */ layoutPath));
|
|
117
|
+
const Layout = getComponentExport(await loadLayout());
|
|
118
|
+
if (Layout) return { Component, Layout };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return { Component };
|
|
110
122
|
}
|
|
111
123
|
|
|
112
124
|
(async () => {
|
|
113
125
|
try {
|
|
114
126
|
const data = JSON.parse(document.getElementById('__ripple_data').textContent);
|
|
115
127
|
const target = document.getElementById('root');
|
|
116
|
-
const
|
|
128
|
+
const resolved = await resolveRouteComponent(data);
|
|
117
129
|
|
|
118
|
-
if (!
|
|
130
|
+
if (!resolved || !target) {
|
|
119
131
|
console.error('[ripple] Unable to hydrate route: missing component export or #root target.');
|
|
120
132
|
return;
|
|
121
133
|
}
|
|
122
134
|
|
|
135
|
+
// With a layout, hydrate the layout and pass the page as its children
|
|
136
|
+
// prop — the same tree the server rendered.
|
|
137
|
+
const { Component, Layout } = resolved;
|
|
138
|
+
const pageProps = { params: data.params };
|
|
139
|
+
const root = Layout ?? Component;
|
|
140
|
+
const props = Layout ? { ...pageProps, children: () => Component(pageProps) } : pageProps;
|
|
141
|
+
|
|
123
142
|
try {
|
|
124
|
-
hydrate(
|
|
125
|
-
target,
|
|
126
|
-
props: { params: data.params },
|
|
127
|
-
rootBoundary,
|
|
128
|
-
});
|
|
143
|
+
hydrate(root, { target, props, rootBoundary });
|
|
129
144
|
} catch (error) {
|
|
130
145
|
console.warn('[ripple] Hydration failed, falling back to mount.', error);
|
|
131
|
-
mount(
|
|
132
|
-
target,
|
|
133
|
-
props: { params: data.params },
|
|
134
|
-
rootBoundary,
|
|
135
|
-
});
|
|
146
|
+
mount(root, { target, props, rootBoundary });
|
|
136
147
|
}
|
|
137
148
|
} catch (error) {
|
|
138
149
|
console.error('[ripple] Failed to bootstrap client hydration.', error);
|
|
@@ -17,7 +17,7 @@ describe('project codegen', () => {
|
|
|
17
17
|
expect(source).toContain('function getRouteEntryExportName(entry)');
|
|
18
18
|
expect(source).toContain('return Array.isArray(entry) ? entry[0] : undefined;');
|
|
19
19
|
expect(source).toContain('const rootBoundary = rippleConfig.rootBoundary;');
|
|
20
|
-
expect(source).toContain('rootBoundary
|
|
20
|
+
expect(source).toContain('hydrate(root, { target, props, rootBoundary });');
|
|
21
21
|
});
|
|
22
22
|
|
|
23
23
|
it('generates server components from named entry tuples', () => {
|