make-content-editable
Converts hardcoded Vue components in a Nuxt Content markdown file into slot-based, Studio-editable MDC components. Use when a user wants their Nuxt Content…
Port a legacy MDC-based PR onto the new comark-based `main`. Use when a contributor's PR was opened against the old `@nuxtjs/mdc` API (any commit before `feat(mdc): comark migration #355`) and now needs to be rebased / merged with the current Nuxt Studio main branch, which uses
$ npx -y skills add nuxt-content/nuxt-studio --skill migrate-mdc-to-comark --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/migrate-mdc-to-comarkContext preview
The summary Claude sees to decide when to auto-load this skill.
Port a legacy MDC-based PR onto the new comark-based `main`. Use when a contributor's PR was opened against the old `@nuxtjs/mdc` API (any commit before `feat(mdc): comark migration #355`) and now needs to be rebased / merged with the current Nuxt Studio main branch, which uses
name: migrate-mdc-to-comark description: Port a legacy MDC-based PR onto the new comark-based `main`. Use when a contributor's PR was opened against the old `@nuxtjs/mdc` API (any commit before `feat(mdc): comark migration #355`) and now needs to be rebased / merged with the current Nuxt Studio main branch, which uses `comark` everywhere. allowed-tools: Read, Write, Edit, Glob, Grep, Bash
Since commit `5464103e feat(mdc): comark migration (#355)` (merged 2026-05-13), Nuxt Studio's `main` branch no longer uses `@nuxtjs/mdc`. The entire conversion layer, document utilities, and TipTap bridges were rewritten on top of [`comark`](https://github.com/nuxt-content/comark).
Any PR opened against `main` **before** this commit will conflict on merge. Do **not** simply resolve the conflicts mechanically — most legacy API calls have semantic equivalents in comark that must be re-implemented.
This skill is the reverse of the previous "merge-main-on-comark" skill: the comark branch is now `main`, and legacy PRs need to be ported forward.
Run these checks at the root of the PR branch:
# Legacy imports — any match means the PR predates the comark migration grep -rE "from '@nuxtjs/mdc'|from 'remark-mdc'|from 'unist-util-visit'|from '@nuxt/content/runtime'" src/ # Legacy function names grep -rE "generateDocumentFromContent|generateDocumentFromMarkdownContent|generateDocumentFromYAMLContent|generateDocumentFromJSONContent|generateContentFromDocument|generateContentFromMarkdownDocument|generateContentFromYAMLDocument|generateContentFromJSONDocument|mdcToTiptap|tiptapToMDC|compressTree|decompressTree|parseMarkdown|stringifyMarkdown|parseFrontMatter|stringifyFrontMatter|remarkEmojiPlugin" src/ # Legacy file references (these files were deleted on main) ls src/app/src/utils/tiptap/mdcToTiptap.ts src/app/src/utils/tiptap/tiptapToMdc.ts 2>/dev/null
If anything matches, the PR is legacy.
| Legacy (pre-#355) | Comark (current main) | |---|---| | `MDCRoot`, `MarkdownRoot` from `@nuxt/content` | `MarkdownDocument` from `comark` | | `MDCNode`, `MDCElement`, `MDCText`, `MDCComment` from `@nuxtjs/mdc` | `MarkdownNode`, `ElementNode`, `CommentNode` from `comark` | | MDC element: `{ type: 'element', tag: 'note', props: {…}, children: [...] }` | Tuple: `['note', attrs, ...children]` | | MDC text: `{ type: 'text', value: 'hello' }` | Plain string: `'hello'` | | MDC comment: `{ type: 'comment', value: 'txt' }` | Tuple: `[null, {}, 'txt']` |
Located in `src/module/src/runtime/utils/document/generate.ts`:
| Legacy | Comark | |---|---| | `generateDocumentFromContent(id, content, opts)` | `documentFromContent(id, content, opts)` | | `generateDocumentFromMarkdownContent(...)` | `documentFromMarkdownContent(...)` | | `generateDocumentFromYAMLContent(...)` | `documentFromYAMLContent(...)` | | `generateDocumentFromJSONContent(...)` | `documentFromJSONContent(...)` | | `generateContentFromDocument(doc)` | `contentFromDocument(doc)` | | `generateContentFromMarkdownDocument(doc)` | `contentFromMarkdownDocument(doc)` | | `generateContentFromYAMLDocument(doc)` | `contentFromYAMLDocument(doc)` | | `generateContentFromJSONDocument(doc)` | `contentFromJSONDocument(doc)` |
The shape `generate-X-from-Y` was reversed to `Y-from-X` for symmetry.
Located in `src/app/src/utils/tiptap/`:
| Legacy file (deleted on main) | Comark replacement | |---|---| | `mdcToTiptap.ts` | `comarkToTiptap.ts` | | `tiptapToMdc.ts` | `tiptapToComark.ts` | | `mdcToTiptap(body, frontmatterData, opts)` | `comarkToTiptap(tree, opts)` — options collapsed to a single object; frontmatter is part of the tree | | `tiptapToMDC(json, opts) → { body, data }` | `tiptapToComark(json, opts) → MarkdownDocument` — returns one tree with `frontmatter` embedded |
| Legacy | Comark | |---|---| | `import { parseMarkdown } from '@nuxtjs/mdc/runtime/parser/index'` | `import { parseMarkdown } from 'comark'` | | `import { stringifyMarkdown } from '@nuxtjs/mdc/runtime'` | `import { renderMarkdown } from 'comark/render'` | | `parseFrontMatter` / `stringifyFrontMatter` from `remark-mdc` | `js-yaml` (`yaml.load` / `yaml.dump`) for pure YAML/JSON files; for Markdown, frontmatter is now embedded in `MarkdownDocument.frontmatter` | | `compressTree` / `decompressTree` from `@nuxt/content/runtime` | No longer used in app code — see §4 "Legacy bridge" | | `visit` from `unist-util-visit` | Walk the tuple tree manually using the helpers from `src/app/src/utils/comark.ts` |
// Legacy
parseMarkdown(content, {
contentHeading: …,
highlight: { theme },
remark: {
plugins: {
'emoji': { instance: remarkEmojiPlugin },
'remark-mdc': { options: { autoUnwrap: true } },
},
},
})
// Comark
import { parseMarkdown } from 'comark'
import comarkEmoji from 'comark/plugins/emoji'
import shiki from 'comark/plugins/shiki'
import tocPlugin from 'comark/plugins/toc'
parseMarkdown(content, {
autoClose: false,
autoUnwrap: true,
plugins: [
comarkEmoji(),
shiki({ themes: { default, dark, light } }),
tocPlugin({ depth: 2, searchDepth: 2, title: '', links: [] }),
],
})For rendering back to markdown:
// Legacy
const markdown = await stringifyMarkdown(body, data, {
frontMatter: { options: { lineWidth: 0 } },
plugins: { remarkMDC: { options: { autoUnwrap: true } } },
})
// Comark
const markdown = await renderMarkdown(tree, {
blockAttributesStyle: 'frontmatter',
components: { br: () => ':br' },
})Removed from runtime deps: `@nuxtjs/mdc`, `remark-mdc` (moved to devDeps), `unist-util-visit`.
Added: `comark` (pulled from `pkg.pr.new` while it stabilises). `js-yaml` is now used directly for YAML.
`minimark` is also a devDep only — do not import
![npm version][npm-version-href] ![npm downloads][npm-downloads-href] ![License][license-href] Visual edition in production for your Nuxt Content website.
Repo: nuxt-content/nuxt-studio
Converts hardcoded Vue components in a Nuxt Content markdown file into slot-based, Studio-editable MDC components. Use when a user wants their Nuxt Content…