this.props.editor.create не является функцией в CKEditor — NextJS

#ckeditor #next.js

#ckeditor #next.js

Вопрос:

Я следую инструкциям из этого. И мой редактор CKEditor теперь может работать в моем приложении nextjs. Но проблема в том, что когда я хочу поместить simpleUploadAdapter, появляется сообщение об ошибке, в котором говорится, что props.editor.create не является функцией. Вот код :

 import Head from 'next/head'
import styles from '../styles/Home.module.css'

import React, { useState, useEffect, useRef } from 'react'

export default function Home() {
  const editorCKRef = useRef()
  const [editorLoaded, setEditorLoaded] = useState(false)
  const { CKEditor, SimpleUploadAdapter, ClassicEditor } = editorCKRef.current || {}

  useEffect(() => {
    editorCKRef.current = {
      CKEditor: require('@ckeditor/ckeditor5-react'),
      // SimpleUploadAdapter: require('@ckeditor/ckeditor5-upload/src/adapters/simpleuploadadapter'),
      ClassicEditor: require('@ckeditor/ckeditor5-build-classic')
    }
    setEditorLoaded(true)
  }, [])

  return (
    <div className={styles.container}>
      <Head>
        <title>My CKEditor 5</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <h2>Using CKEditor 5 build in Next JS</h2>
      {editorLoaded amp;amp; ClassicEditor amp;amp;
        <CKEditor
          name="editor"
          editor={ typeof ClassicEditor !== 'undefined' ? 
            ClassicEditor.create(
              document.getElementsByName("editor"), {
                 plugins: [ SimpleUploadAdapter],
                //toolbar: [ ... ],
                simpleUpload: {
                    // The URL that the images are uploaded to.
                    uploadUrl: 'http://example.com',
        
                    // Enable the XMLHttpRequest.withCredentials property.
                    withCredentials: false
                }
              }

              ): ''
          }
          data="<p>Hello from CKEditor 5!</p>"
          onInit={ editor => {
              // You can store the "editor" and use when it is needed.
              console.log( 'Editor is ready to use!', editor );
          } }
          onChange={ ( event, editor ) => {
              const data = editor.getData();
              console.log('ON CHANGE')
              // console.log(ClassicEditor.create())
              // console.log( { event, editor, data } );
          } }
          onBlur={ ( event, editor ) => {
              console.log( 'Blur.', editor );
          } }
          onFocus={ ( event, editor ) => {
              console.log( 'Focus.', editor );
          } }

          config={
            {
              simpleUpload: {
                uploadUrl: 'localhost:8000/api/files/upload/question/1'
              }
            }
          }

        />
      }
      
    </div>
  )
}
  

и это ошибка:
введите описание изображения здесь

Так в чем же здесь проблема? Спасибо

Ответ №1:

Я заставил свой работать, обернув компонент CKEditor в собственный компонент класса.

     class RichTextEditor extends React.Component<Props, State> {
      render() {
        const { content } = this.props;
        return (
          <CKEditor
            editor={ClassicEditor}
            data={content}
          />
        );
      }
    }
  

Кажется, CKEditor просто плохо работает с функциональными компонентами. Затем используйте динамический импорт для загрузки оболочки, если вы используете NextJS.

     const RichTextEditor = dynamic(() => import("/path/to/RichTextEditor"), {
        ssr: false,
    });
  

Ответ №2:

Я вспомнил, что CKEditor4 проще настроить в Next.js . CKEditor5 требует дополнительной работы, вы должны использовать динамический импорт с режимом ssr=false

Но в вашем случае вы также хотите использовать другой плагин SimpleUploadAdapter

Я попытался использовать компонент CKEditor React build classic SimpleUploadAdapter, но обнаружил ошибку «Дублирование кода между build classic и исходным кодом (SimpleUploadAdapter)».

Поэтому я решил настроить ckeditor5-build-classic, добавить туда плагин и перестроить, а затем заставить его работать :)(https://ckeditor.com/docs/ckeditor5/latest/builds/guides/development/custom-builds.html )

Вот несколько замечаний:

  • Пользовательский ckeditor5-build-classic
 // ckeditor5-build-classic-custom local package
// Add SimpleUploadAdapter into the plugin list
// src/ckeditor.js
import SimpleUploadAdapter from '@ckeditor/ckeditor5-upload/src/adapters/simpleuploadadapter';  

ClassicEditor.builtinPlugins = [
...
SimpleUploadAdapter
...
]

// Rebuild for using in our app
npm run build
  
  • Используйте пользовательскую сборку в нашем приложении
 // app/components/Editor.js

import CKEditor from "@ckeditor/ckeditor5-react";
import ClassicEditor from "@ckeditor/ckeditor5-build-classic";

...
<CKEditor
          editor={ClassicEditor}
          config={{
            // Pass the config for SimpleUploadAdapter
            // https://ckeditor.com/docs/ckeditor5/latest/features/image-upload/simple-upload-adapter.html
            simpleUpload: {
              // The URL that the images are uploaded to.
              uploadUrl: "http://example.com",

              // Enable the XMLHttpRequest.withCredentials property.
              withCredentials: true,

              // Headers sent along with the XMLHttpRequest to the upload server.
              headers: {
                "X-CSRF-TOKEN": "CSRF-Token",
                Authorization: "Bearer <JSON Web Token>",
              },
            },
          }}
...
  
  • Динамический импорт для загрузки редактора со стороны клиента
 // pages/index.js
import dynamic from "next/dynamic";
const Editor = dynamic(() => import("../components/editor"), {ssr: false})
  

Подводя итог:

  • Настройте сборку CKEditor, добавьте необходимые плагины… затем перестройте. Создайте их как локальный пакет
  • Используйте этот локальный пакет в нашем приложении!
  • Проверьте мой пример git с длинными комментариями: https://github.com/nghiaht/nextjs-ckeditor5