Val-istar-Guo / rehype-prism

The unified plugin used to highlight code block in html with Prism
MIT License
12 stars 1 forks source link

Bug: The language "json" has no grammar. #27

Closed amritk closed 5 months ago

amritk commented 5 months ago

Describe the bug We recently switched from rehype-hightlight to rehype-prismjs however in our nuxt (ssr) integration we are getting this error. I tried importing the json language as well but I'm not quite sure where to disable the auto highlight. BUT we would want the autohighlight on the client, just need the server to work.

To Reproduce Steps to reproduce the behavior:

  1. clone this repo https://github.com/scalar/scalar
  2. pnpm i && pnpm build
  3. cd into packages/nuxt
  4. pnpm dev
  5. visit http://localhost:5062/galaxy and see the error

Expected behavior There should be no error, just like if we comment out rehype-prism

Platform (please complete the following information):

Additional context Here is the code I am testing

import rehypeExternalLinks from 'rehype-external-links'
import rehypeFormat from 'rehype-format'
import rehypePrism from 'rehype-prism'
import rehypeRaw from 'rehype-raw'
import rehypeSanitize, { defaultSchema } from 'rehype-sanitize'
import rehypeStringify from 'rehype-stringify'
import remarkGfm from 'remark-gfm'
import remarkParse from 'remark-parse'
import remarkRehype from 'remark-rehype'
import { unified } from 'unified'
import { onServerPrefetch, ref, watch } from 'vue'

import 'prismjs/components/prism-json'
import 'prismjs/components/prism-json5'
import 'prismjs/components/prism-jsonp'

import { sleep } from '../../helpers'

const props = withDefaults(
  defineProps<{
    value?: string
    withImages?: boolean
  }>(),
  {
    withImages: false,
  },
)

const html = ref<string>('')

const disallowedTagNames = props.withImages ? [] : ['img', 'picture']

watch(
  () => props.value,
  async () => {
    // Markdown pipeline
    const result = await unified()
      // Parses markdown
      .use(remarkParse)
      // Support autolink literals, footnotes, strikethrough, tables and tasklists
      .use(remarkGfm)
      // Allows any HTML tags
      .use(remarkRehype, { allowDangerousHtml: true })
      // Creates a HTML AST
      .use(rehypeRaw)
      // Removes disallowed tags
      .use(rehypeSanitize, {
        ...defaultSchema,
        // Makes it even more strict
        tagNames: defaultSchema.tagNames?.filter(
          (tag) => !disallowedTagNames.includes(tag),
        ),
      })
      // Syntax highlighting
      .use(rehypePrism)
      // Adds target="_blank" to external links
      .use(rehypeExternalLinks, { target: '_blank' })
      // Formats the HTML
      .use(rehypeFormat)
      // Converts the HTML AST to a string
      .use(rehypeStringify)
      // Run the pipeline
      .process(props.value)

    // Puts it into the DOM
    html.value = String(result.value)
  },
  { immediate: true },
)

It seems like the json language is not getting loaded

Val-istar-Guo commented 5 months ago
image

If use ssr, <script> window.Prism = { manual: true } </script> should be add to <head>(README). If Prism.manul is not set, PrismJS will automatically parse all <code> on the page, once it is loaded.

The project you provided is very complex and I don't quite understand how to modify and debug this project. I used the following code to add <head> in a nuxt3 project:

useHead({
    {
      innerHTML: 'window.Prism={manual:true};',
    },
  ],
})

However, since I cannot debug this complex project, I am not sure if this is the only problem. If there is still a problem, can you provide me with a simple example repository?

Val-istar-Guo commented 5 months ago

I have also used rehype-prism with nuxt3 and wrote a component:

<template>
  <!-- eslint-disable-next-line vue/no-v-html -->
  <div
    id="main-content"
    :class="[
      'markdown',
      'prose lg:prose-xl',
      'prose-h1:text-xl prose-h1:mt-6',
      'md:prose-h1:text-3xl',
      'lg:prose-h1:text-4xl lg:prose-h1:mt-12',
      'xl:prose-h1:text-4xl xl:prose-h1:mt-12',
      '2xl:prose-h1:text-4xl 2xl:prose-h1:mt-12',
      'prose-table:block prose-table:overflow-x-auto',
      'max-w-none !bg-transparent',
    ]"
    v-html="html"
  />
</template>
<script setup lang="ts">
import rehypeAutolinkHeadings from 'rehype-autolink-headings'
import rehypeKatex from 'rehype-katex'
import rehypePrism from 'rehype-prism'
import rehypeSlug from 'rehype-slug'
import rehypeStringify from 'rehype-stringify'
import remarkFrontmatter from 'remark-frontmatter'
import remarkGfm from 'remark-gfm'
import remarkGithub from 'remark-github'
import remarkMath from 'remark-math'
import remarkParse from 'remark-parse'
import remark2rehype from 'remark-rehype'
import { unified } from 'unified'
// import { remarkRemove } from '~/utils/remark-remove'
import { remarkReplaceImageUrl } from '~/utils/remark-replace-image-url'

// prism.min.css should before themes
import 'prismjs/themes/prism.min.css'
import 'prism-themes/themes/prism-a11y-dark.min.css'
import 'prismjs/components/prism-bash.js'
import 'prismjs/components/prism-docker.js'
import 'prismjs/components/prism-yaml.js'
import 'prismjs/components/prism-toml.js'
import 'prismjs/components/prism-typescript.js'
import 'prismjs/components/prism-json.js'
import 'prismjs/plugins/line-numbers/prism-line-numbers.css'
import 'prismjs/plugins/toolbar/prism-toolbar.min.css'

const props = defineProps<{
  content: string
}>()

const processor = unified()
  .use(remarkParse)
  .use(remarkFrontmatter)
  // .use(remarkRemove, { where: (node: any) => (node.type === 'heading' && node.depth === 1) || (node.type === 'yaml') })
  .use(remarkReplaceImageUrl, {
    replace: (url: string): string => {
      const nodeURL = (url).replace(/^\.\//, '')
      return `/api/articles/files/${nodeURL}`
    },
  })
  .use(remarkGfm)
  .use(remarkMath)
  .use(remarkGithub, { repository: 'val-istar-guo/article' })
  .use(remark2rehype)
  .use(rehypeSlug)
  .use(rehypeAutolinkHeadings)
  .use(rehypeKatex)
  .use(rehypePrism, {
    plugins: [
      'line-numbers',
    ],
  })
  .use(rehypeStringify)

const { data: html } = useAsyncData(
  async () => {
    const html = await processor.process(props.content)
    return html.value
  },
  {
    default: () => '<div></div>',
    watch: [() => props.content],
  },
)
</script>
<style lang="postcss">
.markdown code[class*=language-],
.markdown pre[class*=language-] {
  text-shadow: none;
}
.markdown .token.operator {
  background: none;
}
</style>
hanspagel commented 5 months ago

Woah, this is great! Let me debug this further. If we need more, I’ll make sure to provide a more boiled down example. ✌️

hanspagel commented 5 months ago

Turns out, it seems to work well. It’s just that it’s conflicting with another Prism instance we already have. I’ll try to fix it on our side. If I think the package could benefit from a change, I’ll just open a PR. Feel free to close this here. 👍

Val-istar-Guo commented 5 months ago

😊

Val-istar-Guo commented 5 months ago

@amritk If have any problems, you can reopen this issue.😊