comarkdown/comark/migrate-mdc-to-comark

Claude Code and agent skill by comarkdown/comark

Trust tier 2
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

Migrate a Nuxt project from @nuxtjs/mdc to Comark. Covers package changes, parse/render API mapping, AST format, Nuxt module config, components, slots, plugins, and Nuxt UI integration.

Install

npx vskill@latest install comarkdown/comark/migrate-mdc-to-comark

SKILL.md

Migrate from @nuxtjs/mdc to Comark

@nuxtjs/mdc was Nuxt-only. Comark is its successor: the markdown syntax is fully compatible, your .md files need no changes. What changes is the JavaScript API.

The migration has two parts: Core Package (programmatic API) and Nuxt Module (components, slots, config).

Quick Overview

  • Package: @nuxtjs/mdc → comark (core only) or @comark/nuxt (Nuxt module)
  • Parse: parseMarkdown() → parseMarkdown() · factory: createMarkdownParser() (sync, no await)
  • Render: stringifyMarkdown() → renderMarkdown() from comark/render
  • AST: object tree → compact tuples ['tag', props, ...children]
  • Result: result.body / result.data → document.nodes / document.frontmatter
  • Renderer: <MDCRenderer :body :data> → <MarkdownDocument :value>
  • All-in-one: <MDC :value> → <Markdown :value>
  • Slots: <MDCSlot /> → native <slot />
  • Plugins: global nuxt.config → per-component defineMarkdownComponent({ plugins })
  • Binding: {{ path }} via opt-in binding() plugin + render-time data prop (namespaced paths: data., frontmatter., meta., props.)
  • Markdown files: component syntax unchanged; update binding paths if you used bare MDC names

Core Package

API Mapping
@nuxtjs/mdccomark
parseMarkdown(md, opts)parseMarkdown(md, opts) from comark
createMarkdownParser(opts) (async)createMarkdownParser(opts) (sync, no await)
stringifyMarkdown(body, data)renderMarkdown(document) from comark/render
result.body (MDCRoot)document.nodes (Node[])
result.datadocument.frontmatter
result.data.titledocument.frontmatter.title
result.tocdocument.meta.toc (requires toc plugin)
result.excerptdocument.meta.summary (requires summary plugin)
AST Format
@nuxtjs/mdccomark
{ type: 'root', children: MDCNode[] }{ nodes: Node[], frontmatter: {}, meta: {} }
{ type: 'element', tag: 'p', props: {}, children: [] }['p', {}, ...children]
{ type: 'text', value: 'hello' }'hello' (plain string)
Parse Options
typescript
// Before: MDCOptions
{
remark: { plugins: { /* record */ } },
rehype: { options: {...}, plugins: { /* record */ } },
highlight: { theme: '...', langs: [...] } | false,
toc: { depth: 3, searchDepth: 2 } | false,
}
// After: ParserOptions
{
plugins: ComarkPlugin[], // ordered array, not a record
autoUnwrap: true, // removes <p> from single-paragraph containers
autoClose: true, // completes incomplete syntax (useful for streaming)
// HTML, components, attributes, alerts, task-list, frontmatter are on by default
}
Plugins

The unified/remark/rehype pipeline is replaced by Comark's own lighter plugin interface.

FeatureBeforeAfter
Syntax highlightingrehypeHighlight via createMarkdownParsershiki() from comark/plugins/shiki
Table of ContentsparseMarkdown(md, { toc: { depth: 3 } })toc({ depth: 3 }) plugin
Excerpt / Summaryresult.excerpt (built-in)summary() plugin → document.meta.summary
Emojiremark-emoji (enabled by default)emoji() plugin (opt-in)

