content icon indicating copy to clipboard operation
content copied to clipboard

Code highlighting not working - Nuxt 3

Open mklueh opened this issue 2 years ago • 20 comments

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

mklueh avatar Sep 03 '22 10:09 mklueh

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.

farnabaz avatar Sep 07 '22 08:09 farnabaz

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"
  }

image

Noxdor avatar Sep 07 '22 14:09 Noxdor

Could you provide a simple reproduction on stackblits

farnabaz avatar Sep 07 '22 15:09 farnabaz

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: image

Expected: image

Flowko avatar Nov 02 '22 17:11 Flowko

@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 avatar Nov 03 '22 08:11 farnabaz

@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

Flowko avatar Nov 03 '22 08:11 Flowko

Instead of using transformer in Vue file, you can create a custom API in server/api/ directory and use transformer inside that API endpoint

farnabaz avatar Nov 03 '22 09:11 farnabaz

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>



Flowko avatar Nov 03 '22 09:11 Flowko

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

farnabaz avatar Nov 03 '22 09:11 farnabaz

yes i thought of that, but i have another content i'll have to parse as well

Flowko avatar Nov 03 '22 09:11 Flowko

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.

image

Output:

image

Nuxt Config:

image

Note: I am using tailwindcss prose, but I hope that should not affect.

amit-chaudhary4 avatar Nov 03 '22 12:11 amit-chaudhary4

@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.

nberlette avatar Nov 04 '22 14:11 nberlette

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.

Screenshot 2022-12-12 at 00 49 03

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 avatar Dec 12 '22 00:12 leopoldkristjansson

@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

farnabaz avatar Dec 12 '22 09:12 farnabaz

@Flowko Heads-up for coming changes in next release. Module no longer provide highlight api. Everything should pass through transformers.

farnabaz avatar Dec 12 '22 10:12 farnabaz

@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.

leopoldkristjansson avatar Dec 12 '22 23:12 leopoldkristjansson

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 :-(.

joni1802 avatar May 20 '23 01:05 joni1802

mark,,just add '@nuxt-themes/typography' package. then I fixed it.😒😒😒

zyhnbyyds avatar Jun 16 '23 09:06 zyhnbyyds

After i change:

{
  "devDependencies": {
-   "@nuxt/content": "^2.0.0"
+   "@nuxt/content": "npm:@nuxt/content-edge@latest"
  }
}

it worked!

tandv592082 avatar Jul 15 '23 08:07 tandv592082