Skip to content

Nuxt

Next release

How midcode starts a Nuxt dev server with a layer of its own, which files are pages, how auto-imported components get their props, and where midcode.css goes.

View as Markdown

This ships with the next release of midcode. The version you can download today (1.1.2) doesn’t have it yet.

midcode edits a Nuxt project in the templates of its pages, layouts and components: text, classes, attributes, new elements, their order, and the props a component is given where it’s used. It starts Nuxt’s own dev server with one extra layer, so your nuxt.config is never changed. midcode 1.1.2 and earlier open a Nuxt project to check every breakpoint and leave comments, without editing.

Nuxt’s files are Vue single-file components, and midcode edits them the same way as in any Vue app. This page covers what’s particular to Nuxt; Vue shows each kind of edit with the code it writes.

At a glance

Nuxt
Detected bynuxt in the dependencies of package.json
Runs withnuxi dev, extended with a layer of midcode’s
Elements are marked byA Vite plugin that layer adds, while the dev server runs
EditingText, classes, attributes, tag; insert, move, duplicate, delete, wrap in a stack
ComponentsInstances and their props, auto-imported components included. A component opens on its own canvas, with variants, states and variables
PagesThe .vue files of pages/ or app/pages/. New pages and removing them, when that folder exists
StylesYour Tailwind 4 classes, or mid: utilities with midcode.css imported from app.vue
Tried withNuxt 4

How midcode runs it

A project is Nuxt when nuxt is in its dependencies. midcode looks in your node_modules for Nuxt’s command line (the nuxi package, then @nuxt/cli, then nuxt itself) and runs it:

Terminal
nuxi dev --port 4310 --host localhost --extends <midcode's layer>

The port is the first free one from 4310, and the process runs with the Node your shell has, or with midcode’s own when there is none.

The layer is a folder in midcode’s own data folder (~/Library/Application Support/midcode/injected/nuxt-layer/), with one file in it:

