rasengan 1.2.0-beta.1 → 1.2.0-beta.5
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 +14 -5
- package/lib/esm/core/config/utils/define-config.js +10 -1
- package/lib/esm/core/config/utils/path.js +1 -1
- package/lib/esm/core/config/vite/defaults.js +30 -2
- package/lib/esm/core/plugins/index.js +46 -13
- package/lib/esm/entries/server/entry.server.js +9 -3
- package/lib/esm/routing/index.js +1 -1
- package/lib/esm/routing/providers/metadata.js +9 -3
- package/lib/esm/routing/utils/define-router.js +19 -6
- package/lib/esm/routing/utils/define-static-paths.js +10 -0
- package/lib/esm/routing/utils/generate-routes.js +332 -242
- package/lib/esm/routing/utils/index.js +1 -0
- package/lib/esm/server/build/index.js +2 -1
- package/lib/esm/server/build/manifest.js +3 -0
- package/lib/esm/server/build/rendering.js +8 -6
- package/lib/esm/server/node/index.js +163 -3
- package/lib/esm/server/node/rendering.js +1 -4
- package/lib/esm/server/node/utils.js +131 -0
- package/lib/tsconfig.esm.tsbuildinfo +1 -1
- package/lib/tsconfig.types.tsbuildinfo +1 -1
- package/lib/types/core/config/type.d.ts +22 -0
- package/lib/types/entries/server/entry.server.d.ts +1 -1
- package/lib/types/routing/index.d.ts +1 -1
- package/lib/types/routing/types.d.ts +26 -3
- package/lib/types/routing/utils/define-static-paths.d.ts +10 -0
- package/lib/types/routing/utils/generate-routes.d.ts +8 -0
- package/lib/types/routing/utils/index.d.ts +1 -0
- package/lib/types/server/build/index.d.ts +3 -1
- package/lib/types/server/build/manifest.d.ts +11 -0
- package/lib/types/server/build/rendering.d.ts +1 -0
- package/lib/types/server/node/index.d.ts +30 -1
- package/lib/types/server/node/utils.d.ts +25 -0
- package/package.json +3 -3
- package/vite.config.ts +27 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
## Unreleased
|
|
2
2
|
|
|
3
|
-
## 1.2.0-beta.
|
|
3
|
+
## 1.2.0-beta.5 (2026-01-03)
|
|
4
4
|
|
|
5
|
-
## 1.2.0-beta.
|
|
5
|
+
## 1.2.0-beta.4 (2026-01-02)
|
|
6
6
|
|
|
7
|
-
## 1.
|
|
7
|
+
## 1.2.0-beta.3 (2026-01-02)
|
|
8
8
|
|
|
9
|
-
## 1.
|
|
9
|
+
## 1.2.0-beta.2 (2026-01-02)
|
|
10
|
+
|
|
11
|
+
## 1.2.0-beta.1 (2025-09-19)
|
|
12
|
+
|
|
13
|
+
- fix(rasengan): falling back to route.data if route.loaderData is undefined [3cc418](https://github.com/rasengan-dev/rasenganjs/3cc4186e34a5d115e6ef69e8c8b36538aa8562ed)
|
|
14
|
+
|
|
15
|
+
## 1.2.0-beta.0 (2025-09-18)
|
|
10
16
|
|
|
11
|
-
|
|
17
|
+
- feat: adding experiment lazyLoadPage function [017b26](https://github.com/rasengan-dev/rasenganjs/017b26a480815ff480a0f99368fa8fc0c094d5ab)
|
|
18
|
+
- feat(rasengan): synchronizing metadata on client navigation [75374b](https://github.com/rasengan-dev/rasenganjs/75374b958180ad1f46bb00f91235e22bfa11a321)
|
|
19
|
+
- feat(rasengan): adding support for lazy route loading into file-base routing [1161bc](https://github.com/rasengan-dev/rasenganjs/1161bc409679630e293a376536b2e749cbeeaab8)
|
|
20
|
+
- feat: start adding support for lazy loading pages into file-based routing [cbcfdb](https://github.com/rasengan-dev/rasenganjs/cbcfdb6a1f4992b6cfacc280c68dc0d8fe42059c)
|
|
12
21
|
|
|
13
22
|
## 1.1.3 (2025-08-30)
|
|
14
23
|
|
|
@@ -21,7 +21,10 @@ export const defineConfig = async (loadedConfig) => {
|
|
|
21
21
|
else {
|
|
22
22
|
config = loadedConfig;
|
|
23
23
|
}
|
|
24
|
-
const { ssr, server, vite, redirects } = config;
|
|
24
|
+
const { ssr, prerender, sageMode, server, vite, redirects } = config;
|
|
25
|
+
const defaultSageModeConfig = {
|
|
26
|
+
reactCompiler: sageMode?.reactCompiler ?? false,
|
|
27
|
+
};
|
|
25
28
|
// Define default values for vite config coming from loadedConfig.vite
|
|
26
29
|
const defaultViteConfig = {
|
|
27
30
|
...vite,
|
|
@@ -42,7 +45,9 @@ export const defineConfig = async (loadedConfig) => {
|
|
|
42
45
|
try {
|
|
43
46
|
const config = {
|
|
44
47
|
ssr: ssr ?? true,
|
|
48
|
+
prerender: prerender ?? false,
|
|
45
49
|
server: defaultServerConfig,
|
|
50
|
+
sageMode: defaultSageModeConfig,
|
|
46
51
|
vite: {
|
|
47
52
|
...defaultViteConfig,
|
|
48
53
|
resolve: {
|
|
@@ -62,6 +67,10 @@ export const defineConfig = async (loadedConfig) => {
|
|
|
62
67
|
catch (error) {
|
|
63
68
|
return {
|
|
64
69
|
ssr: true,
|
|
70
|
+
prerender: false,
|
|
71
|
+
sageMode: {
|
|
72
|
+
reactCompiler: false,
|
|
73
|
+
},
|
|
65
74
|
vite: {
|
|
66
75
|
appType: 'custom',
|
|
67
76
|
resolve: {
|
|
@@ -29,15 +29,21 @@ export const createDefaultViteConfig = (rootPath, __dirname, mode, config) => {
|
|
|
29
29
|
chunkSizeWarningLimit: 2000,
|
|
30
30
|
},
|
|
31
31
|
environments: {
|
|
32
|
+
/**
|
|
33
|
+
* Client Environment
|
|
34
|
+
*/
|
|
32
35
|
client: {
|
|
33
36
|
build: {
|
|
34
37
|
manifest: true,
|
|
35
|
-
outDir: config.ssr ? 'dist/client' : 'dist',
|
|
38
|
+
outDir: config.ssr || config.prerender ? 'dist/client' : 'dist',
|
|
36
39
|
rollupOptions: {
|
|
37
40
|
input: './src/index',
|
|
38
41
|
},
|
|
39
42
|
},
|
|
40
43
|
},
|
|
44
|
+
/**
|
|
45
|
+
* SSR Environment
|
|
46
|
+
*/
|
|
41
47
|
ssr: {
|
|
42
48
|
build: {
|
|
43
49
|
outDir: 'dist/server',
|
|
@@ -52,6 +58,23 @@ export const createDefaultViteConfig = (rootPath, __dirname, mode, config) => {
|
|
|
52
58
|
ssrEmitAssets: false,
|
|
53
59
|
},
|
|
54
60
|
},
|
|
61
|
+
/**
|
|
62
|
+
* SSG Environment
|
|
63
|
+
*/
|
|
64
|
+
ssg: {
|
|
65
|
+
build: {
|
|
66
|
+
outDir: 'dist/prerender',
|
|
67
|
+
rollupOptions: {
|
|
68
|
+
input: {
|
|
69
|
+
'entry.server': join(__dirname, './lib/esm/entries/server/entry.server.js'),
|
|
70
|
+
'app.router': './src/app/app.router',
|
|
71
|
+
main: './src/main',
|
|
72
|
+
template: './src/template',
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
ssrEmitAssets: false,
|
|
76
|
+
},
|
|
77
|
+
},
|
|
55
78
|
},
|
|
56
79
|
// Resolve config
|
|
57
80
|
resolve: {
|
|
@@ -66,7 +89,12 @@ export const createDefaultViteConfig = (rootPath, __dirname, mode, config) => {
|
|
|
66
89
|
builder: {
|
|
67
90
|
buildApp: async (builder) => {
|
|
68
91
|
if (config.ssr) {
|
|
69
|
-
|
|
92
|
+
if (!config.prerender) {
|
|
93
|
+
await builder.build(builder.environments.ssr);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (config.prerender) {
|
|
97
|
+
await builder.build(builder.environments.ssg);
|
|
70
98
|
}
|
|
71
99
|
await builder.build(builder.environments.client);
|
|
72
100
|
},
|
|
@@ -5,6 +5,7 @@ import { resolveBuildOptions } from '../../server.js';
|
|
|
5
5
|
import { renderIndexHTML } from '../../server/build/rendering.js';
|
|
6
6
|
import { createVirtualModule } from '../../server/virtual/index.js';
|
|
7
7
|
import { pathToFileURL } from 'url';
|
|
8
|
+
import { preRenderApp } from '../../server/node/index.js';
|
|
8
9
|
function loadRasenganGlobal() {
|
|
9
10
|
return {
|
|
10
11
|
name: 'vite-plugin-rasengan-config',
|
|
@@ -84,7 +85,6 @@ function flatRoutesPlugin() {
|
|
|
84
85
|
'/src/app/_routes/**/layout.{js,ts,jsx,tsx}',
|
|
85
86
|
'/src/app/_routes/**/*.page.{md,mdx,js,ts,jsx,tsx}',
|
|
86
87
|
],
|
|
87
|
-
// { eager: true }
|
|
88
88
|
);
|
|
89
89
|
});
|
|
90
90
|
|
|
@@ -179,32 +179,65 @@ export function rasengan({ adapter = { name: Adapters.DEFAULT, prepare: async ()
|
|
|
179
179
|
const module = await this.load({ id: modulePath });
|
|
180
180
|
// SPA mode only
|
|
181
181
|
if (!config.ssr) {
|
|
182
|
-
|
|
183
|
-
|
|
182
|
+
if (!config.prerender) {
|
|
183
|
+
// Generate the template.js file into the dist/assets
|
|
184
|
+
fs.writeFileSync(path.posix.join(process.cwd(), buildOptions.buildDirectory, buildOptions.assetPathDirectory, 'template.js'), module.code, 'utf-8');
|
|
185
|
+
}
|
|
184
186
|
}
|
|
185
187
|
},
|
|
186
188
|
async closeBundle() {
|
|
187
189
|
// We check here if the environment is client has been built because it's the
|
|
188
190
|
// last environment to be built in the Vite build process
|
|
189
191
|
if (this.environment.name === 'client') {
|
|
190
|
-
//
|
|
191
|
-
|
|
192
|
+
// Generate a config.json file into the dist/client/assets or dist/assets
|
|
193
|
+
const minimizedConfig = {
|
|
194
|
+
buildOptions,
|
|
195
|
+
ssr: config.ssr,
|
|
196
|
+
prerender: !!config.prerender,
|
|
197
|
+
redirects: await config.redirects(),
|
|
198
|
+
};
|
|
199
|
+
fs.writeFileSync(path.posix.join(process.cwd(), buildOptions.buildDirectory, config.ssr || config.prerender
|
|
200
|
+
? buildOptions.clientPathDirectory
|
|
201
|
+
: '', buildOptions.assetPathDirectory, 'config.json'), JSON.stringify(minimizedConfig), 'utf-8');
|
|
202
|
+
// Enable the generation of spa-fallback.html during pre-rendering
|
|
203
|
+
// Only if every pages are not generated
|
|
204
|
+
// @default to false - we assume that all pages are not generated
|
|
205
|
+
let enableIndexFallback = false;
|
|
206
|
+
// Handling the prerendering
|
|
207
|
+
if (config.prerender) {
|
|
208
|
+
let routes = [];
|
|
209
|
+
const buildOptions = resolveBuildOptions({
|
|
210
|
+
serverPathDirectory: 'prerender',
|
|
211
|
+
});
|
|
212
|
+
if (typeof config.prerender === 'object') {
|
|
213
|
+
routes = config.prerender.routes || [];
|
|
214
|
+
}
|
|
215
|
+
const outDir = `${process.cwd()}/static`;
|
|
216
|
+
const { isIndexPrerendered } = await preRenderApp({
|
|
217
|
+
build: buildOptions,
|
|
218
|
+
outDir,
|
|
219
|
+
routes,
|
|
220
|
+
});
|
|
221
|
+
enableIndexFallback = isIndexPrerendered;
|
|
222
|
+
}
|
|
223
|
+
// Check if SPA or SSG mode is enabled
|
|
224
|
+
if (!config.ssr || config.prerender) {
|
|
192
225
|
// Load the template.js file
|
|
193
|
-
|
|
226
|
+
let templatePath = '';
|
|
227
|
+
if (config.prerender) {
|
|
228
|
+
templatePath = path.posix.join(process.cwd(), buildOptions.buildDirectory, 'prerender', 'template.js');
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
templatePath = path.posix.join(process.cwd(), buildOptions.buildDirectory, buildOptions.assetPathDirectory, 'template.js');
|
|
232
|
+
}
|
|
194
233
|
const Template = (await import(templatePath)).default;
|
|
195
234
|
// Render the index.html file
|
|
196
235
|
await renderIndexHTML(Template, {
|
|
197
236
|
rootPath: process.cwd(),
|
|
198
237
|
config,
|
|
238
|
+
enableIndexFallback,
|
|
199
239
|
});
|
|
200
240
|
}
|
|
201
|
-
// Generate a config.json file into the dist/client/assets or dist/assets
|
|
202
|
-
const minimizedConfig = {
|
|
203
|
-
buildOptions,
|
|
204
|
-
ssr: config.ssr,
|
|
205
|
-
redirects: await config.redirects(),
|
|
206
|
-
};
|
|
207
|
-
fs.writeFileSync(path.posix.join(process.cwd(), buildOptions.buildDirectory, config.ssr ? buildOptions.clientPathDirectory : '', buildOptions.assetPathDirectory, 'config.json'), JSON.stringify(minimizedConfig), 'utf-8');
|
|
208
241
|
// Prepare the app for deployment
|
|
209
242
|
await prepareToDeploy(adapter);
|
|
210
243
|
}
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { loadModuleSSR } from '../../core/config/utils/load-modules.js';
|
|
3
3
|
import { TemplateLayout } from './index.js';
|
|
4
4
|
import { join, posix } from 'path/posix';
|
|
5
|
-
import { renderToStream } from '../../server/node/rendering.js';
|
|
5
|
+
import { renderToStream, renderToString } from '../../server/node/rendering.js';
|
|
6
6
|
/**
|
|
7
7
|
* Render the app to a stream
|
|
8
8
|
* @param StaticRouterComponent
|
|
@@ -10,7 +10,7 @@ import { renderToStream } from '../../server/node/rendering.js';
|
|
|
10
10
|
* @param res
|
|
11
11
|
* @returns
|
|
12
12
|
*/
|
|
13
|
-
export const render = async (StaticRouterComponent, res, options) => {
|
|
13
|
+
export const render = async (StaticRouterComponent, res, options, stream = true) => {
|
|
14
14
|
const { metadata, assets, buildOptions } = options;
|
|
15
15
|
// Root path
|
|
16
16
|
const rootPath = process.cwd();
|
|
@@ -27,5 +27,11 @@ export const render = async (StaticRouterComponent, res, options) => {
|
|
|
27
27
|
// Import Template
|
|
28
28
|
Template = (await loadModuleSSR(`${rootPath}/src/template`)).default;
|
|
29
29
|
}
|
|
30
|
-
|
|
30
|
+
if (stream) {
|
|
31
|
+
await renderToStream(_jsx(TemplateLayout, { StaticRouterComponent: StaticRouterComponent, metadata: metadata, assets: assets, App: App, Template: Template }), res);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
const html = renderToString(_jsx(TemplateLayout, { StaticRouterComponent: StaticRouterComponent, metadata: metadata, assets: assets, App: App, Template: Template }));
|
|
35
|
+
return html;
|
|
36
|
+
}
|
|
31
37
|
};
|
package/lib/esm/routing/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CustomLink, ScrollRestoration } from './components/index.js';
|
|
2
|
-
export { defineRouter, defineRoutesGroup, flatRoutes } from './utils/index.js';
|
|
2
|
+
export { defineRouter, defineRoutesGroup, defineStaticPaths, flatRoutes, } from './utils/index.js';
|
|
3
3
|
export { RouterComponent } from './interfaces.js';
|
|
4
4
|
export { Outlet, useLocation, useNavigate, useNavigation, useParams, useSearchParams, useFetcher, useMatch, useRoutes, useResolvedPath, matchRoutes, generatePath, matchPath, createRoutesFromChildren, Navigate, NavLink, } from 'react-router';
|
|
5
5
|
export { CustomLink as Link, ScrollRestoration };
|
|
@@ -10,17 +10,23 @@ export default function MetadataProvider({ children, }) {
|
|
|
10
10
|
if (typeof window === 'undefined')
|
|
11
11
|
return;
|
|
12
12
|
(async () => {
|
|
13
|
-
const loadersData = routes.map((route) => route.loaderData ?? route.data // Normally the route.data is deprecated, we need to consider route.loaderData, but in some cases,
|
|
13
|
+
const loadersData = routes.map((route) => route.loaderData ?? route.data // Normally the route.data is deprecated, we need to consider route.loaderData, but in some cases, route.loaderData is undefined and I don't know why, that's why we are using route.data instead
|
|
14
14
|
);
|
|
15
15
|
handleInjectMetadata(loadersData);
|
|
16
16
|
})();
|
|
17
17
|
}, [location]);
|
|
18
|
+
/**
|
|
19
|
+
* This function is responsible to inject the correct metadata on client routing based on the current URL of the page
|
|
20
|
+
* @param loadersData The metadata coming from loaders functions
|
|
21
|
+
* @returns
|
|
22
|
+
*/
|
|
18
23
|
const handleInjectMetadata = (loadersData) => {
|
|
19
24
|
// We generate the metadata
|
|
20
|
-
const metadatas = generateMetadata(loadersData.map((item) => item.meta));
|
|
25
|
+
const metadatas = generateMetadata(loadersData.map((item) => (item.meta ? item.meta : {})));
|
|
21
26
|
// We get the last metadata
|
|
22
27
|
// This is the metadata of the page
|
|
23
|
-
const
|
|
28
|
+
const leaf = loadersData.at(-1);
|
|
29
|
+
const leafMetadata = leaf ? leaf.meta : {};
|
|
24
30
|
// Find all meta tags with data-rg attribute and remove them
|
|
25
31
|
const metaTagsToRemove = document.querySelectorAll('meta[data-rg="true"]');
|
|
26
32
|
metaTagsToRemove.forEach((metaTag) => {
|
|
@@ -71,14 +71,27 @@ export const isMDXPage = (page) => {
|
|
|
71
71
|
}
|
|
72
72
|
return false;
|
|
73
73
|
};
|
|
74
|
+
/**
|
|
75
|
+
* Load thr MDXRenderer is the dedicated package is installed
|
|
76
|
+
* @returns
|
|
77
|
+
*/
|
|
74
78
|
const loadMDXRenderer = async () => {
|
|
75
79
|
try {
|
|
76
|
-
//
|
|
77
|
-
const
|
|
78
|
-
return MDXRenderer;
|
|
80
|
+
// Dynamically import only if the package exists
|
|
81
|
+
const mod = await import('@rasenganjs/mdx');
|
|
82
|
+
return mod.MDXRenderer;
|
|
79
83
|
}
|
|
80
|
-
catch (
|
|
81
|
-
|
|
82
|
-
|
|
84
|
+
catch (error) {
|
|
85
|
+
// Handle the case when the package is not installed
|
|
86
|
+
if (error.code === 'MODULE_NOT_FOUND' ||
|
|
87
|
+
/Cannot find module '@rasenganjs\/mdx'/.test(error.message)) {
|
|
88
|
+
if (process.env.NODE_ENV === 'development') {
|
|
89
|
+
console.warn('[Rasengan.js] MDX package not found — skipping MDX rendering.');
|
|
90
|
+
}
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
// Other unexpected errors (e.g. runtime bug in the module)
|
|
94
|
+
console.error('[Rasengan.js] Unexpected error while loading MDX module:', error);
|
|
95
|
+
throw error;
|
|
83
96
|
}
|
|
84
97
|
};
|