If you try to use Quill Editor with Nuxt 3 when rendering a page in SSR you will get this error:
500 document is not defined.
That means NodeJS doesn't have the global variable 'document'. Because SSR rendering is executed in
a NodeJS environment, not a browser.
The sad fact: <client-only> won't help with this problem. The problem with quill's code is that during import, it assumes it's being executed in the browser. I hope you remember that the code imported from the module is not just imported, but executed, i.e. the authors of Quill wrote it so that the 'document' object is immediately accessed there. Very bad.
One solution is to disable SSR, but its an awful solution. But the second solution is to use dynamic JS imports.
My <script lang="ts" setup> in QuillEditor.vue in Nuxt 3 project:
import 'quill/dist/quill.core.css';
import 'quill/dist/quill.snow.css';
// import Quill from 'quill'; // SSR problem with 'document', need to use dynamic import
import type Quill from 'quill';
const elemForQuillEditor = ref<HTMLDivElement|null>(null);
let editor: null|Quill = null; // Do not store in ref() - it causes bugs!
// ...
async function createQuillAndSetListeners() {
const Quill = (await import('quill')).default; // This is most important thing - usage of JS dynamic import
if (!elemForQuillEditor.value) return;
editor = new Quill(elemForQuillEditor.value, {
theme: 'snow',
modules: {
history: {
delay: 2000,
maxStack: 500,
userOnly: true,
},
toolbar: {
container: [
['bold', 'italic', 'underline', 'strike'],
['link'],
[{ list: 'ordered' }, { list: 'bullet' }],
[{ script: 'sub' }, { script: 'super' }],
[{ header: [1, 2, 3, 4, 5, 6, false] }],
[{ color: [] }, { background: [] }],
['clean'],
['undo', 'redo'],
],
handlers: {
undo() {
editor?.history.undo();
},
redo() {
editor?.history.redo();
},
},
},
},
placeholder: props.placeholder,
});
editor.on('text-change', () => {
if (!editor) return;
// ... my other code
});
}
// ...
onMounted(createQuillAndSetListeners);
Now your Quill editor will work in Nuxt 3 even during SSR!