Skip to content
Agentmart
Submit a tool

frontend-upgrade-ops

Upgrade a server-rendered Craft CMS/Twig front end: Laravel Mix or Webpack to Vite via craft-vite (manifest, DDEV dev server, HMR, Tailwind v3, legacy builds…

Skill by claude-mods

IndexedMIT★ 75
Write a review

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/0xdarkmatter-frontend-upgrade-ops

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

Upgrade a server-rendered Craft CMS/Twig front end: Laravel Mix or Webpack to Vite via craft-vite (manifest, DDEV dev server, HMR, Tailwind v3, legacy builds, Twig asset URLs) and Vue 2 to Vue 3 (@vue/compat, Vuex to Pinia, plugin swaps, Vue islands in Twig). Use when a site still has webpack.mix.js, mix-manifest.json or Vue 2, or when deciding if a small Vue widget should become Alpine.js or vanilla JS instead.

Use cases: frontend, backend

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md and code. Checked Oct 25, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found
Runs as
Python package

Network hosts it talks to 2

  • codeload.github.com · found in install command
  • repo.packagist.org · found in code

Files it touches

  • ~/.claude/skills/frontend-upgrade-ops

Tools it pre-approves 6

From allowed-tools in SKILL.md: the agent may use these without asking you each time.

  • Read
  • Edit
  • Write
  • Bash
  • Glob
  • Grep

What's inside

Skill name
frontend-upgrade-ops
Description
Upgrade a server-rendered Craft CMS/Twig front end: Laravel Mix or Webpack to Vite via craft-vite (manifest, DDEV dev server, HMR, Tailwind v3, legacy builds, Twig asset URLs) and Vue 2 to Vue 3 (@vue/compat, Vuex to Pinia, plugin swaps, Vue islands in Twig). Use when a site still has webpack.mix.js, mix-manifest.json or Vue 2, or when deciding if a small Vue widget should become Alpine.js or vanilla JS instead.
License
MIT
Allowed tools
Read, Edit, Write, Bash, Glob, Grep
Metadata
author: claude-mods · related-skills: migrate-ops, vue-ops, craftcms-ops, ddev-ops, web-perf-ops, tailwind-ops, playwright-ops, security-ops, package-manager-ops
Instructions
192 lines in SKILL.md · view on GitHub

Before installing

  • Ships executable scripts
  • Pre-approves any shell command

Files (9)

  • SKILL.md
  • frontend-upgrade-facts.json · assets/
  • craft-vite-twig.md · references/
  • mix-webpack-to-vite.md · references/
  • vue-islands-in-twig.md · references/
  • vue-state-and-plugins.md · references/
  • vue2-to-vue3.md · references/
  • check-frontend-upgrade-facts.py · scripts/
  • run.sh · tests/

SKILL.md (first lines)

# Frontend Upgrade Operations

The two front-end upgrades a Craft CMS (or any Twig/PHP) agency keeps meeting: an asset
pipeline still on **Laravel Mix or raw Webpack**, and widgets still on **Vue 2**. Both
are frozen - Mix's last release was 6.0.49 in June 2022 and Laravel calls it "a legacy
package that is no longer actively maintained"; Vue 2 reached end of life on
31 December 2023. This skill is the playbook for moving a server-rendered site to
**Vite 8 + craft-vite** and **Vue 3**, or for deciding that a widget should not be Vue
at all.

> Version facts verified as of 2026-10-05 against npm, Packagist, vite.dev,
> v3-migration.vuejs.org and nystudio107.com/docs/vite. Each reference cites its sources.

## Start here: what does this repo need?

| You find | Do | Read |
|---|---|---|
| `webpack.mix.js`, `mix-manifest.json`, `mix()` in Twig | Replace Mix with Vite + craft-vite | [mix-webpack-to-vite.md](references/mix-webpack-to-vite.md), then [craft-vite-twig.md](references/craft-vite-twig.md) |
| A hand-written `webpack.config.js` | Same move; translate loaders and plugins one by one | [mix-webpack-to-vite.md](references/mix-webpack-to-vite.md) |
| craft-vite already, but the dev server fails behind DDEV | CORS / `allowedHosts` / one port in four places | [craft-vite-twig.md](references/craft-vite-twig.md#troubleshooting) |
| `"vue": "^2` in `package.json` | Decide per widget: migrate or replace (table below) | this file, then [vue2-to-vue3.md](references/vue2-to-vue3.md) |
| Mix **and** Vue 2 | Bundler first, framework second - never one deploy | [Sequencing](#sequencing-both-upgrades) |
| `vuex`, `vue-router` 3, Vue 2-only plugins | Pinia; check every plugin for a Vue 3 path before estimating | [vue-state-and-plugins.md](references/vue-state-and-plugins.md) |
| Vue templates written in Twig (`inline-template`, in-DOM) | Convert to SFC islands; mind the compiler build and template injection | [vue-islands-in-twig.md](references/vue-islands-in-twig.md) |
| Vue 3 + Vite already | Out of scope here - steady-state Vue is `vue-ops`, steady-state Craft is `craftcms-ops` | - |

## Migrate Vue, or replace it?

Most agency Vue 2 code is not an app; it is a handful of widgets. Migrating a widget
that a dozen lines of Alpine would do costs more than replacing it. Decide **per
island**, before estimating the migration.

| The widget is... | Verdict | Why |
|---|---|---|
| Toggle, accordion, tabs, mobile nav, show/hide | **Native HTML or Alpine.js** | `<details>`, `<dialog>`, `popover` cover much of it with zero JS; the rest is a boolean in `x-data` written straight into Twig |
| A form with validation and a submit spinner | **Alpine** + native constraint validation | No component tree, no store; Alpine keeps the markup in Twig where editors expect it |
| A thin wrapper around a framework-free library (slider, date picker, map, lightbox) | **Vanilla JS or Alpine** calling the library directly | The Vue wrapper was the only Vue 2-specific part |
| Renders server data and never changes it | **Delete it; render in Twig** | It's a template, not an app |
| Filtering/sorting a list with derived counts, several child components | **Vue 3** | Computed state and components earn their weight |
| Several islands sharing state (cart, saved items, auth) | **Vue 3 + Pinia** | A shared store across apps is what Vue + Pinia does well |
| Routing inside a section (multi-step tool, dashboard) | **Vue 3** (+ vue-router) | Alpine has no answer for this |
| Built on a Vue 2 UI kit with no Vue 3 release | **Rewrite budget**, Vue 3 or Alpine, decided by the rows above | The kit, not Vue, is the migration |

Rules of thumb for the grey zone: under ~150 lines with one level of state, Alpine
wins; any use of Vuex, a router, or more than two child components, Vue 3 wins. A site
that ends up with both is normal - see the Alpine coexistence rules in
[vue-islands-in-twig.md](references/vue-islands-in-twig.md#coexisting-with-alpine-sprig-and-page-caches).

## Sequencing both upgrades

Each numbered step is a separate deploy with its own parity check. Combining the
bundler swap with the framework swap is the classic mistake: when a page breaks you
cannot tell which change did it.

```
0. Inventory      rg the repo (below); list page types that render JS widgets
1. Vue 2.7.16     if on Vue 2.6 - backports Composition API + <script setup>
2. Mix -> Vite    still on Vue 2: Vite 7.3 + @vitejs/plugin-vue2
                  (plugin-vue2's peer range ends at vite ^7.0.0 as of 2026-10-05;
                   Vite 7.3 still gets important fixes + security patches)
3. Replace        widgets the table above says shouldn't be Vue -> Alpine/vanilla
4. Vuex -> Pinia 2 (optional, still on Vue 2.7; Pinia 3+ dropped Vue 2)
5. Vue 3          @vue/compat on Vite 8 + @vitejs/plugin-vue; burn down warnings
6. Drop compat    then Pinia 4, then remove @vitejs/plugin-legacy if analytics allow
```

No Vue on the site? Steps 1, 3-6 vanish: go straight to Vite 8.

If Vue 2 must die first (a security finding, a hosting rule), the order flips: Vue 3
via `@vue/compat` **on Webpack** is supported by the migration guide, then Vite. It is
the slower path - two configurations of Vue 3 tooling instead of one.

```bash
# Step 0 - inventory in one pass
fd -H "webpack.mix.js|webpack.config.js|mix-manifest.json|vite.config" -E node_modules
jq '{vue:.dependencies.vue, mix:.devDependencies["laravel-mix"], webpack:.devDependencies.webpack, vite:.devDependencies.vite, vuex:.dependencies.vuex}' package.json
rg -n "mix\(|craft\.vite|data-vue-island|inline-template|new Vue\(" templates/ src/ | head -50
```

## Cutover checklist: Mix/Webpack to Vite

Work top to bottom; each line links to the detail.

- [ ] Branch from a green build; record a **parity baseline** - screenshots of every
      page type + the network panel's JS/CSS list on the Mix build, plus lab LCP/CLS/TBT
      for the key templates (median of 5 runs, method in `web-perf-ops`)
- [ ] `npm pkg set type="module"` (or name configs `.mjs`/`.cjs` explicitly)
- [ ] `vite.config.js`: `base`, `build.manifest`, `outDir: web/dist`, entries in
      `build.rolldownOptions.input` ([config](references/mix-webpack-to-vite.md#a-viteconfigjs-for-a-craft-site))
- [ ] Every `webpack.mix.js` call mapped ([translation table](references/mix-webpack-to-vite.md#translate-the-mix-api))
- [ ] Source rewrites: `require`, `require.context`, `.vue` extensions, `process.env`,
      `MIX_` to `VITE_`, Sass `~` imports ([rewrites](references/mix-webpack-to-vite.md#source-rewrites))
- [ ] `postcss.config.js` + `tailwind.config.js` load; `content` globs still find
      `templates/**/*.twig` - **stay on Tailwind v3** for this deploy
- [ ] `composer require nystudio107/craft-vite` (5.x Craft 5, 4.x Craft 4); `config/vite.php`
      with `manifestPath` = `@webroot/dist/.vite/manifest.json`
- [ ] DDEV: the same port in `web_extra_exposed_ports`, `server.port`, `server.origin`,
      `devServerPublic`; `cors` + `allowedHosts` for `.ddev.site`
      ([DDEV](references/craft-vite-twig.md#dev-server-through-ddev))
- [ ] Twig: every `mix()` / hard-coded `/js/`, `/css/` tag replaced with
      `craft.vite.script(...)`; main CSS with `asyncCss = false` unless critical CSS exists
- [ ] Inline scripts that used bundle globals at parse time fixed (module scripts are
      deferred) ([why](references/craft-vite-twig.md#twig-replacing-the-mix-tags))
- [ ] Twig-referenced images resolved via `craft.vite.asset()` or left in `web/`
- [ ] Legacy build: decided from analytics, `@vitejs/plugin-legacy` only if needed
      ([legacy](references/mix-webpack-to-vite.md#legacy-browser-builds))
- [ ] HMR works for CSS + JS; Twig edits reload (`vite-plugin-restart`)
- [ ] `vite build` in CI/deploy; `web/dist/` gitignored; no hashed files committed
- [ ] Parity check against the baseline: every page type, fonts, icons, console clean,
      and the lab metrics - async CSS and `modulepreload` move LCP and CLS
      (`web-perf-ops` has the LCP/CLS fixes)
- [ ] Deploy keeps the previous build until full-page caches are purged
- [ ] Delete `webpack.mix.js`, `mix-manifest.json`, old `web/js` + `web/css`,
      `laravel-mix` and webpack-only devDependencies - in a follow-up commit

## Vue 2 to 3 at a glance

The full workflow, the breaking-change table and testing live in
[vue2-to-vue3.md](references/vue2-to-vue3.md). The shape:

From 0xDarkMatter/claude-mods, MIT.

More from 0xDarkMatter/claude-mods

Signals

Stars
75
Forks
8
Open issues
0
Last commit (this folder)
Oct 7, 2026 (23 days ago)
Last release
Oct 14, 2026 (15 days ago)

From GitHub (fetched Oct 24, 2026).

Details

License
MIT
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from claude-mods

Cite this page

frontend-upgrade-ops skill. Agent Mart. https://agentmart.dev/skills/0xdarkmatter-frontend-upgrade-ops (last updated 2026-10-24)