@bleedingdev/modern-js-create 3.2.0-ultramodern.81 → 3.2.0-ultramodern.83
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/README.md +46 -37
- package/dist/index.js +28 -20
- package/package.json +3 -3
- package/template/pnpm-workspace.yaml +2 -0
- package/template/scripts/validate-ultramodern.mjs.handlebars +14 -2
- package/template-workspace/README.md.handlebars +28 -1
- package/template-workspace/pnpm-workspace.yaml +7 -1
package/README.md
CHANGED
|
@@ -27,24 +27,20 @@ To initialize the empty directory you are already in, pass `.` explicitly:
|
|
|
27
27
|
pnpm dlx @bleedingdev/modern-js-create .
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
verticals:
|
|
30
|
+
The default is the full UltraModern single-app setup. Create a SuperApp
|
|
31
|
+
workspace explicitly when you need independently owned verticals:
|
|
32
32
|
|
|
33
33
|
```bash
|
|
34
34
|
pnpm dlx @bleedingdev/modern-js-create my-super-app --ultramodern-workspace
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
The workspace
|
|
38
|
-
|
|
37
|
+
The workspace starts shell-only so the first commit has no fake business
|
|
38
|
+
domains to delete. It generates:
|
|
39
39
|
|
|
40
40
|
- `apps/shell-super-app` as the Module Federation host and topology owner.
|
|
41
|
-
- `verticals
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
`/decide-api/effect/decide/*`.
|
|
45
|
-
- `verticals/checkout` for cart and checkout UI plus
|
|
46
|
-
`/checkout-api/effect/checkout/*`.
|
|
47
|
-
- `packages/shared-design-tokens` as the shared CSS token owner.
|
|
41
|
+
- `verticals/*` empty until you add a real domain with `--vertical`.
|
|
42
|
+
- `packages/shared-*` placeholders for shared contracts, tokens, and API
|
|
43
|
+
support.
|
|
48
44
|
- `.modernjs/ultramodern-generated-contract.json` with MF, Effect, i18n,
|
|
49
45
|
federated CSS, Cloudflare, and Zephyr dependency metadata.
|
|
50
46
|
|
|
@@ -54,13 +50,14 @@ Validate the generated workspace before making application changes:
|
|
|
54
50
|
cd my-super-app
|
|
55
51
|
mise install
|
|
56
52
|
pnpm install
|
|
57
|
-
pnpm
|
|
53
|
+
pnpm check
|
|
58
54
|
pnpm build
|
|
59
55
|
```
|
|
60
56
|
|
|
61
57
|
### Router Template
|
|
62
58
|
|
|
63
|
-
TanStack Router is generated by default.
|
|
59
|
+
TanStack Router is generated by default. Choose React Router only as an explicit
|
|
60
|
+
compatibility lane:
|
|
64
61
|
|
|
65
62
|
```bash
|
|
66
63
|
pnpm dlx @bleedingdev/modern-js-create my-app --router react-router
|
|
@@ -127,10 +124,10 @@ Use this decision table before adding a vertical:
|
|
|
127
124
|
| Design tokens, primitives, generated clients, or domain-neutral utilities | Yes | Use an ordinary workspace package, not a vertical |
|
|
128
125
|
| Feature composites or workflow state shared across verticals | No | Revisit ownership; do not hide it in shared code |
|
|
129
126
|
|
|
130
|
-
The lower-level `--router`, `--workspace`, and `--sub` flags remain
|
|
131
|
-
for
|
|
132
|
-
`--vertical` so paths, topology, Effect BFF
|
|
133
|
-
consistent.
|
|
127
|
+
The lower-level `--router react-router`, `--workspace`, and `--sub` flags remain
|
|
128
|
+
available for compatibility and local package scaffolding, but UltraModern
|
|
129
|
+
vertical additions should use `--vertical` so paths, topology, Effect BFF
|
|
130
|
+
contracts, and local overlays stay consistent.
|
|
134
131
|
|
|
135
132
|
See
|
|
136
133
|
`docs/super-app-rfc-adr/WORKSPACE-0001-micro-vertical-workspace-scaffolding.md`
|
|
@@ -141,14 +138,13 @@ UltraModern.js entrypoint. The lower-level `--ultramodern-*` flags remain
|
|
|
141
138
|
available for release engineering and local package-source testing, but users
|
|
142
139
|
should not need them for normal app creation.
|
|
143
140
|
|
|
144
|
-
###
|
|
141
|
+
### SuperApp Architecture Contracts
|
|
145
142
|
|
|
146
|
-
The generated shell owns route assembly and policy.
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
packages.
|
|
143
|
+
The generated shell owns route assembly and policy. Each vertical added with
|
|
144
|
+
`--vertical` owns its route subtree, MF exposes, Effect BFF contract, generated
|
|
145
|
+
client, `localisedUrls`, locale JSON, CSS layer, and Cloudflare Worker output.
|
|
146
|
+
The shell consumes vertical UI through MF manifests and vertical APIs through
|
|
147
|
+
generated Effect clients exported by the vertical packages.
|
|
152
148
|
|
|
153
149
|
Route localization is route-owned. Each app writes
|
|
154
150
|
`src/routes/ultramodern-route-metadata` and passes
|
|
@@ -176,7 +172,7 @@ manifest markers in lockstep for the same vertical version.
|
|
|
176
172
|
|
|
177
173
|
### Cloudflare And Zephyr Proof
|
|
178
174
|
|
|
179
|
-
Each generated app has:
|
|
175
|
+
Each generated workspace app has:
|
|
180
176
|
|
|
181
177
|
- `cloudflare:build`, `cloudflare:deploy`, `cloudflare:preview`, and
|
|
182
178
|
`cloudflare:proof` scripts.
|
|
@@ -184,20 +180,33 @@ Each generated app has:
|
|
|
184
180
|
- `zephyr:dependencies` for any consumed verticals.
|
|
185
181
|
- `zephyr-rspack-plugin` wired through the generated Modern.js Rspack bridge.
|
|
186
182
|
|
|
187
|
-
|
|
183
|
+
Deploy first, then pass each deployed app's generated public URL env key into
|
|
184
|
+
the proof step. Shell-only workspaces only need the shell URL; added verticals
|
|
185
|
+
use the same `ULTRAMODERN_PUBLIC_URL_<APP_ID>` pattern with hyphens converted
|
|
186
|
+
to underscores and uppercased:
|
|
188
187
|
|
|
189
188
|
```bash
|
|
190
|
-
|
|
191
|
-
ULTRAMODERN_PUBLIC_URL_DECIDE=https://decide.example.workers.dev \
|
|
192
|
-
ULTRAMODERN_PUBLIC_URL_CHECKOUT=https://checkout.example.workers.dev \
|
|
189
|
+
pnpm cloudflare:deploy
|
|
193
190
|
ULTRAMODERN_PUBLIC_URL_SHELL_SUPER_APP=https://shell-super-app.example.workers.dev \
|
|
191
|
+
ULTRAMODERN_PUBLIC_URL_TRANSPORTATION=https://transportation.example.workers.dev \
|
|
194
192
|
pnpm cloudflare:proof -- --require-public-urls
|
|
195
193
|
```
|
|
196
194
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
195
|
+
Without public URLs and credentials, use local `pnpm check` and `pnpm build`
|
|
196
|
+
evidence only; do not claim live Cloudflare or Zephyr selection has been
|
|
197
|
+
proven.
|
|
198
|
+
|
|
199
|
+
### Troubleshooting
|
|
200
|
+
|
|
201
|
+
| Symptom | Current check | Owner |
|
|
202
|
+
| --- | --- | --- |
|
|
203
|
+
| Package cohort mismatch | Regenerate with one package source strategy, run `mise install`, then rerun `pnpm install` from the activated shell. | Generated workspace package source metadata |
|
|
204
|
+
| Install failure | Check the active Node/pnpm from `mise install`; rerun `pnpm install` after the shell sees the pinned versions. | Toolchain setup |
|
|
205
|
+
| Build failure | Run `pnpm check` before `pnpm build`; fix reported format, lint, type, skill, i18n, or generated-contract failures first. | Owning package or generated contract |
|
|
206
|
+
| Missing public URL | Set the env key from `.modernjs/ultramodern-generated-contract.json`, for example `ULTRAMODERN_PUBLIC_URL_SHELL_SUPER_APP`. | Deployment operator |
|
|
207
|
+
| Cloudflare credentials | Confirm Wrangler credentials before `pnpm cloudflare:deploy`; local checks do not prove live Worker access. | Deployment operator |
|
|
208
|
+
| Asset or CSS 404 | Rebuild with `pnpm build` or `pnpm cloudflare:deploy` and inspect emitted Modern/Rspack asset paths instead of hardcoding CSS URLs. | Framework/runtime asset pipeline |
|
|
209
|
+
| Federation manifest failure | Run the shell and vertical build scripts, then check each deployed `/mf-manifest.json` URL used by the shell. | Module Federation owner |
|
|
201
210
|
|
|
202
211
|
### Local Monorepo Testing
|
|
203
212
|
|
|
@@ -208,14 +217,14 @@ workspace protocol dependencies:
|
|
|
208
217
|
pnpm dlx @bleedingdev/modern-js-create my-app --workspace
|
|
209
218
|
```
|
|
210
219
|
|
|
211
|
-
For package-source validation of the full
|
|
220
|
+
For package-source validation of the full SuperApp workspace, generate with the
|
|
212
221
|
workspace package source, then run the generated contract gate:
|
|
213
222
|
|
|
214
223
|
```bash
|
|
215
|
-
pnpm dlx @bleedingdev/modern-js-create
|
|
216
|
-
cd
|
|
224
|
+
pnpm dlx @bleedingdev/modern-js-create my-super-app --ultramodern-workspace --ultramodern-package-source workspace
|
|
225
|
+
cd my-super-app
|
|
217
226
|
pnpm install
|
|
218
|
-
pnpm
|
|
227
|
+
pnpm check
|
|
219
228
|
```
|
|
220
229
|
|
|
221
230
|
## Documentation
|
package/dist/index.js
CHANGED
|
@@ -465,12 +465,12 @@ const EN_LOCALE = {
|
|
|
465
465
|
optionHelp: ' -h, --help Display this help message',
|
|
466
466
|
optionVersion: ' -v, --version Display version information',
|
|
467
467
|
optionLang: ' -l, --lang Set the language (zh or en)',
|
|
468
|
-
optionRouter: ' -r, --router Select router framework (react-router
|
|
468
|
+
optionRouter: ' -r, --router Select router framework (tanstack default; react-router is compatibility mode)',
|
|
469
469
|
optionBff: ' --bff Keep Effect BFF enabled (default for UltraModern apps)',
|
|
470
470
|
optionBffRuntime: ' --bff-runtime Select BFF runtime (hono or effect)',
|
|
471
471
|
optionTailwind: ' --no-tailwind Disable default Tailwind CSS v4 scaffold',
|
|
472
472
|
optionWorkspace: ' --workspace Use workspace protocol for @modern-js dependencies (for local monorepo testing)',
|
|
473
|
-
optionUltramodernWorkspace: ' --ultramodern-workspace Generate an UltraModern SuperApp workspace (
|
|
473
|
+
optionUltramodernWorkspace: ' --ultramodern-workspace Generate an UltraModern SuperApp workspace (default is a full UltraModern single app)',
|
|
474
474
|
optionUltramodernPackageSource: ' --ultramodern-package-source Select UltraModern package source (workspace or install; BleedingDev defaults to install aliases)',
|
|
475
475
|
optionUltramodernPackageScope: ' --ultramodern-package-scope Publish scope for npm alias installs (for example bleedingdev)',
|
|
476
476
|
optionUltramodernPackageNamePrefix: ' --ultramodern-package-name-prefix Prefix for npm alias package names (default: modern-js-)',
|
|
@@ -487,7 +487,7 @@ const EN_LOCALE = {
|
|
|
487
487
|
example8: ' pnpm dlx @bleedingdev/modern-js-create my-app --workspace',
|
|
488
488
|
example9: ' pnpm dlx @bleedingdev/modern-js-create my-super-app --ultramodern-workspace',
|
|
489
489
|
example10: ' pnpm dlx @bleedingdev/modern-js-create my-app --no-tailwind',
|
|
490
|
-
example11: ' pnpm dlx @bleedingdev/modern-js-create my-app --router react-router',
|
|
490
|
+
example11: ' pnpm dlx @bleedingdev/modern-js-create my-app --router react-router # compatibility mode',
|
|
491
491
|
example12: ' pnpm dlx @bleedingdev/modern-js-create catalog --vertical',
|
|
492
492
|
moreInfo: '📚 Learn more: https://modernjs.dev'
|
|
493
493
|
},
|
|
@@ -523,12 +523,12 @@ const ZH_LOCALE = {
|
|
|
523
523
|
optionHelp: ' -h, --help 显示帮助信息',
|
|
524
524
|
optionVersion: ' -v, --version 显示版本信息',
|
|
525
525
|
optionLang: ' -l, --lang 设置语言 (zh 或 en)',
|
|
526
|
-
optionRouter: ' -r, --router
|
|
526
|
+
optionRouter: ' -r, --router 选择路由框架(默认 tanstack;react-router 为兼容模式)',
|
|
527
527
|
optionBff: ' --bff 保持启用 Effect BFF(UltraModern 应用默认值)',
|
|
528
528
|
optionBffRuntime: ' --bff-runtime 选择 BFF 运行时(hono 或 effect)',
|
|
529
529
|
optionTailwind: ' --no-tailwind 禁用默认 Tailwind CSS v4 模板',
|
|
530
530
|
optionWorkspace: ' --workspace 对 @modern-js 依赖使用 workspace 协议(用于本地 monorepo 联调)',
|
|
531
|
-
optionUltramodernWorkspace: ' --ultramodern-workspace 生成 UltraModern SuperApp
|
|
531
|
+
optionUltramodernWorkspace: ' --ultramodern-workspace 生成 UltraModern SuperApp 工作区(默认创建完整 UltraModern 单应用)',
|
|
532
532
|
optionUltramodernPackageSource: ' --ultramodern-package-source 选择 UltraModern 依赖来源(workspace 或 install;BleedingDev 默认使用 install alias)',
|
|
533
533
|
optionUltramodernPackageScope: ' --ultramodern-package-scope npm alias 安装使用的发布 scope(例如 bleedingdev)',
|
|
534
534
|
optionUltramodernPackageNamePrefix: ' --ultramodern-package-name-prefix npm alias 包名前缀(默认:modern-js-)',
|
|
@@ -545,7 +545,7 @@ const ZH_LOCALE = {
|
|
|
545
545
|
example8: ' pnpm dlx @bleedingdev/modern-js-create my-app --workspace',
|
|
546
546
|
example9: ' pnpm dlx @bleedingdev/modern-js-create my-super-app --ultramodern-workspace',
|
|
547
547
|
example10: ' pnpm dlx @bleedingdev/modern-js-create my-app --no-tailwind',
|
|
548
|
-
example11: ' pnpm dlx @bleedingdev/modern-js-create my-app --router react-router',
|
|
548
|
+
example11: ' pnpm dlx @bleedingdev/modern-js-create my-app --router react-router # 兼容模式',
|
|
549
549
|
example12: ' pnpm dlx @bleedingdev/modern-js-create catalog --vertical',
|
|
550
550
|
moreInfo: '📚 更多信息: https://modernjs.dev'
|
|
551
551
|
},
|
|
@@ -1497,7 +1497,7 @@ const createRemoteManifestUrl = (options: {
|
|
|
1497
1497
|
`;
|
|
1498
1498
|
}
|
|
1499
1499
|
function createModuleFederationRemotesConfig(scope, app, remotes = []) {
|
|
1500
|
-
const remoteEntries = resolveRemoteRefs(app, remotes).map((remote)=>{
|
|
1500
|
+
const remoteEntries = resolveRemoteRefs(app, remotes).toSorted((left, right)=>remoteDependencyAlias(left).localeCompare(remoteDependencyAlias(right))).map((remote)=>{
|
|
1501
1501
|
const key = remoteDependencyAlias(remote);
|
|
1502
1502
|
return ` ${key}: createRemoteManifestUrl({
|
|
1503
1503
|
manifestEnv: '${createRemoteManifestEnv(remote)}',
|
|
@@ -1532,6 +1532,9 @@ const reactDomVersion = (require('react-dom/package.json') as { version: string
|
|
|
1532
1532
|
|
|
1533
1533
|
${createModuleFederationRemoteUrlHelpers(shellHost, remotes)}
|
|
1534
1534
|
export default createModuleFederationConfig({
|
|
1535
|
+
bridge: {
|
|
1536
|
+
enableBridgeRouter: false,
|
|
1537
|
+
},
|
|
1535
1538
|
dev: {
|
|
1536
1539
|
disableDynamicRemoteTypeHints: true,
|
|
1537
1540
|
},
|
|
@@ -1587,6 +1590,9 @@ const reactDomVersion = (require('react-dom/package.json') as { version: string
|
|
|
1587
1590
|
|
|
1588
1591
|
${createModuleFederationRemoteUrlHelpers(app, remotes)}
|
|
1589
1592
|
export default createModuleFederationConfig({
|
|
1593
|
+
bridge: {
|
|
1594
|
+
enableBridgeRouter: false,
|
|
1595
|
+
},
|
|
1590
1596
|
dev: {
|
|
1591
1597
|
disableDynamicRemoteTypeHints: true,
|
|
1592
1598
|
},
|
|
@@ -2350,24 +2356,16 @@ function createShellRemoteComponents(scope, remotes = []) {
|
|
|
2350
2356
|
const componentName = `${toPascalCase(remote.id)}Widget`;
|
|
2351
2357
|
return `const ${componentName} = createHydratedRemote(${componentName}Server, '${remoteDependencyAlias(remote)}/Widget');`;
|
|
2352
2358
|
}).join('\n');
|
|
2353
|
-
const
|
|
2354
|
-
const componentName = `${toPascalCase(remote.id)}Widget`;
|
|
2355
|
-
return ` <${componentName} key="${remote.id}" />`;
|
|
2356
|
-
}).join('\n');
|
|
2357
|
-
const remoteCount = String(widgetRemotes.length);
|
|
2358
|
-
return `import { createLazyComponent } from '@module-federation/bridge-react';
|
|
2359
|
+
const federationImports = widgetRemotes.length > 0 ? `import { createLazyComponent } from '@module-federation/bridge-react';
|
|
2359
2360
|
import { getInstance, loadRemote } from '@module-federation/modern-js-v3/runtime';
|
|
2360
2361
|
import { Suspense, useEffect, useMemo, useState } from 'react';
|
|
2361
2362
|
import type { ComponentType } from 'react';
|
|
2362
|
-
import { I18nLink, useModernI18n } from '@modern-js/plugin-i18n/runtime';
|
|
2363
2363
|
${serverImports}
|
|
2364
|
-
|
|
2365
|
-
interface RemoteComponentModule {
|
|
2364
|
+
` : '';
|
|
2365
|
+
const federationHelpers = widgetRemotes.length > 0 ? `interface RemoteComponentModule {
|
|
2366
2366
|
default: ComponentType;
|
|
2367
2367
|
}
|
|
2368
2368
|
|
|
2369
|
-
const widgetCount = Number('${remoteCount}');
|
|
2370
|
-
|
|
2371
2369
|
const loadRemoteComponent = (specifier: string) =>
|
|
2372
2370
|
loadRemote<RemoteComponentModule>(specifier) as Promise<RemoteComponentModule>;
|
|
2373
2371
|
|
|
@@ -2414,10 +2412,20 @@ const createHydratedRemote =
|
|
|
2414
2412
|
</Suspense>
|
|
2415
2413
|
);
|
|
2416
2414
|
};
|
|
2415
|
+
` : '';
|
|
2416
|
+
const showcaseItems = widgetRemotes.map((remote)=>{
|
|
2417
|
+
const componentName = `${toPascalCase(remote.id)}Widget`;
|
|
2418
|
+
return ` <${componentName} key="${remote.id}" />`;
|
|
2419
|
+
}).join('\n');
|
|
2420
|
+
const remoteCount = String(widgetRemotes.length);
|
|
2421
|
+
return `${federationImports}import { I18nLink, useModernI18n } from '@modern-js/plugin-i18n/runtime';
|
|
2422
|
+
|
|
2423
|
+
const widgetCount = Number('${remoteCount}');
|
|
2417
2424
|
|
|
2418
|
-
${
|
|
2425
|
+
${federationHelpers}
|
|
2426
|
+
${hydratedExports}
|
|
2419
2427
|
|
|
2420
|
-
export const Header = () => {
|
|
2428
|
+
export const Header = () => {
|
|
2421
2429
|
const { i18nInstance } = useModernI18n();
|
|
2422
2430
|
const t = i18nInstance['t'].bind(i18nInstance);
|
|
2423
2431
|
|
package/package.json
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"engines": {
|
|
22
22
|
"node": ">=20"
|
|
23
23
|
},
|
|
24
|
-
"version": "3.2.0-ultramodern.
|
|
24
|
+
"version": "3.2.0-ultramodern.83",
|
|
25
25
|
"types": "./dist/types/index.d.ts",
|
|
26
26
|
"main": "./dist/index.js",
|
|
27
27
|
"bin": {
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"@types/node": "^25.9.1",
|
|
42
42
|
"@typescript/native-preview": "7.0.0-dev.20260527.2",
|
|
43
43
|
"tsx": "^4.22.3",
|
|
44
|
-
"@modern-js/i18n-utils": "npm:@bleedingdev/modern-js-i18n-utils@3.2.0-ultramodern.
|
|
44
|
+
"@modern-js/i18n-utils": "npm:@bleedingdev/modern-js-i18n-utils@3.2.0-ultramodern.83"
|
|
45
45
|
},
|
|
46
46
|
"publishConfig": {
|
|
47
47
|
"registry": "https://registry.npmjs.org/",
|
|
@@ -54,6 +54,6 @@
|
|
|
54
54
|
"start": "node ./dist/index.js"
|
|
55
55
|
},
|
|
56
56
|
"ultramodern": {
|
|
57
|
-
"frameworkVersion": "3.2.0-ultramodern.
|
|
57
|
+
"frameworkVersion": "3.2.0-ultramodern.83"
|
|
58
58
|
}
|
|
59
59
|
}
|
|
@@ -330,8 +330,11 @@ if (readPnpmConfig('minimumReleaseAgeIgnoreMissingTime') !== false) {
|
|
|
330
330
|
console.error('pnpm minimumReleaseAgeIgnoreMissingTime must be false');
|
|
331
331
|
process.exit(1);
|
|
332
332
|
}
|
|
333
|
-
if (
|
|
334
|
-
|
|
333
|
+
if (
|
|
334
|
+
JSON.stringify(readPnpmConfig('minimumReleaseAgeExclude')) !==
|
|
335
|
+
JSON.stringify(['@bleedingdev/modern-js-*'])
|
|
336
|
+
) {
|
|
337
|
+
console.error('pnpm minimumReleaseAgeExclude must allow just-published BleedingDev Modern cohorts only');
|
|
335
338
|
process.exit(1);
|
|
336
339
|
}
|
|
337
340
|
if (readPnpmConfig('trustPolicy') !== 'no-downgrade') {
|
|
@@ -420,6 +423,15 @@ if (typeof expectedModernSpecifier !== 'string' || expectedModernSpecifier.lengt
|
|
|
420
423
|
console.error('Package source metadata must provide a Modern package specifier');
|
|
421
424
|
process.exit(1);
|
|
422
425
|
}
|
|
426
|
+
if (
|
|
427
|
+
packageSource.strategy === 'install' &&
|
|
428
|
+
expectedModernSpecifier !== templateManifest.template?.version
|
|
429
|
+
) {
|
|
430
|
+
console.error(
|
|
431
|
+
`Package source Modern specifier ${expectedModernSpecifier} must match template version ${templateManifest.template?.version}`,
|
|
432
|
+
);
|
|
433
|
+
process.exit(1);
|
|
434
|
+
}
|
|
423
435
|
|
|
424
436
|
const expectedModernDependency = (packageName) => {
|
|
425
437
|
const alias = packageSource.modernPackages?.aliases?.[packageName];
|
|
@@ -28,7 +28,9 @@ Run the scaffold validator before adding business code and after every
|
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
30
|
mise install
|
|
31
|
-
pnpm
|
|
31
|
+
pnpm install
|
|
32
|
+
pnpm check
|
|
33
|
+
pnpm build
|
|
32
34
|
```
|
|
33
35
|
|
|
34
36
|
By default, `pnpm install` also prepares read-only agent reference repositories
|
|
@@ -50,3 +52,28 @@ UltraModern.js runtime and tooling packages on `workspace:*` for monorepo
|
|
|
50
52
|
development. To create a workspace that can install those packages outside the
|
|
51
53
|
monorepo, generate with `--ultramodern-package-source install`; generated shared
|
|
52
54
|
packages still use `workspace:*` because they are part of this workspace.
|
|
55
|
+
|
|
56
|
+
## Cloudflare Proof
|
|
57
|
+
|
|
58
|
+
Deploy the generated apps, then pass each deployed app's generated public URL
|
|
59
|
+
env key into the proof step. A shell-only workspace only needs the shell URL;
|
|
60
|
+
added verticals use the same `ULTRAMODERN_PUBLIC_URL_<APP_ID>` pattern with
|
|
61
|
+
hyphens converted to underscores and uppercased.
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
pnpm cloudflare:deploy
|
|
65
|
+
ULTRAMODERN_PUBLIC_URL_SHELL_SUPER_APP=https://shell-super-app.example.workers.dev \
|
|
66
|
+
pnpm cloudflare:proof -- --require-public-urls
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Troubleshooting
|
|
70
|
+
|
|
71
|
+
| Symptom | Current check | Owner |
|
|
72
|
+
| --- | --- | --- |
|
|
73
|
+
| Package cohort mismatch | Regenerate with one package source strategy, run `mise install`, then rerun `pnpm install` from the activated shell. | Generated workspace package source metadata |
|
|
74
|
+
| Install failure | Check the active Node/pnpm from `mise install`; rerun `pnpm install` after the shell sees the pinned versions. | Toolchain setup |
|
|
75
|
+
| Build failure | Run `pnpm check` before `pnpm build`; fix reported format, lint, type, skill, i18n, or generated-contract failures first. | Owning package or generated contract |
|
|
76
|
+
| Missing public URL | Set the env key from `.modernjs/ultramodern-generated-contract.json`, for example `ULTRAMODERN_PUBLIC_URL_SHELL_SUPER_APP`. | Deployment operator |
|
|
77
|
+
| Cloudflare credentials | Confirm Wrangler credentials before `pnpm cloudflare:deploy`; local checks do not prove live Worker access. | Deployment operator |
|
|
78
|
+
| Asset or CSS 404 | Rebuild with `pnpm build` or `pnpm cloudflare:deploy` and inspect emitted Modern/Rspack asset paths instead of hardcoding CSS URLs. | Framework/runtime asset pipeline |
|
|
79
|
+
| Federation manifest failure | Run the shell and vertical build scripts, then check each deployed `/mf-manifest.json` URL used by the shell. | Module Federation owner |
|
|
@@ -3,7 +3,13 @@ packages:
|
|
|
3
3
|
- verticals/*
|
|
4
4
|
- packages/*
|
|
5
5
|
|
|
6
|
-
minimumReleaseAge:
|
|
6
|
+
minimumReleaseAge: 1440
|
|
7
|
+
minimumReleaseAgeStrict: true
|
|
8
|
+
minimumReleaseAgeIgnoreMissingTime: false
|
|
9
|
+
minimumReleaseAgeExclude:
|
|
10
|
+
- '@bleedingdev/modern-js-*'
|
|
11
|
+
trustPolicy: no-downgrade
|
|
12
|
+
trustPolicyIgnoreAfter: 1440
|
|
7
13
|
blockExoticSubdeps: true
|
|
8
14
|
engineStrict: true
|
|
9
15
|
pmOnFail: error
|