@bleedingdev/modern-js-ultramodern-create 3.9.3-ultramodern.1 → 3.9.3-ultramodern.2
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/dist/cjs/ultramodern-workspace/add-vertical/shell-files.cjs +2 -7
- package/dist/cjs/ultramodern-workspace/api/client.cjs +2 -37
- package/dist/cjs/ultramodern-workspace/api.cjs +0 -3
- package/dist/cjs/ultramodern-workspace/native-app.cjs +0 -2
- package/dist/cjs/ultramodern-workspace/package-json.cjs +1 -3
- package/dist/cjs/ultramodern-workspace/validation/architecture.cjs +24 -11
- package/dist/cjs/ultramodern-workspace/validation/native-shell-runtime.cjs +134 -0
- package/dist/cjs/ultramodern-workspace/write-app.cjs +1 -3
- package/dist/esm/ultramodern-workspace/add-vertical/shell-files.js +3 -8
- package/dist/esm/ultramodern-workspace/api/client.js +4 -36
- package/dist/esm/ultramodern-workspace/api.js +1 -1
- package/dist/esm/ultramodern-workspace/native-app.js +0 -2
- package/dist/esm/ultramodern-workspace/package-json.js +1 -3
- package/dist/esm/ultramodern-workspace/validation/architecture.js +24 -11
- package/dist/esm/ultramodern-workspace/validation/native-shell-runtime.js +96 -0
- package/dist/esm/ultramodern-workspace/write-app.js +1 -3
- package/dist/esm-node/ultramodern-workspace/add-vertical/shell-files.js +3 -8
- package/dist/esm-node/ultramodern-workspace/api/client.js +4 -36
- package/dist/esm-node/ultramodern-workspace/api.js +1 -1
- package/dist/esm-node/ultramodern-workspace/native-app.js +0 -2
- package/dist/esm-node/ultramodern-workspace/package-json.js +1 -3
- package/dist/esm-node/ultramodern-workspace/validation/architecture.js +24 -11
- package/dist/esm-node/ultramodern-workspace/validation/native-shell-runtime.js +97 -0
- package/dist/esm-node/ultramodern-workspace/write-app.js +1 -3
- package/dist/types/ultramodern-workspace/api/client.d.ts +1 -2
- package/dist/types/ultramodern-workspace/api.d.ts +1 -1
- package/dist/types/ultramodern-workspace/validation/native-shell-runtime.d.ts +19 -0
- package/package.json +18 -18
- package/release-cohort.json +51 -51
- package/templates/workspace-scripts/proof-workerd-ssr.mjs +371 -38
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
const FEDERATION_RUNTIME = '@module-federation/modern-js-v3/runtime';
|
|
2
|
+
const FEDERATION_MEMBER_LOADERS = new Set([
|
|
3
|
+
'loadRemote',
|
|
4
|
+
'loadShare'
|
|
5
|
+
]);
|
|
6
|
+
const DECLARATION_FILE = /\.d\.[cm]?ts$/u;
|
|
7
|
+
function createNativeShellRuntimeEvidence(typescript, typescriptApi, checker, sourceFile) {
|
|
8
|
+
const unwrapParentheses = (node)=>{
|
|
9
|
+
while(typescript.isParenthesizedExpression(node))node = node.expression;
|
|
10
|
+
return node;
|
|
11
|
+
};
|
|
12
|
+
const isAmbientProcess = (node)=>{
|
|
13
|
+
if (!typescript.isIdentifier(node) || 'process' !== node.text) return false;
|
|
14
|
+
const symbol = checker.getSymbolAtLocation(node);
|
|
15
|
+
return void 0 === symbol || symbol.declarations.every((declaration)=>DECLARATION_FILE.test(declaration.path));
|
|
16
|
+
};
|
|
17
|
+
const isBuildTargetAccess = (node)=>typescript.isPropertyAccessExpression(node) && void 0 === node.questionDotToken && 'MODERN_TARGET' === node.name.text && typescript.isPropertyAccessExpression(node.expression) && void 0 === node.expression.questionDotToken && 'env' === node.expression.name.text && isAmbientProcess(node.expression.expression);
|
|
18
|
+
const isBuildTargetLiteral = (node)=>typescript.isStringLiteral(node) && ('browser' === node.text || 'node' === node.text);
|
|
19
|
+
const buildTargetComparison = (node)=>{
|
|
20
|
+
node = unwrapParentheses(node);
|
|
21
|
+
if (!typescript.isBinaryExpression(node) || node.operatorToken.kind !== typescript.SyntaxKind.EqualsEqualsEqualsToken) return;
|
|
22
|
+
const literal = isBuildTargetAccess(node.left) ? node.right : isBuildTargetAccess(node.right) ? node.left : void 0;
|
|
23
|
+
return void 0 !== literal && isBuildTargetLiteral(literal) ? literal.text : void 0;
|
|
24
|
+
};
|
|
25
|
+
const isConditionOf = (node)=>{
|
|
26
|
+
let condition = node;
|
|
27
|
+
for(;;){
|
|
28
|
+
const parent = condition.parent;
|
|
29
|
+
if (typescript.isParenthesizedExpression(parent) || typescript.isPrefixUnaryExpression(parent) && parent.operator === typescript.SyntaxKind.ExclamationToken || typescript.isBinaryExpression(parent) && (parent.operatorToken.kind === typescript.SyntaxKind.AmpersandAmpersandToken || parent.operatorToken.kind === typescript.SyntaxKind.BarBarToken)) {
|
|
30
|
+
condition = parent;
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
return typescript.isIfStatement(parent) && parent.expression === condition || typescript.isConditionalExpression(parent) && parent.condition === condition;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
const isBuildTargetCondition = (node)=>{
|
|
37
|
+
const access = node.parent;
|
|
38
|
+
if (!isBuildTargetAccess(access) || access.expression !== node) return false;
|
|
39
|
+
const comparison = access.parent;
|
|
40
|
+
return void 0 !== buildTargetComparison(comparison) && isConditionOf(comparison);
|
|
41
|
+
};
|
|
42
|
+
const conjuncts = (node)=>{
|
|
43
|
+
node = unwrapParentheses(node);
|
|
44
|
+
return typescript.isBinaryExpression(node) && node.operatorToken.kind === typescript.SyntaxKind.AmpersandAmpersandToken ? [
|
|
45
|
+
...conjuncts(node.left),
|
|
46
|
+
...conjuncts(node.right)
|
|
47
|
+
] : [
|
|
48
|
+
node
|
|
49
|
+
];
|
|
50
|
+
};
|
|
51
|
+
const requiresBrowserTarget = (condition)=>conjuncts(condition).some((conjunct)=>'browser' === buildTargetComparison(conjunct));
|
|
52
|
+
const isBrowserGuarded = (node)=>{
|
|
53
|
+
for(let child = node; void 0 !== child.parent; child = child.parent){
|
|
54
|
+
const parent = child.parent;
|
|
55
|
+
if (typescript.isIfStatement(parent) && parent.thenStatement === child && requiresBrowserTarget(parent.expression)) return true;
|
|
56
|
+
if (typescript.isConditionalExpression(parent) && parent.whenTrue === child && requiresBrowserTarget(parent.condition)) return true;
|
|
57
|
+
}
|
|
58
|
+
return false;
|
|
59
|
+
};
|
|
60
|
+
let federationInstanceTypeIds;
|
|
61
|
+
const federationInstanceTypes = ()=>{
|
|
62
|
+
if (void 0 !== federationInstanceTypeIds) return federationInstanceTypeIds;
|
|
63
|
+
const typeIds = new Set();
|
|
64
|
+
const recordRuntime = (specifier)=>{
|
|
65
|
+
const runtime = checker.getSymbolAtLocation(specifier);
|
|
66
|
+
const getInstance = void 0 === runtime ? void 0 : checker.getMemberInModuleExports(runtime, 'getInstance');
|
|
67
|
+
const getInstanceType = void 0 === getInstance ? void 0 : checker.getTypeOfSymbol(getInstance);
|
|
68
|
+
if (void 0 === getInstanceType) return;
|
|
69
|
+
for (const signature of checker.getSignaturesOfType(getInstanceType, typescriptApi.SignatureKind.Call)){
|
|
70
|
+
const returnType = checker.getReturnTypeOfSignature(signature);
|
|
71
|
+
const instanceType = void 0 === returnType ? void 0 : checker.getNonNullableType(returnType);
|
|
72
|
+
if (void 0 !== instanceType && instanceType.getSymbol()?.name === 'ModuleFederation') typeIds.add(instanceType.id);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
const visit = (node)=>{
|
|
76
|
+
if (typescript.isImportDeclaration(node) && typescript.isStringLiteralLikeNode(node.moduleSpecifier) && node.moduleSpecifier.text === FEDERATION_RUNTIME && node.importClause?.phaseModifier !== typescript.SyntaxKind.TypeKeyword) recordRuntime(node.moduleSpecifier);
|
|
77
|
+
else if (typescript.isCallExpression(node) && node.expression.kind === typescript.SyntaxKind.ImportKeyword && 1 === node.arguments.length && typescript.isStringLiteralLikeNode(node.arguments[0]) && node.arguments[0].text === FEDERATION_RUNTIME) recordRuntime(node.arguments[0]);
|
|
78
|
+
node.forEachChild(visit);
|
|
79
|
+
};
|
|
80
|
+
visit(sourceFile);
|
|
81
|
+
federationInstanceTypeIds = typeIds;
|
|
82
|
+
return typeIds;
|
|
83
|
+
};
|
|
84
|
+
const isBrowserFederationMemberLoad = (node)=>{
|
|
85
|
+
if (!typescript.isCallExpression(node)) return false;
|
|
86
|
+
const callee = unwrapParentheses(node.expression);
|
|
87
|
+
if (!typescript.isPropertyAccessExpression(callee) || !FEDERATION_MEMBER_LOADERS.has(callee.name.text)) return false;
|
|
88
|
+
const receiverType = checker.getTypeAtLocation(callee.expression);
|
|
89
|
+
return void 0 !== receiverType && federationInstanceTypes().has(receiverType.id) && isBrowserGuarded(node);
|
|
90
|
+
};
|
|
91
|
+
return {
|
|
92
|
+
isBrowserFederationMemberLoad,
|
|
93
|
+
isBuildTargetCondition
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
export { createNativeShellRuntimeEvidence };
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { createShellApiClient } from "./api.js";
|
|
2
1
|
import { writeAppApiFiles } from "./api/write-app-api.js";
|
|
3
2
|
import { createAppEnvDts, createAppRuntimeConfig, createAppStyles, createShellFrameComponent, createTailwindConfig } from "./app-files.js";
|
|
4
3
|
import { createFederatedComponentsRegistry, createLayout, createRemoteEntry, createRemoteExposeComponent, createRemoteExposeFragmentPage, createRemotePage, createShellPage, createShellRemoteComponents, createShellWorkerRemoteComponents, remoteComponentOutputPath } from "./demo-components.js";
|
|
@@ -78,7 +77,7 @@ function writeAppFederationConfigFiles({ targetDir, scope, resolvedApp, emitsUi,
|
|
|
78
77
|
if (emitsUi) writeFile(targetDir, `${resolvedApp.directory}/module-federation.config.ts`, 'shell' === resolvedApp.kind ? createShellModuleFederationConfig(scope, resolvedApp, remotes) : createRemoteModuleFederationConfig(scope, resolvedApp, remotes));
|
|
79
78
|
if (appHasApi(resolvedApp)) writeFile(targetDir, `${resolvedApp.directory}/backend-federation.config.ts`, createBackendModuleFederationConfig(resolvedApp));
|
|
80
79
|
}
|
|
81
|
-
function writeAppRouteAndShellFiles({ targetDir, scope, resolvedApp, emitsUi, remotes,
|
|
80
|
+
function writeAppRouteAndShellFiles({ targetDir, scope, resolvedApp, emitsUi, remotes, publicWeb, writeAppFile }) {
|
|
82
81
|
if (!emitsUi) return;
|
|
83
82
|
if ((resolvedApp.verticalRefs?.length ?? 0) > 0) {
|
|
84
83
|
writeAppFile('src/federated-components.tsx', createFederatedComponentsRegistry(scope, resolvedApp, remotes));
|
|
@@ -92,7 +91,6 @@ function writeAppRouteAndShellFiles({ targetDir, scope, resolvedApp, emitsUi, re
|
|
|
92
91
|
writeAppFile('src/routes/vertical-components.tsx', createShellRemoteComponents(resolvedApp, remotes.filter(appEmitsBrowserUi)));
|
|
93
92
|
writeAppFile('src/routes/vertical-components.worker.tsx', createShellWorkerRemoteComponents(resolvedApp, remotes.filter(appEmitsBrowserUi)));
|
|
94
93
|
writeAppFile('src/routes/shell-frame.tsx', createShellFrameComponent(resolvedApp));
|
|
95
|
-
writeFile(targetDir, `${resolvedApp.directory}/src/api/vertical-clients.ts`, createShellApiClient(scope, availableRemotes));
|
|
96
94
|
} else for (const expose of distributedSsrExposes(resolvedApp))writeAppFile(`src/routes/[lang]/_mf/fragment/${distributedSsrFragmentSlug(expose)}/page.tsx`, createRemoteExposeFragmentPage(resolvedApp, expose));
|
|
97
95
|
}
|
|
98
96
|
function writeAppRemoteExposeFiles({ resolvedApp, emitsUi, writeAppFile }) {
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import "node:module";
|
|
2
2
|
import node_fs from "node:fs";
|
|
3
3
|
import node_path from "node:path";
|
|
4
|
-
import { createShellApiClient } from "../api.js";
|
|
5
4
|
import { createAppEnvDts, createAppRuntimeConfig, createShellFrameComponent } from "../app-files.js";
|
|
6
5
|
import { createShellPage, createShellRemoteComponents, createShellWorkerRemoteComponents } from "../demo-components.js";
|
|
7
|
-
import { appEmitsBrowserUi,
|
|
6
|
+
import { appEmitsBrowserUi, appI18nNamespace, resolveRemoteRefs, shellApp } from "../descriptors.js";
|
|
8
7
|
import { readJsonFile, writeJsonFile } from "../fs-io.js";
|
|
9
8
|
import { createAppPublicLocaleMessages } from "../locales.js";
|
|
10
9
|
import { createAppModernConfig, createShellModuleFederationConfig } from "../module-federation.js";
|
|
@@ -41,10 +40,7 @@ function shellAppArtifacts(scope, packageSource, enableTailwind, remotes, bridge
|
|
|
41
40
|
...Object.fromEntries(createNativeFederationArtifacts(scope, shellHost, remotes).map((artifact)=>[
|
|
42
41
|
`${shellHost.directory}/${artifact.path}`,
|
|
43
42
|
artifact.content
|
|
44
|
-
]))
|
|
45
|
-
...remotes.some(appHasApi) ? {
|
|
46
|
-
[`${shellHost.directory}/src/api/vertical-clients.ts`]: createShellApiClient(scope, remotes)
|
|
47
|
-
} : {}
|
|
43
|
+
]))
|
|
48
44
|
};
|
|
49
45
|
return {
|
|
50
46
|
shellHost,
|
|
@@ -84,8 +80,7 @@ function shellAppArtifacts(scope, packageSource, enableTailwind, remotes, bridge
|
|
|
84
80
|
[`${shellHost.directory}/src/routes/[lang]/page.tsx`]: createShellPage(shellHost, uiRemotes),
|
|
85
81
|
[`${shellHost.directory}/src/routes/vertical-components.tsx`]: createShellRemoteComponents(shellHost, uiRemotes),
|
|
86
82
|
[`${shellHost.directory}/src/routes/vertical-components.worker.tsx`]: createShellWorkerRemoteComponents(shellHost, uiRemotes),
|
|
87
|
-
[`${shellHost.directory}/src/routes/shell-frame.tsx`]: createShellFrameComponent(shellHost)
|
|
88
|
-
[`${shellHost.directory}/src/api/vertical-clients.ts`]: createShellApiClient(scope, remotes)
|
|
83
|
+
[`${shellHost.directory}/src/routes/shell-frame.tsx`]: createShellFrameComponent(shellHost)
|
|
89
84
|
};
|
|
90
85
|
return {
|
|
91
86
|
shellHost,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "node:module";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { createCheckoutCartClientExports
|
|
2
|
+
import { resolveApiStem } from "../descriptors.js";
|
|
3
|
+
import { toPascalCase } from "../naming.js";
|
|
4
|
+
import { createCheckoutCartClientExports } from "./checkout-cart.js";
|
|
5
5
|
import { verticalApiErrorStem, verticalApiExport, verticalApiGroupName, verticalApiNotFoundErrorExport } from "./names.js";
|
|
6
6
|
function createApiClient(service, contractImportPath, options) {
|
|
7
7
|
const apiExport = verticalApiExport(service);
|
|
@@ -149,36 +149,4 @@ export const ${createName} = (
|
|
|
149
149
|
);${checkoutCartClientExports}
|
|
150
150
|
`;
|
|
151
151
|
}
|
|
152
|
-
|
|
153
|
-
const exports = verticalApiApps(remotes).map((remote)=>{
|
|
154
|
-
const stem = resolveApiStem(remote);
|
|
155
|
-
const pascalStem = toPascalCase(stem);
|
|
156
|
-
const rpc = 'rpc' === resolveApiProtocol(remote);
|
|
157
|
-
const pascalSingular = toPascalCase(verticalApiErrorStem(remote));
|
|
158
|
-
const checkoutCartExports = !rpc && serviceHasCheckoutCartState(remote) ? ` addCheckoutCartItem,
|
|
159
|
-
clearCheckoutCart,
|
|
160
|
-
getCheckoutCart,
|
|
161
|
-
removeCheckoutCartItem,
|
|
162
|
-
type CheckoutAddCartItemInput,
|
|
163
|
-
type CheckoutCart,
|
|
164
|
-
type CheckoutCartLine,
|
|
165
|
-
` : '';
|
|
166
|
-
if (rpc) return `export {
|
|
167
|
-
get${pascalStem}Rpc,
|
|
168
|
-
list${pascalStem}Rpc,
|
|
169
|
-
make${pascalStem}RpcClient,
|
|
170
|
-
type ${pascalStem}RpcClientOptions,
|
|
171
|
-
} from '${packageName(scope, remote.packageSuffix)}/api/rpc-client';`;
|
|
172
|
-
return `export {
|
|
173
|
-
${checkoutCartExports} create${pascalSingular},
|
|
174
|
-
create${pascalStem}Client,
|
|
175
|
-
get${pascalSingular},
|
|
176
|
-
get${pascalStem}Readiness,
|
|
177
|
-
list${pascalStem},
|
|
178
|
-
type ${pascalStem}ClientOptions,
|
|
179
|
-
} from '${packageName(scope, remote.packageSuffix)}/api/client';`;
|
|
180
|
-
}).join('\n\n');
|
|
181
|
-
return exports ? `${exports}\n` : `export const ultramodernVerticalClients = [] as const;
|
|
182
|
-
`;
|
|
183
|
-
}
|
|
184
|
-
export { createApiClient, createShellApiClient };
|
|
152
|
+
export { createApiClient };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "node:module";
|
|
2
|
-
export { createApiClient
|
|
2
|
+
export { createApiClient } from "./api/client.js";
|
|
3
3
|
export { apiTopologyMetadata } from "./api/contracts.js";
|
|
4
4
|
export { verticalApiCreatePayloadSchemaExport, verticalApiErrorStem, verticalApiExport, verticalApiGroupName, verticalApiMarkerSchemaExport, verticalApiName, verticalApiNotFoundErrorExport, verticalApiNotFoundSchemaExport, verticalApiReadinessSchemaExport, verticalApiSchemaExport } from "./api/names.js";
|
|
5
5
|
export { createRpcApiServiceEntry, createRpcClientFile, createRpcContractFile, rpcPath, verticalRpcContractExport, verticalRpcGroupExport } from "./api/rpc.js";
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import "node:module";
|
|
2
|
-
import { createShellApiClient } from "./api.js";
|
|
3
2
|
import { writeAppApiFiles } from "./api/write-app-api.js";
|
|
4
3
|
import { createAppStyles, createTailwindConfig } from "./app-files.js";
|
|
5
4
|
import { appHasApi } from "./descriptors.js";
|
|
@@ -62,6 +61,5 @@ function writeNativeApp(targetDir, scope, app, packageSource, enableTailwind, re
|
|
|
62
61
|
resolvedApp: app,
|
|
63
62
|
emitsUi: true
|
|
64
63
|
});
|
|
65
|
-
if ('shell' === app.kind && remotes.some(appHasApi)) write('src/api/vertical-clients.ts', createShellApiClient(scope, remotes));
|
|
66
64
|
}
|
|
67
65
|
export { writeNativeApp };
|
|
@@ -270,9 +270,7 @@ function createAppPackage(scope, app, packageSource, enableTailwind, remotes = [
|
|
|
270
270
|
'./api': './shared/api.ts',
|
|
271
271
|
'./api/client': `./${clientDirectory}/${app.api.stem}-client.ts`
|
|
272
272
|
});
|
|
273
|
-
}
|
|
274
|
-
'./api/clients': './src/api/vertical-clients.ts'
|
|
275
|
-
});
|
|
273
|
+
}
|
|
276
274
|
if (Object.keys(packageExports).length > 0) packageJson.exports = packageExports;
|
|
277
275
|
return packageJson;
|
|
278
276
|
}
|
|
@@ -5,6 +5,7 @@ import node_path from "node:path";
|
|
|
5
5
|
import { hasNativeAppGeneration } from "../renderer-generations.js";
|
|
6
6
|
import { getRendererGenerationProfile, isApplicationRenderer } from "../renderer-profile.js";
|
|
7
7
|
import { assert, sameJson, selfCheckFailure } from "./assertions.js";
|
|
8
|
+
import { createNativeShellRuntimeEvidence } from "./native-shell-runtime.js";
|
|
8
9
|
import { isForeignRendererPackage } from "./renderer.js";
|
|
9
10
|
function assertCompilerArchitecture(root, workspaceValidationContract) {
|
|
10
11
|
const fullStackVerticals = workspaceValidationContract.apps.filter((app)=>'shell' !== app.kind);
|
|
@@ -63,12 +64,16 @@ function assertCompilerArchitecture(root, workspaceValidationContract) {
|
|
|
63
64
|
]
|
|
64
65
|
});
|
|
65
66
|
};
|
|
66
|
-
const
|
|
67
|
+
const compilerInput = (absolutePath)=>{
|
|
67
68
|
const project = compilerSnapshot?.getDefaultProjectForFile(absolutePath);
|
|
68
69
|
const sourceFile = project?.program.getSourceFile(absolutePath);
|
|
69
|
-
assert(void 0 !== sourceFile, `Native TypeScript compiler could not parse ${node_path.relative(root, absolutePath)}`);
|
|
70
|
-
return
|
|
70
|
+
assert(void 0 !== project && void 0 !== sourceFile, `Native TypeScript compiler could not parse ${node_path.relative(root, absolutePath)}`);
|
|
71
|
+
return {
|
|
72
|
+
checker: project.checker,
|
|
73
|
+
sourceFile
|
|
74
|
+
};
|
|
71
75
|
};
|
|
76
|
+
const parseCompilerInput = (absolutePath)=>compilerInput(absolutePath).sourceFile;
|
|
72
77
|
const nodeName = (node)=>{
|
|
73
78
|
if (!node) return;
|
|
74
79
|
if (typescript.isIdentifier(node) || typescript.isPrivateIdentifier(node) || typescript.isStringLiteralLikeNode(node) || typescript.isNumericLiteral(node)) return node.text;
|
|
@@ -156,6 +161,12 @@ function assertCompilerArchitecture(root, workspaceValidationContract) {
|
|
|
156
161
|
const accessPath = propertyAccessPath(node.expression);
|
|
157
162
|
return void 0 !== accessPath && names.has(accessPath.at(-1));
|
|
158
163
|
};
|
|
164
|
+
const calleeName = (node)=>{
|
|
165
|
+
let callee = node.expression;
|
|
166
|
+
while(typescript.isParenthesizedExpression(callee) || typescript.isNonNullExpression(callee) || typescript.isAsExpression(callee))callee = callee.expression;
|
|
167
|
+
if (typescript.isIdentifier(callee)) return callee.text;
|
|
168
|
+
if (typescript.isPropertyAccessExpression(callee)) return callee.name.text;
|
|
169
|
+
};
|
|
159
170
|
const objectLiteralProperty = (objectLiteral, name)=>objectLiteral.properties.find((property)=>typescript.isPropertyAssignment(property) && nodeName(property.name) === name);
|
|
160
171
|
const moduleFederationConfigArgument = (sourceFile)=>{
|
|
161
172
|
let argument;
|
|
@@ -303,11 +314,12 @@ function assertCompilerArchitecture(root, workspaceValidationContract) {
|
|
|
303
314
|
...configFiles.map((relativePath)=>node_path.join(root, relativePath)).filter((absolutePath)=>node_fs.existsSync(absolutePath))
|
|
304
315
|
]);
|
|
305
316
|
for (const absolutePath of checkedFiles){
|
|
306
|
-
const sourceFile =
|
|
317
|
+
const { checker, sourceFile } = compilerInput(absolutePath);
|
|
307
318
|
const isShellRoute = shellRouteDirectories.some((relativeDirectory)=>{
|
|
308
319
|
const absoluteDirectory = node_path.join(root, relativeDirectory);
|
|
309
320
|
return absolutePath.startsWith(absoluteDirectory + node_path.sep);
|
|
310
321
|
});
|
|
322
|
+
const shellRuntime = isShellRoute ? createNativeShellRuntimeEvidence(typescript, typescriptApi, checker, sourceFile) : void 0;
|
|
311
323
|
const moduleFederationAppPath = moduleFederationConfigAppPaths.get(absolutePath);
|
|
312
324
|
const nativeFederation = void 0 === moduleFederationAppPath ? void 0 : nativeModuleFederationApps.get(moduleFederationAppPath);
|
|
313
325
|
const tailwindFactories = new Set();
|
|
@@ -330,6 +342,12 @@ function assertCompilerArchitecture(root, workspaceValidationContract) {
|
|
|
330
342
|
].includes(imported)) presetFactories.add(binding.name.text);
|
|
331
343
|
}
|
|
332
344
|
}
|
|
345
|
+
const manualLoadingCallees = new Set([
|
|
346
|
+
'hydrateRoot',
|
|
347
|
+
'loadRemote',
|
|
348
|
+
'loadShare',
|
|
349
|
+
...nativeRemoteLoaders
|
|
350
|
+
]);
|
|
333
351
|
const modernConfigApp = workspaceValidationContract.apps.find((app)=>absolutePath === node_path.join(root, app.path, 'modern.config.ts'));
|
|
334
352
|
let insideDefaultExport = false;
|
|
335
353
|
const visit = (node)=>{
|
|
@@ -357,7 +375,7 @@ function assertCompilerArchitecture(root, workspaceValidationContract) {
|
|
|
357
375
|
if (sameJson(accessPath, [
|
|
358
376
|
'process',
|
|
359
377
|
'env'
|
|
360
|
-
])) compilerFailure(sourceFile, node, 'framework config API direct-process-env-access', 'Generated config must use the framework config environment API instead of process.env.', 'use getBuildConfigEnvironment');
|
|
378
|
+
]) && !shellRuntime?.isBuildTargetCondition(node)) compilerFailure(sourceFile, node, 'framework config API direct-process-env-access', 'Generated config must use the framework config environment API instead of process.env.', 'use getBuildConfigEnvironment');
|
|
361
379
|
if (typescript.isIdentifier(node) && 'ULTRAMODERN_ZEPHYR' === node.text) compilerFailure(sourceFile, node, 'zephyr gating ultramodern-zephyr-environment-gate', 'Generated Zephyr integration must not be gated through ULTRAMODERN_ZEPHYR.', 'use Zephyr native deploy-token behavior');
|
|
362
380
|
if (typescript.isPropertyAssignment(node) || typescript.isShorthandPropertyAssignment(node)) {
|
|
363
381
|
const property = nodeName(node.name);
|
|
@@ -365,12 +383,7 @@ function assertCompilerArchitecture(root, workspaceValidationContract) {
|
|
|
365
383
|
}
|
|
366
384
|
if (isShellRoute) {
|
|
367
385
|
if (typescript.isJsxOpeningElement(node) && 'a' === jsxTagName(node.tagName) && void 0 !== jsxAttribute(node.attributes, 'onClick')) compilerFailure(sourceFile, node, 'shell routing synthetic-anchor-click-interception', 'Shell routing must not intercept anchor clicks synthetically.', 'use the router Link primitive');
|
|
368
|
-
if (
|
|
369
|
-
'hydrateRoot',
|
|
370
|
-
'loadRemote',
|
|
371
|
-
'loadShare',
|
|
372
|
-
...nativeRemoteLoaders
|
|
373
|
-
])) && !nativeLoaderCalls.has(node)) compilerFailure(sourceFile, node, 'module federation native loading', 'Shell routing must use framework Module Federation loading primitives.', 'remove manual hydration or remote-loading wrappers');
|
|
386
|
+
if (typescript.isCallExpression(node) && manualLoadingCallees.has(calleeName(node) ?? '') && !nativeLoaderCalls.has(node) && !shellRuntime?.isBrowserFederationMemberLoad(node)) compilerFailure(sourceFile, node, 'module federation native loading', 'Shell routing must use framework Module Federation loading primitives.', 'remove manual hydration or remote-loading wrappers');
|
|
374
387
|
if (typescript.isBinaryExpression(node) && node.operatorToken.kind === typescript.SyntaxKind.EqualsToken && propertyAccessPath(node.left)?.slice(0, 2).join('.') === 'window.location' || typescript.isCallExpression(node) && propertyAccessPath(node.expression)?.slice(0, 2).join('.') === 'window.location') compilerFailure(sourceFile, node, 'shell routing window-location-navigation', 'Shell routing must use router navigation instead of window.location.', 'use the router navigation primitive');
|
|
375
388
|
}
|
|
376
389
|
node.forEachChild(visit);
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
const FEDERATION_RUNTIME = '@module-federation/modern-js-v3/runtime';
|
|
3
|
+
const FEDERATION_MEMBER_LOADERS = new Set([
|
|
4
|
+
'loadRemote',
|
|
5
|
+
'loadShare'
|
|
6
|
+
]);
|
|
7
|
+
const DECLARATION_FILE = /\.d\.[cm]?ts$/u;
|
|
8
|
+
function createNativeShellRuntimeEvidence(typescript, typescriptApi, checker, sourceFile) {
|
|
9
|
+
const unwrapParentheses = (node)=>{
|
|
10
|
+
while(typescript.isParenthesizedExpression(node))node = node.expression;
|
|
11
|
+
return node;
|
|
12
|
+
};
|
|
13
|
+
const isAmbientProcess = (node)=>{
|
|
14
|
+
if (!typescript.isIdentifier(node) || 'process' !== node.text) return false;
|
|
15
|
+
const symbol = checker.getSymbolAtLocation(node);
|
|
16
|
+
return void 0 === symbol || symbol.declarations.every((declaration)=>DECLARATION_FILE.test(declaration.path));
|
|
17
|
+
};
|
|
18
|
+
const isBuildTargetAccess = (node)=>typescript.isPropertyAccessExpression(node) && void 0 === node.questionDotToken && 'MODERN_TARGET' === node.name.text && typescript.isPropertyAccessExpression(node.expression) && void 0 === node.expression.questionDotToken && 'env' === node.expression.name.text && isAmbientProcess(node.expression.expression);
|
|
19
|
+
const isBuildTargetLiteral = (node)=>typescript.isStringLiteral(node) && ('browser' === node.text || 'node' === node.text);
|
|
20
|
+
const buildTargetComparison = (node)=>{
|
|
21
|
+
node = unwrapParentheses(node);
|
|
22
|
+
if (!typescript.isBinaryExpression(node) || node.operatorToken.kind !== typescript.SyntaxKind.EqualsEqualsEqualsToken) return;
|
|
23
|
+
const literal = isBuildTargetAccess(node.left) ? node.right : isBuildTargetAccess(node.right) ? node.left : void 0;
|
|
24
|
+
return void 0 !== literal && isBuildTargetLiteral(literal) ? literal.text : void 0;
|
|
25
|
+
};
|
|
26
|
+
const isConditionOf = (node)=>{
|
|
27
|
+
let condition = node;
|
|
28
|
+
for(;;){
|
|
29
|
+
const parent = condition.parent;
|
|
30
|
+
if (typescript.isParenthesizedExpression(parent) || typescript.isPrefixUnaryExpression(parent) && parent.operator === typescript.SyntaxKind.ExclamationToken || typescript.isBinaryExpression(parent) && (parent.operatorToken.kind === typescript.SyntaxKind.AmpersandAmpersandToken || parent.operatorToken.kind === typescript.SyntaxKind.BarBarToken)) {
|
|
31
|
+
condition = parent;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
return typescript.isIfStatement(parent) && parent.expression === condition || typescript.isConditionalExpression(parent) && parent.condition === condition;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
const isBuildTargetCondition = (node)=>{
|
|
38
|
+
const access = node.parent;
|
|
39
|
+
if (!isBuildTargetAccess(access) || access.expression !== node) return false;
|
|
40
|
+
const comparison = access.parent;
|
|
41
|
+
return void 0 !== buildTargetComparison(comparison) && isConditionOf(comparison);
|
|
42
|
+
};
|
|
43
|
+
const conjuncts = (node)=>{
|
|
44
|
+
node = unwrapParentheses(node);
|
|
45
|
+
return typescript.isBinaryExpression(node) && node.operatorToken.kind === typescript.SyntaxKind.AmpersandAmpersandToken ? [
|
|
46
|
+
...conjuncts(node.left),
|
|
47
|
+
...conjuncts(node.right)
|
|
48
|
+
] : [
|
|
49
|
+
node
|
|
50
|
+
];
|
|
51
|
+
};
|
|
52
|
+
const requiresBrowserTarget = (condition)=>conjuncts(condition).some((conjunct)=>'browser' === buildTargetComparison(conjunct));
|
|
53
|
+
const isBrowserGuarded = (node)=>{
|
|
54
|
+
for(let child = node; void 0 !== child.parent; child = child.parent){
|
|
55
|
+
const parent = child.parent;
|
|
56
|
+
if (typescript.isIfStatement(parent) && parent.thenStatement === child && requiresBrowserTarget(parent.expression)) return true;
|
|
57
|
+
if (typescript.isConditionalExpression(parent) && parent.whenTrue === child && requiresBrowserTarget(parent.condition)) return true;
|
|
58
|
+
}
|
|
59
|
+
return false;
|
|
60
|
+
};
|
|
61
|
+
let federationInstanceTypeIds;
|
|
62
|
+
const federationInstanceTypes = ()=>{
|
|
63
|
+
if (void 0 !== federationInstanceTypeIds) return federationInstanceTypeIds;
|
|
64
|
+
const typeIds = new Set();
|
|
65
|
+
const recordRuntime = (specifier)=>{
|
|
66
|
+
const runtime = checker.getSymbolAtLocation(specifier);
|
|
67
|
+
const getInstance = void 0 === runtime ? void 0 : checker.getMemberInModuleExports(runtime, 'getInstance');
|
|
68
|
+
const getInstanceType = void 0 === getInstance ? void 0 : checker.getTypeOfSymbol(getInstance);
|
|
69
|
+
if (void 0 === getInstanceType) return;
|
|
70
|
+
for (const signature of checker.getSignaturesOfType(getInstanceType, typescriptApi.SignatureKind.Call)){
|
|
71
|
+
const returnType = checker.getReturnTypeOfSignature(signature);
|
|
72
|
+
const instanceType = void 0 === returnType ? void 0 : checker.getNonNullableType(returnType);
|
|
73
|
+
if (void 0 !== instanceType && instanceType.getSymbol()?.name === 'ModuleFederation') typeIds.add(instanceType.id);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
const visit = (node)=>{
|
|
77
|
+
if (typescript.isImportDeclaration(node) && typescript.isStringLiteralLikeNode(node.moduleSpecifier) && node.moduleSpecifier.text === FEDERATION_RUNTIME && node.importClause?.phaseModifier !== typescript.SyntaxKind.TypeKeyword) recordRuntime(node.moduleSpecifier);
|
|
78
|
+
else if (typescript.isCallExpression(node) && node.expression.kind === typescript.SyntaxKind.ImportKeyword && 1 === node.arguments.length && typescript.isStringLiteralLikeNode(node.arguments[0]) && node.arguments[0].text === FEDERATION_RUNTIME) recordRuntime(node.arguments[0]);
|
|
79
|
+
node.forEachChild(visit);
|
|
80
|
+
};
|
|
81
|
+
visit(sourceFile);
|
|
82
|
+
federationInstanceTypeIds = typeIds;
|
|
83
|
+
return typeIds;
|
|
84
|
+
};
|
|
85
|
+
const isBrowserFederationMemberLoad = (node)=>{
|
|
86
|
+
if (!typescript.isCallExpression(node)) return false;
|
|
87
|
+
const callee = unwrapParentheses(node.expression);
|
|
88
|
+
if (!typescript.isPropertyAccessExpression(callee) || !FEDERATION_MEMBER_LOADERS.has(callee.name.text)) return false;
|
|
89
|
+
const receiverType = checker.getTypeAtLocation(callee.expression);
|
|
90
|
+
return void 0 !== receiverType && federationInstanceTypes().has(receiverType.id) && isBrowserGuarded(node);
|
|
91
|
+
};
|
|
92
|
+
return {
|
|
93
|
+
isBrowserFederationMemberLoad,
|
|
94
|
+
isBuildTargetCondition
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
export { createNativeShellRuntimeEvidence };
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import "node:module";
|
|
2
|
-
import { createShellApiClient } from "./api.js";
|
|
3
2
|
import { writeAppApiFiles } from "./api/write-app-api.js";
|
|
4
3
|
import { createAppEnvDts, createAppRuntimeConfig, createAppStyles, createShellFrameComponent, createTailwindConfig } from "./app-files.js";
|
|
5
4
|
import { createFederatedComponentsRegistry, createLayout, createRemoteEntry, createRemoteExposeComponent, createRemoteExposeFragmentPage, createRemotePage, createShellPage, createShellRemoteComponents, createShellWorkerRemoteComponents, remoteComponentOutputPath } from "./demo-components.js";
|
|
@@ -79,7 +78,7 @@ function writeAppFederationConfigFiles({ targetDir, scope, resolvedApp, emitsUi,
|
|
|
79
78
|
if (emitsUi) writeFile(targetDir, `${resolvedApp.directory}/module-federation.config.ts`, 'shell' === resolvedApp.kind ? createShellModuleFederationConfig(scope, resolvedApp, remotes) : createRemoteModuleFederationConfig(scope, resolvedApp, remotes));
|
|
80
79
|
if (appHasApi(resolvedApp)) writeFile(targetDir, `${resolvedApp.directory}/backend-federation.config.ts`, createBackendModuleFederationConfig(resolvedApp));
|
|
81
80
|
}
|
|
82
|
-
function writeAppRouteAndShellFiles({ targetDir, scope, resolvedApp, emitsUi, remotes,
|
|
81
|
+
function writeAppRouteAndShellFiles({ targetDir, scope, resolvedApp, emitsUi, remotes, publicWeb, writeAppFile }) {
|
|
83
82
|
if (!emitsUi) return;
|
|
84
83
|
if ((resolvedApp.verticalRefs?.length ?? 0) > 0) {
|
|
85
84
|
writeAppFile('src/federated-components.tsx', createFederatedComponentsRegistry(scope, resolvedApp, remotes));
|
|
@@ -93,7 +92,6 @@ function writeAppRouteAndShellFiles({ targetDir, scope, resolvedApp, emitsUi, re
|
|
|
93
92
|
writeAppFile('src/routes/vertical-components.tsx', createShellRemoteComponents(resolvedApp, remotes.filter(appEmitsBrowserUi)));
|
|
94
93
|
writeAppFile('src/routes/vertical-components.worker.tsx', createShellWorkerRemoteComponents(resolvedApp, remotes.filter(appEmitsBrowserUi)));
|
|
95
94
|
writeAppFile('src/routes/shell-frame.tsx', createShellFrameComponent(resolvedApp));
|
|
96
|
-
writeFile(targetDir, `${resolvedApp.directory}/src/api/vertical-clients.ts`, createShellApiClient(scope, availableRemotes));
|
|
97
95
|
} else for (const expose of distributedSsrExposes(resolvedApp))writeAppFile(`src/routes/[lang]/_mf/fragment/${distributedSsrFragmentSlug(expose)}/page.tsx`, createRemoteExposeFragmentPage(resolvedApp, expose));
|
|
98
96
|
}
|
|
99
97
|
function writeAppRemoteExposeFiles({ resolvedApp, emitsUi, writeAppFile }) {
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import type { WorkspaceApi
|
|
1
|
+
import type { WorkspaceApi } from '../types.js';
|
|
2
2
|
export declare function createApiClient(service: {
|
|
3
3
|
id: string;
|
|
4
4
|
api?: WorkspaceApi;
|
|
5
5
|
}, contractImportPath: string, options?: {
|
|
6
6
|
readonly scope: string;
|
|
7
7
|
}): string;
|
|
8
|
-
export declare function createShellApiClient(scope: string, remotes?: WorkspaceApp[]): string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { createApiClient
|
|
1
|
+
export { createApiClient } from './api/client.js';
|
|
2
2
|
export { apiTopologyMetadata } from './api/contracts.js';
|
|
3
3
|
export { verticalApiCreatePayloadSchemaExport, verticalApiErrorStem, verticalApiExport, verticalApiGroupName, verticalApiMarkerSchemaExport, verticalApiName, verticalApiNotFoundErrorExport, verticalApiNotFoundSchemaExport, verticalApiReadinessSchemaExport, verticalApiSchemaExport, } from './api/names.js';
|
|
4
4
|
export { createRpcApiServiceEntry, createRpcClientFile, createRpcContractFile, rpcPath, verticalRpcContractExport, verticalRpcGroupExport, } from './api/rpc.js';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type * as ts from '@typescript/native/unstable/ast';
|
|
2
|
+
import type { Checker } from '@typescript/native/unstable/sync';
|
|
3
|
+
type TypeScriptAst = typeof import('@typescript/native/unstable/ast');
|
|
4
|
+
type TypeScriptApi = typeof import('@typescript/native/unstable/sync');
|
|
5
|
+
export type ModernBuildTarget = 'browser' | 'node';
|
|
6
|
+
/**
|
|
7
|
+
* Compiler evidence for shell source that branches on the framework build
|
|
8
|
+
* target and loads remotes through the native Module Federation instance.
|
|
9
|
+
*
|
|
10
|
+
* `process.env.MODERN_TARGET` is not ambient environment access: the Modern.js
|
|
11
|
+
* runtime plugin defines it as `'browser'` or `'node'` for every bundler
|
|
12
|
+
* environment, so a strict comparison is a compile-time constant that dead-code
|
|
13
|
+
* elimination folds per target.
|
|
14
|
+
*/
|
|
15
|
+
export declare function createNativeShellRuntimeEvidence(typescript: TypeScriptAst, typescriptApi: TypeScriptApi, checker: Checker, sourceFile: ts.SourceFile): {
|
|
16
|
+
isBrowserFederationMemberLoad: (node: ts.Node) => boolean;
|
|
17
|
+
isBuildTargetCondition: (node: ts.Node) => boolean;
|
|
18
|
+
};
|
|
19
|
+
export {};
|
package/package.json
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"engines": {
|
|
27
27
|
"node": ">=26.10.0"
|
|
28
28
|
},
|
|
29
|
-
"version": "3.9.3-ultramodern.
|
|
29
|
+
"version": "3.9.3-ultramodern.2",
|
|
30
30
|
"types": "./dist/types/index.d.ts",
|
|
31
31
|
"main": "./dist/esm-node/index.js",
|
|
32
32
|
"bin": {
|
|
@@ -86,22 +86,22 @@
|
|
|
86
86
|
"@babel/core": "7.29.7",
|
|
87
87
|
"@babel/parser": "^8.0.6",
|
|
88
88
|
"@effect/tsgo": "0.47.2",
|
|
89
|
-
"@modern-js/app-tools": "npm:@bleedingdev/modern-js-app-tools@3.9.3-ultramodern.
|
|
90
|
-
"@modern-js/app-tools-extensions": "npm:@bleedingdev/modern-js-app-tools-extensions@3.9.3-ultramodern.
|
|
91
|
-
"@modern-js/backend-federation-contracts": "npm:@bleedingdev/modern-js-backend-federation-contracts@3.9.3-ultramodern.
|
|
89
|
+
"@modern-js/app-tools": "npm:@bleedingdev/modern-js-app-tools@3.9.3-ultramodern.2",
|
|
90
|
+
"@modern-js/app-tools-extensions": "npm:@bleedingdev/modern-js-app-tools-extensions@3.9.3-ultramodern.2",
|
|
91
|
+
"@modern-js/backend-federation-contracts": "npm:@bleedingdev/modern-js-backend-federation-contracts@3.9.3-ultramodern.2",
|
|
92
92
|
"@modern-js/codesmith": "2.6.9",
|
|
93
|
-
"@modern-js/i18n-integration": "npm:@bleedingdev/modern-js-i18n-integration@3.9.3-ultramodern.
|
|
94
|
-
"@modern-js/i18n-utils": "npm:@bleedingdev/modern-js-i18n-utils@3.9.3-ultramodern.
|
|
95
|
-
"@modern-js/plugin-bff-build-extensions": "npm:@bleedingdev/modern-js-plugin-bff-build-extensions@3.9.3-ultramodern.
|
|
96
|
-
"@modern-js/plugin-i18n": "npm:@bleedingdev/modern-js-plugin-i18n@3.9.3-ultramodern.
|
|
97
|
-
"@modern-js/plugin-tanstack": "npm:@bleedingdev/modern-js-plugin-tanstack@3.9.3-ultramodern.
|
|
98
|
-
"@modern-js/renderer-core": "npm:@bleedingdev/modern-js-renderer-core@3.9.3-ultramodern.
|
|
99
|
-
"@modern-js/renderer-octane": "npm:@bleedingdev/modern-js-renderer-octane@3.9.3-ultramodern.
|
|
100
|
-
"@modern-js/renderer-solid": "npm:@bleedingdev/modern-js-renderer-solid@3.9.3-ultramodern.
|
|
101
|
-
"@modern-js/runtime": "npm:@bleedingdev/modern-js-runtime@3.9.3-ultramodern.
|
|
102
|
-
"@modern-js/runtime-renderer-extensions": "npm:@bleedingdev/modern-js-runtime-renderer-extensions@3.9.3-ultramodern.
|
|
103
|
-
"@modern-js/ultramodern-app-tools": "npm:@bleedingdev/modern-js-ultramodern-app-tools@3.9.3-ultramodern.
|
|
104
|
-
"@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.9.3-ultramodern.
|
|
93
|
+
"@modern-js/i18n-integration": "npm:@bleedingdev/modern-js-i18n-integration@3.9.3-ultramodern.2",
|
|
94
|
+
"@modern-js/i18n-utils": "npm:@bleedingdev/modern-js-i18n-utils@3.9.3-ultramodern.2",
|
|
95
|
+
"@modern-js/plugin-bff-build-extensions": "npm:@bleedingdev/modern-js-plugin-bff-build-extensions@3.9.3-ultramodern.2",
|
|
96
|
+
"@modern-js/plugin-i18n": "npm:@bleedingdev/modern-js-plugin-i18n@3.9.3-ultramodern.2",
|
|
97
|
+
"@modern-js/plugin-tanstack": "npm:@bleedingdev/modern-js-plugin-tanstack@3.9.3-ultramodern.2",
|
|
98
|
+
"@modern-js/renderer-core": "npm:@bleedingdev/modern-js-renderer-core@3.9.3-ultramodern.2",
|
|
99
|
+
"@modern-js/renderer-octane": "npm:@bleedingdev/modern-js-renderer-octane@3.9.3-ultramodern.2",
|
|
100
|
+
"@modern-js/renderer-solid": "npm:@bleedingdev/modern-js-renderer-solid@3.9.3-ultramodern.2",
|
|
101
|
+
"@modern-js/runtime": "npm:@bleedingdev/modern-js-runtime@3.9.3-ultramodern.2",
|
|
102
|
+
"@modern-js/runtime-renderer-extensions": "npm:@bleedingdev/modern-js-runtime-renderer-extensions@3.9.3-ultramodern.2",
|
|
103
|
+
"@modern-js/ultramodern-app-tools": "npm:@bleedingdev/modern-js-ultramodern-app-tools@3.9.3-ultramodern.2",
|
|
104
|
+
"@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.9.3-ultramodern.2",
|
|
105
105
|
"@module-federation/modern-js-v3": "npm:@bleedingdev/mf-modern-js-v3@2.9.4",
|
|
106
106
|
"@rsbuild/plugin-tailwindcss": "2.0.3",
|
|
107
107
|
"@typescript/native": "npm:typescript@7.0.2",
|
|
@@ -118,7 +118,7 @@
|
|
|
118
118
|
"zephyr-rspack-plugin": "1.4.2"
|
|
119
119
|
},
|
|
120
120
|
"devDependencies": {
|
|
121
|
-
"@modern-js/i18n-runtime-extensions": "npm:@bleedingdev/modern-js-i18n-runtime-extensions@3.9.3-ultramodern.
|
|
121
|
+
"@modern-js/i18n-runtime-extensions": "npm:@bleedingdev/modern-js-i18n-runtime-extensions@3.9.3-ultramodern.2",
|
|
122
122
|
"@octanejs/rspack-plugin": "0.1.55",
|
|
123
123
|
"@rslib/core": "1.0.3",
|
|
124
124
|
"@scripts/rstest-config": "2.66.0",
|
|
@@ -142,6 +142,6 @@
|
|
|
142
142
|
},
|
|
143
143
|
"ultramodern": {
|
|
144
144
|
"sourceName": "@modern-js/ultramodern-create",
|
|
145
|
-
"frameworkVersion": "3.9.3-ultramodern.
|
|
145
|
+
"frameworkVersion": "3.9.3-ultramodern.2"
|
|
146
146
|
}
|
|
147
147
|
}
|