@webikon/webentor-codemods 0.1.0 → 0.3.0

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.
Files changed (30) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/README.md +71 -13
  3. package/bin/webentor-codemods.mjs +27 -2
  4. package/lib/changelog.mjs +87 -0
  5. package/migrations/0.13.0/README.md +11 -0
  6. package/migrations/0.13.0/changelog/root.md +8 -0
  7. package/migrations/0.13.0/changelog/theme.md +7 -0
  8. package/migrations/0.15.0/README.md +130 -0
  9. package/migrations/0.15.0/changelog/root.md +11 -0
  10. package/migrations/0.15.0/changelog/theme.md +8 -0
  11. package/migrations/0.15.0/rules/app-glob-vite8.yml +32 -0
  12. package/migrations/0.15.0/rules/deps.yml +83 -0
  13. package/migrations/__fixtures__/0.15.0/after/composer.json +63 -0
  14. package/migrations/__fixtures__/0.15.0/after/package.json +86 -0
  15. package/migrations/__fixtures__/0.15.0/after/resources/scripts/app.ts +19 -0
  16. package/migrations/__fixtures__/0.15.0/before/composer.json +63 -0
  17. package/migrations/__fixtures__/0.15.0/before/package.json +86 -0
  18. package/migrations/__fixtures__/0.15.0/before/resources/scripts/app.ts +15 -0
  19. package/migrations/__fixtures__/0.15.0/customized/composer.json +63 -0
  20. package/migrations/__fixtures__/0.15.0/customized/package.json +86 -0
  21. package/migrations/__fixtures__/0.15.0/customized/resources/scripts/app.ts +22 -0
  22. package/migrations/__fixtures__/starter-2.1.1/after/composer.json +63 -0
  23. package/migrations/__fixtures__/starter-2.1.1/before/composer.json +63 -0
  24. package/migrations/__fixtures__/starter-2.1.1/customized/composer.json +55 -0
  25. package/migrations/index.json +36 -0
  26. package/migrations/starter-2.1.1/README.md +95 -0
  27. package/migrations/starter-2.1.1/changelog/root.md +7 -0
  28. package/migrations/starter-2.1.1/changelog/theme.md +7 -0
  29. package/migrations/starter-2.1.1/rules/deps.yml +24 -0
  30. package/package.json +3 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,51 @@
1
1
  # Webentor Codemods Changelog
2
2
 
3
+ ## 0.3.0
4
+
5
+ - Add the `starter-2.1.1` migration (theme **2.1.0 → 2.1.1**, **Acorn 6 / Laravel
6
+ 13**) — the first **package-scoped** migration (`appliesTo.package:
7
+ webentor-starter`), selectable by id or `--package webentor-starter`. It does
8
+ **not** bump `webentor-core`.
9
+ - `deps.yml` (JSON): rewrites the theme's `composer.json` `roots/acorn` to `^6.0`.
10
+ This is the complete dependency delta from the 2.1.0 baseline — `roots/acorn` is
11
+ the only change; `webikon/webentor-core` stays `^0.15` (it already covers the
12
+ transparent `0.15.1` patch). Scoped to `composer.json` (the project root
13
+ `composer.json` has no `roots/acorn`), value-is-string guarded, idempotent.
14
+ - Changelog sync prepends the `2.1.1` block to the project root `changelog.md`
15
+ (marker `### 2.1.1`) and the theme `web/app/themes/*/changelog.md` (marker
16
+ `### Version 2.1.1`), matching the coupled starter + theme `2.1.1` bump.
17
+ - The Acorn 6 `.env` runtime changes (pin `CACHE_PREFIX`/`SESSION_COOKIE`/
18
+ `REDIS_PREFIX` to preserve caches/sessions; rename `MAIL_ENCRYPTION` →
19
+ `MAIL_SCHEME`) are a documented manual step (see the migration README).
20
+
21
+ ## 0.2.0
22
+
23
+ - **New capability — changelog sync.** A migration can now declare a `changelog`
24
+ block (in `index.json`) that prepends a release's version section to a consumer
25
+ project's root `changelog.md` and theme `web/app/themes/*/changelog.md`, under the
26
+ `# … Changelog` H1, so they stay up to date and match the stack. Idempotent (skips
27
+ if the version heading is already present), additive (never clobbers existing
28
+ entries), and conservative (missing targets are reported, not created). It's plain
29
+ Markdown insertion (`lib/changelog.mjs`), not ast-grep. The `0.13.0` migration
30
+ syncs the `2.0.7` blocks and `0.15.0` syncs the `2.1.0` blocks, so a range run
31
+ (`run --since …`) accumulates the full history.
32
+ - Add the `0.15.0` migration (webentor-core 0.13 → 0.15 — the **Vite 8 / Rolldown**
33
+ toolchain move), with two automated rule sets plus one documented manual step:
34
+ - `deps.yml` (JSON): rewrites the theme's `package.json` + `composer.json` to the
35
+ 0.15.0 baseline — `webentor-core` `^0.15`, `vite` `^8`, `@roots/vite-plugin`
36
+ `^2.2.0`, `@vitejs/plugin-react` `^6`, `laravel-vite-plugin` `^3`,
37
+ `@webikon/webentor-configs` `^1.1.0`. This is the complete dependency delta from
38
+ the 0.13.0 baseline (only the Vite-8 toolchain ranges changed).
39
+ - `app-glob-vite8.yml` (TS): adds `{ eager: true, query: '?url', import: 'default' }`
40
+ to the static-asset `import.meta.glob(['../images/**', '../fonts/**'])` in
41
+ `resources/scripts/app.ts` (a bare glob no longer emits assets under Rolldown).
42
+ Conservative — only the single-argument asset glob matches; unrelated globs and
43
+ the already-migrated form are untouched.
44
+ - The `vite.config.js` WordPress-externals rewrite (now
45
+ `...wordpressExternals(command)` from `@webikon/webentor-configs/vite`) is too
46
+ project-specific to codemod safely and is documented as a manual before→after in
47
+ `migrations/0.15.0/README.md`.
48
+
3
49
  ## 0.1.0
