@se-studio/skills 1.0.1
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/CHANGELOG.md +7 -0
- package/package.json +25 -0
- package/skills/contentful-cms-alt-text-audit/SKILL.md +60 -0
- package/skills/contentful-cms-cms-guidelines/README.md +166 -0
- package/skills/contentful-cms-cms-guidelines/colour-hint-prompt.md +77 -0
- package/skills/contentful-cms-cms-guidelines/evaluation-prompt.md +84 -0
- package/skills/contentful-cms-cms-guidelines/generate-component-guidelines.md +126 -0
- package/skills/contentful-cms-cms-guidelines/generation-prompt.md +231 -0
- package/skills/contentful-cms-cms-guidelines/html-component-authoring.md +401 -0
- package/skills/contentful-cms-cms-guidelines/validation-prompt.md +170 -0
- package/skills/contentful-cms-cms-guidelines/variant-loop.md +189 -0
- package/skills/contentful-cms-cms-guidelines/variant-proposal-prompt.md +131 -0
- package/skills/contentful-cms-core/SKILL.md +793 -0
- package/skills/contentful-cms-generate-all-guidelines/SKILL.md +313 -0
- package/skills/contentful-cms-generate-cms-guidelines/SKILL.md +313 -0
- package/skills/contentful-cms-image-guide/SKILL.md +240 -0
- package/skills/contentful-cms-navigation/SKILL.md +23 -0
- package/skills/contentful-cms-rich-text/SKILL.md +96 -0
- package/skills/contentful-cms-schema-org/SKILL.md +74 -0
- package/skills/contentful-cms-screenshots/SKILL.md +46 -0
- package/skills/contentful-cms-seo-descriptions/SKILL.md +54 -0
- package/skills/contentful-cms-templates/SKILL.md +21 -0
- package/skills/contentful-cms-update-cms-guidelines/SKILL.md +348 -0
- package/skills/performance-audit/SKILL.md +344 -0
- package/skills/se-marketing-sites-cms-routes-and-appshared/SKILL.md +99 -0
- package/skills/se-marketing-sites-create-collection/SKILL.md +295 -0
- package/skills/se-marketing-sites-create-component/SKILL.md +250 -0
- package/skills/se-marketing-sites-create-page/SKILL.md +183 -0
- package/skills/se-marketing-sites-curate-showcase-mocks/SKILL.md +344 -0
- package/skills/se-marketing-sites-handling-media/SKILL.md +195 -0
- package/skills/se-marketing-sites-lib-cms-structure/SKILL.md +83 -0
- package/skills/se-marketing-sites-register-cms-features/SKILL.md +95 -0
- package/skills/se-marketing-sites-styling-system/SKILL.md +122 -0
- package/skills/site-workflows-brand-context-builder/SKILL.md +98 -0
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: update-cms-guidelines
|
|
3
|
+
description: Primary CMS guideline orchestration. Use `fresh` only after a full clean slate and complete pipeline (showcase → screenshots → new component prose via Phase B/C/D — never git-restore fragments). Use `sync` for incremental changes but always delete stale types. If the user is vague, ask whether they want a full clean regeneration or incremental sync before acting.
|
|
4
|
+
license: Private
|
|
5
|
+
metadata:
|
|
6
|
+
author: se-core-product
|
|
7
|
+
version: "1.1.0"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Update CMS Guidelines
|
|
11
|
+
|
|
12
|
+
This is the **primary entry point** for all CMS guideline work. It wraps the lower-level skills
|
|
13
|
+
into three clear modes so you always know which path to take.
|
|
14
|
+
|
|
15
|
+
## Terms: full regeneration vs incremental
|
|
16
|
+
|
|
17
|
+
| Term | Meaning |
|
|
18
|
+
|---|---|
|
|
19
|
+
| **Full regeneration** (brand-new run) | **Clean slate** of generated artifacts, then rerun the **entire** pipeline: showcase data → mocks → field list → **all** screenshots (components **and** collections) → **new** component guideline markdown (Phase B + C + D for **every** type — no restoring old `.md` from git) → collection/external CLI step → merge → commit. Collections are CLI-regenerated; externals may need hand-filled sections after stub creation. |
|
|
20
|
+
| **Incremental** (`sync` + targeted work) | Discovery/registrations are the source of truth. **Remove every stale artifact** for types no longer registered (fragments, PNGs, `screenshots/index.json` rows, `accepted-variants` JSON where your app tracks them). Then add or refresh only **new** or **changed** types (screenshots + `generate-cms-guidelines` single / generate-all partial). Always merge at the end if fragments changed. |
|
|
21
|
+
|
|
22
|
+
**Not** a full regeneration: restoring `docs/cms-guidelines/components/*.md` (or externals) from `git checkout`, merge-only, or screenshots-only while leaving years-old prose in place.
|
|
23
|
+
|
|
24
|
+
## When the user is vague
|
|
25
|
+
|
|
26
|
+
Phrases like “regenerate guidelines”, “refresh CMS docs”, “update showcase/guidelines”, or “redo screenshots” are **ambiguous**.
|
|
27
|
+
|
|
28
|
+
**Before doing substantial work, ask briefly:**
|
|
29
|
+
|
|
30
|
+
1. Do you want a **full clean regeneration** (delete existing fragments and screenshots, rewrite every component guideline from scratch, full screenshot pass)?
|
|
31
|
+
2. Or an **incremental** update (sync with registrations — **including removing** dropped types — plus only new/changed types)?
|
|
32
|
+
3. Or something narrower (e.g. **merge-only**, **one component**, **collections CLI only**)?
|
|
33
|
+
|
|
34
|
+
If they insist on “everything” / “from scratch” / “totally regenerate” / “wipe and rebuild”, treat that as **full regeneration** and follow **`fresh`** including the **clean slate** steps below — do **not** shortcut with git-restored fragments.
|
|
35
|
+
|
|
36
|
+
## When to use which mode
|
|
37
|
+
|
|
38
|
+
| Situation | Mode |
|
|
39
|
+
|---|---|
|
|
40
|
+
| New app — no guidelines exist yet | `fresh` |
|
|
41
|
+
| User wants **total** / **full** / **clean-slate** regeneration | `fresh` (must include **clean slate** + full **generate-all-guidelines** Phase 3 for all components) |
|
|
42
|
+
| Types added or removed in `registrations.ts` (incremental) | `sync` — **always** remove stale files and index entries, then add/refresh new types |
|
|
43
|
+
| Fragment files edited manually, combined doc needs rebuild | `merge-only` |
|
|
44
|
+
| Major refactor but user confirms they **do not** need new prose | Rare — confirm explicitly; otherwise use `fresh` |
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Inputs
|
|
49
|
+
|
|
50
|
+
| Input | Example |
|
|
51
|
+
|---|---|
|
|
52
|
+
| App directory (repo-relative or absolute) | `apps/example-se2026` |
|
|
53
|
+
| Port | `3012` |
|
|
54
|
+
| Discovery URL | `http://localhost:3012/api/cms/discovery/` |
|
|
55
|
+
| Mode | `fresh` \| `sync` \| `merge-only` |
|
|
56
|
+
|
|
57
|
+
**App ports:**
|
|
58
|
+
|
|
59
|
+
| App | Port |
|
|
60
|
+
|---|---|
|
|
61
|
+
| example-brightline | 3010 |
|
|
62
|
+
| example-se2026 | 3012 |
|
|
63
|
+
| example-om1 | 3013 |
|
|
64
|
+
| example-empty | 3014 |
|
|
65
|
+
| example-brightlifekids | 3015 |
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Mode: fresh
|
|
70
|
+
|
|
71
|
+
Full pipeline from a **clean slate** (or a brand-new app). Expect roughly **30–90+ minutes** for a typical site (component count × LLM time for Phase B/C/D).
|
|
72
|
+
|
|
73
|
+
### Step 0 — Clean slate (mandatory for true full regeneration)
|
|
74
|
+
|
|
75
|
+
If any guideline or screenshot files already exist, **delete generated guideline outputs** before re-running the pipeline. Otherwise you risk mixed old/new content or skipping work.
|
|
76
|
+
|
|
77
|
+
**Do:**
|
|
78
|
+
|
|
79
|
+
1. Remove per-type fragments:
|
|
80
|
+
`docs/cms-guidelines/components/*.md`, `docs/cms-guidelines/collections/*.md`, `docs/cms-guidelines/externals/*.md`
|
|
81
|
+
**Keep** editorial/meta files if present (e.g. `README.md`, `CHECKLIST.md`, `LAYOUT.md`, `GENERATE_NEXT_*.md`).
|
|
82
|
+
2. Remove merged bundle: `docs/cms-guidelines/COMPONENT_GUIDELINES_FOR_LLM.md`.
|
|
83
|
+
3. Remove screenshots: all `docs/cms-guidelines/screenshots/components/*.png`, `.../collections/*.png`, `.../externals/*.png` (if used), then reset `docs/cms-guidelines/screenshots/index.json` to `[]` **or** delete it so captures recreate it.
|
|
84
|
+
4. Clear showcase pipeline inputs as needed: remove `src/generated/showcase-examples.json`, `src/generated/showcase-mocks-draft.json`, and the tree `src/generated/cms-discovery/accepted-variants/` (or empty `components/` / `collections/` / `externals/` subdirs). Stub `src/generated/showcase-mocks.json` per **curate-showcase-mocks** if the import must compile.
|
|
85
|
+
5. Remove any **duplicate** variant path some apps still have (e.g. `generated/cms-discovery/accepted-variants/` at repo root of the app) if it is not the canonical `src/generated/...` tree.
|
|
86
|
+
6. Optionally reset `generated/cms-discovery/colour-hints.json` if you want colour hints re-derived during Phase C.
|
|
87
|
+
|
|
88
|
+
**Do not** (for a claimed full regeneration):
|
|
89
|
+
|
|
90
|
+
- Restore `docs/cms-guidelines/components/*.md` or `externals/*.md` from git instead of running **generate-all-guidelines Phase 3** (Phase B + C + D per component).
|
|
91
|
+
- Skip collection screenshot capture when collections are registered — Phase 1 must cover **both** components and collections for a complete visual record.
|
|
92
|
+
|
|
93
|
+
After this, run Steps 1–4 in order (prerequisites → showcase mocks → field list → generate-all-guidelines).
|
|
94
|
+
|
|
95
|
+
### Step 1 — Prerequisites
|
|
96
|
+
|
|
97
|
+
Check all of these before starting:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
# 1. Dev server is running
|
|
101
|
+
curl -sL http://localhost:<PORT>/api/cms/discovery/ | head -c 100
|
|
102
|
+
# Should return: {"components":[
|
|
103
|
+
|
|
104
|
+
# 2. agent-browser is installed
|
|
105
|
+
agent-browser --version
|
|
106
|
+
# If missing: npm install -g agent-browser && agent-browser install
|
|
107
|
+
|
|
108
|
+
# 3. Env vars present in <appDir>/.env.local
|
|
109
|
+
grep -E "CONTENTFUL_SPACE_ID|CONTENTFUL_ACCESS_TOKEN|OPENAI_API_KEY|ANTHROPIC_API_KEY" <appDir>/.env.local
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Step 2 — Curate showcase mocks
|
|
113
|
+
|
|
114
|
+
Read and follow the **curate-showcase-mocks** skill:
|
|
115
|
+
`.agents/skills/se-marketing-sites-curate-showcase-mocks/SKILL.md`
|
|
116
|
+
|
|
117
|
+
This produces `src/generated/showcase-mocks.json` (committed) and
|
|
118
|
+
`src/generated/cms-discovery/accepted-variants/{components|collections|externals}/<slug>.json` (often gitignored — **some apps commit them**; follow the app’s `.gitignore`).
|
|
119
|
+
|
|
120
|
+
When complete, confirm:
|
|
121
|
+
- `src/generated/showcase-mocks.json` has non-empty `components` and `collections` keys
|
|
122
|
+
- `src/generated/cms-discovery/accepted-variants/` has `components/` and `collections/` subdirs with JSON files
|
|
123
|
+
|
|
124
|
+
Backfill any registered types missing from the LLM draft using `showcase-examples.json` (see curate skill), and add minimal `accepted-variants` JSON for types with no variant file so screenshot capture can run.
|
|
125
|
+
|
|
126
|
+
### Step 3 — Generate HTML Component Style Guide
|
|
127
|
+
|
|
128
|
+
Generate the design system reference used when authoring `HtmlComponent` entries:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
# From the app directory:
|
|
132
|
+
pnpm run cms-generate-html-style-guide
|
|
133
|
+
# or from repo root:
|
|
134
|
+
pnpm --filter <appName> exec cms-generate-html-style-guide --app-dir .
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Reads `tailwind.config.json` and `src/app/globals.css`; writes `docs/cms-guidelines/html-component-style-guide.md`. No dev server required. Safe to skip if the design system has not changed since the last run.
|
|
138
|
+
|
|
139
|
+
### Step 4 — Generate field list
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
# From the app directory:
|
|
143
|
+
pnpm run cms-discovery:field-list
|
|
144
|
+
# or from repo root:
|
|
145
|
+
pnpm --filter <appName> exec cms-generate-field-list --app-dir .
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Produces `generated/cms-discovery/field-list.json` (discovery API reads from this path). Some apps use `src/generated/` for showcase artifacts; see app docs.
|
|
149
|
+
|
|
150
|
+
### Step 5 — Run generate-all-guidelines
|
|
151
|
+
|
|
152
|
+
Read and follow the **generate-all-guidelines** skill:
|
|
153
|
+
`.agents/skills/contentful-cms-generate-all-guidelines/SKILL.md`
|
|
154
|
+
|
|
155
|
+
Skip its prerequisite check (you already verified everything through Step 4).
|
|
156
|
+
Run Phases 0–5 from that skill with **full regeneration rules**:
|
|
157
|
+
|
|
158
|
+
- **Phase 0** — Discover types; **do not** skip components that already had old fragments (there should be none after clean slate).
|
|
159
|
+
- **Phase 1** — Bulk screenshot capture for **all components**, then **all collections** (and externals if your app captures them).
|
|
160
|
+
- **Phase 2** — Collections + externals (`cms-generate-collection-guidelines`)
|
|
161
|
+
- **Phase 3** — Component guidelines (**every** type: Phase B + C + D; **overwrite** `components/<slug>.md`)
|
|
162
|
+
- **Phase 4** — Merge (`cms-merge-guidelines`)
|
|
163
|
+
- **Phase 5** — Commit
|
|
164
|
+
|
|
165
|
+
### After Phase 2 (externals)
|
|
166
|
+
|
|
167
|
+
If any `docs/cms-guidelines/externals/<slug>.md` stubs were created, fill in their
|
|
168
|
+
`## Fields & Schema` and `## Usage` sections before committing. See the
|
|
169
|
+
**generate-cms-guidelines** skill (`Step 2b`) for guidance on what to put in these sections.
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Mode: sync
|
|
174
|
+
|
|
175
|
+
Use when types have been added or removed in `registrations.ts` (or from the Contentful space).
|
|
176
|
+
This mode diffs the current registered types against existing guideline files and handles both
|
|
177
|
+
stale files and new types.
|
|
178
|
+
|
|
179
|
+
**Incremental is not “append only”.** If a type left registrations or discovery, you **must** remove its artifacts (markdown, PNGs, index rows, optional `accepted-variants` files). Otherwise the repo and `COMPONENT_GUIDELINES_FOR_LLM.md` will lie.
|
|
180
|
+
|
|
181
|
+
### Phase 0 — Diff
|
|
182
|
+
|
|
183
|
+
Fetch the discovery endpoint and compute the current set of registered type slugs:
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
curl -sL http://localhost:<PORT>/api/cms/discovery/ > /tmp/discovery.json
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Slug formula: `name.toLowerCase().replace(/\s+/g, '-').replace(/[()]/g, '')`
|
|
190
|
+
|
|
191
|
+
Examples: `"Article Browser Sticky"` → `article-browser-sticky`, `"Two Column (Rich Text)"` → `two-column-rich-text`
|
|
192
|
+
|
|
193
|
+
Build three diff lists by comparing discovery slugs against existing files:
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
# List existing guideline file slugs (strip .md extension)
|
|
197
|
+
ls <appDir>/docs/cms-guidelines/components/ # → component file slugs
|
|
198
|
+
ls <appDir>/docs/cms-guidelines/collections/ # → collection file slugs
|
|
199
|
+
ls <appDir>/docs/cms-guidelines/externals/ # → external file slugs
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
From the diff, identify:
|
|
203
|
+
|
|
204
|
+
| Status | Meaning | Action |
|
|
205
|
+
|---|---|---|
|
|
206
|
+
| **STALE** | File exists, type not in discovery | Remove files |
|
|
207
|
+
| **NEW** | Type in discovery, no file exists | Generate guidelines |
|
|
208
|
+
| **UNCHANGED** | Both exist | Skip |
|
|
209
|
+
|
|
210
|
+
Report the full diff to the user before taking any action.
|
|
211
|
+
|
|
212
|
+
### Phase 1 — Remove stale files
|
|
213
|
+
|
|
214
|
+
For each **stale component** slug (`<slug>`):
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
# 1. Delete the guideline fragment
|
|
218
|
+
rm <appDir>/docs/cms-guidelines/components/<slug>.md
|
|
219
|
+
|
|
220
|
+
# 2. Delete all screenshot variants (screenshots live under components/ or collections/ subdirs)
|
|
221
|
+
rm -f <appDir>/docs/cms-guidelines/screenshots/components/<slug>-*.png
|
|
222
|
+
rm -f <appDir>/docs/cms-guidelines/screenshots/collections/<slug>-*.png
|
|
223
|
+
|
|
224
|
+
# 3. Remove screenshot index entries for this type (index.json has typeName and file e.g. "components/<slug>-default.png")
|
|
225
|
+
# Read screenshots/index.json, filter out entries where typeName matches or file starts with "components/<slug>-" or "collections/<slug>-", rewrite
|
|
226
|
+
node -e "
|
|
227
|
+
const fs = require('node:fs');
|
|
228
|
+
const p = '<appDir>/docs/cms-guidelines/screenshots/index.json';
|
|
229
|
+
const idx = JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
230
|
+
const filtered = idx.filter(e => !e.file.startsWith('components/<slug>-') && !e.file.startsWith('collections/<slug>-'));
|
|
231
|
+
fs.writeFileSync(p, JSON.stringify(filtered, null, 2));
|
|
232
|
+
console.log('Removed', idx.length - filtered.length, 'entries for <slug>');
|
|
233
|
+
"
|
|
234
|
+
|
|
235
|
+
# 4. Remove accepted-variants file if present (check both components/ and collections/)
|
|
236
|
+
rm -f <appDir>/src/generated/cms-discovery/accepted-variants/components/<slug>.json
|
|
237
|
+
rm -f <appDir>/src/generated/cms-discovery/accepted-variants/collections/<slug>.json
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
For each **stale collection** slug (`<slug>`):
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
# 1. Fragment
|
|
244
|
+
rm <appDir>/docs/cms-guidelines/collections/<slug>.md
|
|
245
|
+
|
|
246
|
+
# 2. Screenshots for that collection
|
|
247
|
+
rm -f <appDir>/docs/cms-guidelines/screenshots/collections/<slug>-*.png
|
|
248
|
+
|
|
249
|
+
# 3. Remove index entries (same pattern as components — filter by file prefix)
|
|
250
|
+
# e.g. drop rows where e.file.startsWith('collections/<slug>-')
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Use the same **index.json** filtering approach as for stale components (adjust the `startsWith` prefix to `collections/<slug>-`).
|
|
254
|
+
|
|
255
|
+
For each **stale external** slug:
|
|
256
|
+
|
|
257
|
+
> **Caution:** External guideline files contain hand-authored schema documentation. Confirm
|
|
258
|
+
> with the user before deleting. If confirmed:
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
rm <appDir>/docs/cms-guidelines/externals/<slug>.md
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Phase 2 — Add new types
|
|
265
|
+
|
|
266
|
+
**New components** (one or more):
|
|
267
|
+
|
|
268
|
+
Run the [generate-all-guidelines](../generate-all-guidelines/SKILL.md) skill's Phase 1 (screenshots)
|
|
269
|
+
and Phase 3 (component subagents) for **only the new types**, then skip to Phase 4 (merge).
|
|
270
|
+
|
|
271
|
+
If the new component does not yet have an `accepted-variants/components/<slug>.json` file (or `collections/<slug>.json` for a collection), run:
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
pnpm --filter <appName> generate-showcase-mocks -- --types "<Type Name 1>,<Type Name 2>"
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
This regenerates the variant file for just those types. Then capture screenshots and run the
|
|
278
|
+
Phase 3 subagent prompt as described in generate-all-guidelines.
|
|
279
|
+
|
|
280
|
+
**New collections or externals:**
|
|
281
|
+
|
|
282
|
+
Re-running the generator is safe — it always overwrites collections and only creates externals
|
|
283
|
+
if the file does not already exist:
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
cms-generate-collection-guidelines \
|
|
287
|
+
--discovery-url http://localhost:<PORT>/api/cms/discovery/ \
|
|
288
|
+
--app-dir <appDir>
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
If a new external stub was created, fill in its `## Fields & Schema` and `## Usage` sections
|
|
292
|
+
before committing (see Mode: fresh → After Phase 2).
|
|
293
|
+
|
|
294
|
+
### Phase 3 — Merge and commit
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
# Rebuild the combined document
|
|
298
|
+
cms-merge-guidelines --app-dir <appDir>
|
|
299
|
+
# or: pnpm --filter <appName> run cms-guidelines:merge
|
|
300
|
+
|
|
301
|
+
# Commit everything
|
|
302
|
+
git add <appDir>/docs/cms-guidelines/ <appDir>/src/generated/cms-discovery/
|
|
303
|
+
git commit -m "chore(<appName>): sync CMS guidelines with registrations"
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## Mode: merge-only
|
|
309
|
+
|
|
310
|
+
Rebuilds `docs/cms-guidelines/COMPONENT_GUIDELINES_FOR_LLM.md` from all existing fragment files.
|
|
311
|
+
Use after manual edits to fragment files, or after any of the other modes if the combined doc
|
|
312
|
+
looks stale.
|
|
313
|
+
|
|
314
|
+
```bash
|
|
315
|
+
cms-merge-guidelines --app-dir <appDir>
|
|
316
|
+
# or from the app directory:
|
|
317
|
+
pnpm run cms-guidelines:merge
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
## Output files (reference)
|
|
323
|
+
|
|
324
|
+
All under `<appDir>`:
|
|
325
|
+
|
|
326
|
+
| File | Description | Committed |
|
|
327
|
+
|---|---|---|
|
|
328
|
+
| `docs/cms-guidelines/components/<slug>.md` | Per-component fragment | Yes |
|
|
329
|
+
| `docs/cms-guidelines/collections/<slug>.md` | Per-collection fragment | Yes |
|
|
330
|
+
| `docs/cms-guidelines/externals/<slug>.md` | Per-external fragment | Yes |
|
|
331
|
+
| `docs/cms-guidelines/screenshots/index.json` | Screenshot index | Yes |
|
|
332
|
+
| `docs/cms-guidelines/screenshots/{components\|collections\|externals}/*.png` | Screenshot images | Yes |
|
|
333
|
+
| `docs/cms-guidelines/COMPONENT_GUIDELINES_FOR_LLM.md` | Merged document (AI-readable) | Yes |
|
|
334
|
+
| `generated/cms-discovery/field-list.json` | Field metadata (discovery API) | Yes |
|
|
335
|
+
| `src/generated/showcase-mocks.json` | Curated showcase mocks | Yes |
|
|
336
|
+
| `src/generated/cms-discovery/accepted-variants/{components\|collections\|externals}/<slug>.json` | Variant files (per type) | Usually no (app-dependent) |
|
|
337
|
+
| `src/generated/showcase-examples.json` | Raw Contentful data dump | No |
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
## Sub-skills reference
|
|
342
|
+
|
|
343
|
+
| Purpose | Skill |
|
|
344
|
+
|---|---|
|
|
345
|
+
| Curate showcase mocks (Step 2 of `fresh`) | `.agents/skills/se-marketing-sites-curate-showcase-mocks/SKILL.md` |
|
|
346
|
+
| Full-site bulk generation (Step 4 of `fresh`: Phases 0–5) | `.agents/skills/contentful-cms-generate-all-guidelines/SKILL.md` |
|
|
347
|
+
| Single-type regeneration (after code change) | `.agents/skills/contentful-cms-generate-cms-guidelines/SKILL.md` (mode: single) |
|
|
348
|
+
| Per-component pipeline detail | `packages/skills/skills/contentful-cms-cms-guidelines/generate-component-guidelines.md` |
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: performance-audit
|
|
3
|
+
description: >
|
|
4
|
+
Measure and improve Next.js app performance: bundle analysis, Lighthouse,
|
|
5
|
+
and real-user monitoring. Generic — works with any Next.js deployment on Vercel.
|
|
6
|
+
metadata:
|
|
7
|
+
author: se-core-product
|
|
8
|
+
version: "1.0.0"
|
|
9
|
+
priority: 5
|
|
10
|
+
promptSignals:
|
|
11
|
+
phrases:
|
|
12
|
+
- performance
|
|
13
|
+
- lighthouse
|
|
14
|
+
- bundle size
|
|
15
|
+
- bundle analysis
|
|
16
|
+
- LCP
|
|
17
|
+
- core web vitals
|
|
18
|
+
- CWV
|
|
19
|
+
- speed insights
|
|
20
|
+
- page speed
|
|
21
|
+
- slow pages
|
|
22
|
+
- optimize performance
|
|
23
|
+
- analyse bundle
|
|
24
|
+
- analyze bundle
|
|
25
|
+
- web vitals
|
|
26
|
+
retrieval:
|
|
27
|
+
aliases:
|
|
28
|
+
- perf
|
|
29
|
+
- web vitals
|
|
30
|
+
- bundle
|
|
31
|
+
- lighthouse audit
|
|
32
|
+
- performance measurement
|
|
33
|
+
intents:
|
|
34
|
+
- measure page performance
|
|
35
|
+
- analyze bundle sizes
|
|
36
|
+
- improve Lighthouse scores
|
|
37
|
+
- set up performance tooling
|
|
38
|
+
- investigate slow LCP
|
|
39
|
+
- add speed insights
|
|
40
|
+
- run bundle analyzer
|
|
41
|
+
entities:
|
|
42
|
+
- LCP
|
|
43
|
+
- CLS
|
|
44
|
+
- TBT
|
|
45
|
+
- TTFB
|
|
46
|
+
- FCP
|
|
47
|
+
- bundle analyzer
|
|
48
|
+
- Lighthouse
|
|
49
|
+
- Speed Insights
|
|
50
|
+
- Core Web Vitals
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
# Next.js Performance Audit
|
|
54
|
+
|
|
55
|
+
## Overview — Three-layer measurement strategy
|
|
56
|
+
|
|
57
|
+
Always use all three layers. Bundle size ≠ Lighthouse score ≠ real-user experience.
|
|
58
|
+
|
|
59
|
+
| Layer | Tool | What it measures | When to use |
|
|
60
|
+
|---|---|---|---|
|
|
61
|
+
| Bundle | `@next/bundle-analyzer` | JS/CSS weight by package, lazy vs eager chunks | Before/after any dependency or code change |
|
|
62
|
+
| Lab | Lighthouse | CWV scores in controlled conditions | Before deploying an optimisation |
|
|
63
|
+
| Field | Vercel Speed Insights | Real-user CWV on production | Ongoing monitoring post-deploy |
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Phase 1 — Bundle Analysis
|
|
68
|
+
|
|
69
|
+
### Setup (if not already present)
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
pnpm add -D @next/bundle-analyzer
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
In `next.config.ts`, wrap the export:
|
|
76
|
+
```ts
|
|
77
|
+
import bundleAnalyzer from '@next/bundle-analyzer';
|
|
78
|
+
const withBundleAnalyzer = bundleAnalyzer({ enabled: process.env.ANALYZE === 'true' });
|
|
79
|
+
export default withBundleAnalyzer(nextConfig);
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Add script to `package.json`:
|
|
83
|
+
```json
|
|
84
|
+
"analyze": "ANALYZE=true next build"
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Run
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
pnpm analyze
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Opens `client.html`, `nodejs.html`, `edge.html` in `.next/analyze/`. The treemap shows every package in every chunk with parsed and gzip sizes.
|
|
94
|
+
|
|
95
|
+
### What to look for
|
|
96
|
+
|
|
97
|
+
**Good:**
|
|
98
|
+
- Heavy libraries (video players, animation libraries, charting) appear as separate lazy chunks — they're only loaded when needed.
|
|
99
|
+
|
|
100
|
+
**Investigate:**
|
|
101
|
+
- Any package >30 KB gzip in the first-load chunks that isn't React or Next.js internals.
|
|
102
|
+
- Libraries that should be server-only (e.g. CMS SDKs, data parsers) appearing in client bundles.
|
|
103
|
+
- The same library duplicated across multiple chunks at different versions.
|
|
104
|
+
|
|
105
|
+
**Node.js SSR bundle (`nodejs.html`):**
|
|
106
|
+
Large client-only packages here inflate server cold-start time. Check for missing `'use client'` boundaries.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Phase 2 — Lighthouse
|
|
111
|
+
|
|
112
|
+
### Prerequisites
|
|
113
|
+
|
|
114
|
+
| Node version | Lighthouse version |
|
|
115
|
+
|---|---|
|
|
116
|
+
| 20.18.x | `lighthouse@12` (`npm i -g lighthouse@12`) |
|
|
117
|
+
| 20.19+ or 22+ | `lighthouse@13` |
|
|
118
|
+
|
|
119
|
+
Chrome path:
|
|
120
|
+
- Linux / WSL: `/usr/bin/google-chrome`
|
|
121
|
+
- macOS: Lighthouse finds it automatically
|
|
122
|
+
|
|
123
|
+
### Run against key page types
|
|
124
|
+
|
|
125
|
+
Substitute `<SITE_URL>` with the production (or preview) domain.
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
mkdir -p .lighthouse
|
|
129
|
+
|
|
130
|
+
# Homepage
|
|
131
|
+
npx lighthouse@12 <SITE_URL>/ \
|
|
132
|
+
--chrome-path /usr/bin/google-chrome \
|
|
133
|
+
--chrome-flags="--headless=new --no-sandbox --disable-gpu --disable-dev-shm-usage" \
|
|
134
|
+
--only-categories=performance,accessibility,best-practices,seo \
|
|
135
|
+
--output json --output-path .lighthouse/home.json --quiet
|
|
136
|
+
|
|
137
|
+
# A list or index page
|
|
138
|
+
npx lighthouse@12 <SITE_URL>/blog/ \
|
|
139
|
+
--chrome-path /usr/bin/google-chrome \
|
|
140
|
+
--chrome-flags="--headless=new --no-sandbox --disable-gpu --disable-dev-shm-usage" \
|
|
141
|
+
--only-categories=performance,accessibility,best-practices,seo \
|
|
142
|
+
--output json --output-path .lighthouse/list.json --quiet
|
|
143
|
+
|
|
144
|
+
# A detail page (pick a URL from the sitemap)
|
|
145
|
+
npx lighthouse@12 <DETAIL_URL> \
|
|
146
|
+
--chrome-path /usr/bin/google-chrome \
|
|
147
|
+
--chrome-flags="--headless=new --no-sandbox --disable-gpu --disable-dev-shm-usage" \
|
|
148
|
+
--only-categories=performance,accessibility,best-practices,seo \
|
|
149
|
+
--output json --output-path .lighthouse/detail.json --quiet
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
To find page URLs: `curl -s <SITE_URL>/sitemap.xml | grep -oP 'https://[^<]+'`
|
|
153
|
+
|
|
154
|
+
### Extract scores from JSON
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
node -e "
|
|
158
|
+
const pages = ['home','list','detail'];
|
|
159
|
+
pages.forEach(p => {
|
|
160
|
+
try {
|
|
161
|
+
const d = JSON.parse(require('fs').readFileSync('.lighthouse/' + p + '.json', 'utf8'));
|
|
162
|
+
const c = d.categories;
|
|
163
|
+
const a = d.audits;
|
|
164
|
+
console.log(p.padEnd(10),
|
|
165
|
+
'Perf:', Math.round(c.performance.score * 100),
|
|
166
|
+
'| LCP:', (a['largest-contentful-paint'].numericValue / 1000).toFixed(2) + 's',
|
|
167
|
+
'| CLS:', a['cumulative-layout-shift'].numericValue.toFixed(3),
|
|
168
|
+
'| TBT:', Math.round(a['total-blocking-time'].numericValue) + 'ms',
|
|
169
|
+
'| TTFB:', Math.round(a['server-response-time'].numericValue) + 'ms'
|
|
170
|
+
);
|
|
171
|
+
} catch(e) { console.log(p + ': not found'); }
|
|
172
|
+
});
|
|
173
|
+
"
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Targets
|
|
177
|
+
|
|
178
|
+
| Metric | Target | Fail threshold |
|
|
179
|
+
|---|---|---|
|
|
180
|
+
| LCP | < 2.5s | > 4s |
|
|
181
|
+
| CLS | < 0.1 | > 0.25 |
|
|
182
|
+
| TBT | < 200ms | > 600ms |
|
|
183
|
+
| TTFB | < 600ms | > 1800ms |
|
|
184
|
+
| FCP | < 1.8s | > 3s |
|
|
185
|
+
|
|
186
|
+
### Key diagnostic signal
|
|
187
|
+
|
|
188
|
+
If a simple page (e.g. About) scores 90+ but heavier pages score < 80, the delta is almost always media loading or third-party scripts present only on those pages.
|
|
189
|
+
|
|
190
|
+
If all pages score similarly low, the issue is in the shared layout — fonts, analytics scripts, or global CSS.
|
|
191
|
+
|
|
192
|
+
### Extracting opportunities
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
node -e "
|
|
196
|
+
const d = JSON.parse(require('fs').readFileSync('.lighthouse/home.json', 'utf8'));
|
|
197
|
+
const a = d.audits;
|
|
198
|
+
|
|
199
|
+
console.log('=== LARGEST PAYLOADS ===');
|
|
200
|
+
(a['total-byte-weight']?.details?.items || []).slice(0, 8).forEach(i =>
|
|
201
|
+
console.log(' ' + ((i.totalBytes||0)/1024).toFixed(0).padStart(6) + 'KB | ' + (i.url||'').substring(0,90))
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
console.log('\n=== UNUSED JS ===');
|
|
205
|
+
(a['unused-javascript']?.details?.items || []).slice(0, 6).forEach(i =>
|
|
206
|
+
console.log(' ' + ((i.wastedBytes||0)/1024).toFixed(0).padStart(6) + 'KB | ' + (i.url||'').substring(0,90))
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
console.log('\n=== RENDER BLOCKING ===');
|
|
210
|
+
(a['render-blocking-resources']?.details?.items || []).forEach(i =>
|
|
211
|
+
console.log(' ' + Math.round(i.wastedMs||0) + 'ms | ' + (i.url||'').substring(0,90))
|
|
212
|
+
);
|
|
213
|
+
"
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Phase 3 — Real-User Monitoring (Speed Insights)
|
|
219
|
+
|
|
220
|
+
### Setup
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
pnpm add @vercel/speed-insights
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Add to the **root layout** (`src/app/layout.tsx`) — must be root, not a route group layout:
|
|
227
|
+
```tsx
|
|
228
|
+
import { SpeedInsights } from '@vercel/speed-insights/next';
|
|
229
|
+
|
|
230
|
+
// Inside <body>:
|
|
231
|
+
<SpeedInsights />
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Deploy to production. View in **Vercel dashboard → Speed Insights**.
|
|
235
|
+
|
|
236
|
+
Data appears within minutes of the first production visit. Field data reflects real network conditions and will differ from Lighthouse's simulated throttling.
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## Common Fixes
|
|
241
|
+
|
|
242
|
+
### Fix 1: Heavy libraries loading on every page
|
|
243
|
+
|
|
244
|
+
**Symptom**: Lighthouse flags large unused JS. Bundle analyzer shows a library in first-load chunks but it's only used on specific pages/routes.
|
|
245
|
+
|
|
246
|
+
**Fix** — Use dynamic import with `next/dynamic` or native `import()` inside `useEffect`:
|
|
247
|
+
```tsx
|
|
248
|
+
// next/dynamic (renders a component lazily)
|
|
249
|
+
import dynamic from 'next/dynamic';
|
|
250
|
+
const HeavyComponent = dynamic(() => import('./HeavyComponent'), { ssr: false });
|
|
251
|
+
|
|
252
|
+
// Conditional import in useEffect (for web components / side-effect-only libraries)
|
|
253
|
+
useEffect(() => {
|
|
254
|
+
if (document.querySelector('my-web-component')) {
|
|
255
|
+
import('my-web-component-library');
|
|
256
|
+
}
|
|
257
|
+
}, []);
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
### Fix 2: Render-blocking third-party scripts
|
|
263
|
+
|
|
264
|
+
**Symptom**: GTM, consent scripts, or analytics tags appear in the Lighthouse render-blocking or TBT audits.
|
|
265
|
+
|
|
266
|
+
**Fix** — Use Next.js `<Script>` with appropriate strategy. Requires `'use client'`:
|
|
267
|
+
```tsx
|
|
268
|
+
'use client';
|
|
269
|
+
import Script from 'next/script';
|
|
270
|
+
|
|
271
|
+
// Load after page becomes interactive (GTM, analytics)
|
|
272
|
+
<Script src="https://www.googletagmanager.com/gtm.js?id=..." strategy="afterInteractive" />
|
|
273
|
+
|
|
274
|
+
// Load during browser idle time (consent banners, low-priority widgets)
|
|
275
|
+
<Script src="https://cdn.example.com/widget.js" strategy="lazyOnload" />
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
### Fix 3: Legacy JS polyfills inflating bundle
|
|
281
|
+
|
|
282
|
+
**Symptom**: Lighthouse legacy-JavaScript audit flags `Array.prototype.at`, `.flat`, `.flatMap` being polyfilled.
|
|
283
|
+
|
|
284
|
+
**Fix** — Create `.browserslistrc` at the project root:
|
|
285
|
+
```
|
|
286
|
+
last 2 Chrome versions
|
|
287
|
+
last 2 Firefox versions
|
|
288
|
+
last 2 Safari versions
|
|
289
|
+
last 2 Edge versions
|
|
290
|
+
not dead
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
Verify audience browser share before applying — check analytics for any legacy traffic.
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
### Fix 4: Visuals without dimensions causing CLS
|
|
298
|
+
|
|
299
|
+
**Symptom**: CLS > 0.1. Lighthouse "Avoid large layout shifts" audit lists image or media elements.
|
|
300
|
+
|
|
301
|
+
**Fix** — Always set explicit `width` and `height` on `<img>` and `<video>` elements, or use `aspect-ratio` CSS on their container so the browser can reserve space before the asset loads:
|
|
302
|
+
```tsx
|
|
303
|
+
<div style={{ aspectRatio: '16 / 9' }}>
|
|
304
|
+
<video ... />
|
|
305
|
+
</div>
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## Tracking baselines
|
|
311
|
+
|
|
312
|
+
Save Lighthouse JSON to `.lighthouse/<page>.json`. After each round of fixes, save to `.lighthouse/<page>-v2.json`, `v3.json`, etc.
|
|
313
|
+
|
|
314
|
+
Compare LCP across versions:
|
|
315
|
+
```bash
|
|
316
|
+
node -e "
|
|
317
|
+
const v1 = JSON.parse(require('fs').readFileSync('.lighthouse/home.json','utf8'));
|
|
318
|
+
const v2 = JSON.parse(require('fs').readFileSync('.lighthouse/home-v2.json','utf8'));
|
|
319
|
+
const lcp = a => (a.audits['largest-contentful-paint'].numericValue/1000).toFixed(2)+'s';
|
|
320
|
+
const perf = a => Math.round(a.categories.performance.score * 100);
|
|
321
|
+
console.log('Home LCP: v1=' + lcp(v1) + ' → v2=' + lcp(v2));
|
|
322
|
+
console.log('Home Perf: v1=' + perf(v1) + ' → v2=' + perf(v2));
|
|
323
|
+
"
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
Commit `.lighthouse/` to git for team-visible historical baselines.
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
## Troubleshooting
|
|
331
|
+
|
|
332
|
+
| Error | Cause | Fix |
|
|
333
|
+
|---|---|---|
|
|
334
|
+
| `Unable to connect to Chrome` | Lighthouse can't find Chrome binary | Add `--chrome-path /usr/bin/google-chrome` |
|
|
335
|
+
| Lighthouse fails on Node 20.18.x | Requires lighthouse@12 | Use `npm i -g lighthouse@12` |
|
|
336
|
+
| `ANALYZE=true next build` fails | `next.config.ts` export not wrapped | Ensure `export default withBundleAnalyzer(nextConfig)` |
|
|
337
|
+
| Speed Insights shows no data | Wrong layout, or not deployed to production | Must be in root `src/app/layout.tsx`; requires production traffic |
|
|
338
|
+
| Lighthouse score varies between runs | CPU/network simulation variability | Run 3× and average; use `--throttling-method=provided` for stable local results |
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## See also
|
|
343
|
+
|
|
344
|
+
- **SE Studio stack**: if the project uses `@se-studio/core-ui`, Contentful CMS, or ImageKit, see the SE-Studio-specific performance-audit skill for additional fixes (lazy video/animation loading, variable font subsetting, lottie-player optimisation).
|