뷰(Vue)

Vue3 Ckeditor5 적용하기...!

뭘하지 2024. 1. 15. 16:09
반응형

Vue3를 기반으로하는 프로젝트에서 에디터 적용이 필요하여 여러가지 대조군을 비교하며 정리하였다.

최초에 대상이 되던 플러그인은 총 3가지로 다음과 같았다.

  • Sun Editor —> 이미지 resize 선택하여 가능 (Vue지원)
  • Tiptap Editor
  • Ckeditor5 ckeditor5-Vue 지원. 그러나 이전 js버전의 경우 image resize가 정상적으로 동작안한다고 함. 확인이 필요하다.

 

위와 같은 리스트업중 필요성과 접근성 등등 여러가지를 고려해서 확인 해보았다.

sun editor를 사용할까 했었는데.. Vue를 지원하는것 같지만 들어가보면 소스가 없다. (텅 비어있음.)

Tiptap과 ckeditor5는 모두 image resize를 제공하는듯 보였다.
사람들이 이미 익숙하게 사용중인 ckeditor5를 적용해보자.

 

주소

https://github.com/ckeditor/ckeditor5-vue

 

GitHub - ckeditor/ckeditor5-vue: Official CKEditor 5 Vue.js component.

Official CKEditor 5 Vue.js component. Contribute to ckeditor/ckeditor5-vue development by creating an account on GitHub.

github.com

원하는 컴포넌트를 골라서 설치하라고 한다.

리스트

https://ckeditor.com/docs/ckeditor5/latest/installation/getting-started/predefined-builds.html#available-builds

 

Predefined builds | CKEditor 5 documentation

Learn how to install, integrate and configure CKEditor 5 Builds and how to work with CKEditor 5 Framework, customize it, create your own plugins and custom editors, change the UI or even bring your own UI to the editor. API reference and examples included.

ckeditor.com

 

위 리스트에서 원하는 형태로도 제공하고 데모버전도 확인 할 수 있는 사이트가 별도로 있었다. 유명하면서도 여러가지 참고 할 수 있는 자료가 다른 플러그인들에 비해서 확실히 많았다.

 

설치 명령어

npm install @ckeditor/ckeditor5-vue @ckeditor/ckeditor5-build-classic

main.js 글로벌 설정 추가

import { createApp } from 'vue';
import CKEditor from '@ckeditor/ckeditor5-vue';

createApp( { /* options */ } ).use( CKEditor ).mount( /* DOM element */ );

 

Vue3 에서 적용한 예시들 공식문서

Vue.js 3+ rich text editor component | CKEditor 5 documentation

 

Vue.js 3+ rich text editor component | CKEditor 5 documentation

Learn how to install, integrate and configure CKEditor 5 Builds and how to work with CKEditor 5 Framework, customize it, create your own plugins and custom editors, change the UI or even bring your own UI to the editor. API reference and examples included.

ckeditor.com

 

만약 builder를 통한 예시파일을 받아서 확인해보고 싶다면..!

원하는 옵션들을 추가한 builder를 제공한다. 예시화면을 보고싶다면 참고하면 좋을듯 하다.

CKEditor 5 Online Builder | Create your own editor in 5 steps

 

CKEditor 5 Online Builder | Create your own editor in 5 steps

Create your own CKEditor 5 build with customized plugins, toolbar and language in 5 simple steps.

ckeditor.com

 

해당사이트에 들어가면 다음과 같이 모드 선택도 가능하고

 

그다음 스텝에선 원하는 모듈을 선택하여 선택한 모듈을 포함한 파일을 확인 할 수 있다.

 

 

결국 최종적으로는 다음과 같은 형태로 적용하였다.

추가 플러그인들 설치

npm install @ckeditor/ckeditor5-editor-classic
npm install @ckeditor/ckeditor5-essentials
npm install @ckeditor/ckeditor5-basic-styles
npm install @ckeditor/ckeditor5-link
npm install @ckeditor/ckeditor5-paragraph
npm install @ckeditor/ckeditor5-indent
npm install @ckeditor/ckeditor5-list
npm install @ckeditor/ckeditor5-table
npm install @ckeditor/ckeditor5-typing
npm install @ckeditor/ckeditor5-alignment
npm install @ckeditor/ckeditor5-autoformat
npm install @ckeditor/ckeditor5-image
npm install @ckeditor/ckeditor5-vue
npm install @ckeditor/ckeditor5-media-embed
npm install @ckeditor/ckeditor5-theme-lark

vite.config.js

vite를 사용하기 때문에 다음과 같이 설정 추가

import { fileURLToPath, URL } from 'node:url';

import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import { manualChunksPlugin } from 'vite-plugin-webpackchunkname';

// ckeditor
import ckeditor5 from '@ckeditor/vite-plugin-ckeditor5';
import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);

export default defineConfig({
    plugins: [vue(), manualChunksPlugin(), ckeditor5({ theme: require.resolve('@ckeditor/ckeditor5-theme-lark') })],
    resolve: {
        alias: {
            '@': fileURLToPath(new URL('./src', import.meta.url)),
        },
    },
});

 

 

CommonCkeditor.vue 파일

<template>
    <Ckeditor :editor="editor" v-model="text" :config="editorConfig"></Ckeditor>