nuxt.config.mjs (midcode's layer, outside your project)
// Written by midcode: a Nuxt layer that adds the midcode plugin to Vite.
import { midcode } from 'file:///…/vite-plugin.mjs'
export default { vite: { plugins: [midcode(process.env.MIDCODE_ROOT)] } }

Nuxt merges a layer under your own config, so your nuxt.config, your modules and your package.json stay as they are. The plugin only applies to the dev server.

As each .vue file is loaded, the plugin marks the elements of its <template> before Vue compiles it: data-mc="app/pages/index.vue:3:5" (file, line and column) on every element, and data-mci="Card|app/pages/index.vue:8:5" on every component used there. Nothing is written to disk. Vue shows a template before and after.

Nuxt’s own pass-through components get no instance mark, because an attribute on them would land on a whole page: <NuxtPage>, <NuxtLayout>, <NuxtLoadingIndicator>, <NuxtRouteAnnouncer>, <ClientOnly>, <DevOnly> and <ServerOnly>.

If the server doesn’t come up this way (the process stops, or nothing answers in 45 seconds), midcode runs your own dev script instead and says so: the site shows, without marks, and you can only view and comment. The same happens when Nuxt’s command line isn’t found in node_modules.

What you can edit

Everything on the canvas works on the template of the file the element is written in: a page, a layout, app.vue or a component.

  • Text: double-click and type. Text that’s written in the template is replaced there. Text that comes from {{ }} is looked for as an exact string in the project’s .ts, .js, .json and .md files and edited there when midcode can tell which one it is (Text, images and video).

  • Styles: the style panel writes into the static class attribute. A :class binding is left alone.

  • Attributes: links, images, inputs, a <select> and its options. A value that’s code is written the way Vue binds it (:maxlength="40").

  • Structure: Insert, drag to move within the same file (⌥-drag to leave a copy there instead), duplicate, delete, and wrap several elements in a stack with ⇧A.

A style edit on a page looks like this:

app/pages/index.vue
 <template>-  <h1 class="text-4xl font-medium">Studio</h1>+  <h1 class="text-5xl font-medium">Studio</h1> </template>

Auto-imported components

Nuxt lets a template use a component without importing it. When midcode finds no import for <BaseButton> in the file, it looks for a .vue file by that name under components/, app/components/, src/components/ and layers/, up to five folders deep. It follows Nuxt’s naming: components/base/Button.vue is <BaseButton>, and so is components/base/BaseButton.vue.

Once the file is found, the instance’s Props are typed controls, read from the component’s defineProps (a type argument with withDefaults or a destructuring, an object of constructors, or an array of names). A change is written on the instance:

app/pages/index.vue
-    <BaseButton label="Start" />+    <BaseButton label="Start now" :size="2" outline />

A text is written as label="…", a number or other code as :size="…", a switch that’s on as the bare name. A value equal to the declared default removes the attribute.

A component Nuxt or a module provides (<NuxtLink>) has no file in your project, so midcode lists what the instance is given, without the component’s own types.

A component of your own is in the Assets tab under the name Nuxt gives it (components/base/Button.vue is BaseButton), and opens on its own canvas, where you add variants and states. They’re written as in any Vue component: see Variants and states. Pages, layouts, app.vue and error.vue aren’t listed as components.

Pages

Pages are the .vue files of pages/ and app/pages/, whichever your project has:

FilePage
app/pages/index.vueThe home page
app/pages/about.vue/about
app/pages/blog/index.vue/blog
app/pages/blog/[slug].vue/blog/[slug], a dynamic route

For a dynamic route, the page menu in the top bar lists its real pages, found in the running site’s sitemap and links (Pages and navigation). Folders whose name starts with _ or a dot aren’t listed, and a folder in parentheses doesn’t count in the path. A project with no pages folder shows the home page alone.

When the project has a pages folder, “New page” in the page menu writes a page in it, and “Remove” moves a page’s file to the Trash:

app/pages/about.vue
<template>
  <main class="mx-auto max-w-3xl px-6 py-24">
    <h1 class="text-4xl font-semibold">About</h1>
    <p class="mt-4">A new page, made in midcode.</p>
  </main>
</template>

The class names are written when Tailwind is in your package.json; without it the tags come bare. Without a pages folder the plus isn’t in the menu: Nuxt only draws pages once there is one and app.vue has a <NuxtPage />, so the first page is yours or your agent’s to set up.

Nuxt keeps the site’s <head> in its config, so that’s where Site settings reads and writes: app.head.title, app.head.htmlAttrs.lang, the description, robots and og:image items of app.head.meta and the rel: 'icon' item of app.head.link in nuxt.config, with the favicon and the social image copied to public/. Each edit is one value, or a new property or item written like its neighbours. A value the config computes shows as code and isn’t written. Tried with Nuxt 4.

Styles

With Tailwind 4 (a stylesheet with @import "tailwindcss" or an @theme block), the panel writes your own utilities: see Tailwind CSS.

Without it, midcode writes its own prefixed utilities (mid:p-6, mid:md:flex) and keeps their plain CSS in midcode.css, next to your app.vue (app/app.vue, or app.vue at the root). The first style edit creates the file and imports it from that component, as one undoable step:

app/app.vue
+<script setup>+  import './midcode.css'+</script>+ <template>   <NuxtLayout>     <NuxtPage />   </NuxtLayout> </template>

When app.vue already has a <script>, the import goes on its first line. Without Tailwind explains what’s in the file and why every rule is !important.

Limits

  • Tried with Nuxt 4, component mode included. Nuxt 3 wasn’t tried, and Nuxt 2 isn’t covered.

  • The marks come from a Vite plugin: a Nuxt app set to build with webpack gets none.

  • A project without app.vue has nowhere midcode knows to import midcode.css. It creates the file and tells you (“midcode added midcode.css but couldn’t tell where to import it. Import it in your app’s entry so its styles show.”). Import it yourself, for example by listing it under css in your nuxt.config.

  • A <template lang="pug"> isn’t read.

  • Elements move within one file. midcode doesn’t follow what a v-for gives its contents, so an element that reads the loop’s item can be dragged out of the loop. ⌘Z puts it back.

  • A component dragged in from the Assets tab is written without an import when its file is under components/, which Nuxt brings in by itself. One from another folder gets its import in the file’s <script setup>, and is refused in a component written with the Options API. Insert’s interactive components are React (“Needs a React page”), and icons go in as inline SVG.

  • Markdown rendered by a content module has no marks on the canvas. A folder of .md files with front matter shows up in the CMS instead.

  • variables are written as in any Vue component. Variants and variables aren’t written for a component on the Options API or one that lists its props as defineProps([...]).

  • The free canvas is for Next.js projects on the App Router.

Troubleshooting

The site shows, but nothing can be edited. midcode fell back to your dev script. Open the Dev server log in the top bar: it has the line that says why midcode’s own start didn’t come up. A config that needs something only your script sets up (an env file, a second process, a fixed port) is the usual reason.

“Dependencies are missing”. The project has no node_modules yet. The canvas offers to install them with your package manager; see Open a project.