PrismJS / prism

Lightweight, robust, elegant syntax highlighting.
https://prismjs.com
MIT License
12.29k stars 1.29k forks source link

How to use line-number plugin with webpack #1487

Open yinxin630 opened 6 years ago

yinxin630 commented 6 years ago

I hava code link this. But it not show line number

const Prism = require('prismjs/components/prism-core.js');
require('prismjs/plugins/line-numbers/prism-line-numbers.js');
require('prismjs/themes/prism.css');
require('prismjs/components/prism-javascript');
const code = 'var a = 1;';

render() {
    <pre className="line-numbers" data-start="0">
        <code className="language-javascript" dangerouslySetInnerHTML={{ __html: code }} />
    </pre>
}
mAAdhaTTah commented 6 years ago

If you're using webpack, we recommend configuring with the babel plugin: https://github.com/mAAdhaTTah/babel-plugin-prismjs

yinxin630 commented 6 years ago

Thanks, i will try it

yinxin630 commented 6 years ago

Hi. I have used babel-plugin-prismjs. But it still not show line numbers. Debug code found that it has never executed the Prism.plugins.lineNumbers.getLine method.

.babelrc

[
    "prismjs", {
        "languages": ["clike", "javascript", "typescript", "java", "c", "cpp", "python", "ruby", "markup", "markup-templating", "php", "go", "csharp", "css", "markdown", "sql", "json" ],
        "plugins": ["line-numbers"],
        "theme": "default",
        "css": true
    }
]

use

import Prism from 'prismjs';
const html = Prism.highlight(rawCode, Prism.languages[language]);

render() {
    <pre className="line-numbers language-javascript" data-start="0">
            <code className={`language-javascript`} dangerouslySetInnerHTML={{ __html: html }} />
    </pre>
}
yinxin630 commented 6 years ago
setTimeout(() => {
    Prism.highlightAll();
}, 0);

If I add this code after Prism.highlight(), It can display the line number correctly.

edgexie commented 6 years ago

@yinxin630 why it need a setTimeout ?

yinxin630 commented 6 years ago

Is magic

cavo789 commented 5 years ago

Thanks a lot @yinxin630 !

I had a similar problem: using Vue.js, in my HTML page, in the left part, I've an editor allowing to type markdown content and in the right part, the rendered html.

By displaying the page the first time, the rendering was correct like here below

2019-01-22_18h19_02

By typing something in the editor, the HTML is automatically refreshed by Vue and the style is lost

2019-01-22_18h20_41

But, by adding the timeout, the style is correctly applied.

setTimeout(() => {
    Prism.highlightAll();
}, 0);

2019-01-22_18h21_28

jermerf commented 4 years ago

I also am having a problem with this. Trying to use line numbers with VueJS. I've tried doing it with es6 imports:

import Prism from "prismjs"
import "prismjs/plugins/line-numbers/prism-line-numbers"
import "prismjs/components/prism-markup-templating"
import "prismjs/components/prism-swift"
import "prismjs/components/prism-typescript"
import "prismjs/components/prism-php"
import "prismjs/themes/prism-tomorrow.css"
import "prismjs/plugins/line-numbers/prism-line-numbers.css"
...
let html = Prism.highlight(source, Prism.languages[lang], lang)

and I've tried using babel

plugins: [
    [
      "prismjs",
      {
        languages: ["javascript", "css", "markup"],
        plugins: ["line-numbers"],
        theme: "twilight",
        css: true,
      },
    ],
  ],

But no luck, no lines.

mAAdhaTTah commented 4 years ago

First, if you're using the plugin, you only need the import Prism from 'prismjs' line, as the plugin will inject the rest. Second, if you're highlighting server-side or otherwise in Node, line-numbers won't work as it needs an actual DOM. Third, if you can provide a reproducible example, that would be easier to take a look at.

adi518 commented 4 years ago

@yinxin630 It can be even more succinct:

setTimeout(Prism.highlightAll);

