Skip to content

Commit 62ad8a5

Browse files
authored
feat: use Rspack to compile document & support data fetch and ssgByEntries for ssg (#7667)
1 parent bf2390c commit 62ad8a5

File tree

34 files changed

+1255
-684
lines changed

34 files changed

+1255
-684
lines changed

packages/cli/plugin-ssg/package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,7 @@
7070
"@modern-js/utils": "workspace:*",
7171
"@swc/helpers": "^0.5.17",
7272
"node-mocks-http": "^1.11.0",
73-
"normalize-path": "3.0.0",
74-
"portfinder": "^1.0.38"
73+
"normalize-path": "3.0.0"
7574
},
7675
"peerDependencies": {
7776
"react-router-dom": ">=7.0.0"

packages/cli/plugin-ssg/src/index.ts

Lines changed: 39 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import path from 'path';
22
import type { AppTools, CliPlugin } from '@modern-js/app-tools';
3-
import type { NestedRouteForCli, PageRoute } from '@modern-js/types';
3+
import type {
4+
NestedRouteForCli,
5+
PageRoute,
6+
SSGSingleEntryOptions,
7+
} from '@modern-js/types';
48
import { filterRoutesForServer, logger } from '@modern-js/utils';
5-
import { generatePath } from 'react-router-dom';
69
import { makeRoute } from './libs/make';
710
import { writeHtmlFile } from './libs/output';
811
import { replaceRoute } from './libs/replace';
@@ -15,7 +18,13 @@ import {
1518
writeJSONSpec,
1619
} from './libs/util';
1720
import { createServer } from './server';
18-
import type { AgreedRouteMap, SSGConfig, SsgRoute } from './types';
21+
import type {
22+
AgreedRoute,
23+
AgreedRouteMap,
24+
SSGConfig,
25+
SSGRouteOptions,
26+
SsgRoute,
27+
} from './types';
1928

2029
export const ssgPlugin = (): CliPlugin<AppTools> => ({
2130
name: '@modern-js/plugin-ssg',
@@ -42,11 +51,12 @@ export const ssgPlugin = (): CliPlugin<AppTools> => ({
4251
const { output, server } = resolvedConfig;
4352
const {
4453
ssg,
54+
ssgByEntries,
4555
distPath: { root: outputPath } = {},
4656
} = output;
4757

4858
const ssgOptions: SSGConfig =
49-
(Array.isArray(ssg) ? ssg.pop() : ssg) || true;
59+
(Array.isArray(ssg) ? ssg.pop() : ssg) ?? true;
5060

5161
const buildDir = path.join(appDirectory, outputPath as string);
5262
const routes = readJSONSpec(buildDir);
@@ -65,6 +75,7 @@ export const ssgPlugin = (): CliPlugin<AppTools> => ({
6575
entrypoints,
6676
pageRoutes,
6777
server,
78+
ssgByEntries,
6879
);
6980

7081
if (!intermediateOptions) {
@@ -76,9 +87,8 @@ export const ssgPlugin = (): CliPlugin<AppTools> => ({
7687
pageRoutes.forEach(pageRoute => {
7788
const { entryName, entryPath } = pageRoute;
7889
const agreedRoutes = agreedRouteMap[entryName as string];
79-
let entryOptions =
80-
intermediateOptions[entryName as string] ||
81-
intermediateOptions[pageRoute.urlPath];
90+
let entryOptions = (intermediateOptions[entryName as string] ||
91+
intermediateOptions[pageRoute.urlPath]) as SSGSingleEntryOptions;
8292

8393
if (!agreedRoutes) {
8494
// default behavior for non-agreed route
@@ -93,7 +103,7 @@ export const ssgPlugin = (): CliPlugin<AppTools> => ({
93103
// if entryOptions is object and has routes options
94104
// add every route in options
95105
const { routes: enrtyRoutes, headers } = entryOptions;
96-
enrtyRoutes.forEach(route => {
106+
enrtyRoutes.forEach((route: SSGRouteOptions) => {
97107
ssgRoutes.push(makeRoute(pageRoute, route, headers));
98108
});
99109
}
@@ -105,42 +115,32 @@ export const ssgPlugin = (): CliPlugin<AppTools> => ({
105115
}
106116

107117
if (entryOptions === true) {
108-
entryOptions = { preventDefault: [], routes: [], headers: {} };
118+
entryOptions = { routes: [], headers: {} };
109119
}
110120

111-
const {
112-
preventDefault = [],
113-
routes: userRoutes = [],
114-
headers,
115-
} = entryOptions;
121+
const { routes: userRoutes = [], headers } =
122+
(entryOptions as {
123+
routes?: SSGRouteOptions[];
124+
headers?: Record<string, string>;
125+
}) || {};
116126
// if the user sets the routes, then only add them
117127
if (userRoutes.length > 0) {
118-
userRoutes.forEach(route => {
119-
if (typeof route === 'string') {
120-
ssgRoutes.push(makeRoute(pageRoute, route, headers));
121-
} else if (Array.isArray(route.params)) {
122-
route.params.forEach(param => {
123-
ssgRoutes.push(
124-
makeRoute(
125-
pageRoute,
126-
{ ...route, url: generatePath(route.url, param) },
127-
headers,
128-
),
129-
);
130-
});
131-
} else {
132-
ssgRoutes.push(makeRoute(pageRoute, route, headers));
128+
(userRoutes as SSGRouteOptions[]).forEach(
129+
(route: SSGRouteOptions) => {
130+
if (typeof route === 'string') {
131+
ssgRoutes.push(makeRoute(pageRoute, route, headers));
132+
} else {
133+
ssgRoutes.push(makeRoute(pageRoute, route, headers));
134+
}
135+
},
136+
);
137+
} else {
138+
// default: add all non-dynamic routes
139+
agreedRoutes.forEach((route: AgreedRoute) => {
140+
if (!isDynamicUrl(route.path!)) {
141+
ssgRoutes.push(makeRoute(pageRoute, route.path!, headers));
133142
}
134143
});
135-
} else {
136-
// otherwith add all except dynamic routes
137-
agreedRoutes
138-
.filter(route => !preventDefault.includes(route.path!))
139-
.forEach(route => {
140-
if (!isDynamicUrl(route.path!)) {
141-
ssgRoutes.push(makeRoute(pageRoute, route.path!, headers));
142-
}
143-
});
144144
}
145145
}
146146
});
@@ -177,12 +177,11 @@ export const ssgPlugin = (): CliPlugin<AppTools> => ({
177177
});
178178

179179
const htmlAry = await createServer(
180-
api,
180+
appContext,
181181
ssgRoutes,
182182
pageRoutes,
183183
apiRoutes,
184184
resolvedConfig,
185-
appDirectory,
186185
);
187186

188187
// write to dist file

packages/cli/plugin-ssg/src/libs/util.ts

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export function formatPath(str: string) {
4141
}
4242

4343
export function isDynamicUrl(url: string): boolean {
44-
return url.includes(':');
44+
return url.includes(':') || url.endsWith('*');
4545
}
4646

4747
export function getUrlPrefix(route: SsgRoute, baseUrl: string | string[]) {
@@ -112,7 +112,48 @@ export const standardOptions = (
112112
entrypoints: EntryPoint[],
113113
routes: ModernRoute[],
114114
server: ServerUserConfig,
115+
ssgByEntries?: SSGMultiEntryOptions,
115116
) => {
117+
if (ssgByEntries && Object.keys(ssgByEntries).length > 0) {
118+
const result: SSGMultiEntryOptions = {};
119+
120+
Object.keys(ssgByEntries).forEach(key => {
121+
const val = ssgByEntries[key];
122+
if (typeof val !== 'function') {
123+
result[key] = val;
124+
}
125+
});
126+
127+
for (const entry of entrypoints) {
128+
const { entryName } = entry;
129+
const configured = ssgByEntries[entryName];
130+
if (typeof configured === 'function') {
131+
const routesForEntry = routes.filter(r => r.entryName === entryName);
132+
if (Array.isArray(server?.baseUrl)) {
133+
for (const url of server.baseUrl) {
134+
routesForEntry
135+
.filter(
136+
r => typeof r.urlPath === 'string' && r.urlPath.startsWith(url),
137+
)
138+
.forEach(r => {
139+
result[r.urlPath as string] = configured(entryName, {
140+
baseUrl: url,
141+
});
142+
});
143+
}
144+
} else {
145+
result[entryName] = configured(entryName, {
146+
baseUrl: server?.baseUrl,
147+
});
148+
}
149+
} else if (typeof configured !== 'undefined') {
150+
result[entryName] = configured;
151+
}
152+
}
153+
154+
return result;
155+
}
156+
116157
if (ssgOptions === false) {
117158
return false;
118159
}
@@ -125,24 +166,30 @@ export const standardOptions = (
125166
} else if (typeof ssgOptions === 'object') {
126167
const isSingle = isSingleEntry(entrypoints);
127168

128-
if (isSingle && typeof (ssgOptions as any).main === 'undefined') {
169+
if (isSingle) {
129170
return { main: ssgOptions } as SSGMultiEntryOptions;
130-
} else {
131-
return ssgOptions as SSGMultiEntryOptions;
132171
}
172+
173+
return entrypoints.reduce((opt, entry) => {
174+
opt[entry.entryName] = ssgOptions;
175+
return opt;
176+
}, {} as SSGMultiEntryOptions);
133177
} else if (typeof ssgOptions === 'function') {
134178
const intermediateOptions: SSGMultiEntryOptions = {};
135179
for (const entrypoint of entrypoints) {
136180
const { entryName } = entrypoint;
137-
// TODO: may be async function
181+
const routesForEntry = routes.filter(r => r.entryName === entryName);
138182
if (Array.isArray(server?.baseUrl)) {
139183
for (const url of server.baseUrl) {
140-
const matchUrl = entryName === 'main' ? url : `${url}/${entryName}`;
141-
const route = routes.find(route => route.urlPath === matchUrl);
142-
intermediateOptions[route?.urlPath as string] = ssgOptions(
143-
entryName,
144-
{ baseUrl: url },
145-
);
184+
routesForEntry
185+
.filter(
186+
r => typeof r.urlPath === 'string' && r.urlPath.startsWith(url),
187+
)
188+
.forEach(r => {
189+
intermediateOptions[r.urlPath as string] = ssgOptions(entryName, {
190+
baseUrl: url,
191+
});
192+
});
146193
}
147194
} else {
148195
intermediateOptions[entryName] = ssgOptions(entryName, {

0 commit comments

Comments
 (0)