Closed joshgoebel closed 3 years ago
For the record, as of (I assume) 8 days ago, module singleton does not work with the vue2 plugin whatsoever, even if I finagle with versioning to try to get everything to use the same version.
Does your project have multiple versions of the library?
I've been having a hard time registering any languages using Vue 3. Results looks the same as in https://github.com/highlightjs/vue-plugin/issues/8 so possibly the same underlying cause. ~I could only see one version of highlight.js in my node_modules though 🤔~ EDIT: think I was mistaken here.
I ended up forking this and making Vue.ts return a function to construct the plugin, which we can pass an instance of hljs in to. Looks like:
import { ref, h, computed, defineComponent, Plugin, watch } from 'vue'
import { escapeHtml } from './lib/utils'
function createPlugin (hljs: any): Plugin {
const component = defineComponent({...})
return {
install(app) {
app.component('highlightjs', component)
},
}
}
export default createPlugin
Usage looks almost identical to current:
import 'highlight.js/styles/default.css'
import hljs from 'highlight.js/lib/core'
import javascript from 'highlight.js/lib/languages/javascript'
import hljsVuePlugin from "@highlightjs/vue-plugin"
hljs.registerLanguage('javascript', javascript);
const app = createApp(App)
app.use(hljsVuePlugin(hljs))
app.mount('#app')
Would you consider moving to dependency injection instead of relying on singletons? I realise it would be breaking API change but this way you don't even need to register highlight.js as a dependency; people can just bring their own.
We may end up going that route... but I'd be very curious for anyone to track down WHY this isn't working as expected. Is one place using a different import? Is one place using require vs import? There has got to be a reason the behavior changed.
Thanks for the speedy reply! 🙂
I'm not sure what I did wrong yesterday but from testing today things are starting to make a bit more sense.
So, as you already know, the problem comes from installing @highlightjs/vue-plugin@next
and highlight.js
at a version other than ^10.7.1
(e.g. highlight.js@9
, highlight.js@10.7.0
, or highlight.js@11
.)
In any of these cases, NPM will also install a separate copy of highlight.js@^10.7.1
within the vue plugin folder and hljs will not work as a singleton. This structure will be saved in the package-lock.json and I'm not sure how to fix it without deleting the lock file and node_modules then starting afresh with npm install highlight.js@10 @highlightjs/vue-plugin@next
.
I'm still in favour of using injection to allow people to bring whatever version they please, but for the time being we could update the readme to specify ^10.7.1
should be used? I think I got in to this mess by allowing highlight.js to install @ latest, i.e. 11.0.1
.
I'm still in favour of using injection
Me too, I'd like the option app.use(hljsVuePlugin, { hljs })
So if we went that route... should we deprecate slightly using the bundled Highlight.js or change how it works? I think (because there are so few talking here) that it must work great as-is for a LOT of people... so I'd hate to make it more complex for everyone just to solve what is more of an edge case for some with more complex apps... So what about:
core
to common
so that "by default" you get a workable set of 30-40 languages out of the box...Thoughts?
If someone wants to contribute small PRs (eventually we'd need for both v1 and v2 I think?) to allow injecting a different HLJS instance, makes sense. Tagging accordingly.
i have same problem. The plugin is use difference highlight,js instance when difference version highlight.js be installed in one project.
Opened a PR but working through this problem, I realized there are other ways to fix this problem:
Only install this plugin rather than both highlight.js
and @highlightjs/vue-plugin
If using yarn, adding this to package.json
will force only 1 instance of highlight.js
to exist
"resolutions": {
"highlight.js": "^11.0.1"
}
If using webpack, adding this to your config will force it to resolve to a fixed instance
export default {
resolve: {
alias: {
'highlight.js': path.resolve('node_modules/highlight.js'),
},
},
}
I think this is closed with #17 also and 2.1.0.
The module singleton works most of the time but it's not guaranteed across submodules in node.js.
A module "singleton" is based on the resolved file path of the imported module url (that's not a "great article" but it does define the import process).
Normally, when version requirements match, all packages will collapse down to a single
highlight.js
in the parent package. It is perfectly acceptable for the main project code and every sub module to rely on a separate version ofhighlight.js
though as they can each resolve to their ownnode_modules
copy of the module and each have their own "singleton" (per resolved file path).I haven't dug into the new vue plugin completely so if there is some
window.hljs
magic happening that was briefly mentioned above ignore this...It looks like with the current setup
@highlightjs/vue-plugin
has a dependency of"highlight.js": "^10.7.1"
. If the parent package that imports@highlightjs/vue-plugin
had a lock file at10.7.0
the project would end up structured like this:Here the docco example
hljs.registerLanguage('javascript', javascript)
would not be seen by thehljs
instance in the@highlightjs/vue-plugin
module.Barring the parent package injecting
hljs
into the plugin already suggested above, you start needing peer dependencies which have their own issues.It's a bit of a wat moment when you do run into the "not quite a singleton" issue in the wild, so personally I only rely on module singletons within a single module/package. The super esoteric version of this I've seen is when running on case insensitive file systems and one file in your project does an import on a differently cased name of a file : /
Originally posted by @mhio in https://github.com/highlightjs/highlight.js/issues/2815#issuecomment-813751467