content
content copied to clipboard
Code highlighting not working - Nuxt 3
Environment
- Operating System:
Linux
- Node Version:
v16.17.0
- Nuxt Version:
3.0.0-rc.9-27702110.abd5dc5
- Nitro Version:
0.5.0-27700766.92d711f
- Package Manager:
[email protected]
- Builder:
vite
- User Config:
preset
,target
,mode
,nitro
,runtimeConfig
,app
,css
,imports
,components
,build
,modules
,vueuse
,content
,experimental
,vite
,directus
- Runtime Modules:
@nuxtjs/tailwindcss
,nuxt-directus
,@nuxtjs/[email protected]
,unplugin-icons/nuxt
,@nuxtjs/[email protected]
,@vueuse/[email protected]
,@nuxt/content
,@pinia/nuxt
- Build Modules:
-
Reproduction
nuxt.config.js
// content
content: {
toc: {
depth: 2,
searchDepth: 2
},
highlight: {
// Theme used in all color schemes.
theme: 'github-light',
preload: ['diff', 'ts', 'js', 'css', 'java', 'groovy', 'sql', 'xml', 'json'],
}
},
page.vue
<template>
<ContentRenderer :value="post"/>`
</template>
<script setup>
const post = await queryContent("blog")
.where({slug: route.params.slug})
.findOne();
</script>
package.json
"@nuxt/content": "^2.0.1",
Describe the bug
Whatever I try, the code highlighting does not work and the document tree does not seem to get any additional classes attached.
I'm currently migrating my blog from Gridsome to Nuxt, so the markdown files are correct and already used in production.
Am I missing something?
Additional context
No response
Logs
No response
There was some issue with shiki highlighter which is resolved in edge version, and soon will be released as v2.1.0
.
This issue also should resolve using edge channel, Feel free to install the edge channel and test it.
I am on the edge channel and I am having the same issue.
"devDependencies": {
"@nuxtjs/eslint-config-typescript": "^10.0.0",
"@nuxtjs/eslint-module": "^3.1.0",
"@typescript-eslint/eslint-plugin": "^5.30.6",
"@typescript-eslint/parser": "^5.30.6",
"eslint": "^8.20.0",
"eslint-plugin-nuxt": "^3.2.0",
"eslint-plugin-vue": "^9.2.0",
"nuxt": "3.0.0-rc.9",
"sass": "^1.50.0",
"sass-loader": "^10.2.1",
"@nuxt/content": "npm:@nuxt/content-edge@latest"
}
Could you provide a simple reproduction on stackblits
it somehow doesn't work with <ContentRenderer :value="blogContent" />
im using the parser directly, which was the only way to render the md content coming from my server
my script:
<template>
<div>
<ContentRenderer :value="blogContent" />
</div>
</template>
<script setup lang="ts">
import markdownParser from "@nuxt/content/transformers/markdown";
const { data: blog, error } = await useFetch<Blog>(
() => `/blog/blog-details/${slug}`,
{
baseURL: config.public.baseURL,
initialCache: false,
}
);
const blogContent = await markdownParser.parse(
"blog-content-test",
blog.value.content
);
<script>
Result:
Expected:
@Flowko Using "@nuxt/content/transformers
in Vue files is a bad practise, please avoid doing this
Most likely there is a simple solution for your case, could you provide a reproduction in Stackblitz so we can dig for the real issue here?
@farnabaz is there a better option that u recommend using? all I need is a way to convert MD string content coming from the server into component-based HTML, like how it's being done on this library, for the reproduction I'll try to do that when I'm free, its just the code above btw
Instead of using transformer in Vue file, you can create a custom API in server/api/
directory and use transformer inside that API endpoint
thanks for the note, seems that was it, plus i had to use shiki transformer as well to format the code: for anyone having the same issues:
//File: server/api/transform.post.ts
import markdownParser from "@nuxt/content/transformers/markdown";
import shikiParser from "@nuxt/content/transformers/shiki";
export default defineEventHandler(async (event) => {
const body = await readBody(event);
const blogContent = await markdownParser.parse(
"blog-content-test",
body.content,
{}
);
const shikiContent = await shikiParser.transform(blogContent, {
theme: "one-dark-pro",
preload: [
"json",
"js",
"ts",
"html",
"css",
"vue",
"diff",
"shell",
"markdown",
"yaml",
"bash",
"ini",
],
apiURL: "/api/_content/highlight",
});
return shikiContent;
});
//File: pages/blog/[slug].vue
<template>
<div>
<ContentRenderer :value="content" />
</div>
</template>
<script setup lang="ts">
const { data: blog, error } = await useFetch<Blog>(
() => `/blog/blog-details/${slug}`,
{
baseURL: config.public.baseURL,
initialCache: false,
}
);
const { data: content } = await useFetch(() => `/api/transform`, {
method: "POST",
body: {
content: blog.value.content,
},
});
</script>
Why don't you merge these two api calls into single one? You can simply pass slug
to your API and fetch your markdown, parse it and return the result
yes i thought of that, but i have another content i'll have to parse as well
Hi, I am facing the same issue. Not able to integrate Shiki as suggested in the docs.
For example, in .md files, the code is highlighted properly, but doesn't render it same way.

Output:

Nuxt Config:

Note: I am using tailwindcss prose, but I hope that should not affect.
@amit-chaudhary4 I think your issue is because you're trying to use the shiki highlighter API directly, and in the wrong place. Check out the docs on @nuxt/content Configuration. I'm a bit behind on the status of edge-channel features, but last I checked, highlighter
wasn't a configurable property under the content.markdown
key path.
If you need to implement custom syntax highlighting logic the easiest route is probably to create a server-side middleware or content transformer.
I am also not getting code highlighting to work fully. The rendered HTML seems to be missing the wrapper div
.
<div class="highlight-ts prose-code">...</div>
I do get some styles on the text, but there is no frame with a background-color etc.
It does not seem to make a difference what way I use to render the MD file to the page:
<ContentDoc />
<ContentRenderer :value="currentArticle" />
My package.json
{
"private": true,
"scripts": {
"build": "nuxt build",
"dev": "nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview",
"postinstall": "nuxt prepare"
},
"devDependencies": {
"@nuxt/content": "^2.2.2",
"@nuxt/image-edge": "^1.0.0-27827328.bc9ddc0",
"@nuxtjs/eslint-config-typescript": "^12.0.0",
"eslint": "^8.28.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.2.1",
"nuxt": "3.0.0",
"prettier": "^2.7.1"
},
"dependencies": {
"@vueuse/core": "^9.5.0",
"@vueuse/nuxt": "^9.5.0"
}
}
nuxt.config.ts
export default defineNuxtConfig({
modules: ['@vueuse/nuxt', '@nuxt/content', '@nuxt/image-edge'],
typescript: { strict: true },
content: {
highlight: {
theme: 'github-light',
},
},
image: {
cloudinary: {
baseURL:
'https://res.cloudinary.com/xyz/image/upload/xyz/',
},
},
})
@leopoldkristjansson By default Content module does not add background or border to code blocks. What are you referring as wrapper div is part of Nuxt Typography Theme which provide a nice styling for Prose components.
You can also create your custom Prose component in components/content
directory, See Docs
@Flowko Heads-up for coming changes in next release. Module no longer provide highlight
api. Everything should pass through transformers.
@leopoldkristjansson By default Content module does not add background or border to code blocks. What are you referring as wrapper div is part of Nuxt Typography Theme which provide a nice styling for Prose components. You can also create your custom Prose component in
components/content
directory, See Docs
Thank you. That was it. I didn't realize right away that these were separate.
Hey is there any update on this? Installing Nuxt Typography Theme breaks my freshly created Nuxt Content project completely.
Failed to resolve import "@vueuse/core" from "node_modules\@nuxt-themes\typography\components\ProseCodeCopyButton.vue". Does the file exist?
I have already tried to add the div wrapper by customizing the ProseCode.vue component. But this did not help :-(.
mark,,just add '@nuxt-themes/typography' package. then I fixed it.😒😒😒
After i change:
{
"devDependencies": {
- "@nuxt/content": "^2.0.0"
+ "@nuxt/content": "npm:@nuxt/content-edge@latest"
}
}
it worked!