I want to add this script to my Nuxt code:
<script>
tinymce.init({
selector: "#mytextarea",
plugins: "emoticons",
toolbar: "emoticons",
toolbar_location: "bottom",
menubar: false
});
</script>
I can just throw it into my component's template body (This script has to be inside <body>
not <head>
) like this:
and interestingly enough it works but there are two issues here:
selector
dynamically to a prop or a data property! It has to be hardcoded.So I was wondering if anybody knows how can I integrate such scripts into my Nuxt project properly?
<script>
tags in the templates with error message:Templates should only be responsible for mapping the state to the UI. Avoid placing tags with side-effects in your templates, such as
<script>
, as they will not be parsed.
However I do not recommend doing this by yourself and instead use official Vue wrapper (docs) - use v3 for Vue 2. Official integration handles all the edge cases like component activation/deactivation (when used together with <keep-alive>
) and proper cleanup when the component is destroyed which is required in order to avoid nasty memory leaks
const ed = Vue.component("MyEditor", {
props: ["id", "value"],
template: `
<div>
<textarea :id="id" :value="value"></textarea>
</div>
`,
mounted() {
const me = this;
window.tinymce.init({
selector: "#" + this.id,
plugins: "emoticons",
toolbar: "emoticons",
toolbar_location: "bottom",
menubar: false,
setup: function (editor) {
editor.on("change input undo redo", function () {
me.$emit('input', editor.getContent({format: 'text'}))
});
}
});
}
});
Demo
As TinyMCE is completely JS rendered, it does not make sense to execute it during server side rendering. In fact, above code will not work at all on server as there is no window
variable. Use Nuxt's <client-only>
component to force Nuxt to render editor only on the client...
UPDATE: On the other side the mounted
lifecycle hook is not called during SSR at all so maybe this will work just fine even without the <client-only>
As mentioned in the accepted answer, the official vue package is the way to go. Even with the official package, there were a number of issues once I pulled it into Nuxt.
Here's a step by step of how I got it working. Here are the versions of everything involved:
"tinymce": "^5.10.3",
"@tinymce/tinymce-vue": "^3.2.8",
"vue": "^2.6.11",
"nuxt": "2.15.8",
The tinymce-vue package requires a tinymce to be available. You can either install it via npm like above, or use the cloud-hosted version (see Prerequisites here).
You'll need to ensure the component is wrapped in the <client-only>
tag to avoid SSR errors.
Additionally, if self-hosting the tinymce package, you'll want to only import it on the client-side. Otherwise you will see errors like:
[Vue warn]: Failed to resolve async component: ... Reason: ReferenceError: navigator is not defined
You can do this by using require
and if (process.client) {
around them.
Ex:
if (process.client) {
require('tinymce/tinymce')
require('tinymce/themes/silver')
require('tinymce/icons/default')
require('tinymce/plugins/lists') // do this for any plugins you use on the editor
}
import Editor from '@tinymce/tinymce-vue'
At this point the editor should be loading on your page, but styles are probably not loading.
You can fix this by adding require('tinymce/skins/ui/oxide/skin.min.css')
below the other require
s.
Now the styles will be fixed but the tinymce theme will still look for other CSS files like mobile, min versions on its own, and cause network errors.
Ex:
404 http://localhost:3000/_nuxt/skins/ui/oxide/content.min.css
404 http://localhost:3000/_nuxt/skins/ui/oxide/skin.min.css
For content:
You can either copy that file to the static folder with the same path, or override them with the content_css setting (in the Vue component init
options).
For skin:
Since you already provided it as a module, set skin: false
in the Vue component init
options.
UPDATED 2022-11-29: Fixed Typo
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With