comarkdown/comark/migrate-mdc-to-comark
Claude Code and agent skill by comarkdown/comark
- community
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-comarkSKILL.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()fromcomark/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-componentdefineMarkdownComponent({ plugins }) - Binding:
{{ path }}via opt-inbinding()plugin + render-timedataprop (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/mdc | comark | |
|---|---|---|
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.data | document.frontmatter | |
result.data.title | document.frontmatter.title | |
result.toc | document.meta.toc (requires toc plugin) | |
result.excerpt | document.meta.summary (requires summary plugin) |
AST Format
@nuxtjs/mdc | comark | |
|---|---|---|
{ 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
Plugins
The unified/remark/rehype pipeline is replaced by Comark's own lighter plugin interface.
| Feature | Before | After | |
|---|---|---|---|
| Syntax highlighting | rehypeHighlight via createMarkdownParser | shiki() from comark/plugins/shiki | |
| Table of Contents | parseMarkdown(md, { toc: { depth: 3 } }) | toc({ depth: 3 }) plugin | |
| Excerpt / Summary | result.excerpt (built-in) | summary() plugin → document.meta.summary | |
| Emoji | remark-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
@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 | |
unwrap | unwrap prop / parse option | <Markdown unwrap /> or parse unwrap | |
| — | data | Runtime values for data binding / {{ }} — not frontmatter | |
components | components | Same purpose | |
| — | componentsManifest | New: dynamic async component resolver | |
| — | streaming | New: streaming mode | |
| — | caret | New: animated caret for streaming |
Summary rendering
defineMarkdownComponent
Replaces global mdc: { ... } config. Define reusable components with their own plugins and component mappings:
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:
These are only available with Nuxt UI. Without it, use ::callout{icon="..." color="..."}.
Common Pitfalls
- `createMarkdownParser` is sync: no
awaitneeded (unlikecreateMarkdownParser) - Attribute naming: Comark uses
attrs.lang, notattrs.language - Frontmatter: stored in
document.frontmatter, not passed separately - `renderMarkdown` includes frontmatter: reads
document.frontmatterautomatically - No `unified` pipeline:
mdc.config.tshooks (pre,remark,rehype,post) have no equivalent, useComarkPlugininterface instead - 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:
- Opt-in: register
binding()and the frameworkBindingcomponent. - Namespaced paths:
{{ data.user.name }},{{ frontmatter.title }}, not bare{{ user.name }}. - Data at render time: pass
:data="{ user, count }"on<Markdown>/<MarkdownDocument>. Do not pass{ data }intoparseMarkdown.
: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
- SKILL.md in the repositoryCheckingdocs/skills/migrate-mdc-to-comark/SKILL.md
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
[](https://verified-skill.com/skills/comarkdown/comark/migrate-mdc-to-comark)