Next.js集成CKEditor自定义图片缩放功能编译失败的解决方案求助
解决Next.js中CKEditor编译失败及图片自定义缩放问题
一、编译失败原因及修复
你当前代码直接将ImageResizeButtons、ImageResizeEditing、ImageResizeHandles等源码级插件添加到extraPlugins中,但@ckeditor/ckeditor5-build-classic是预编译好的编辑器包,不支持直接引入未包含在预构建内的源码插件,这会触发模块解析错误,导致编译失败。
修复步骤:
移除错误的插件导入
删除以下导入语句:import {Image, ImageResizeButtons, ImageResizeEditing, ImageResizeHandles} from '@ckeditor/ckeditor5-image'同时从
config.extraPlugins数组中移除这些插件。改用Next.js动态导入避免SSR问题
CKEditor依赖浏览器API,Next.js的SSR环境下直接加载会报错,替换原有的动态导入逻辑为Next.js官方的dynamic函数并禁用SSR:import dynamic from 'next/dynamic'; const CKEditor = dynamic(() => import('@ckeditor/ckeditor5-react').then(mod => mod.CKEditor), { ssr: false, loading: () => <p>加载编辑器中...</p> }); const ClassicEditor = dynamic(() => import('@ckeditor/ckeditor5-build-classic'), { ssr: false });同时移除原有的
editorRef及相关useEffect代码,直接使用上述导入的组件。
二、实现自定义图片缩放功能
预构建的Classic Editor默认不包含图片缩放插件,有两种可行方案实现需求:
方案1:自定义构建CKEditor(推荐)
按照官方指南构建包含ImageResize插件的自定义编辑器包:
- 克隆CKEditor5构建仓库,安装图片缩放相关依赖:
npm install @ckeditor/ckeditor5-image --save-dev - 在构建配置文件
src/ckeditor.js中添加:
将import ImageResize from '@ckeditor/ckeditor5-image/src/imageresize';ImageResize加入builtinPlugins数组,重新构建编辑器后,替换项目中的@ckeditor/ckeditor5-build-classic依赖。 - 组件中配置图片缩放:
config={{ removePlugins: ['MediaEmbed'], image: { resizeOptions: [ { name: 'resizeImage:original', value: null, label: '原始大小' }, { name: 'resizeImage:50', value: '50', label: '50%' }, { name: 'resizeImage:75', value: '75', label: '75%' }, { name: 'resizeImage:custom', value: 'custom', label: '自定义' } ], toolbar: [ 'imageStyle:full', 'imageStyle:side', 'imageTextAlternative', '|', 'resizeImage' ] } }}
方案2:预构建编辑器的临时替代方案
若不想自定义构建,可通过ImageStyle插件配合自定义CSS实现近似效果:
config={{ removePlugins: ['MediaEmbed'], image: { styles: [ 'full', 'side', 'alignLeft', 'alignRight' ], toolbar: [ 'imageStyle:full', 'imageStyle:side', 'imageStyle:alignLeft', 'imageStyle:alignRight', 'imageTextAlternative' ] } }}
添加自定义CSS控制样式宽度:
.ck-content .image-style-alignLeft { max-width: 50%; float: left; margin-right: 1em; } .ck-content .image-style-alignRight { max-width: 50%; float: right; margin-left: 1em; }
三、完整修复后的组件代码示例
import { config } from '@/configs'; import { postFile } from '@/utils/fetch'; import { Editor } from '@ckeditor/ckeditor5-core'; import { regexDescription } from '@/utils/regex-message'; import { FileLoader, UploadAdapter } from '@ckeditor/ckeditor5-upload/src/filerepository'; import { useState } from 'react'; import dynamic from 'next/dynamic'; // 动态导入CKEditor,禁用SSR const CKEditor = dynamic(() => import('@ckeditor/ckeditor5-react').then(mod => mod.CKEditor), { ssr: false, loading: () => <p>加载编辑器中...</p> }); const ClassicEditor = dynamic(() => import('@ckeditor/ckeditor5-build-classic'), { ssr: false }); const CKEditorComp = ({ name, formDesc, setFormDesc, register, error }: any) => { const [errorMsg, setErrorMsg] = useState('') const [isValid, setIsValid] = useState<boolean>(false) function uploadAdapter(loader: FileLoader): UploadAdapter { return { upload: () => { return new Promise(async (resolve, reject) => { try { const file: any = await loader.file; const { data } = await postFile(`?folder_path=images/blog&save_to=AWS&max_size=${config.MAX_FILE}`, { images: file }); resolve({ default: `${data.files[0].path}`, }); } catch (error) { console.log(error) reject('图片上传失败'); } }); }, abort: () => {}, }; } function uploadPlugin(editor: Editor) { /* @ts-ignore */ editor.plugins.get('FileRepository').createUploadAdapter = (loader: any) => { return uploadAdapter(loader); }; } const handleChange = (value: any) => { const check = regexDescription.regex.test(value) if(check){ setIsValid(true) setErrorMsg('请勿使用HTML标签或类似内容') }else{ setIsValid(false) setErrorMsg('') setFormDesc(value) } }; return ( <div> <CKEditor config={{ extraPlugins: [uploadPlugin], removePlugins: ['MediaEmbed'], // 若使用自定义构建的编辑器,保留以下image配置;否则替换为方案2的配置 image: { resizeOptions: [ { name: 'resizeImage:original', value: null, label: '原始大小' }, { name: 'resizeImage:50', value: '50', label: '50%' }, { name: 'resizeImage:75', value: '75', label: '75%' }, { name: 'resizeImage:custom', value: 'custom', label: '自定义' } ], toolbar: [ 'imageStyle:full', 'imageStyle:side', 'imageTextAlternative', '|', 'resizeImage' ] } }} editor={ClassicEditor} data={formDesc} onChange={(event: any, editor: any) => handleChange(editor.getData())} /> {isValid && errorMsg && (<p className="text-sm text-red-500">{errorMsg}</p>)} </div> ) }; export default CKEditorComp;
注意事项
- 自定义构建CKEditor时,需确保所有依赖版本与项目中CKEditor React组件版本一致,避免版本冲突。
- Next.js中使用CKEditor必须禁用SSR,否则会出现浏览器API未定义的错误。
- 图片上传的
postFile函数需确保能正确处理文件上传并返回有效图片URL,否则图片插入会失败。
内容的提问来源于stack exchange,提问作者Hovi Sohibul Wafa
相关产品推荐
相关产品推荐

