@elliemae/pui-cli 9.0.0-alpha.11 → 9.0.0-alpha.12
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 +2 -1
- package/build/docs/404.html +2 -2
- package/build/docs/api/functions/loadRoutes/index.html +2 -2
- package/build/docs/api/index.html +2 -2
- package/build/docs/api/type-aliases/LIB_NAME/index.html +2 -2
- package/build/docs/api/variables/babelConfig/index.html +2 -2
- package/build/docs/api/variables/commitlintConfig/index.html +2 -2
- package/build/docs/api/variables/eslintBaseConfig/index.html +2 -2
- package/build/docs/api/variables/eslintConfig/index.html +2 -2
- package/build/docs/api/variables/eslintFlatBaseConfig/index.html +2 -2
- package/build/docs/api/variables/eslintFlatBaseConfigStrict/index.html +2 -2
- package/build/docs/api/variables/eslintFlatConfig/index.html +2 -2
- package/build/docs/api/variables/eslintFlatConfigStrict/index.html +2 -2
- package/build/docs/api/variables/jestConfig/index.html +2 -2
- package/build/docs/api/variables/jestNodeConfig/index.html +2 -2
- package/build/docs/api/variables/lintStagedConfig/index.html +2 -2
- package/build/docs/api/variables/prettierConfig/index.html +2 -2
- package/build/docs/api/variables/stylelintConfig/index.html +2 -2
- package/build/docs/api/variables/vitestConfig/index.html +2 -2
- package/build/docs/assets/js/04ee7372.2852111b.js +1 -0
- package/build/docs/assets/js/13097d8d.7877421c.js +1 -0
- package/build/docs/assets/js/4fb6949f.69e375e4.js +1 -0
- package/build/docs/assets/js/{main.7f815b7e.js → main.d5acb4ca.js} +2 -2
- package/build/docs/assets/js/runtime~main.4f7cd700.js +1 -0
- package/build/docs/eslint-rules-migration/index.html +6 -6
- package/build/docs/index.html +2 -2
- package/build/docs/pui-cli-9-migration/index.html +63 -6
- package/build/docs/ssl-certificate-setup/index.html +2 -2
- package/build/docs/stylelint-migration/index.html +2 -2
- package/build/docs/usage-guide/index.html +4 -4
- package/dist/cjs/commands/storybook.js +33 -4
- package/dist/cjs/lint-config/eslint/flat/compat.mjs +5 -5
- package/dist/cjs/skills/migrate-storybook-out-of-cjs/SKILL.md +188 -0
- package/dist/cjs/skills/migrate-to-pui-cli-9/SKILL.md +93 -18
- package/dist/cjs/testing/jest.config.cjs +5 -1
- package/dist/cjs/testing/setup-textencoder.cjs +4 -0
- package/dist/cjs/webpack/webpack.storybook.js +62 -0
- package/dist/esm/commands/storybook.js +22 -4
- package/dist/esm/lint-config/eslint/flat/compat.mjs +5 -5
- package/dist/esm/skills/migrate-storybook-out-of-cjs/SKILL.md +188 -0
- package/dist/esm/skills/migrate-to-pui-cli-9/SKILL.md +93 -18
- package/dist/esm/testing/jest.config.cjs +5 -1
- package/dist/esm/testing/setup-textencoder.cjs +4 -0
- package/dist/esm/webpack/webpack.storybook.js +61 -0
- package/dist/types/lib/commands/storybook.d.ts +1 -0
- package/dist/types/lib/lint-config/eslint/flat/compat.d.mts +1 -1
- package/dist/types/lib/testing/setup-textencoder.d.cts +1 -0
- package/dist/types/lib/webpack/webpack.storybook.d.ts +2 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/lib/lint-config/eslint/flat/compat.mjs +5 -5
- package/lib/skills/migrate-storybook-out-of-cjs/SKILL.md +188 -0
- package/lib/skills/migrate-to-pui-cli-9/SKILL.md +93 -18
- package/package.json +15 -21
- package/build/docs/assets/js/04ee7372.eaa386ed.js +0 -1
- package/build/docs/assets/js/13097d8d.af480dfd.js +0 -1
- package/build/docs/assets/js/4fb6949f.369cc1b9.js +0 -1
- package/build/docs/assets/js/runtime~main.f7c5bef0.js +0 -1
- /package/build/docs/assets/js/{main.7f815b7e.js.LICENSE.txt → main.d5acb4ca.js.LICENSE.txt} +0 -0
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,22 +17,45 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
var storybook_exports = {};
|
|
20
30
|
__export(storybook_exports, {
|
|
21
31
|
storybookCmd: () => storybookCmd
|
|
22
32
|
});
|
|
23
33
|
module.exports = __toCommonJS(storybook_exports);
|
|
34
|
+
var import_node_path = __toESM(require("node:path"), 1);
|
|
35
|
+
var import_node_url = require("node:url");
|
|
24
36
|
var import_utils = require("./utils.js");
|
|
37
|
+
const import_meta = {};
|
|
38
|
+
const DEFAULT_PORT = 11e3;
|
|
39
|
+
const puiCliRoot = import_node_path.default.resolve(
|
|
40
|
+
import_node_path.default.dirname((0, import_node_url.fileURLToPath)(import_meta.url)),
|
|
41
|
+
"../../.."
|
|
42
|
+
);
|
|
43
|
+
const storybookBin = import_node_path.default.join(puiCliRoot, "node_modules/.bin/storybook");
|
|
44
|
+
const crossEnvBin = import_node_path.default.join(puiCliRoot, "node_modules/.bin/cross-env");
|
|
45
|
+
const puiCliNodeModules = import_node_path.default.join(puiCliRoot, "node_modules");
|
|
46
|
+
const getStorybookEnv = () => {
|
|
47
|
+
const nodePath = [puiCliNodeModules, process.env.NODE_PATH].filter(Boolean).join(import_node_path.default.delimiter);
|
|
48
|
+
return `NODE_PATH="${nodePath}"`;
|
|
49
|
+
};
|
|
25
50
|
const buildStoryBook = async (outputDir = "demo", isDoc = false) => {
|
|
26
51
|
const additionalParams = isDoc ? `--docs -o ${outputDir}/docs` : `-o ${outputDir}`;
|
|
27
52
|
await (0, import_utils.exec)(
|
|
28
|
-
`
|
|
53
|
+
`"${crossEnvBin}" ${getStorybookEnv()} NODE_ENV=production "${storybookBin}" build --quiet ${additionalParams}`
|
|
29
54
|
);
|
|
30
55
|
};
|
|
31
|
-
const startStoryBook = async (isDoc = false) => {
|
|
56
|
+
const startStoryBook = async (isDoc = false, port = DEFAULT_PORT) => {
|
|
32
57
|
await (0, import_utils.exec)(
|
|
33
|
-
`
|
|
58
|
+
`"${crossEnvBin}" ${getStorybookEnv()} NODE_ENV=development STORYBOOK_BUILD=true "${storybookBin}" dev ${isDoc ? "--docs" : ""} -p ${port} --quiet`
|
|
34
59
|
);
|
|
35
60
|
};
|
|
36
61
|
const cmdArgs = {
|
|
@@ -47,13 +72,17 @@ const cmdArgs = {
|
|
|
47
72
|
string: true,
|
|
48
73
|
alias: "o",
|
|
49
74
|
default: "demo"
|
|
75
|
+
},
|
|
76
|
+
port: {
|
|
77
|
+
number: true,
|
|
78
|
+
default: DEFAULT_PORT
|
|
50
79
|
}
|
|
51
80
|
};
|
|
52
81
|
const storybookCmd = {
|
|
53
82
|
handler: async (argv) => {
|
|
54
83
|
try {
|
|
55
84
|
if (!argv.build) {
|
|
56
|
-
await startStoryBook(argv.docs);
|
|
85
|
+
await startStoryBook(argv.docs, argv.port);
|
|
57
86
|
(0, import_utils.logInfo)("Storybook started");
|
|
58
87
|
} else {
|
|
59
88
|
await buildStoryBook(argv.output, argv.docs);
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* ESLint 10 removed deprecated context APIs (e.g. getSourceCode, getScope, getFilename).
|
|
3
3
|
* Wrap legacy plugins via @eslint/compat v2 (ESLint 10–aware fixupPluginRules).
|
|
4
4
|
*/
|
|
5
|
-
import {
|
|
5
|
+
import { fixupPluginRules } from '@eslint/compat';
|
|
6
6
|
import react from 'eslint-plugin-react';
|
|
7
7
|
import reduxSaga from 'eslint-plugin-redux-saga';
|
|
8
8
|
import storybook from 'eslint-plugin-storybook';
|
|
@@ -20,8 +20,8 @@ export const reactPlugin = fixupPluginRules(react);
|
|
|
20
20
|
/** @type {import('eslint').ESLint.Plugin} */
|
|
21
21
|
export const reduxSagaPlugin = fixupPluginRules(reduxSaga);
|
|
22
22
|
|
|
23
|
-
/** Storybook flat presets —
|
|
23
|
+
/** Storybook flat presets — native flat config (eslint-plugin-storybook@10). */
|
|
24
24
|
/** @type {import('eslint').Linter.Config[]} */
|
|
25
|
-
export const storybookFlatConfigs =
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
export const storybookFlatConfigs = Array.isArray(storybookFlat)
|
|
26
|
+
? storybookFlat
|
|
27
|
+
: [storybookFlat];
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: migrate-storybook-out-of-cjs
|
|
3
|
+
description: >-
|
|
4
|
+
Migrate PUI Storybook from CJS wrappers and @elliemae/pui-app-sdk/storybook/cjs/* to ESM
|
|
5
|
+
(.storybook/*.mjs) and @elliemae/pui-app-sdk/storybook/* imports. Use when upgrading Storybook
|
|
6
|
+
10 with pui-cli 9, replacing require() in .storybook/main.js, removing storybook/cjs/main or
|
|
7
|
+
storybook/cjs/middleware, deleting .storybook/middleware.js, or converting preview/manager/theme
|
|
8
|
+
to ESM.
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Migrate Storybook out of CJS
|
|
12
|
+
|
|
13
|
+
Moves consumer repos from legacy CommonJS Storybook wrappers (`require('@elliemae/pui-app-sdk/storybook/cjs/...')`) to ESM (`.storybook/*.mjs` + `@elliemae/pui-app-sdk/storybook/*`).
|
|
14
|
+
|
|
15
|
+
Requires **pui-cli 9** and a matching **pui-app-sdk** release on the same train. The `storybook/cjs/*` package paths are **removed** from pui-app-sdk — repos still on CJS imports will fail at install or runtime.
|
|
16
|
+
|
|
17
|
+
For the full pui-cli 9 upgrade (Node 24, ESLint 10, etc.), install `migrate-to-pui-cli-9` first or in parallel.
|
|
18
|
+
|
|
19
|
+
## When to use
|
|
20
|
+
|
|
21
|
+
- `.storybook/main.js` uses `require('@elliemae/pui-app-sdk/storybook/cjs/main')`
|
|
22
|
+
- `.storybook/middleware.js` exists or imports `storybook/cjs/middleware`
|
|
23
|
+
- Storybook fails after bumping pui-app-sdk with “Cannot find module …/storybook/cjs/…”
|
|
24
|
+
- Moving from Storybook 6 CJS config to Storybook 10 ESM config with pui-cli
|
|
25
|
+
|
|
26
|
+
## What changed
|
|
27
|
+
|
|
28
|
+
| Topic | Before (CJS / SB6) | After (ESM / SB10) |
|
|
29
|
+
| ----------------- | ------------------------------------------ | ---------------------------------------------------------------- |
|
|
30
|
+
| Consumer config | `.storybook/main.js` | `.storybook/main.mjs` |
|
|
31
|
+
| Shared import | `@elliemae/pui-app-sdk/storybook/cjs/main` | `@elliemae/pui-app-sdk/storybook/main` |
|
|
32
|
+
| Export name | `getConfig()` (CJS default) | **`getStorybookConfig()`** (named export) |
|
|
33
|
+
| API mocks | `.storybook/middleware.js` | Built into pui-cli Storybook dev server |
|
|
34
|
+
| Preview / manager | `.storybook/preview.js`, `manager.js` | `.storybook/preview.mjs`, `manager.mjs` (when using ESM imports) |
|
|
35
|
+
| CLI | `start-storybook` / `build-storybook` | `pui-cli storybook` → `storybook dev` / `storybook build` |
|
|
36
|
+
| Addons | Installed in consumer `package.json` | Bundled in pui-cli; resolved via pui-app-sdk |
|
|
37
|
+
|
|
38
|
+
## Pre-flight
|
|
39
|
+
|
|
40
|
+
1. Bump `@elliemae/pui-cli@9` and `@elliemae/pui-app-sdk@*` together.
|
|
41
|
+
2. Run `pnpm install`. If using a local `file:` link to pui-app-sdk, reinstall after rebuilding app-sdk so workspace `node_modules` picks up fresh dist.
|
|
42
|
+
3. Confirm the repo uses `pui-cli storybook` (not raw `start-storybook` scripts).
|
|
43
|
+
|
|
44
|
+
## Migration steps
|
|
45
|
+
|
|
46
|
+
### Step 1 — Replace `.storybook/main.js`
|
|
47
|
+
|
|
48
|
+
Delete `main.js`. Create `.storybook/main.mjs`:
|
|
49
|
+
|
|
50
|
+
```javascript
|
|
51
|
+
import { getStorybookConfig } from '@elliemae/pui-app-sdk/storybook/main';
|
|
52
|
+
|
|
53
|
+
export default getStorybookConfig();
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Do not** use `getConfig` or `require('…/storybook/cjs/main')` — those paths and names are removed.
|
|
57
|
+
|
|
58
|
+
### Step 2 — Remove middleware
|
|
59
|
+
|
|
60
|
+
Delete `.storybook/middleware.js` if present.
|
|
61
|
+
|
|
62
|
+
pui-cli registers mock API routes during `storybook dev`. The deprecated `@elliemae/pui-app-sdk/storybook/middleware` export exists only for repos not yet on pui-cli 9 Storybook — **do not** add it back in new ESM configs.
|
|
63
|
+
|
|
64
|
+
### Step 3 — Convert preview, manager, theme (if customized)
|
|
65
|
+
|
|
66
|
+
If the repo only uses shared pui-app-sdk defaults, you may have no preview file — skip.
|
|
67
|
+
|
|
68
|
+
**Minimal preview** (no custom theme):
|
|
69
|
+
|
|
70
|
+
```javascript
|
|
71
|
+
// .storybook/preview.mjs
|
|
72
|
+
export {
|
|
73
|
+
decorators,
|
|
74
|
+
parameters,
|
|
75
|
+
loaders,
|
|
76
|
+
} from '@elliemae/pui-app-sdk/storybook/preview';
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Preview with local theme** (see `pui-react-boilerplate`, `pui-app-sdk`):
|
|
80
|
+
|
|
81
|
+
```javascript
|
|
82
|
+
// .storybook/preview.mjs
|
|
83
|
+
import {
|
|
84
|
+
getParameters,
|
|
85
|
+
loaders,
|
|
86
|
+
decorators,
|
|
87
|
+
} from '@elliemae/pui-app-sdk/storybook/preview';
|
|
88
|
+
import { theme } from './theme.mjs';
|
|
89
|
+
|
|
90
|
+
const parameters = getParameters(theme);
|
|
91
|
+
|
|
92
|
+
export { decorators, parameters, loaders };
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Manager / theme** — convert `manager.js` → `manager.mjs`, `theme.js` → `theme.mjs` when they use `import`/`export`:
|
|
96
|
+
|
|
97
|
+
```javascript
|
|
98
|
+
// .storybook/manager.mjs
|
|
99
|
+
export { managerConfig } from '@elliemae/pui-app-sdk/storybook/manager';
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
```javascript
|
|
103
|
+
// .storybook/theme.mjs
|
|
104
|
+
export { theme } from '@elliemae/pui-app-sdk/storybook/theme';
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Keep `.storybook/preview-head.html` unchanged.
|
|
108
|
+
|
|
109
|
+
Delete obsolete `.js` duplicates after creating `.mjs` files (`preview.js`, `manager.js`, `theme.js`, `middleware.js`).
|
|
110
|
+
|
|
111
|
+
### Step 4 — Monorepo lib packages (no `app/` directory)
|
|
112
|
+
|
|
113
|
+
pui-app-sdk omits `../app/**` story globs when no `app/` folder exists. If globs still fail, filter explicitly in `main.mjs`:
|
|
114
|
+
|
|
115
|
+
```javascript
|
|
116
|
+
import { getStorybookConfig } from '@elliemae/pui-app-sdk/storybook/main';
|
|
117
|
+
|
|
118
|
+
const config = getStorybookConfig();
|
|
119
|
+
config.stories = config.stories.filter((s) => !s.includes('/app/'));
|
|
120
|
+
|
|
121
|
+
export default config;
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Pilot: `pui-mono-repo-boilerplate/libs/foo`.
|
|
125
|
+
|
|
126
|
+
### Step 5 — Stories and types
|
|
127
|
+
|
|
128
|
+
- Prefer CSF3 and `@storybook/react-webpack5` types where TypeScript fails.
|
|
129
|
+
- Remove Storybook 6 webpack alias workarounds (MDX pinning, react-select hacks) unless a story still breaks after upgrade.
|
|
130
|
+
- Consumers do **not** install `@storybook/addon-*` separately — addons resolve from pui-cli via pui-app-sdk.
|
|
131
|
+
|
|
132
|
+
### Step 6 — ESLint
|
|
133
|
+
|
|
134
|
+
Ensure `.storybook/**` is linted. After pui-cli 9 ESLint flat config migration, run `pnpm exec pui-cli lint` on story files.
|
|
135
|
+
|
|
136
|
+
## Verify
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
pnpm exec pui-cli storybook # dev, default port 11000
|
|
140
|
+
pnpm exec pui-cli storybook -b # static build to demo/
|
|
141
|
+
pnpm exec pui-cli storybook -b --docs # docs build
|
|
142
|
+
pnpm exec pui-cli lint
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Checklist:
|
|
146
|
+
|
|
147
|
+
- [ ] No `require('@elliemae/pui-app-sdk/storybook/cjs/…')` anywhere
|
|
148
|
+
- [ ] `.storybook/main.mjs` exists; `main.js` removed
|
|
149
|
+
- [ ] `.storybook/middleware.js` removed (if it existed)
|
|
150
|
+
- [ ] Story dev server starts; mock API routes work without middleware file
|
|
151
|
+
- [ ] Static build succeeds
|
|
152
|
+
|
|
153
|
+
## Troubleshooting
|
|
154
|
+
|
|
155
|
+
| Symptom | Fix |
|
|
156
|
+
| -------------------------------------------- | ------------------------------------------------------------------------------------- |
|
|
157
|
+
| `Cannot find module '…/storybook/cjs/main'` | Migrate to `@elliemae/pui-app-sdk/storybook/main` in `main.mjs` |
|
|
158
|
+
| `getConfig is not a function` | Use named import **`getStorybookConfig`**, not `getConfig` |
|
|
159
|
+
| `Can't resolve './app'` in lib-only package | Use conditional globs in app-sdk or filter `config.stories` in `main.mjs` |
|
|
160
|
+
| `Failed to load native binding` / SWC errors | Rebuild pui-app-sdk; reinstall workspace; Babel compiler addon is bundled via pui-cli |
|
|
161
|
+
| “Using default Webpack5 setup” (no Babel) | Refresh pnpm install after bumping `file:` pui-cli / pui-app-sdk links |
|
|
162
|
+
| API mocks missing | Delete middleware file; use `pui-cli storybook` (not legacy CLI) |
|
|
163
|
+
| Stale app-sdk in monorepo | `pnpm install --ignore-scripts` after rebuilding linked packages |
|
|
164
|
+
|
|
165
|
+
## Reference repos
|
|
166
|
+
|
|
167
|
+
- `pui-react-boilerplate` — app with `app/` stories
|
|
168
|
+
- `pui-mono-repo-boilerplate/libs/foo` — lib-only package
|
|
169
|
+
- `pui-app-sdk/.storybook/` — dogfood ESM wrappers
|
|
170
|
+
|
|
171
|
+
Full guide: [pui-cli 9 migration — Storybook 10](https://docs.pui.mortgagetech.q1.ice.com/cli/pui-cli-9-migration) (`docs/pui-cli-9-migration.md` in pui-cli).
|
|
172
|
+
|
|
173
|
+
## Install this skill
|
|
174
|
+
|
|
175
|
+
From a consumer repo (after `@elliemae/pui-cli` is installed):
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
pnpm exec pui-cli skills list
|
|
179
|
+
pnpm exec pui-cli skills install migrate-storybook-out-of-cjs --target all
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Skills are copied to `.cursor/skills/`, `.claude/skills/`, and `.github/skills/`.
|
|
183
|
+
|
|
184
|
+
## What NOT to change
|
|
185
|
+
|
|
186
|
+
- Production Webpack build config — Storybook migration is dev/docs tooling only
|
|
187
|
+
- Business logic in stories unless types or CSF3 require it
|
|
188
|
+
- Do not re-add `@storybook/*` addon packages to consumer `package.json` unless pui-cli docs explicitly require an exception
|
|
@@ -5,8 +5,8 @@ description: >-
|
|
|
5
5
|
Husky 9, Vitest 4, semantic-release 25, Lerna 9, Nx 22). Use when upgrading @elliemae/pui-cli,
|
|
6
6
|
migrating from .eslintrc.cjs to eslint.config.mjs, release.config.cjs to release.config.mjs,
|
|
7
7
|
upgrading Husky 8 hooks, fixing Vitest 4 / coverage-v8 breakages, migrating monorepo nx.json from
|
|
8
|
-
@nrwl/workspace to nx 22,
|
|
9
|
-
stay on Webpack.
|
|
8
|
+
@nrwl/workspace to nx 22, moving shamefully-hoist from .npmrc to pnpm-workspace.yaml for pnpm 11,
|
|
9
|
+
or adopting shared configs from pui-cli. App/library production builds stay on Webpack.
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
# Migrate to pui-cli 9
|
|
@@ -35,9 +35,46 @@ pnpm install
|
|
|
35
35
|
|
|
36
36
|
1. Update `.node-version` to `24` if needed.
|
|
37
37
|
2. Ensure CI Jenkins/docker images use Node 24.
|
|
38
|
-
3. Upgrade pnpm to 11
|
|
38
|
+
3. Upgrade pnpm to 11 — set `engines.pnpm` to `>=11` in root `package.json` (do not pin an exact version in `packageManager`; customers may use any pnpm 11 minor/patch).
|
|
39
39
|
4. Run `pnpm install`, `pnpm test`, `pnpm run build` — fix any Node/pnpm breakages only.
|
|
40
40
|
|
|
41
|
+
### Phase 1b — pnpm 11 hoisting (`pnpm-workspace.yaml`)
|
|
42
|
+
|
|
43
|
+
**Required for every repo** (apps, libs, monorepos). pnpm 11 ignores hoist settings in `.npmrc`.
|
|
44
|
+
|
|
45
|
+
1. **Keep org hoisting policy** — set `shamefullyHoist: true` in `pnpm-workspace.yaml` (same as legacy `shamefully-hoist=true`). Do not switch to isolated/no-hoist; PUI apps use `@elliemae/app-react-dependencies` and pui-cli webpack `getAlias()` expects deps at repo root `node_modules/`.
|
|
46
|
+
|
|
47
|
+
2. **Create or update `pnpm-workspace.yaml`** at the repo root. Move settings out of `.npmrc` using camelCase:
|
|
48
|
+
|
|
49
|
+
| `.npmrc` (ignored by pnpm 11) | `pnpm-workspace.yaml` |
|
|
50
|
+
| --------------------------------- | ----------------------------- |
|
|
51
|
+
| `shamefully-hoist=true` | `shamefullyHoist: true` |
|
|
52
|
+
| `public-hoist-pattern[]=…` | `publicHoistPattern: [ "…" ]` |
|
|
53
|
+
| `strict-peer-dependencies` | `strictPeerDependencies` |
|
|
54
|
+
| `auto-install-peers` | `autoInstallPeers` |
|
|
55
|
+
| `package.json` `"pnpm".overrides` | top-level `overrides:` |
|
|
56
|
+
|
|
57
|
+
3. **Single-package repo** — include `packages: ['.']`. Reference: `pui-react-boilerplate/pnpm-workspace.yaml`.
|
|
58
|
+
|
|
59
|
+
4. **Monorepo** — include `packages: ["libs/*", "apps/*"]`. Optional explicit `publicHoistPattern` for webpack alias targets: `esbuild-loader`, `@elliemae/*`, `styled-components`, `history`, `lodash`. Reference: `pui-microfe/pnpm-workspace.yaml`.
|
|
60
|
+
|
|
61
|
+
5. **Migrate `allowBuilds`** — replace `onlyBuiltDependencies` / placeholder `allowBuilds` entries with `true` for packages that need postinstall scripts (`@swc/core`, `esbuild`, `nx`, etc.). Fix `ERR_PNPM_IGNORED_BUILDS`.
|
|
62
|
+
|
|
63
|
+
6. **Trim `.npmrc`** — keep auth/registry only (for example `legacy-peer-deps=true`).
|
|
64
|
+
|
|
65
|
+
7. **Clean reinstall and verify:**
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
rm -rf node_modules libs/*/node_modules # if monorepo
|
|
69
|
+
SKIP_POST_INSTALL_BUILD=1 pnpm install --no-frozen-lockfile
|
|
70
|
+
grep publicHoistPattern node_modules/.modules.yaml # must NOT be []
|
|
71
|
+
pnpm run build
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Symptoms if skipped:** `Can't resolve 'esbuild-loader'` / `styled-components` / `@elliemae/pui-theme` during webpack; `publicHoistPattern: []` in `.modules.yaml`.
|
|
75
|
+
|
|
76
|
+
See migration guide section **1b. Migrate pnpm hoisting to `pnpm-workspace.yaml`**.
|
|
77
|
+
|
|
41
78
|
### Phase 2 — Bump pui-cli
|
|
42
79
|
|
|
43
80
|
```bash
|
|
@@ -255,8 +292,36 @@ pnpm exec pui-cli lint
|
|
|
255
292
|
|
|
256
293
|
See [pui-cli 9 migration guide](https://docs.pui.mortgagetech.q1.ice.com/cli/pui-cli-9-migration) — **Lerna 9 and Nx 22** section for the full `nx.json` template.
|
|
257
294
|
|
|
295
|
+
### Phase 11 — Storybook 10 (out of CJS)
|
|
296
|
+
|
|
297
|
+
Applies when the repo uses `pui-cli storybook`. Requires pui-cli 9 **and** a matching pui-app-sdk release.
|
|
298
|
+
|
|
299
|
+
Install the dedicated skill for agents:
|
|
300
|
+
|
|
301
|
+
```bash
|
|
302
|
+
pnpm exec pui-cli skills install migrate-storybook-out-of-cjs --target all
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
Follow **`migrate-storybook-out-of-cjs`** for the full CJS → ESM playbook (`storybook/cjs/*` removed; use `.storybook/main.mjs` + `getStorybookConfig()`). Summary:
|
|
306
|
+
|
|
307
|
+
1. Bump `@elliemae/pui-app-sdk` with `@elliemae/pui-cli@9`.
|
|
308
|
+
2. Replace `.storybook/main.js` with `.storybook/main.mjs` importing `@elliemae/pui-app-sdk/storybook/main`.
|
|
309
|
+
3. Delete `.storybook/middleware.js`; migrate `preview` / `manager` / `theme` to `.mjs` when customized.
|
|
310
|
+
4. Update stories to CSF3 where types fail; remove SB6 webpack alias workarounds unless still required.
|
|
311
|
+
|
|
312
|
+
Verify:
|
|
313
|
+
|
|
314
|
+
```bash
|
|
315
|
+
pnpm exec pui-cli storybook
|
|
316
|
+
pnpm exec pui-cli storybook -b
|
|
317
|
+
pnpm exec pui-cli lint
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
See [pui-cli 9 migration guide — Storybook 10](https://docs.pui.mortgagetech.q1.ice.com/cli/pui-cli-9-migration) for addon removals and troubleshooting.
|
|
321
|
+
|
|
258
322
|
### Phase 10 — Verify
|
|
259
323
|
|
|
324
|
+
- [ ] `shamefullyHoist` in `pnpm-workspace.yaml` (not `.npmrc`); `publicHoistPattern` not `[]` in `.modules.yaml`
|
|
260
325
|
- [ ] `pnpm exec pui-cli lint` — 0 errors
|
|
261
326
|
- [ ] `pnpm exec pui-cli tscheck --files`
|
|
262
327
|
- [ ] `pnpm test` (or `pui-cli vitest` if applicable)
|
|
@@ -267,21 +332,30 @@ See [pui-cli 9 migration guide](https://docs.pui.mortgagetech.q1.ice.com/cli/pui
|
|
|
267
332
|
|
|
268
333
|
## Common lint fixes after upgrade
|
|
269
334
|
|
|
270
|
-
| Symptom
|
|
271
|
-
|
|
|
272
|
-
| `import-x/no-unresolved`
|
|
273
|
-
| `@typescript-eslint/no-explicit-any`
|
|
274
|
-
| `@typescript-eslint/no-unused-vars`
|
|
275
|
-
| Stale `eslint-disable` comments
|
|
276
|
-
| Test/fixture files flagged
|
|
277
|
-
| `.d.ts` files
|
|
278
|
-
| Cannot find module `vite` in tscheck
|
|
279
|
-
| Vitest `optimizer.web` unknown
|
|
280
|
-
| Coverage fails after upgrade
|
|
281
|
-
| `release.config.cjs` extends fails
|
|
282
|
-
| `nx` fails after pui-cli 9 bump
|
|
283
|
-
| `lerna bootstrap` / `add` / `link`
|
|
284
|
-
| Stale `@nrwl/workspace` in lockfile
|
|
335
|
+
| Symptom | Fix |
|
|
336
|
+
| ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
337
|
+
| `import-x/no-unresolved` | Use `import type` for type-only imports |
|
|
338
|
+
| `@typescript-eslint/no-explicit-any` | Type the value or add targeted override (warn) during transition |
|
|
339
|
+
| `@typescript-eslint/no-unused-vars` | Remove or prefix with `_` |
|
|
340
|
+
| Stale `eslint-disable` comments | Remove disables for rules no longer in config |
|
|
341
|
+
| Test/fixture files flagged | Shared config includes `lib/**/tests/**` globs — ensure pui-cli 9.0.0+ |
|
|
342
|
+
| `.d.ts` files | pui-cli turns off `no-explicit-any` for `**/*.d.ts` |
|
|
343
|
+
| Cannot find module `vite` in tscheck | Set `moduleResolution: "bundler"` or extend pui-cli 9 tsconfig |
|
|
344
|
+
| Vitest `optimizer.web` unknown | Rename to `test.deps.optimizer.client` (Vitest 4) |
|
|
345
|
+
| Coverage fails after upgrade | Remove `@vitest/coverage-c8`; use `@vitest/coverage-v8@4` |
|
|
346
|
+
| `release.config.cjs` extends fails | Migrate to `release.config.mjs`; requires semantic-release 22+ (pui-cli 9 ships 25) |
|
|
347
|
+
| `nx` fails after pui-cli 9 bump | Migrate `nx.json` off `@nrwl/*`; use `targetDefaults` not `targetDependencies` |
|
|
348
|
+
| `lerna bootstrap` / `add` / `link` | Removed in lerna 9 — use `pnpm` workspaces and `pnpm add --filter` |
|
|
349
|
+
| Stale `@nrwl/workspace` in lockfile | Remove direct `@nrwl/*` pins; rely on pui-cli's `nx` + `@nx/workspace` |
|
|
350
|
+
| `Can't resolve 'esbuild-loader'` | Move `shamefullyHoist: true` to `pnpm-workspace.yaml`; clean reinstall |
|
|
351
|
+
| `Can't resolve 'styled-components'` / `@elliemae/pui-theme` | Same — hoisting ignored if still only in `.npmrc` |
|
|
352
|
+
| `publicHoistPattern: []` in `.modules.yaml` | Migrate hoist settings from `.npmrc` to `pnpm-workspace.yaml` |
|
|
353
|
+
| `ERR_PNPM_IGNORED_BUILDS` | Set real `allowBuilds` in `pnpm-workspace.yaml` or run `pnpm approve-builds` |
|
|
354
|
+
| `husky: command not found` on prepare | `shamefullyHoist` + `publicHoistPattern: [husky]` or direct root `devDependency` |
|
|
355
|
+
| Storybook fails after pui-cli 9 bump | Migrate `.storybook/main.js` → `main.mjs`; import `@elliemae/pui-app-sdk/storybook/main` |
|
|
356
|
+
| `Failed to load native binding` / SWC errors | Ensure pui-app-sdk resolves Babel compiler from pui-cli; rebuild app-sdk and reinstall workspace deps |
|
|
357
|
+
| `middleware.js` ignored / API mocks missing | Delete middleware file; pui-cli Storybook dev server loads routes automatically |
|
|
358
|
+
| Jest `TextEncoder is not defined` | Built into pui-cli `jestConfig` — remove repo `jest-textencoder-setup.cjs`; keep `delete moduleNameMapper['@elliemae/pui-diagnostics']` only if using real package |
|
|
285
359
|
|
|
286
360
|
Full rule comparison: [eslint-rules-migration.md](https://docs.pui.mortgagetech.q1.ice.com/cli/eslint-rules-migration) (also at `docs/eslint-rules-migration.md` in pui-cli).
|
|
287
361
|
|
|
@@ -300,6 +374,7 @@ Skills are copied to `.cursor/skills/`, `.claude/skills/`, and `.github/skills/`
|
|
|
300
374
|
- Application business logic — migration is tooling/config only
|
|
301
375
|
- Webpack/babel production build config — pui-cli 9 does not migrate apps to Vite for bundling
|
|
302
376
|
- Prettier / commitlint configs unless pui-cli 9 bumps those presets
|
|
377
|
+
- **Org hoisting policy** — keep `shamefullyHoist: true`; do not remove hoisting or duplicate webpack deps in root `package.json` as a workaround
|
|
303
378
|
|
|
304
379
|
## Additional resources
|
|
305
380
|
|
|
@@ -80,7 +80,11 @@ const jestConfig = {
|
|
|
80
80
|
},
|
|
81
81
|
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
|
|
82
82
|
setupFilesAfterEnv: [path.resolve(__dirname, './setup-tests.js')],
|
|
83
|
-
setupFiles: [
|
|
83
|
+
setupFiles: [
|
|
84
|
+
path.resolve(__dirname, './setup-textencoder.cjs'),
|
|
85
|
+
'raf/polyfill',
|
|
86
|
+
'whatwg-fetch',
|
|
87
|
+
],
|
|
84
88
|
testRegex: '(app|lib).*/tests/.*\\.test\\.[jt]sx?$',
|
|
85
89
|
snapshotSerializers: [],
|
|
86
90
|
testResultsProcessor: 'jest-sonar-reporter',
|
|
@@ -29,15 +29,28 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
29
29
|
var webpack_storybook_exports = {};
|
|
30
30
|
__export(webpack_storybook_exports, {
|
|
31
31
|
managerWebpack: () => managerWebpack,
|
|
32
|
+
resolveStorybookAddon: () => resolveStorybookAddon,
|
|
32
33
|
webpackFinal: () => webpackFinal
|
|
33
34
|
});
|
|
34
35
|
module.exports = __toCommonJS(webpack_storybook_exports);
|
|
36
|
+
var import_node_module = require("node:module");
|
|
37
|
+
var import_node_url = require("node:url");
|
|
35
38
|
var import_webpack = __toESM(require("webpack"), 1);
|
|
36
39
|
var import_mini_css_extract_plugin = __toESM(require("mini-css-extract-plugin"), 1);
|
|
37
40
|
var import_copy_webpack_plugin = __toESM(require("copy-webpack-plugin"), 1);
|
|
38
41
|
var import_resolve_typescript_plugin = __toESM(require("resolve-typescript-plugin"), 1);
|
|
39
42
|
var import_helpers = require("./helpers.js");
|
|
43
|
+
var import_appRoutes = require("../server/appRoutes.js");
|
|
40
44
|
var import_utils = require("../utils.js");
|
|
45
|
+
const import_meta = {};
|
|
46
|
+
const puiCliRequire = (0, import_node_module.createRequire)((0, import_node_url.fileURLToPath)(import_meta.url));
|
|
47
|
+
const resolveStorybookAddon = (addonName) => {
|
|
48
|
+
try {
|
|
49
|
+
return puiCliRequire.resolve(addonName);
|
|
50
|
+
} catch {
|
|
51
|
+
return addonName;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
41
54
|
const IS_APP = (0, import_utils.isApp)();
|
|
42
55
|
const CWD = process.cwd();
|
|
43
56
|
const getAdditionalPlugins = () => [
|
|
@@ -84,12 +97,50 @@ const getModuleRules = () => [
|
|
|
84
97
|
type: "asset/resource"
|
|
85
98
|
}
|
|
86
99
|
];
|
|
100
|
+
const setupStorybookMiddlewares = (middlewares, devServer) => {
|
|
101
|
+
if (devServer.app) {
|
|
102
|
+
(0, import_appRoutes.loadRoutes)(devServer.app).catch((err) => {
|
|
103
|
+
console.error(err);
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
return middlewares;
|
|
107
|
+
};
|
|
108
|
+
const usesSwcLoader = (rule) => {
|
|
109
|
+
if (typeof rule.loader === "string" && rule.loader.includes("swc-loader")) {
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
const uses = Array.isArray(rule.use) ? rule.use : rule.use ? [rule.use] : [];
|
|
113
|
+
return uses.some((useEntry) => {
|
|
114
|
+
const loader = typeof useEntry === "string" ? useEntry : useEntry.loader;
|
|
115
|
+
return loader?.includes("swc-loader");
|
|
116
|
+
});
|
|
117
|
+
};
|
|
118
|
+
const removeSwcLoaderRules = (rules = []) => rules.filter((rule) => !usesSwcLoader(rule)).map((rule) => {
|
|
119
|
+
if (rule.oneOf) {
|
|
120
|
+
return {
|
|
121
|
+
...rule,
|
|
122
|
+
oneOf: removeSwcLoaderRules(rule.oneOf)
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
if (rule.rules) {
|
|
126
|
+
return {
|
|
127
|
+
...rule,
|
|
128
|
+
rules: removeSwcLoaderRules(rule.rules)
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
return rule;
|
|
132
|
+
});
|
|
87
133
|
const webpackFinal = (config, { configType }) => {
|
|
88
134
|
const isProd = configType === "PRODUCTION";
|
|
89
135
|
const fileLoaderRule = config?.module?.rules?.find?.(
|
|
90
136
|
(rule) => rule.test?.test?.(".svg")
|
|
91
137
|
);
|
|
92
138
|
if (fileLoaderRule) fileLoaderRule.exclude = /\.svg$/i;
|
|
139
|
+
if (config.module?.rules) {
|
|
140
|
+
config.module.rules = removeSwcLoaderRules(
|
|
141
|
+
config.module.rules
|
|
142
|
+
);
|
|
143
|
+
}
|
|
93
144
|
config?.module?.rules?.unshift(...getModuleRules());
|
|
94
145
|
config?.plugins?.push(...getAdditionalPlugins());
|
|
95
146
|
if (isProd) {
|
|
@@ -118,6 +169,17 @@ const webpackFinal = (config, { configType }) => {
|
|
|
118
169
|
config.externals["@elliemae/pui-diagnostics"] = "emuiDiagnostics";
|
|
119
170
|
config.externals["@elliemae/pui-logrocket"] = "emuiLogrocket";
|
|
120
171
|
}
|
|
172
|
+
if (!isProd) {
|
|
173
|
+
const existingDevServer = config.devServer ?? {};
|
|
174
|
+
const existingSetupMiddlewares = existingDevServer.setupMiddlewares;
|
|
175
|
+
config.devServer = {
|
|
176
|
+
...existingDevServer,
|
|
177
|
+
setupMiddlewares: (middlewares, devServer) => {
|
|
178
|
+
const nextMiddlewares = typeof existingSetupMiddlewares === "function" ? existingSetupMiddlewares(middlewares, devServer) : middlewares;
|
|
179
|
+
return setupStorybookMiddlewares(nextMiddlewares, devServer);
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
}
|
|
121
183
|
return config;
|
|
122
184
|
};
|
|
123
185
|
const managerWebpack = (config) => {
|
|
@@ -1,13 +1,27 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
1
3
|
import { exec, logInfo, logError, logSuccess } from "./utils.js";
|
|
4
|
+
const DEFAULT_PORT = 11e3;
|
|
5
|
+
const puiCliRoot = path.resolve(
|
|
6
|
+
path.dirname(fileURLToPath(import.meta.url)),
|
|
7
|
+
"../../.."
|
|
8
|
+
);
|
|
9
|
+
const storybookBin = path.join(puiCliRoot, "node_modules/.bin/storybook");
|
|
10
|
+
const crossEnvBin = path.join(puiCliRoot, "node_modules/.bin/cross-env");
|
|
11
|
+
const puiCliNodeModules = path.join(puiCliRoot, "node_modules");
|
|
12
|
+
const getStorybookEnv = () => {
|
|
13
|
+
const nodePath = [puiCliNodeModules, process.env.NODE_PATH].filter(Boolean).join(path.delimiter);
|
|
14
|
+
return `NODE_PATH="${nodePath}"`;
|
|
15
|
+
};
|
|
2
16
|
const buildStoryBook = async (outputDir = "demo", isDoc = false) => {
|
|
3
17
|
const additionalParams = isDoc ? `--docs -o ${outputDir}/docs` : `-o ${outputDir}`;
|
|
4
18
|
await exec(
|
|
5
|
-
`
|
|
19
|
+
`"${crossEnvBin}" ${getStorybookEnv()} NODE_ENV=production "${storybookBin}" build --quiet ${additionalParams}`
|
|
6
20
|
);
|
|
7
21
|
};
|
|
8
|
-
const startStoryBook = async (isDoc = false) => {
|
|
22
|
+
const startStoryBook = async (isDoc = false, port = DEFAULT_PORT) => {
|
|
9
23
|
await exec(
|
|
10
|
-
`
|
|
24
|
+
`"${crossEnvBin}" ${getStorybookEnv()} NODE_ENV=development STORYBOOK_BUILD=true "${storybookBin}" dev ${isDoc ? "--docs" : ""} -p ${port} --quiet`
|
|
11
25
|
);
|
|
12
26
|
};
|
|
13
27
|
const cmdArgs = {
|
|
@@ -24,13 +38,17 @@ const cmdArgs = {
|
|
|
24
38
|
string: true,
|
|
25
39
|
alias: "o",
|
|
26
40
|
default: "demo"
|
|
41
|
+
},
|
|
42
|
+
port: {
|
|
43
|
+
number: true,
|
|
44
|
+
default: DEFAULT_PORT
|
|
27
45
|
}
|
|
28
46
|
};
|
|
29
47
|
const storybookCmd = {
|
|
30
48
|
handler: async (argv) => {
|
|
31
49
|
try {
|
|
32
50
|
if (!argv.build) {
|
|
33
|
-
await startStoryBook(argv.docs);
|
|
51
|
+
await startStoryBook(argv.docs, argv.port);
|
|
34
52
|
logInfo("Storybook started");
|
|
35
53
|
} else {
|
|
36
54
|
await buildStoryBook(argv.output, argv.docs);
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* ESLint 10 removed deprecated context APIs (e.g. getSourceCode, getScope, getFilename).
|
|
3
3
|
* Wrap legacy plugins via @eslint/compat v2 (ESLint 10–aware fixupPluginRules).
|
|
4
4
|
*/
|
|
5
|
-
import {
|
|
5
|
+
import { fixupPluginRules } from '@eslint/compat';
|
|
6
6
|
import react from 'eslint-plugin-react';
|
|
7
7
|
import reduxSaga from 'eslint-plugin-redux-saga';
|
|
8
8
|
import storybook from 'eslint-plugin-storybook';
|
|
@@ -20,8 +20,8 @@ export const reactPlugin = fixupPluginRules(react);
|
|
|
20
20
|
/** @type {import('eslint').ESLint.Plugin} */
|
|
21
21
|
export const reduxSagaPlugin = fixupPluginRules(reduxSaga);
|
|
22
22
|
|
|
23
|
-
/** Storybook flat presets —
|
|
23
|
+
/** Storybook flat presets — native flat config (eslint-plugin-storybook@10). */
|
|
24
24
|
/** @type {import('eslint').Linter.Config[]} */
|
|
25
|
-
export const storybookFlatConfigs =
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
export const storybookFlatConfigs = Array.isArray(storybookFlat)
|
|
26
|
+
? storybookFlat
|
|
27
|
+
: [storybookFlat];
|