How to install Highlight.js to Rails 7 with importmap?
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.
Solution 1:
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'
Solution 2:
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).