4
50
 
5
51
  - Initial release of `@webikon/webentor-codemods` — a reusable, ast-grep–powered
package/README.md CHANGED
@@ -37,23 +37,71 @@ applying, rebuild the theme and clear caches (`wp acorn optimize:clear`).
37
37
 
38
38
  ## Available migrations
39
39
 
40
- Migrations are **named by the webentor-core version** they bring you to — the id
41
- *is* the target version, so "run the 0.13.0 codemod" reads literally.
42
-
43
- | id | core | what |
40
+ | id | scope | what |
44
41
  | --- | --- | --- |
45
- | `0.13.0` | 0.12 → 0.13 | WP 7.0 iframe editor-asset enqueue change (`app/setup.php`) + the full dependency bump set (`package.json` + `composer.json`) |
42
+ | `0.13.0` | core 0.12 → 0.13 | WP 7.0 iframe editor-asset enqueue change (`app/setup.php`) + the full dependency bump set (`package.json` + `composer.json`) + changelog sync (2.0.7) |
43
+ | `0.15.0` | core 0.13 → 0.15 | Vite 8 / Rolldown: dependency bumps (`package.json` + `composer.json`) + the static-asset `import.meta.glob` fix (`resources/scripts/app.ts`) + changelog sync (2.1.0). The `vite.config.js` externals rewrite is a documented manual step. |
46
44
 
47
45
  See each migration's `migrations/<id>/README.md` for before/after detail.
48
46
 