Available plugins include: toc, shiki, emoji, task-list, summary, security, alert, math, mermaid, punctuation, binding. Prefer framework paths in apps (@comark/nuxt/plugins/* or @comark/vue/plugins/*); use comark/plugins/* only for bare parseMarkdown().

Nuxt Module

Configuration
typescript
// Before
export default defineNuxtConfig({
modules: ['@nuxtjs/mdc'],
mdc: { highlight: { ... }, remarkPlugins: { ... } },
})
// After
export default defineNuxtConfig({
modules: ['@comark/nuxt'],
// No plugin config here (plugins are defined per-component)
})

@comark/nuxt auto-imports: Markdown, MarkdownDocument, defineMarkdownComponent, defineMarkdownDocumentComponent.

Components
@nuxtjs/mdc@comark/nuxt
<MDCRenderer :body :data :components><MarkdownDocument :value :components>
<MDC :value :parser-options><Markdown :value :options> or <Markdown>{{ md }}</Markdown>
<MDCSlot /><slot />
<MDCSlot unwrap="p" /><slot unwrap="p" />
<slot mdc-unwrap="p" /><slot unwrap="p" />

For a pre-parsed document, use <MarkdownDocument> directly instead of <Markdown>.

<MarkdownDocument> props changes
MDC <MDCRenderer>Comark <MarkdownDocument>Notes
body (MDCRoot)value (MarkdownDocument)Different AST shape
data—Frontmatter is in value.frontmatter
tag—Wrapper is always <div class="comark-content">
prose—Prose* resolution is automatic
unwrapunwrap prop / parse option<Markdown unwrap /> or parse unwrap
—dataRuntime values for data binding / {{ }} — not frontmatter
componentscomponentsSame purpose
—componentsManifestNew: dynamic async component resolver
—streamingNew: streaming mode
—caretNew: animated caret for streaming
Summary rendering
vue
<!-- Before -->
<MDCRenderer :body="result.excerpt ?? result.body" :data="result.data" />
<!-- After -->
<Markdown summary>{{ markdown }}</Markdown>
defineMarkdownComponent

Replaces global mdc: { ... } config. Define reusable components with their own plugins and component mappings:

typescript
import { defineMarkdownComponent } from '@comark/vue'
import shiki from '@comark/nuxt/plugins/shiki'
import toc from '@comark/nuxt/plugins/toc'
import githubLight from '@shikijs/themes/github-light'
import githubDark from '@shikijs/themes/github-dark'
export const ArticleMarkdown = defineMarkdownComponent({
name: 'ArticleMarkdown',
plugins: [shiki({ themes: { light: githubLight, dark: githubDark } }), toc()],
components: { alert: CustomAlert },
})
Slots

<MDCSlot /> → native <slot />. Named slots work the same (#slotName in markdown, <slot name="slotName"> in component). The unwrap attribute (<slot unwrap="p">) strips wrapper tags from children.

Prose Components

Same Prose*.vue naming convention in components/prose/. Resolution changed from kebab-case (prose-p) to PascalCase (ProseP) internally. No file changes needed.

Nuxt UI Integration

When using Nuxt UI, @comark/nuxt registers Nuxt UI prose components automatically. Shorthand callout components are available:

mdc
::note (informational)
::tip (helpful suggestion)
::warning (something to watch out for)
::caution (critical warning)

These are only available with Nuxt UI. Without it, use ::callout{icon="..." color="..."}.

Common Pitfalls

  1. `createMarkdownParser` is sync: no await needed (unlike createMarkdownParser)
  2. Attribute naming: Comark uses attrs.lang, not attrs.language
  3. Frontmatter: stored in document.frontmatter, not passed separately
  4. `renderMarkdown` includes frontmatter: reads document.frontmatter automatically
  5. No `unified` pipeline: mdc.config.ts hooks (pre, remark, rehype, post) have no equivalent, use ComarkPlugin interface instead
  6. Emoji is opt-in: not enabled by default like in MDC's remark-emoji

Component Syntax

The MDC block and inline component syntax is identical, so no changes are needed in .md files for components, slots, and attributes.

Binding and data passing

Supported via the binding plugin + render-time data prop. Differences from MDC:

  1. Opt-in: register binding() and the framework Binding component.
  2. Namespaced paths: {{ data.user.name }}, {{ frontmatter.title }}, not bare {{ user.name }}.
  3. Data at render time: pass :data="{ user, count }" on <Markdown> / <MarkdownDocument>. Do not pass { data } into parseMarkdown.
vue
<script setup lang="ts">
import binding, { Binding } from '@comark/nuxt/plugins/binding'
</script>
<template>
<Markdown
:value="markdown"
:plugins="[binding()]"
:components="{ Binding }"
:data="{ user: { name: 'Ada' }, count: 3 }"
/>
</template>

:prefixed component props (:label="data.user.name") resolve without the binding plugin. Use the plugin for inline {{ path }} text (and renderer If for ::if).

Security

  • Security scanPassed, 96 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
905
Repository forks
33
7-day trend score
34

Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/comarkdown/comark/migrate-mdc-to-comark/badge)](https://verified-skill.com/skills/comarkdown/comark/migrate-mdc-to-comark)

Something wrong with this skill or its page? Tell us.