And it works because of how the event loop in JavaScript works. Prism is manipulating DOM, which in turn triggers a repaint (asynchronous operation abstracted by the browser) that invokes from a queue of tasks. By using setTimeout, it makes sure that highlightAll queues up after the repaint, so everything is ready-to-go before another manipulation is done.

Yee1014 commented 4 years ago

In Vue.js Components

<template>
      <div>
        <pre class="line-numbers language-markup"><code v-html="codeData"></code></pre>
      </div>
</template>

<script>
import Prism from 'prismjs'
import 'prismjs/plugins/line-numbers/prism-line-numbers.js'
import 'prismjs/plugins/line-numbers/prism-line-numbers.css'
import 'prismjs/themes/prism-tomorrow.css'

export default {
 data () {
    return {
      codeData: '',
    }
  },
 methods: {
    /**
     * show highlight code
     * @param {string} data
     */
 showCode (data) {
      this.codeData = data
      this.codeData = Prism.highlight(data, Prism.languages.markup)
      // key code
      this.$nextTick(() => {
        Prism.highlightAll()
      })
    }
}
}

ReView

QQ截图20200311172539

Others

babel-plugin-prismjs, i don't know it how to work?😂

tonix-tuft commented 4 years ago

Cannot make it work with React (create-react-app) and ES6, below the code I am using:

import React, { useEffect } from "react";
import Prism from "prismjs";
import "../../node_modules/prism-themes/themes/prism-vsc-dark-plus.css";
import { compose } from "js-utl";
import { classNames } from "react-js-utl/utils";
import { useUniqueKey } from "react-js-utl/hooks";
import "prismjs/plugins/line-numbers/prism-line-numbers";

const PrismCode = compose(React.memo)(function PrismCode({
  className = void 0,
  codeClassName = void 0,
  children,
  withLineNumbers = true,
} = {}) {
  const id = useUniqueKey();

  useEffect(() => {
    setTimeout(() => {
      // Prism.highlightAllUnder(document.getElementById(id));
      Prism.highlightAll();
    });
  }, [id, children]);

  return (
    <div id={id} className={classNames("prism-code", className)}>
      <pre
        className={classNames(codeClassName, withLineNumbers && "line-numbers")}
      >
        <code className={codeClassName}>{children}</code>
      </pre>
    </div>
  );
});
PrismCode.displayName = "PrismCode";
export default PrismCode;

<pre> is rendered with line-numbers class, but no line numbers are displayed? Any idea?

Thank you!

mAAdhaTTah commented 4 years ago

@tonix-tuft Line numbers has a css file.

tonix-tuft commented 4 years ago

@mAAdhaTTah Awesome man! It works, thanks here is the complete working code:

import React, { useEffect } from "react";
import Prism from "prismjs";
import "../../node_modules/prism-themes/themes/prism-vsc-dark-plus.css";
import { compose } from "js-utl";
import { classNames } from "react-js-utl/utils";
import { useUniqueKey } from "react-js-utl/hooks";
import "prismjs/plugins/line-numbers/prism-line-numbers";
import "../../node_modules/prismjs/plugins/line-numbers/prism-line-numbers.css";

const PrismCode = compose(React.memo)(function PrismCode({
  className = void 0,
  codeClassName = void 0,
  children,
  withLineNumbers = true,
} = {}) {
  const id = useUniqueKey();

  useEffect(() => {
    Prism.highlightAllUnder(document.getElementById(id));
  }, [id, children]);

  return (
    <div id={id} className={classNames("prism-code", className)}>
      <pre
        className={classNames(codeClassName, withLineNumbers && "line-numbers")}
      >
        <code className={codeClassName}>{children}</code>
      </pre>
    </div>
  );
});
PrismCode.displayName = "PrismCode";
export default PrismCode;
songz commented 2 years ago

Here's how I got mine working:

export function CodeBlock({ children, language }) {
  const ref = React.useRef(null);

  React.useEffect(() => {
    if (ref.current) {
      Prism.highlightElement(ref.current, false);
    }
  }, [children]);

  return (
    <pre className={`language-${language} line-numbers`}>
      <code ref={ref}>{children}</code>
    </pre>
  );
}