Scaffold a plugin's frontend into the plugin, so it can be pruned

`flask plugin new` wrote views to frontend/src/views/<name>/ and a route file
to frontend/src/router/routes/<name>.js. Every one of the 16 bundled plugins
keeps its frontend in plugins/<name>/frontend/ instead, staged into
.plugins-staged by stage-frontend.mjs and aggregated into routes.gen.js.

It was not visibly broken, which is why it lasted: the router still globs
./routes/*.js during the Phase 4 dual-location transition, so a scaffolded
plugin's pages loaded. What a new plugin author silently lost was ADR-013 lean
builds. Pruning works off the staged tree, so a frontend in the core tree
cannot be excluded from a site build, and deleting the plugin strands its
views behind.

The templates for the correct layout already existed; only the output paths
were wrong. Also fixed the imports they carry: core imports now use the @
alias (@/api, @/components/...), which resolves both before and after staging,
where the previous ../../api was correct only in the old location. Sibling
views stay relative and travel with the route file.

frontend_dir is gone from scaffold_plugin. There is no second output tree to
point at, and a plugin developed in its own repo now gets the same frontend as
a bundled one rather than being skipped.

Proven end to end: scaffolded a throwaway plugin, confirmed it stages, builds
real chunks, and that SITE_PLUGINS=network prunes it, which is what the old
layout could not do.
This commit is contained in:
cproudlock
2026-08-24 14:05:15 -04:00
parent eecb0595dd
commit 7b79a444b8
7 changed files with 232 additions and 207 deletions

View File

@@ -78,12 +78,12 @@
<script setup>
import { ref, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import api from '../../api'
import { useAuthStore } from '../../stores/auth'
import api from '@/api'
import { useAuthStore } from '@/stores/auth'
// local api client. move into src/api/index.js (see
// plugins/${name}/frontend-api-snippet.js) then swap for:
// import { ${name}Api } from '../../api'
// import { ${name}Api } from '@/api'
const ${name}Api = {
list(params = {}) { return api.get('/${name}', { params }) },
get(itemId) { return api.get(`/${name}/${itemId}`) },