47
+ ### Naming convention
48
+
49
+ A migration's `id` encodes the **package** it upgrades and the **target version**:
50
+
51
+ - **webentor-core** migrations use the **bare core version** — `0.13.0`, `0.15.0`.
52
+ Core is the primary package (it's the default for `run --since`), so "run the
53
+ 0.13.0 codemod" reads literally. These also set `appliesTo.package: "webentor-core"`.
54
+ - **Other packages** use a **`<package>-<version>`** prefix — e.g. `starter-2.1.1`
55
+ for a webentor-starter-only release that doesn't bump core. These set
56
+ `appliesTo.package` accordingly (e.g. `"webentor-starter"`).
57
+
58
+ This keeps the two numbering schemes from colliding (core `0.x` vs starter `2.x`)
59
+ and makes a migration's package obvious from its id.
60
+
61
+ #### Package-scoped runs
62
+
63
+ A migration can be **changelog-only / tooling-only** — it needs *either* ast-grep
64
+ `rules` *or* a `changelog` block, not both, so a starter release with no code
65
+ rewrites is valid. Select package-scoped migrations the same way as core ones:
66
+
67
+ ```sh
68
+ # by id (any package)
69
+ pnpm dlx @webikon/webentor-codemods run starter-2.1.1
70
+
71
+ # by version range — note --package (defaults to webentor-core)
72
+ pnpm dlx @webikon/webentor-codemods run --since 2.1.0 --package webentor-starter --apply
73
+ ```
74
+
75
+ ## Changelog sync
76
+
77
+ Besides code rewrites, a migration can keep a consumer project's **changelogs**
78
+ up to date with the stack. A project generated from the starter has a root
79
+ `changelog.md` and a theme `web/app/themes/<theme>/changelog.md` that mirror the
80
+ Webentor baseline — running a migration prepends that release's version block to
81
+ them (under the `# … Changelog` H1), so they read exactly like the stack's.
82
+
83
+ - **Idempotent:** if the version heading is already present, the file is skipped.
84
+ - **Additive:** the block is inserted above existing entries; nothing is removed.
85
+ Project-specific entries you added stay put.
86
+ - **Conservative:** if a target changelog isn't found, it's reported and skipped
87
+ (never created from scratch).
88
+ - Runs as part of `run <id>` / `run --since …` — dry-run prints the block it would
89
+ insert; `--apply` writes it. Running a version *range* accumulates each release's
90
+ block in order.
91
+
92
+ This is plain Markdown insertion (not ast-grep — headings don't parse cleanly as a
93
+ syntax tree), implemented in `lib/changelog.mjs`.
94
+
49
95
  ## How it's built
50
96
 
51
97
  ```
52
98
  migrations/
53
- index.json registry (id = version, title, appliesTo range, rule files)
54
- <version>/ e.g. 0.13.0
99
+ index.json registry (id, title, appliesTo {package,from,to}, rules, changelog)
100
+ <id>/ e.g. 0.13.0 (core) or starter-2.1.1 (starter)
55
101
  rules/*.yml ast-grep rewrite rule(s), applied in order; one .yml
56
102
  may hold several rules as `---`-separated documents
103
+ changelog/*.md (optional) version blocks prepended to consumer
104
+ changelogs (root + theme), declared in index.json
57
105
  README.md what/why + before→after
58
106
  __fixtures__/<version>/
59
107
  before/ after/ golden project subtrees (drive the tests); each holds
@@ -61,17 +109,27 @@ migrations/
61
109
  package.json, composer.json
62
110
  customized/ (optional) a subtree that must NOT change (no-op guard)
63
111
  bin/webentor-codemods.mjs the CLI runner (wraps the bundled ast-grep)
112
+ lib/changelog.mjs the changelog-sync step (plain Markdown insertion)
64
113
  ```
65
114
 
66
115
  ### Adding a future migration
67
116
 
68
- 1. Create `migrations/<version>/rules/<rule>.yml` ast-grep rule(s) with a `fix`.
69
- Rules can target multiple languages (PHP, JSON, …) — ast-grep dispatches each
70
- rule to the files matching its `language`. JSON dependency rules use
117
+ 0. Pick an `id` per the naming convention above — bare version for core
118
+ (`0.16.0`), `<package>-<version>` for anything else (`starter-2.1.1`).
119
+ 1. (Optional) Create `migrations/<id>/rules/<rule>.yml` ast-grep rule(s) with a
120
+ `fix`. Rules can target multiple languages (PHP, JSON, …) — ast-grep dispatches
121
+ each rule to the files matching its `language`. JSON dependency rules use
71
122
  `files:` globs to scope to `package.json` / `composer.json`.
72
- 2. Add `before/` + `after/` (and optional `customized/`) fixture subtrees under
73
- `migrations/__fixtures__/<version>/`.
74
- 3. Register it in `migrations/index.json` (`id` = the version, `appliesTo`, `rules`).
123
+ 2. (If you added rules) add `before/` + `after/` (and optional `customized/`)
124
+ fixture subtrees under `migrations/__fixtures__/<id>/`.
125
+ 3. (Optional) To sync changelogs, drop the version block(s) in
126
+ `migrations/<id>/changelog/*.md` and add a `changelog` array to the index entry:
127
+ `[{ "entry": "changelog/root.md", "target": "changelog.md", "marker": "### <ver>" }, …]`.
128
+ The `marker` is the block's first heading and is used for the idempotency check.
129
+ A migration needs *either* `rules` *or* `changelog` — a changelog-only /
130
+ tooling-only migration (e.g. a starter release with no core bump) is valid.
131
+ 4. Register it in `migrations/index.json` (`id`, `appliesTo` {`package`, `from`,
132
+ `to`}, optional `rules`, optional `changelog`).
75
133
 
76
134
  The runner and the test suite are generic — no code changes needed. Migrations
77
135
  are **idempotent** (re-running is a no-op) and **conservative** (anything that
@@ -18,8 +18,9 @@
18
18
  import { createRequire } from 'node:module';
19
19
  import { spawnSync } from 'node:child_process';
20
20
  import { existsSync, readFileSync } from 'node:fs';
21
- import { dirname, join, resolve } from 'node:path';
21
+ import { dirname, join, resolve, relative } from 'node:path';
22
22
  import { fileURLToPath } from 'node:url';
23
+ import { applyChangelogStep } from '../lib/changelog.mjs';
23
24
 
24
25
  const require = createRequire(import.meta.url);
25
26
  const PKG_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
@@ -114,7 +115,10 @@ function runMigration(migration, { targetPath, apply }) {
114
115
  const bin = astGrepBin();
115
116
  const migDir = join(MIGRATIONS_DIR, migration.id);
116
117
  const rules = migration.rules ?? [];
117
- if (!rules.length) fail(`migration "${migration.id}" declares no rules`);
118
+ const changelog = migration.changelog ?? [];
119
+ if (!rules.length && !changelog.length) {
120
+ fail(`migration "${migration.id}" declares no rules`);
121
+ }
118
122
 
119
123
  console.log(
120
124
  `\n▶ ${migration.id}${apply ? ' (apply)' : ' (dry-run — pass --apply to write)'}`,
@@ -134,6 +138,27 @@ function runMigration(migration, { targetPath, apply }) {
134
138
  anyError = true;
135
139
  }
136
140
  }
141
+
142
+ // Changelog sync (not an ast-grep rule — prepend version blocks if missing).
143
+ for (const step of changelog) {
144
+ const results = applyChangelogStep(migDir, step, { root: targetPath, apply });
145
+ for (const r of results) {
146
+ const where = r.status === 'missing' ? r.file : relative(targetPath, r.file) || r.file;
147
+ if (r.status === 'updated') {
148
+ console.log(`\nchangelog[${step.marker}] → ${where}${apply ? ' (written)' : ''}:`);
149
+ console.log(
150
+ r.preview
151
+ .split('\n')
152
+ .map((l) => ` + ${l}`)
153
+ .join('\n'),
154
+ );
155
+ } else if (r.status === 'unchanged') {
156
+ console.log(`changelog[${step.marker}] → ${where}: already present, skipped`);
157
+ } else {
158
+ console.log(`changelog[${step.marker}]: ${where} — ${r.reason} (skipped)`);
159
+ }
160
+ }
161
+ }
137
162
  return !anyError;
138
163
  }
139
164
 
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Changelog sync - the one codemod step that isn't an ast-grep rewrite.
3
+ *
4
+ * A consumer project inherits its root `changelog.md` and theme `changelog.md`
5
+ * from the starter, so they are meant to mirror the Webentor baseline changelogs.
6
+ * This prepends a release's version block to those files (under the H1 heading) so
7
+ * a consumer's changelog stays up to date, same as the stack.
8
+ *
9
+ * Markdown is a poor fit for ast-grep (headings split the marker from inline text),
10
+ * so this is plain, deterministic string work: insert-if-missing, idempotent,
11
+ * additive (never clobbers existing entries).
12
+ */
13
+ import { existsSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
14
+ import { join } from 'node:path';
15
+
16
+ /**
17
+ * Return `existing` with `entryBlock` inserted after the first H1, or `null` if
18
+ * `marker` (the entry's version heading) is already present (no change).
19
+ */
20
+ export function syncChangelog(existing, entryBlock, marker) {
21
+ const wanted = marker.trim();
22
+ const alreadyThere = existing.split('\n').some((l) => l.trim() === wanted);
23
+ if (alreadyThere) return null;
24
+
25
+ const block = entryBlock.replace(/\n+$/, '');
26
+ const lines = existing.split('\n');
27
+ const h1 = lines.findIndex((l) => /^#\s+/.test(l));
28
+
29
+ if (h1 === -1) {
30
+ // No H1: prepend the block at the very top.
31
+ return block + '\n\n' + existing.replace(/^\n+/, '');
32
+ }
33
+ const head = lines.slice(0, h1 + 1).join('\n');
34
+ const rest = lines.slice(h1 + 1).join('\n').replace(/^\n+/, '');
35
+ return head + '\n\n' + block + '\n\n' + rest;
36
+ }
37
+
38
+ /**
39
+ * Minimal path resolver supporting a whole-segment `*` wildcard (no partial or
40
+ * recursive globs). Enough for `changelog.md` and `web/app/themes/*\/changelog.md`.
41
+ * Returns existing paths only.
42
+ */
43
+ export function resolveTargets(root, pattern) {
44
+ let dirs = [root];
45
+ const segs = pattern.split('/').filter(Boolean);
46
+ segs.forEach((seg, i) => {
47
+ const last = i === segs.length - 1;
48
+ const next = [];
49
+ for (const d of dirs) {
50
+ if (!existsSync(d)) continue;
51
+ if (seg === '*') {
52
+ for (const e of readdirSync(d, { withFileTypes: true })) {
53
+ if (last ? e.isFile() : e.isDirectory()) next.push(join(d, e.name));
54
+ }
55
+ } else {
56
+ const p = join(d, seg);
57
+ if (existsSync(p)) next.push(p);
58
+ }
59
+ }
60
+ dirs = next;
61
+ });
62
+ return dirs;
63
+ }
64
+
65
+ /**
66
+ * Apply one changelog step against `root`. Returns a per-file result list:
67
+ * { file, status: 'updated' | 'unchanged' | 'missing', preview? }
68
+ * Writes only when `apply` is true.
69
+ */
70
+ export function applyChangelogStep(migrationDir, step, { root, apply }) {
71
+ const entryPath = join(migrationDir, step.entry);
72
+ if (!existsSync(entryPath)) {
73
+ return [{ file: step.target, status: 'missing', reason: 'entry not found: ' + entryPath }];
74
+ }
75
+ const entryBlock = readFileSync(entryPath, 'utf8');
76
+ const targets = resolveTargets(root, step.target);
77
+ if (!targets.length) {
78
+ return [{ file: step.target, status: 'missing', reason: 'no matching file in project' }];
79
+ }
80
+ return targets.map((file) => {
81
+ const existing = readFileSync(file, 'utf8');
82
+ const updated = syncChangelog(existing, entryBlock, step.marker);
83
+ if (updated === null) return { file, status: 'unchanged' };
84
+ if (apply) writeFileSync(file, updated);
85
+ return { file, status: 'updated', preview: entryBlock.replace(/\n+$/, '') };
86
+ });
87
+ }
@@ -97,3 +97,14 @@ major (8), `typescript` major (6), `lint-staged` major (17 — needs Node 22).
97
97
  0.12 → 0.13 upgrade; adjust by hand if you intentionally run newer.
98
98
 
99
99
  After applying, run `pnpm install` + `composer update` to refresh the lockfiles.
100
+
101
+ ## 3. Changelog sync
102
+
103
+ Prepends the `2.0.7` version block to the project's changelogs so they match the
104
+ stack:
105
+
106
+ - `changelog.md` (project root) ← `changelog/root.md` (marker `### 2.0.7`)
107
+ - `web/app/themes/*/changelog.md` ← `changelog/theme.md` (marker `### Version 2.0.7`)
108
+
109
+ Idempotent (skipped if the heading is already present) and additive (inserted under
110
+ the `# … Changelog` H1, above existing entries).
@@ -0,0 +1,8 @@
1
+ ### 2.0.7
2
+
3
+ - WordPress 7.0 / PHP 8.4 compatibility
4
+ - Allow `roots/wordpress` `^7.0` (constraint widened to `^6.5 || ^7.0`)
5
+ - Bump bundled theme to `2.0.7` (`webentor-core` `^0.13`)
6
+ - Editor assets: move editor canvas styles (`editor.css`, `button.style.css`) from `enqueue_block_editor_assets` to `enqueue_block_assets` (`is_admin()` guarded) so WP 7.0's iframed editor styles the canvas correctly.
7
+ - Update theme dependencies to the 0.13.0 baseline, including majors `@wordpress/components` 35, `@wordpress/icons` 14, `stylelint` 17 (+ `stylelint-config-recommended` 18), `@types/wordpress__block-editor` 15, `prettier-plugin-tailwindcss` 0.8.
8
+ - Existing projects can apply the editor enqueue change **and** the dependency bumps via the `0.13.0` codemod (`pnpm dlx @webikon/webentor-codemods run 0.13.0`).
@@ -0,0 +1,7 @@
1
+ ### Version 2.0.7
2
+
3
+ - Bump `webentor-core` to `^0.13` (WordPress 7.0 / PHP 8.4 block-editor deprecation fixes).
4
+ - Enqueue theme block-editor styles on `enqueue_block_assets` (guarded by `is_admin()`) instead of `enqueue_block_editor_assets`, so WordPress routes them into the editor iframe correctly (fixes "added to the iframe incorrectly" on WP 7.0). Styles remain off the public frontend.
5
+ - Update `@wordpress/*` dev dependencies to latest stable (block-editor/blocks 15.21, components 35, block-library 9.48, i18n 6.21, icons 14, dependency-extraction 6.48), `@10up/block-components` 1.22.2, `@alpinejs/intersect` 3.15.12.
6
+ - Update dev tooling, including majors: `stylelint` 17 + `stylelint-config-recommended` 18, `@types/wordpress__block-editor` 15, `prettier-plugin-tailwindcss` 0.8 (plus `typescript-eslint` 8.61, `prettier` 3.8, `postcss` 8.5, `tailwindcss` 4.3). ESLint 10, React 19, Vite 8, TypeScript 6, lint-staged 17 held back.
7
+ - All theme dependency bumps for 0.13.0 are reproducible in existing projects via `pnpm dlx @webikon/webentor-codemods run 0.13.0`.
@@ -0,0 +1,130 @@
1
+ # `0.15.0` — upgrade a consumer theme to webentor-core 0.15.0 (Vite 8 / Rolldown)
2
+
3
+ **Applies to:** consumer themes moving `webentor-core` `0.13.x` → `0.15.0`. This is
4
+ the **Vite 8 / Rolldown** toolchain migration. (Coming from an older baseline? Run
5
+ the `0.13.0` codemod first.)
6
+
7
+ Run from your project root:
8
+
9
+ ```sh
10
+ pnpm dlx @webikon/webentor-codemods run 0.15.0 # preview (dry-run)
11
+ pnpm dlx @webikon/webentor-codemods run 0.15.0 --apply # apply
12
+ ```
13
+
14
+ Then apply the **manual `vite.config.js` change** below, reinstall, rebuild, and
15
+ clear caches:
16
+
17
+ ```sh
18
+ # in the theme dir
19
+ pnpm install && composer update
20
+ pnpm build
21
+ wp acorn optimize:clear
22
+ ```
23
+
24
+ This migration has two automated rule sets — a **dependency** bump set
25
+ (`package.json` + `composer.json`) and a **static-asset glob** fix
26
+ (`resources/scripts/app.ts`) — plus one **manual** `vite.config.js` step.
27
+
28
+ ## 1. Dependencies (`rules/deps.yml`, JSON)
29
+
30
+ Rewrites the theme's dependency ranges to the **0.15.0 baseline**. This is the
31
+ complete delta from the 0.13.0 baseline (theme 2.0.7) — only the Vite-8 toolchain
32
+ ranges and the `webentor-core` bump changed. Each rule matches a dependency by its
33
+ exact key (value-is-string guarded) and is scoped to `package.json` /
34
+ `composer.json` via `files:`.
35
+
36
+ | manifest | dependency | → range |
37
+ |---|---|---|
38
+ | package.json + composer.json | webentor-core | `^0.15.0` / `^0.15` |
39
+ | package.json | `vite` (major 7→8) | `^8.0.0` |
40
+ | package.json | `@roots/vite-plugin` (major 1→2) | `^2.2.0` |
41
+ | package.json | `@vitejs/plugin-react` (major 5→6) | `^6.0.0` |
42
+ | package.json | `laravel-vite-plugin` (major 2→3) | `^3.0.0` |
43
+ | package.json | `@webikon/webentor-configs` (1.0→1.1, adds the `/vite` export) | `^1.1.0` |
44
+
45
+ - **Idempotent:** re-running rewrites to the same range → no diff.
46
+ - **Baseline caveat:** the fix pins the 0.15.0 ranges, so a project already *ahead*
47
+ within a major would be set back to it. Expected for a 0.13 → 0.15 upgrade.
48
+
49
+ After applying, run `pnpm install` + `composer update` to refresh the lockfiles.
50
+
51
+ ## 2. Static-asset glob (`rules/app-glob-vite8.yml`, TS)
52
+
53
+ On Vite 7 a bare `import.meta.glob(['../images/**', '../fonts/**'])` registered
54
+ static assets into the build manifest. On Vite 8 / Rolldown a bare glob no longer
55
+ emits them, so `asset()` lookups for images/fonts (e.g. block-preview thumbnails)
56
+ 404. The call must become eager and resolve each match to its versioned URL:
57
+
58
+ ```ts
59
+ // before
60
+ import.meta.glob(['../images/**', '../fonts/**']);
61
+
62
+ // after
63
+ import.meta.glob(['../images/**', '../fonts/**'], {
64
+ eager: true,
65
+ query: '?url',
66
+ import: 'default',
67
+ });
68
+ ```
69
+
70
+ - **Conservative:** only the single-argument asset glob (its array contains an
71
+ `images`/`fonts` pattern) is matched. The already-migrated two-argument form and
72
+ any unrelated `import.meta.glob` (e.g. a module glob) are left untouched. A glob
73
+ with customized paths won't match — migrate it by hand using the above.
74
+
75
+ ## Changelog sync
76
+
77
+ Prepends the `2.1.0` version block to the project's changelogs so they match the
78
+ stack:
79
+
80
+ - `changelog.md` (project root) ← `changelog/root.md` (marker `### 2.1.0`)
81
+ - `web/app/themes/*/changelog.md` ← `changelog/theme.md` (marker `### Version 2.1.0`)
82
+
83
+ Idempotent (skipped if the heading is already present) and additive (inserted under
84
+ the `# … Changelog` H1, above existing entries). If you've customized a changelog,
85
+ your entries are preserved.
86
+
87
+ ## 3. `vite.config.js` — WordPress externals (manual)
88
+
89
+ This step is **not** codemodded — `vite.config.js` is too project-specific to
90
+ rewrite safely. Apply it by hand. The WordPress externals interop (the
91
+ `@wordpress/*` → `wp.*` / React shims) now lives in `@webikon/webentor-configs/vite`
92
+ as `wordpressExternals(command)`, and the config must become a function of
93
+ `{ command }` so it can pick the dev vs build strategy:
94
+
95
+ ```diff
96
+ import { v4wp } from '@kucrut/vite-for-wp';
97
+ - import { wp_scripts } from '@kucrut/vite-for-wp/plugins';
98
+ import { wordpressThemeJson } from '@roots/vite-plugin';
99
+ import tailwindcss from '@tailwindcss/vite';
100
+ - import react from '@vitejs/plugin-react';
101
+ + import { wordpressExternals } from '@webikon/webentor-configs/vite';
102
+ import { glob } from 'glob';
103
+ import { defineConfig, normalizePath } from 'vite';
104
+
105
+ - export default defineConfig({
106
+ + export default defineConfig(({ command }) => ({
107
+ base: '/app/themes/<your-theme>/public/build/',
108
+ // …
109
+ plugins: [
110
+ // …
111
+ - wp_scripts(),
112
+ - react({ jsxRuntime: 'classic' }),
113
+ + // WordPress externals (@wordpress/* -> wp.*, react -> window.React) — hybrid per
114
+ + // command: roots wordpressPlugin + interop shims for build, kucrut wp_scripts()
115
+ + // for the dev server. See @webikon/webentor-configs/vite.
116
+ + ...wordpressExternals(command),
117
+ // …
118
+ ],
119
+ // …
120
+ - });
121
+ + }));
122
+ ```
123
+
124
+ Reference: the starter theme's `vite.config.js` at theme 2.1.0.
125
+
126
+ ## Relationship to `update-webentor-packages-in-project`
127
+
128
+ This codemod's `webentor-core` bump overlaps with the
129
+ `update-webentor-packages-in-project` flow; that's intentional — the `0.15.0`
130
+ codemod is the self-contained "bring me to 0.15.0" unit (deps + code changes).
@@ -0,0 +1,11 @@
1
+ ### 2.1.0
2
+
3
+ - Bump `webentor-core` to `^0.15` (from `^0.13`). This pulls in the `0.14.0` and `0.14.1` core releases as well:
4
+ - `0.14.0`: extensible `l-section` background settings + first-class overlay feature (opacity/color), new JS/PHP extension filters, and a fix for the "Hidden" responsive display on sections. Available transparently to consumers via core.
5
+ - `0.14.1`: frontend `wp-i18n` dependency declared on block frontend scripts (fixes a "wp is not defined" error on front-end slider blocks).
6
+ - `0.15.0`: Vite 8 / Rolldown build toolchain.
7
+ - **Vite 8 / Rolldown toolchain migration** (requires consumer action):
8
+ - Theme dependency bumps: `vite` `^8`, `@roots/vite-plugin` `^2.2.0`, `@vitejs/plugin-react` `^6`, `laravel-vite-plugin` `^3`, `@webikon/webentor-configs` `^1.1.0`.
9
+ - `vite.config.js`: WordPress externals now come from `@webikon/webentor-configs/vite` (`...wordpressExternals(command)`), and `defineConfig` takes a `({ command }) => ({ … })` function so it can pick the dev vs build externals strategy.
10
+ - `resources/scripts/app.ts`: the static-asset `import.meta.glob(['../images/**', '../fonts/**'])` now needs `{ eager: true, query: '?url', import: 'default' }` — a bare glob no longer emits assets under Rolldown.
11
+ - Existing projects can apply the dependency bumps and the `app.ts` change via the `0.15.0` codemod (`pnpm dlx @webikon/webentor-codemods run 0.15.0`); the `vite.config.js` rewrite is a documented manual step in that codemod's README.
@@ -0,0 +1,8 @@
1
+ ### Version 2.1.0
2
+
3
+ - Bump `webentor-core` to `^0.15` (from `^0.13`), which also brings the `0.14.0` overlay/`l-section` extensibility work and the `0.14.1` frontend `wp-i18n` fix transparently via core.
4
+ - **Vite 8 / Rolldown toolchain migration:**
5
+ - Dependency bumps: `vite` `^8`, `@roots/vite-plugin` `^2.2.0`, `@vitejs/plugin-react` `^6`, `laravel-vite-plugin` `^3`, `@webikon/webentor-configs` `^1.1.0`.
6
+ - `vite.config.js`: replace the local `wp_scripts()` + `react()` plugins with `...wordpressExternals(command)` from `@webikon/webentor-configs/vite`, and wrap the config as `defineConfig(({ command }) => ({ … }))`.
7
+ - `resources/scripts/app.ts`: the static-asset glob now uses `import.meta.glob([...], { eager: true, query: '?url', import: 'default' })` so Rolldown versions images/fonts into the manifest.
8
+ - All theme dependency bumps and the `app.ts` change are reproducible in existing projects via `pnpm dlx @webikon/webentor-codemods run 0.15.0`; apply the `vite.config.js` change by hand (documented in the codemod README).
@@ -0,0 +1,32 @@
1
+ # Vite 8 / Rolldown static-asset glob fix (resources/scripts/app.ts, TS).
2
+ #
3
+ # On Vite 7 a bare `import.meta.glob(['../images/**', '../fonts/**'])` was enough to
4
+ # register static assets into the build manifest. On Vite 8 / Rolldown a bare glob
5
+ # no longer emits them — the call must be eager and resolve each match to its
6
+ # versioned URL, i.e. `{ eager: true, query: '?url', import: 'default' }`. Without
7
+ # this, asset() lookups for images/fonts (e.g. block-preview thumbnails) 404.
8
+ #
9
+ # Matches the single-argument asset glob only (the argument array must contain an
10
+ # `images`/`fonts` pattern), so unrelated `import.meta.glob` calls and the
11
+ # already-migrated two-argument form are left untouched (idempotent + conservative).
12
+ # A customized glob (different paths) won't match — migrate it by hand per the README.
13
+ id: app-asset-glob-vite8
14
+ language: typescript
15
+ files: ['**/resources/scripts/app.ts']
16
+ rule:
17
+ pattern: import.meta.glob($ARR)
18
+ has:
19
+ field: arguments
20
+ has:
21
+ kind: array
22
+ stopBy: end
23
+ has:
24
+ kind: string
25
+ stopBy: end
26
+ regex: 'images|fonts'
27
+ fix: |-
28
+ import.meta.glob($ARR, {
29
+ eager: true,
30
+ query: '?url',
31
+ import: 'default',
32
+ })
@@ -0,0 +1,83 @@
1
+ # Dependency bumps for the webentor-core 0.15.0 upgrade (Vite 8 / Rolldown).
2
+ #
3
+ # Baseline = the 0.13.0 starter (theme 2.0.7). This is the COMPLETE
4
+ # `git diff starter-v2.0.7 -- <theme>/{package,composer}.json` dependency delta
5
+ # to the 0.15.0 baseline — only the Vite-8 toolchain ranges and the webentor-core
6
+ # bump changed; everything else carried over from 0.13.0 unchanged and is therefore
7
+ # absent here (run the 0.13.0 codemod first if coming from an older baseline).
8
+ #
9
+ # Same shape as the 0.13.0 deps rules: one rule per dependency, matched by its
10
+ # exact key (anchored regex) with a value-is-string guard (so a config object that
11
+ # shares a key is never clobbered), rewritten to the 0.15.0 baseline range
12
+ # regardless of the consumer's current value. `files:` scopes npm rules to
13
+ # package.json and the composer rule to composer.json. `name`/`version` are never
14
+ # touched.
15
+ id: deps-roots-vite-plugin
16
+ language: json
17
+ files: ['**/package.json']
18
+ rule:
19
+ kind: pair
20
+ all:
21
+ - has: { field: key, regex: '^"@roots/vite-plugin"$' }
22
+ - has: { field: value, kind: string }
23
+ fix: '"@roots/vite-plugin": "^2.2.0"'
24
+ ---
25
+ id: deps-vitejs-plugin-react
26
+ language: json
27
+ files: ['**/package.json']
28
+ rule:
29
+ kind: pair
30
+ all:
31
+ - has: { field: key, regex: '^"@vitejs/plugin-react"$' }
32
+ - has: { field: value, kind: string }
33
+ fix: '"@vitejs/plugin-react": "^6.0.0"'
34
+ ---
35
+ id: deps-webentor-configs
36
+ language: json
37
+ files: ['**/package.json']
38
+ rule:
39
+ kind: pair
40
+ all:
41
+ - has: { field: key, regex: '^"@webikon/webentor-configs"$' }
42
+ - has: { field: value, kind: string }
43
+ fix: '"@webikon/webentor-configs": "^1.1.0"'
44
+ ---
45
+ id: deps-laravel-vite-plugin
46
+ language: json
47
+ files: ['**/package.json']
48
+ rule:
49
+ kind: pair
50
+ all:
51
+ - has: { field: key, regex: '^"laravel-vite-plugin"$' }
52
+ - has: { field: value, kind: string }
53
+ fix: '"laravel-vite-plugin": "^3.0.0"'
54
+ ---
55
+ id: deps-vite
56
+ language: json
57
+ files: ['**/package.json']
58
+ rule:
59
+ kind: pair
60
+ all:
61
+ - has: { field: key, regex: '^"vite"$' }
62
+ - has: { field: value, kind: string }
63
+ fix: '"vite": "^8.0.0"'
64
+ ---
65
+ id: deps-webentor-core-npm
66
+ language: json
67
+ files: ['**/package.json']
68
+ rule:
69
+ kind: pair
70
+ all:
71
+ - has: { field: key, regex: '^"@webikon/webentor-core"$' }
72
+ - has: { field: value, kind: string }
73
+ fix: '"@webikon/webentor-core": "^0.15.0"'
74
+ ---
75
+ id: deps-webentor-core-composer
76
+ language: json
77
+ files: ['**/composer.json']
78
+ rule:
79
+ kind: pair
80
+ all:
81
+ - has: { field: key, regex: '^"webikon/webentor-core"$' }
82
+ - has: { field: value, kind: string }
83
+ fix: '"webikon/webentor-core": "^0.15"'