How to install Highlight.js to Rails 7 with importmap?
Asked Answered
J

2

6

I created a simple Rails 7 application with Post, Comment models using Tailwindcss.

And I have a problem with importing the highlight.js library to render syntax code in Trix editor.

This is config/importmap.rb:

# Pin npm packages by running ./bin/importmap

pin "application", preload: true
pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true
pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true
pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true
pin_all_from "app/javascript/controllers", under: "controllers"
pin "trix"
pin "@rails/actiontext", to: "actiontext.js"
pin "highlight.js", to: "https://ga.jspm.io/npm:[email protected]/es/index.js"

And javascrip/application.js

// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
import "@hotwired/turbo-rails"
import "controllers"
import "trix"
import "@rails/actiontext"

import "highlight.js"

import hljs from "highlight.js/lib/core"
import javascript from 'highlight.js/lib/languages/javascript'
import bash from 'highlight.js/lib/languages/bash'
import ruby from 'highlight.js/lib/languages/ruby'

hljs.registerLanguage('javascript', javascript)
hljs.registerLanguage('bash', bash)
hljs.registerLanguage('ruby', ruby)

document.addEventListener('turbo:load', (event) => {
    document.querySelectorAll('pre').forEach(function(preElement) {
        const languageRegex = /(?!lang\-\\w\*)lang-\w*\W*/gm
        const codeElement = document.createElement('code')

        let preElementTextNode = preElement.removeChild(preElement.firstChild)
        let language = preElementTextNode.textContent.match(languageRegex)

        if (language) {
            language = language[0].toString().trim()
            preElementTextNode.textContent = preElementTextNode.textContent.replace(language, '')
            codeElement.classList.add(language, 'line-numbers')
        }

        codeElement.append(preElementTextNode)
        preElement.append(codeElement)
    })

    document.querySelectorAll('pre code').forEach((el) => {
        hljs.highlightElement(el)
    })
})

The message error in a browser:

Uncaught Error: Unable to resolve specifier 'highlight.js/lib/core' from http://localhost:3000/assets/application-18666563d3b8c368b2de6f038dc38276f2eb21cb75d45593f9efd1e4200f55c4.js
    throwUnresolved es-module-shims.js:792
    d es-module-shims.js:655
    L es-module-shims.js:646
    promise callback*getOrCreateLoad es-module-shims.js:644
    d es-module-shims.js:659
    L es-module-shims.js:646
    promise callback*getOrCreateLoad es-module-shims.js:644
    topLevelLoad es-module-shims.js:393
    processScript es-module-shims.js:766
    processScriptsAndPreloads es-module-shims.js:668
    ze es-module-shims.js:373
    promise callback* es-module-shims.js:335
    <anonymous> es-module-shims.js:2

Am I wrong anything?

Thanks.

Justiciary answered 10/1, 2022 at 17:24 Comment(0)
B
3

according to the code from your pin url [email protected] index, you should use import HighlightJS, beside that, this index js file already import js, bash and ruby (and also ~ other 40 popular languages), so you no need to register by yourself.

pin "highlight.js", to: "https://ga.jspm.io/npm:[email protected]/es/index.js"
// application.js
import { HighlightJS } from "highlight.js"

document.addEventListener('turbo:load', (event) => {
  document.querySelectorAll('pre').forEach(function(preElement) {
    // your code
    // after extract the lang, for example: lang-ruby
    // you could highlight code as below
    HighlightJS.highlightElement(codeElement, language.split("-")[1])
  });
});
application.html.erb
<%= stylesheet_link_tag "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.4.0/styles/default.min.css" %>
<%= javascript_importmap_tags %>

Note: about the line-number, i tried highlightjs-line-numbers.js but it looks like this plugin just work with CommonJS (your index js file is es6).

Ballplayer answered 11/1, 2022 at 9:10 Comment(3)
It's working! However, at the end of pre block in Trix, we must add the line "lang-xxx". How to make highlight.js auto detect language programming? Thanks.Justiciary
@Justiciary it's hard problem =,=Ballplayer
It will load all languages files, can I just load the ones needed?Kosygin
G
3

It looks like you import highlight.js in your application.js then attempt to import it again from the pinned location which is not the pattern recommended in importmaps documentation.

Try either importing the entirety of highlight.js or just import the specific languages you want.

Try updating the imports on your application.js file and removing the language specific

import hljs from 'highlight.js';
//import hljs from "highlight.js/lib/core"
//import javascript from 'highlight.js/lib/languages/javascript'
//import bash from 'highlight.js/lib/languages/bash'
//import ruby from 'highlight.js/lib/languages/ruby'

or

import {javascript, ruby, bash} from 'highlight.js'
Guillermo answered 11/1, 2022 at 3:16 Comment(1)
I'm getting this error Uncaught SyntaxError: The requested module 'highlight.js' does not provide an export named 'bash'Yarndyed
B
3

according to the code from your pin url [email protected] index, you should use import HighlightJS, beside that, this index js file already import js, bash and ruby (and also ~ other 40 popular languages), so you no need to register by yourself.

pin "highlight.js", to: "https://ga.jspm.io/npm:[email protected]/es/index.js"
// application.js
import { HighlightJS } from "highlight.js"

document.addEventListener('turbo:load', (event) => {
  document.querySelectorAll('pre').forEach(function(preElement) {
    // your code
    // after extract the lang, for example: lang-ruby
    // you could highlight code as below
    HighlightJS.highlightElement(codeElement, language.split("-")[1])
  });
});
application.html.erb
<%= stylesheet_link_tag "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.4.0/styles/default.min.css" %>
<%= javascript_importmap_tags %>

Note: about the line-number, i tried highlightjs-line-numbers.js but it looks like this plugin just work with CommonJS (your index js file is es6).

Ballplayer answered 11/1, 2022 at 9:10 Comment(3)
It's working! However, at the end of pre block in Trix, we must add the line "lang-xxx". How to make highlight.js auto detect language programming? Thanks.Justiciary
@Justiciary it's hard problem =,=Ballplayer
It will load all languages files, can I just load the ones needed?Kosygin

© 2022 - 2024 — McMap. All rights reserved.