</template>

<script setup>
import { ClassicEditor } from '@ckeditor/ckeditor5-editor-classic';
import { Essentials } from '@ckeditor/ckeditor5-essentials';
import { Bold, Italic } from '@ckeditor/ckeditor5-basic-styles';
import { BlockQuote } from '@ckeditor/ckeditor5-block-quote';
import { Link } from '@ckeditor/ckeditor5-link';
import { Paragraph } from '@ckeditor/ckeditor5-paragraph';
import { Indent } from '@ckeditor/ckeditor5-indent';
import { List } from '@ckeditor/ckeditor5-list';
import { MediaEmbed } from '@ckeditor/ckeditor5-media-embed';
import { Table, TableColumnResize, TableToolbar } from '@ckeditor/ckeditor5-table';
import { TextTransformation } from '@ckeditor/ckeditor5-typing';
import { Alignment } from '@ckeditor/ckeditor5-alignment';
import { Image, ImageCaption, ImageStyle, ImageToolbar, ImageUpload, ImageResize } from '@ckeditor/ckeditor5-image';

import { ref, watch } from 'vue';

let text = ref();

const emits = defineEmits(['update:modelValue']);

/**
 * v-model 값 연결
 */
watch(text, (newValue, oldValue) => {
    emits('update:modelValue', newValue);
});

// import Upload Adapter
import UploadAdapter from '@/components/common/editor/UploadAdapter';

// Custom Upload Adapter Plugin function
function CustomUploadAdapterPlugin(editor) {
    editor.plugins.get('FileRepository').createUploadAdapter = (loader) => {
        // Create new object and pass server url
        return new UploadAdapter(loader, '');
    };
}

const editor = ClassicEditor;
const editorConfig = {
    extraPlugins: [CustomUploadAdapterPlugin],
    plugins: [
        Essentials,
        Bold,
        Italic,
        Link,
        Paragraph,
        BlockQuote,
        Indent,
        List,
        Table,
        TableToolbar,
        TableColumnResize,
        TextTransformation,
        Alignment,
        Image,
        ImageCaption,
        ImageStyle,
        ImageToolbar,
        ImageUpload,
        ImageResize,
        MediaEmbed,
    ],
    toolbar: {
        items: [
            'bold',
            'italic',
            'link',
            'imageUpload',
            'indent',
            'outdent',
            'numberedList',
            'bulletedList',
            'alignment',
            'blockQuote',
            'mediaEmbed',
            'undo',
            'redo',
            'insertTable',
        ],
    },
    image: {
        toolbar: [
            'imageTextAlternative',
            'toggleImageCaption',
            'imageStyle:inline',
            'imageStyle:block',
            'imageStyle:side',
        ],
    },
    table: {
        contentToolbar: ['tableColumn', 'tableRow', 'mergeTableCells', 'tableProperties', 'tableCellProperties'],
    },
};
</script>

<style>
.ck.ck-editor {
    width: 100%;
    margin: 0 auto;
}

.ck-editor__editable {
    min-height: 200px !important;
    max-height: 400px !important;
}
</style>

 

파일업로드 로직 커스텀을 위한 파일추가.

UploadAdapter.js

import axios from '@/api/defaultAxios';
const noConextPathUrl = import.meta.env.VITE_APP_NO_CONTEXT_PATH_URL;

export default class UploadAdapter {
    constructor(loader, url) {
        this.url = url;
        this.loader = loader;
        this.loader.file.then((pic) => (this.file = pic));

        this.upload();
    }

    // Starts the upload process.
    upload() {
        return this.loader.file.then((uploadedFile) => {
            return new Promise((resolve, reject) => {
                const params = {
                    upload: uploadedFile,
                };
                axios.api
                    .fetchFileUpload(params)
                    .then((res) => {
                        const returnUrl = res.data.data.url;
                        resolve({
                            default: `${noConextPathUrl}${returnUrl}`,
                        });
                    })
                    .catch((error) => {
                        console.log(error);
                        reject(error.response.data.message);
                    });
            });
        });
    }
}

 

보고 참고한 인터넷 글

https://favourkelvin17.medium.com/using-ckeditor-5-with-vue-js-a-step-by-step-guide-ff231bf226ed

 

Using CKEditor 5 with Vue.js: A Step-by-Step Guide

Let’s start with the basics. What exactly is a Rich Text Editor? In simple terms, it’s like the control center for content creation on the…

favourkelvin17.medium.com

 

이미지 업로드 로직 구성하는데 실질적으로 참고한 사이트

stackoverflow 답변 중 참고.

https://stackoverflow.com/questions/55105674/ckeditor-upload-adapter-sends-object-promise-to-server

 

CKEditor Upload Adapter Sends [object Promise] to Server

I have been trying to implement CKEditor5 into a vuejs project and after getting all the infrastructure working, I cannot get the actual file to upload to a php server. The code calls the server a...

stackoverflow.com

 

 

적용된 예시 모습

 

다른사람이 만들어둔 오픈소스를 사용하는데도 여기저기 참고해야 하는 부분들이 많아서 개인적으로 따로 정리를 하였다 
그래도 한번 작업해두면 두고두고 쓸 수 있으니 만들어준 사람들에게 항상 감사함을 표한다.

반응형