@bleedingdev/modern-js-ultramodern-app-tools 0.0.0 → 3.9.0-ultramodern.10
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/LICENSE +21 -0
- package/dist/cjs/native-composition/index.js +131 -0
- package/dist/cjs/native-composition/preset.js +178 -0
- package/dist/cjs/native-composition/release-envelope-plugin.js +44 -0
- package/dist/cjs/native-composition/router-integration-plugin.js +55 -0
- package/dist/cjs/native-composition/router-runtime.js +66 -0
- package/dist/cjs/native-composition/rsc-disabled-plugin.js +117 -0
- package/dist/cjs/native-composition/server-plugin.js +50 -0
- package/dist/cjs/native-composition/ssr-integration-plugin.js +145 -0
- package/dist/cjs/native-composition/types.js +18 -0
- package/dist/esm/native-composition/index.mjs +71 -0
- package/dist/esm/native-composition/preset.mjs +126 -0
- package/dist/esm/native-composition/release-envelope-plugin.mjs +6 -0
- package/dist/esm/native-composition/router-integration-plugin.mjs +17 -0
- package/dist/esm/native-composition/router-runtime.mjs +26 -0
- package/dist/esm/native-composition/rsc-disabled-plugin.mjs +79 -0
- package/dist/esm/native-composition/server-plugin.mjs +1 -0
- package/dist/esm/native-composition/ssr-integration-plugin.mjs +104 -0
- package/dist/esm/native-composition/types.mjs +0 -0
- package/dist/esm-node/native-composition/index.mjs +72 -0
- package/dist/esm-node/native-composition/preset.mjs +127 -0
- package/dist/esm-node/native-composition/release-envelope-plugin.mjs +7 -0
- package/dist/esm-node/native-composition/router-integration-plugin.mjs +18 -0
- package/dist/esm-node/native-composition/router-runtime.mjs +27 -0
- package/dist/esm-node/native-composition/rsc-disabled-plugin.mjs +81 -0
- package/dist/esm-node/native-composition/server-plugin.mjs +2 -0
- package/dist/esm-node/native-composition/ssr-integration-plugin.mjs +105 -0
- package/dist/esm-node/native-composition/types.mjs +1 -0
- package/dist/types/native-composition/index.d.ts +6 -0
- package/dist/types/native-composition/preset.d.ts +86 -0
- package/dist/types/native-composition/release-envelope-plugin.d.ts +2 -0
- package/dist/types/native-composition/router-integration-plugin.d.ts +3 -0
- package/dist/types/native-composition/router-runtime.d.ts +4 -0
- package/dist/types/native-composition/rsc-disabled-plugin.d.ts +2 -0
- package/dist/types/native-composition/server-plugin.d.ts +1 -0
- package/dist/types/native-composition/ssr-integration-plugin.d.ts +7 -0
- package/dist/types/native-composition/types.d.ts +24 -0
- package/dist/types-esm/native-composition/index.d.mts +6 -0
- package/dist/types-esm/native-composition/preset.d.mts +86 -0
- package/dist/types-esm/native-composition/release-envelope-plugin.d.mts +2 -0
- package/dist/types-esm/native-composition/router-integration-plugin.d.mts +3 -0
- package/dist/types-esm/native-composition/router-runtime.d.mts +4 -0
- package/dist/types-esm/native-composition/rsc-disabled-plugin.d.mts +2 -0
- package/dist/types-esm/native-composition/server-plugin.d.mts +1 -0
- package/dist/types-esm/native-composition/ssr-integration-plugin.d.mts +7 -0
- package/dist/types-esm/native-composition/types.d.mts +24 -0
- package/package.json +100 -5
- package/src/native-composition/index.ts +92 -0
- package/src/native-composition/preset.ts +338 -0
- package/src/native-composition/release-envelope-plugin.ts +6 -0
- package/src/native-composition/router-integration-plugin.ts +20 -0
- package/src/native-composition/router-runtime.ts +28 -0
- package/src/native-composition/rsc-disabled-plugin.ts +117 -0
- package/src/native-composition/server-plugin.ts +1 -0
- package/src/native-composition/ssr-integration-plugin.ts +244 -0
- package/src/native-composition/types.ts +32 -0
- package/README.md +0 -3
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { builderPluginAdapterPrecompress } from '@modern-js/app-tools-extensions/build-config/precompress/plugin';
|
|
4
|
+
import { resolveEffectTsgoCompiler } from '@modern-js/app-tools-extensions/config';
|
|
5
|
+
import { configureUltramodernTypeChecker } from '@modern-js/app-tools-extensions/native-type-checker';
|
|
6
|
+
import { resolveUltramodernReleaseIdentity } from '@modern-js/app-tools-extensions/release-identity';
|
|
7
|
+
import { mergeConfig } from '@modern-js/plugin/cli';
|
|
8
|
+
import { type RspackChain, rspack } from '@rsbuild/core';
|
|
9
|
+
import type { AppUserConfig } from './types';
|
|
10
|
+
|
|
11
|
+
const DEFAULT_OTLP_ENDPOINT = 'http://127.0.0.1:4318/v1/logs';
|
|
12
|
+
const DEFAULT_VICTORIA_METRICS_ENDPOINT =
|
|
13
|
+
'http://127.0.0.1:8428/api/v1/import/prometheus';
|
|
14
|
+
|
|
15
|
+
export interface PresetUltramodernOptions {
|
|
16
|
+
/**
|
|
17
|
+
* Stable producer identity used by BFF cross-project clients.
|
|
18
|
+
* @default "app"
|
|
19
|
+
*/
|
|
20
|
+
appId?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Generation-time identity root for a generated delivery unit. When set, the
|
|
23
|
+
* preset derives one build identity from the immutable source revision and
|
|
24
|
+
* injects it into every browser, SSR, API, and backend bundle.
|
|
25
|
+
*/
|
|
26
|
+
deliveryUnit?: {
|
|
27
|
+
buildMarker: string;
|
|
28
|
+
unitId: string;
|
|
29
|
+
version: string;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Enable BFF requestId contract by default.
|
|
33
|
+
* @default true
|
|
34
|
+
*/
|
|
35
|
+
enableBffRequestId?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Enable telemetry contract by default.
|
|
38
|
+
* Exporters are still configured separately by applications.
|
|
39
|
+
* @default true
|
|
40
|
+
*/
|
|
41
|
+
enableTelemetry?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Enable telemetry exporters.
|
|
44
|
+
*
|
|
45
|
+
* By default each exporter is enabled only when its endpoint is explicitly
|
|
46
|
+
* configured (via the matching option or environment variable), so a bare
|
|
47
|
+
* preset app boots in production without local collectors.
|
|
48
|
+
* Set `true` to force both exporters on with their default localhost
|
|
49
|
+
* endpoints, or `false` to disable exporters entirely.
|
|
50
|
+
* @default undefined (endpoint-driven)
|
|
51
|
+
*/
|
|
52
|
+
enableTelemetryExporters?: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* OTLP exporter endpoint. Setting it (or the environment variable)
|
|
55
|
+
* enables the OTLP exporter unless `enableTelemetryExporters` is `false`.
|
|
56
|
+
* The localhost endpoint is used only when exporters are forced on with
|
|
57
|
+
* `enableTelemetryExporters: true` and no endpoint was provided.
|
|
58
|
+
* @default process.env.MODERN_TELEMETRY_OTLP_ENDPOINT
|
|
59
|
+
*/
|
|
60
|
+
otlpEndpoint?: string;
|
|
61
|
+
/**
|
|
62
|
+
* VictoriaMetrics exporter endpoint. Setting it (or the environment
|
|
63
|
+
* variable) enables the VictoriaMetrics exporter unless
|
|
64
|
+
* `enableTelemetryExporters` is `false`.
|
|
65
|
+
* The localhost endpoint is used only when exporters are forced on with
|
|
66
|
+
* `enableTelemetryExporters: true` and no endpoint was provided.
|
|
67
|
+
* @default process.env.MODERN_TELEMETRY_VICTORIA_ENDPOINT
|
|
68
|
+
*/
|
|
69
|
+
victoriaMetricsEndpoint?: string;
|
|
70
|
+
/**
|
|
71
|
+
* Enable fail-loud startup probing for telemetry exporters.
|
|
72
|
+
* Probes only run for exporters that are actually enabled.
|
|
73
|
+
* @default false
|
|
74
|
+
*/
|
|
75
|
+
telemetryFailLoudStartup?: boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Enable app-level Module Federation SSR handshake by default.
|
|
78
|
+
* @default true
|
|
79
|
+
*/
|
|
80
|
+
enableModuleFederationSSR?: boolean;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const resolveReactRouterPackageDir = (appDirectory: string) => {
|
|
84
|
+
const resolveNodeModulePackageJson = (
|
|
85
|
+
packageName: string,
|
|
86
|
+
fromDirectory: string,
|
|
87
|
+
) => {
|
|
88
|
+
let currentDirectory = path.resolve(fromDirectory);
|
|
89
|
+
|
|
90
|
+
while (true) {
|
|
91
|
+
const packageJson = path.join(
|
|
92
|
+
currentDirectory,
|
|
93
|
+
'node_modules',
|
|
94
|
+
packageName,
|
|
95
|
+
'package.json',
|
|
96
|
+
);
|
|
97
|
+
if (fs.existsSync(packageJson)) {
|
|
98
|
+
return fs.realpathSync(packageJson);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const parentDirectory = path.dirname(currentDirectory);
|
|
102
|
+
if (parentDirectory === currentDirectory) {
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
currentDirectory = parentDirectory;
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const reactRouterPackageJson = resolveNodeModulePackageJson(
|
|
110
|
+
'react-router',
|
|
111
|
+
appDirectory,
|
|
112
|
+
);
|
|
113
|
+
if (reactRouterPackageJson) {
|
|
114
|
+
return path.dirname(reactRouterPackageJson);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const reactRouterDomPackageJson = resolveNodeModulePackageJson(
|
|
118
|
+
'react-router-dom',
|
|
119
|
+
appDirectory,
|
|
120
|
+
);
|
|
121
|
+
if (!reactRouterDomPackageJson) {
|
|
122
|
+
return undefined;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const nestedReactRouterPackageJson = resolveNodeModulePackageJson(
|
|
126
|
+
'react-router',
|
|
127
|
+
path.dirname(reactRouterDomPackageJson),
|
|
128
|
+
);
|
|
129
|
+
if (nestedReactRouterPackageJson) {
|
|
130
|
+
return path.dirname(nestedReactRouterPackageJson);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return undefined;
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
// Dependency-driven opt-in surface for apps that explicitly install
|
|
137
|
+
// react-router/react-router-dom. Default TanStack workspaces install neither,
|
|
138
|
+
// so resolveReactRouterPackageDir returns undefined and this must no-op.
|
|
139
|
+
// Do not remove as dead code: it is the supported escape hatch for apps that
|
|
140
|
+
// bring their own react-router dependency.
|
|
141
|
+
const setReactRouterBridgeSafeAliases = (
|
|
142
|
+
chain: RspackChain,
|
|
143
|
+
{ isProd }: { isProd: boolean },
|
|
144
|
+
) => {
|
|
145
|
+
const chainContext = chain.get('context');
|
|
146
|
+
const appDirectory =
|
|
147
|
+
typeof chainContext === 'string' && chainContext.length > 0
|
|
148
|
+
? chainContext
|
|
149
|
+
: process.cwd();
|
|
150
|
+
const reactRouterPackageDir = resolveReactRouterPackageDir(appDirectory);
|
|
151
|
+
if (!reactRouterPackageDir) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const productionEntry = path.join(
|
|
156
|
+
reactRouterPackageDir,
|
|
157
|
+
'dist/production/index.mjs',
|
|
158
|
+
);
|
|
159
|
+
const developmentEntry = path.join(
|
|
160
|
+
reactRouterPackageDir,
|
|
161
|
+
'dist/development/index.mjs',
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
chain.resolve.alias.set(
|
|
165
|
+
'react-router$',
|
|
166
|
+
isProd ? productionEntry : developmentEntry,
|
|
167
|
+
);
|
|
168
|
+
chain.resolve.alias.set(
|
|
169
|
+
'react-router/dist/production/index.js',
|
|
170
|
+
productionEntry,
|
|
171
|
+
);
|
|
172
|
+
chain.resolve.alias.set(
|
|
173
|
+
'react-router/dist/development/index.js',
|
|
174
|
+
developmentEntry,
|
|
175
|
+
);
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Materialize a fresh UltraModern preset config.
|
|
180
|
+
*
|
|
181
|
+
* This is the advanced inspection API. Use `presetUltramodern` when composing
|
|
182
|
+
* an application config so nested records, arrays, and hooks keep the normal
|
|
183
|
+
* Modern.js merge behavior.
|
|
184
|
+
*/
|
|
185
|
+
export const createPresetUltramodernConfig = (
|
|
186
|
+
options: PresetUltramodernOptions = {},
|
|
187
|
+
): AppUserConfig => {
|
|
188
|
+
const {
|
|
189
|
+
appId = 'app',
|
|
190
|
+
deliveryUnit,
|
|
191
|
+
enableBffRequestId = true,
|
|
192
|
+
enableTelemetry = true,
|
|
193
|
+
enableTelemetryExporters,
|
|
194
|
+
otlpEndpoint = process.env.MODERN_TELEMETRY_OTLP_ENDPOINT,
|
|
195
|
+
victoriaMetricsEndpoint = process.env.MODERN_TELEMETRY_VICTORIA_ENDPOINT,
|
|
196
|
+
telemetryFailLoudStartup = false,
|
|
197
|
+
enableModuleFederationSSR = true,
|
|
198
|
+
} = options;
|
|
199
|
+
|
|
200
|
+
const server: NonNullable<AppUserConfig['server']> = {};
|
|
201
|
+
const releaseIdentity = deliveryUnit
|
|
202
|
+
? resolveUltramodernReleaseIdentity({
|
|
203
|
+
generationBuildMarker: deliveryUnit.buildMarker,
|
|
204
|
+
unitId: deliveryUnit.unitId,
|
|
205
|
+
})
|
|
206
|
+
: undefined;
|
|
207
|
+
const bundledReleaseIdentity = releaseIdentity
|
|
208
|
+
? {
|
|
209
|
+
...releaseIdentity,
|
|
210
|
+
releaseVersion: deliveryUnit!.version,
|
|
211
|
+
}
|
|
212
|
+
: undefined;
|
|
213
|
+
|
|
214
|
+
if (enableTelemetry) {
|
|
215
|
+
server.telemetry = {
|
|
216
|
+
enabled: true,
|
|
217
|
+
failLoudStartup: telemetryFailLoudStartup,
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
if (enableTelemetryExporters !== false) {
|
|
221
|
+
const exporters: NonNullable<
|
|
222
|
+
NonNullable<typeof server.telemetry>['exporters']
|
|
223
|
+
> = {};
|
|
224
|
+
|
|
225
|
+
if (enableTelemetryExporters === true || otlpEndpoint) {
|
|
226
|
+
exporters.otlp = {
|
|
227
|
+
enabled: true,
|
|
228
|
+
endpoint: otlpEndpoint || DEFAULT_OTLP_ENDPOINT,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (enableTelemetryExporters === true || victoriaMetricsEndpoint) {
|
|
233
|
+
exporters.victoriaMetrics = {
|
|
234
|
+
enabled: true,
|
|
235
|
+
endpoint:
|
|
236
|
+
victoriaMetricsEndpoint || DEFAULT_VICTORIA_METRICS_ENDPOINT,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (Object.keys(exporters).length > 0) {
|
|
241
|
+
server.telemetry.exporters = exporters;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if (enableModuleFederationSSR) {
|
|
247
|
+
server.ssr = {
|
|
248
|
+
mode: 'stream',
|
|
249
|
+
moduleFederationAppSSR: true,
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const presetConfig: AppUserConfig = {
|
|
254
|
+
output: {
|
|
255
|
+
// Keep build artifacts predictable across apps.
|
|
256
|
+
precompress: true,
|
|
257
|
+
},
|
|
258
|
+
server,
|
|
259
|
+
source: {
|
|
260
|
+
reactCompiler: true,
|
|
261
|
+
...(deliveryUnit
|
|
262
|
+
? {
|
|
263
|
+
globalVars: {
|
|
264
|
+
ULTRAMODERN_BUILD_MARKER: releaseIdentity?.buildMarker,
|
|
265
|
+
ULTRAMODERN_RELEASE_VERSION: deliveryUnit.version,
|
|
266
|
+
ULTRAMODERN_SOURCE_REVISION: releaseIdentity?.sourceRevision,
|
|
267
|
+
},
|
|
268
|
+
}
|
|
269
|
+
: {}),
|
|
270
|
+
},
|
|
271
|
+
tools: {
|
|
272
|
+
bundlerChain: (chain, utils) => {
|
|
273
|
+
setReactRouterBridgeSafeAliases(chain, utils);
|
|
274
|
+
configureUltramodernTypeChecker(
|
|
275
|
+
chain,
|
|
276
|
+
utils.CHAIN_ID.PLUGIN.TS_CHECKER,
|
|
277
|
+
from => resolveEffectTsgoCompiler({ from }),
|
|
278
|
+
);
|
|
279
|
+
},
|
|
280
|
+
// Keep generated Tailwind apps on Rsbuild's native CSS pipeline.
|
|
281
|
+
lightningcssLoader: true,
|
|
282
|
+
...(bundledReleaseIdentity
|
|
283
|
+
? {
|
|
284
|
+
rspack: config => {
|
|
285
|
+
config.plugins ??= [];
|
|
286
|
+
config.plugins.push(
|
|
287
|
+
new rspack.BannerPlugin({
|
|
288
|
+
banner: `void ${JSON.stringify(bundledReleaseIdentity.buildMarker)};void ${JSON.stringify(bundledReleaseIdentity.sourceRevision)};void ${JSON.stringify(bundledReleaseIdentity.releaseVersion)};`,
|
|
289
|
+
raw: true,
|
|
290
|
+
// The default additions stage runs before production
|
|
291
|
+
// minimization, which removes side-effect-free identity
|
|
292
|
+
// expressions from browser and Module Federation assets.
|
|
293
|
+
// Inject after minimization but before Rspack derives asset
|
|
294
|
+
// hashes, so the identity survives in browser assets and a
|
|
295
|
+
// changed identity necessarily changes [contenthash].
|
|
296
|
+
stage: rspack.Compilation.PROCESS_ASSETS_STAGE_SUMMARIZE,
|
|
297
|
+
test: /\.(?:c|m)?js$/u,
|
|
298
|
+
}),
|
|
299
|
+
);
|
|
300
|
+
return config;
|
|
301
|
+
},
|
|
302
|
+
}
|
|
303
|
+
: {}),
|
|
304
|
+
},
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
if (enableBffRequestId) {
|
|
308
|
+
presetConfig.bff = {
|
|
309
|
+
requestId: appId,
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
return presetConfig;
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Compose an application config over the UltraModern preset.
|
|
318
|
+
*
|
|
319
|
+
* The application config is merged after the preset. Nested records are
|
|
320
|
+
* preserved, scalar values and `false` override preset values, and omitted or
|
|
321
|
+
* `undefined` values keep the preset value. Arrays and hooks compose in
|
|
322
|
+
* preset-first order. An empty record does not reset nested preset defaults;
|
|
323
|
+
* use the typed `PresetUltramodernOptions` opt-outs instead.
|
|
324
|
+
*/
|
|
325
|
+
export const presetUltramodern = (
|
|
326
|
+
config: AppUserConfig,
|
|
327
|
+
options: PresetUltramodernOptions = {},
|
|
328
|
+
): AppUserConfig => {
|
|
329
|
+
const merged = mergeConfig<AppUserConfig, AppUserConfig>([
|
|
330
|
+
createPresetUltramodernConfig(options),
|
|
331
|
+
config,
|
|
332
|
+
]);
|
|
333
|
+
merged.builderPlugins = [
|
|
334
|
+
builderPluginAdapterPrecompress(merged.output?.precompress),
|
|
335
|
+
...(merged.builderPlugins ?? []),
|
|
336
|
+
];
|
|
337
|
+
return merged;
|
|
338
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { AppTools, CliPlugin } from '@modern-js/app-tools';
|
|
2
|
+
import { resolveDeployTarget } from '@modern-js/app-tools-extensions/deploy-output/target';
|
|
3
|
+
import { createUltramodernReleaseEnvelopePlugin } from '@modern-js/app-tools-extensions/release-envelope/plugin';
|
|
4
|
+
|
|
5
|
+
export const ultramodernReleaseEnvelopePlugin = (): CliPlugin<AppTools> =>
|
|
6
|
+
createUltramodernReleaseEnvelopePlugin({ resolveDeployTarget });
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AppTools, CliPlugin } from '@modern-js/app-tools';
|
|
2
|
+
|
|
3
|
+
/** Add fork router policy after the native and optional provider selectors. */
|
|
4
|
+
export const ultramodernRouterIntegrationPlugin = (): CliPlugin<AppTools> => ({
|
|
5
|
+
name: '@modern-js/ultramodern-router-integration',
|
|
6
|
+
pre: ['@modern-js/plugin-router', '@modern-js/plugin-tanstack'],
|
|
7
|
+
setup(api) {
|
|
8
|
+
api._internalRuntimePlugins(({ entrypoint, plugins }) => ({
|
|
9
|
+
entrypoint,
|
|
10
|
+
plugins: plugins.map(plugin =>
|
|
11
|
+
plugin.path === '@modern-js/runtime/router/internal'
|
|
12
|
+
? {
|
|
13
|
+
...plugin,
|
|
14
|
+
path: '@modern-js/ultramodern-app-tools/router-runtime',
|
|
15
|
+
}
|
|
16
|
+
: plugin,
|
|
17
|
+
),
|
|
18
|
+
}));
|
|
19
|
+
},
|
|
20
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import {
|
|
2
|
+
routerPlugin as nativeRouterPlugin,
|
|
3
|
+
routerProviderRegistryHooks,
|
|
4
|
+
} from '@modern-js/runtime/router/internal';
|
|
5
|
+
import { createRouterPlugin } from '@modern-js/runtime-extensions/router-provider';
|
|
6
|
+
import { createRouterStatePlugin } from '@modern-js/runtime-extensions/router-state-plugin';
|
|
7
|
+
|
|
8
|
+
const createProvider = createRouterPlugin({
|
|
9
|
+
defaultProvider: { name: 'react-router', factory: nativeRouterPlugin },
|
|
10
|
+
registryHooks: routerProviderRegistryHooks,
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
/** Install fork observers before the native provider registers its lifecycle. */
|
|
14
|
+
export const routerPlugin: typeof nativeRouterPlugin = config => {
|
|
15
|
+
const state = createRouterStatePlugin({
|
|
16
|
+
registryHooks: routerProviderRegistryHooks,
|
|
17
|
+
});
|
|
18
|
+
const provider = createProvider(config);
|
|
19
|
+
return {
|
|
20
|
+
...provider,
|
|
21
|
+
setup(api) {
|
|
22
|
+
state.setup?.(api);
|
|
23
|
+
return provider.setup?.(api);
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export default routerPlugin;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import type { RsbuildPlugin, Rspack } from '@rsbuild/core';
|
|
2
|
+
|
|
3
|
+
const disabledRuntimeModules = {
|
|
4
|
+
'react-server-dom-rspack/client.browser': './rscDisabledClientBrowserRuntime',
|
|
5
|
+
'react-server-dom-rspack/client.edge': './rscDisabledClientEdgeRuntime',
|
|
6
|
+
'react-server-dom-rspack/client.node': './rscDisabledClientNodeRuntime',
|
|
7
|
+
'react-server-dom-rspack/server.edge': './rscDisabledServerEdgeRuntime',
|
|
8
|
+
'react-server-dom-rspack/server.node': './rscDisabledServerNodeRuntime',
|
|
9
|
+
} as const;
|
|
10
|
+
|
|
11
|
+
const disabledRuntimeRequests = Object.keys(disabledRuntimeModules);
|
|
12
|
+
|
|
13
|
+
function aliasMatchesRequest(aliasName: string, request: string) {
|
|
14
|
+
const exact = aliasName.endsWith('$');
|
|
15
|
+
const normalizedName = exact ? aliasName.slice(0, -1) : aliasName;
|
|
16
|
+
return exact
|
|
17
|
+
? normalizedName === request
|
|
18
|
+
: request === normalizedName || request.startsWith(`${normalizedName}/`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function objectAliasMatchesDisabledRuntime(aliasName: string) {
|
|
22
|
+
return disabledRuntimeRequests.some(request =>
|
|
23
|
+
aliasMatchesRequest(aliasName, request),
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function arrayAliasMatchesDisabledRuntime(alias: {
|
|
28
|
+
name: string;
|
|
29
|
+
onlyModule?: boolean;
|
|
30
|
+
}) {
|
|
31
|
+
const aliasName = `${alias.name}${alias.onlyModule ? '$' : ''}`;
|
|
32
|
+
return objectAliasMatchesDisabledRuntime(aliasName);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function normalizeArrayAliases(
|
|
36
|
+
aliases: Array<{
|
|
37
|
+
alias: string | false | Array<string | false>;
|
|
38
|
+
name: string;
|
|
39
|
+
onlyModule?: boolean;
|
|
40
|
+
}>,
|
|
41
|
+
) {
|
|
42
|
+
const normalized: Record<string, string | false | Array<string | false>> = {};
|
|
43
|
+
for (const alias of aliases) {
|
|
44
|
+
if (arrayAliasMatchesDisabledRuntime(alias)) {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const aliasName = `${alias.name}${alias.onlyModule ? '$' : ''}`;
|
|
48
|
+
const existing = normalized[aliasName];
|
|
49
|
+
if (existing === undefined) {
|
|
50
|
+
normalized[aliasName] = alias.alias;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
normalized[aliasName] = [
|
|
54
|
+
...(Array.isArray(existing) ? existing : [existing]),
|
|
55
|
+
...(Array.isArray(alias.alias) ? alias.alias : [alias.alias]),
|
|
56
|
+
];
|
|
57
|
+
}
|
|
58
|
+
return normalized;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function resolveDisabledRuntimeModules() {
|
|
62
|
+
return Object.fromEntries(
|
|
63
|
+
Object.entries(disabledRuntimeModules).map(([request, moduleRequest]) => [
|
|
64
|
+
`${request}$`,
|
|
65
|
+
require.resolve(
|
|
66
|
+
`@modern-js/runtime-extensions/rsc-disabled/${moduleRequest.slice(2)}`,
|
|
67
|
+
),
|
|
68
|
+
]),
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function applyDisabledRuntimeAliases(
|
|
73
|
+
config: Rspack.Configuration,
|
|
74
|
+
disabledAliases: Record<string, string>,
|
|
75
|
+
) {
|
|
76
|
+
config.resolve ??= {};
|
|
77
|
+
if (Array.isArray(config.resolve.alias)) {
|
|
78
|
+
config.resolve.alias = {
|
|
79
|
+
...disabledAliases,
|
|
80
|
+
...normalizeArrayAliases(config.resolve.alias),
|
|
81
|
+
};
|
|
82
|
+
} else {
|
|
83
|
+
config.resolve.alias = {
|
|
84
|
+
...disabledAliases,
|
|
85
|
+
...Object.fromEntries(
|
|
86
|
+
Object.entries(config.resolve.alias ?? {}).filter(
|
|
87
|
+
([aliasName]) => !objectAliasMatchesDisabledRuntime(aliasName),
|
|
88
|
+
),
|
|
89
|
+
),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function rscDisabledRuntimePlugin(): RsbuildPlugin {
|
|
95
|
+
return {
|
|
96
|
+
name: 'builder:rsc-disabled-runtime',
|
|
97
|
+
|
|
98
|
+
setup(api) {
|
|
99
|
+
const disabledAliases = resolveDisabledRuntimeModules();
|
|
100
|
+
|
|
101
|
+
api.modifyRspackConfig({
|
|
102
|
+
order: 'post',
|
|
103
|
+
handler(config) {
|
|
104
|
+
applyDisabledRuntimeAliases(config, disabledAliases);
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
api.onBeforeCreateCompiler({
|
|
108
|
+
order: 'post',
|
|
109
|
+
handler({ bundlerConfigs }) {
|
|
110
|
+
for (const config of bundlerConfigs) {
|
|
111
|
+
applyDisabledRuntimeAliases(config, disabledAliases);
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@modern-js/server-runtime-extensions/server-plugin';
|