NextJS + CKEditor5 with CodeBlock plugin fails (global CSS import error)

3.9k views Asked by At

I am trying to use CKEditor5 in NextJS. Here are my package versions:

"@ckeditor/ckeditor5-build-classic": "^22.0.0",
"@ckeditor/ckeditor5-code-block": "^22.0.0",
"@ckeditor/ckeditor5-react": "^2.1.0",
"next": "9.5.1",

Related part of my component is:

import CKEditor from '@ckeditor/ckeditor5-react';
import ClassicEditor from '@ckeditor/ckeditor5-build-classic';
import CodeBlock from '@ckeditor/ckeditor5-code-block/src/codeblock';

const editorConfig = {
  toolbar: ['heading', '|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'blockQuote', 'codeBlock'],
  plugins: [CodeBlock],
  codeBlock: {
    languages: [
      { language: 'plaintext', label: 'Plain text' },
      { language: 'c', label: 'C' },
      { language: 'cs', label: 'C#' },
      { language: 'cpp', label: 'C++' },
      { language: 'css', label: 'CSS' },
      { language: 'diff', label: 'Diff' },
      { language: 'html', label: 'HTML' },
      { language: 'java', label: 'Java' },
      { language: 'javascript', label: 'JavaScript' },
      { language: 'php', label: 'PHP' },
      { language: 'python', label: 'Python' },
      { language: 'ruby', label: 'Ruby' },
      { language: 'typescript', label: 'TypeScript' },
      { language: 'xml', label: 'XML' }
    ]
  }
};

export default function AddForm() {
  return (
    <CKEditor
      editor={ClassicEditor}
      config={editorConfig}
    />
  )
}

And I am getting the following error.

./node_modules/@ckeditor/ckeditor5-code-block/theme/codeblock.css
Global CSS cannot be imported from within node_modules.
Read more: https://err.sh/next.js/css-npm
Location: node_modules/@ckeditor/ckeditor5-code-block/src/codeblockui.js

CKEditor CodeBlock plugin trying to import global CSS in package as I see. Here is one example in node_modules package in codeblockui.js:

import '../theme/codeblock.css';

How can I solve this issue?

5

There are 5 answers

0
plsdev89 On BEST ANSWER

The global CSS import error problem is addressed from Next.js 13. https://github.com/vercel/next.js/discussions/27953#discussioncomment-3978605

1
Artiphishle On

have you set type or module in the package.json?

If there is any hope you could upgrade packages, or copy the whole repo and check if it's a legacy issue?

Node version comes to mind too, but I had the issue as well with NextJS 13 and Node LTS, I think it had to do with setting type: module (or let's say: not setting). I had to enable it once due to another issue, then finally walked into it, there is no need for that properties.

before NextJS 9 you had to use the next-css package which allowed to import from anywhere, so uninstall that package if you have it (also provide the whole package.json please. and next.config.

If you're using multiple CSS files, import them all from _app.js, read that could introduce conflicts as well.

Otherwise I recommend showing a tsconfig/jsconfig additionally, if you're in a monorepo or single package, how you

0
Suraj KV On

Since it's a limitation on the next js side, the easiest way to get this done is by using a custom built version from https://ckeditor.com/ckeditor-5/online-builder/

Add in all the plugins you wanted and then follow the instructions in https://ckeditor.com/docs/ckeditor5/latest/installation/frameworks/react.html#integrating-a-build-from-the-online-builder

I have tried it on next js 12.2.2


    import { useRef } from 'react';

    import { CKEditor } from '@ckeditor/ckeditor5-react';
    import DecoupledEditor from 'ckeditor5-custom-build/build/ckeditor';

    const Editor = () => {
        const editorRef = useRef(null);

        return (
            <CKEditor
                editor={DecoupledEditor}
                data="<p>Hello from CKEditor 5!</p>"
                style={{ height: 500 }}
                config={{
                    codeBlock: {
                        languages: [
                            { language: 'plaintext', label: 'Plain text' },
                            { language: 'c', label: 'C' },
                            { language: 'cs', label: 'C#' },
                            { language: 'cpp', label: 'C++' },
                            { language: 'css', label: 'CSS' },
                            { language: 'diff', label: 'Diff' },
                            { language: 'html', label: 'HTML' },
                            { language: 'java', label: 'Java' },
                            { language: 'javascript', label: 'JavaScript' },
                            { language: 'php', label: 'PHP' },
                            { language: 'python', label: 'Python' },
                            { language: 'ruby', label: 'Ruby' },
                            { language: 'typescript', label: 'TypeScript' },
                            { language: 'xml', label: 'XML' }
                        ]
                    }

                }}
                onReady={editor => {
                    // You can store the "editor" and use when it is needed.
                    console.log('Editor is ready to use!', editor);
                    editor.ui.getEditableElement().parentElement.insertBefore(
                        editor.ui.view.toolbar.element,
                        editor.ui.getEditableElement()
                    );

                    editorRef.current = editor;
                }}
                onChange={(event, editor) => {
                    const data = editor.getData();
                    console.log({ event, editor, data });
                }}
                onBlur={(event, editor) => {
                    console.log('Blur.', editor);
                }}
                onFocus={(event, editor) => {
                    console.log('Focus.', editor);
                }}

                onError={(error, { willEditorRestart }) => {
                    // If the editor is restarted, the toolbar element will be created once again.
                    // The `onReady` callback will be called again and the new toolbar will be added.
                    // This is why you need to remove the older toolbar.
                    if (willEditorRestart) {
                        if (editorRef.current) {
                            editorRef.current.ui.view.toolbar.element.remove();
                        }
                    }
                }}
            />
        )
    }

    export default Editor

0
Mahesh On

@hco You have to use a custom build which by default has a code blocks plugin.

https://ckeditor.com/ckeditor-5/online-builder/
You can build it on the above site and use it as a npm package. This is the package I created as per my requirements.

https://www.npmjs.com/package/ckeditor5-custom-build-mathtype-imageresize

0
Aliasghar Ahmadpour On

Since you are using NextJs, you must consider NextJs css import rules.

If you want to import css file inside your components(module), css file name must be something like [any name].module.css.

How to Import:

import styles from './index.module.css';

How to Use:

<div className={`${styles.class1} ${styles.class2}`}>

If your css file doesn't match naming rule, you got error.

Also you can import the css file with any name only inside _app.js with normal manner.