loading...
Cover image for CKEditor 5, Webpacker, VueJS, and you.

CKEditor 5, Webpacker, VueJS, and you.

brandoncordell profile image Brandon Cordell ・4 min read

The documentation for using CKEditor 5 with VueJS is pretty good, at least as far as open source technical documentation goes, but it makes the assumption that you're using vue-cli so it falls a bit short if you've you set up Webpacker yourself or you're using Rails/Webpacker like I am.

Note: I am building CKEditor from source rather than using the prebuilt package.

The Setup

First we need to add the proper packages to build CKEditor in our project.

yarn add @ckeditor/ckeditor5-vue \
         @ckeditor/ckeditor5-dev-webpack-plugin \ 
         @ckeditor/ckeditor5-dev-utils \
         raw-loader@0.5.1

Next we can prepend a new instance of CKEditorWebpackPlugin to
environment.plugins in config/webpack/environment.js.

// config/webpack/environment.js

const { environment } = require('@rails/webpacker');
// ... existing `require`s
const CKEditorWebpackPlugin = require('@ckeditor/ckeditor5-dev-webpack-plugin');

// ... existing code

environment.plugins.prepend('CKEditorWebpackPlugin', new CKEditorWebpackPlugin({
  addMainLanguageTranslationsToAllAssets: true,
  buildAllTranslationsToSeparateFiles: true,
  language: 'en',
}));

module.exports = environment;

Don't forget to restart your server when your webpack config changes!

If you only use the language property like the documentation shows you'll be met with two errors.

[CKEditorWebpackPlugin] Error: No JS asset has been found during the compilation. You should add translation assets directly to the application from the `translations` directory. If that was intentional use the `buildAllTranslationsToSeparateFiles` option to get rid of the error.
[CKEditorWebpackPlugin] Error: Too many JS assets has been found during the compilation. You should add translation assets directly to the application from the `translations` directory or use the `addMainLanguageTranslationsToAllAssets` option to add translations for the main language to all assets or use the `buildAllTranslationsToSeparateFiles` if you want to add translation files on your own.

Now that the Webpack plugin is set up we need to configure how the CKEditor SVG icons and css are parsed so we'll set up a loader for each. I like to keep my config/webpack/environment.js as clean as possible so we'll be creating small modules to include.

First we'll deal with the SVG icons. We need to use raw-loader to load the SVG icons as text.

Create the following config/webpack/loaders/ckeditor-svg.js

// config/webpack/loaders/ckeditor-svg.js

module.exports = {
  test: /ckeditor5-[^/\\]+[/\\]theme[/\\]icons[/\\][^/\\]+\.svg$/,
  use: 'raw-loader',
};

Let's go ahead and create the CKEditor css loader at
config/webpack/loaders/ckeditor-css.js.

// config/webpack/loaders/ckeditor-css.js

const { styles } = require('@ckeditor/ckeditor5-dev-utils');

module.exports = {
  test: /ckeditor5-[^/\\]+[/\\].+\.css$/,
  use: [{
    loader: 'style-loader',
    options: {
      injectType: 'singletonStyleTag',
      attributes: {
        'data-cke': true,
      },
    },
  }, {
    loader: 'postcss-loader',
    options: styles.getPostCssConfig({
      minify: true,
      themeImporter: {
        themePath: require.resolve('@ckeditor/ckeditor5-theme-lark'),
      },
    }),
  }],
};

Now back in config/webpack/environment.js we can require these files and prepend them to environment.loaders.

// config/webpack/environment.js

const { environment } = require('@rails/webpacker');
// ... existing `require`s
const ckeditorSvgLoader = require('./loaders/ckeditor-svg');
const ckeditorCssLoader = require('./loaders/ckeditor-css');

// ... existing code

environment.loaders.prepend('ckeditor-svg', ckeditorSvgLoader);
environment.loaders.prepend('ckeditor-css', ckeditorCssLoader);

module.exports = environment;

If we try to compile our project now it will fail with the following error (or something similar) for every CKEditor css file:

ERROR in ./node_modules/@ckeditor/ckeditor5-ui/theme/components/<component>/<stylesheet>.css (./node_modules/postcss-loader/src??ref--1-1!./node_modules/mini-css-extract-plugin/dist/loader.js!./node_modules/css-loader/dist/cjs.js??ref--5-1!./node_modules/postcss-loader/src??ref--5-2!./node_modules/@ckeditor/ckeditor5-ui/theme/components/<component>/<stylesheet>.css)
Module build failed (from ./node_modules/postcss-loader/src/index.js):
SyntaxError

(1:1) Unknown word

 > 1 | // extracted by mini-css-extract-plugin

To fix this we'll have to exclude CKEditor's assets for our other loaders. Add the following lines to config/webpack/environment.js.

// config/webpack/environment.js

// ... the rest of the code

// The default value for css.exclude is `/\.module\.[a-z]+$/`
environment.loaders.get('css').exclude = [
  /\.module\.[a-z]+$/,
  /ckeditor5-[^/]+\/theme\/[\w-/]+\.css$/,
];
environment.loaders.get('file').exclude = path.resolve(__dirname, '..', '..', 'node_modules', '@ckeditor');
environment.loaders.get('moduleCss').exclude = /ckeditor5-[^/]+\/theme\/[\w-/]+\.css$/;

module.exports = environment;

Using CKEditor

Add the packages you need.

yarn add @ckeditor/ckeditor5-editor-classic \
         @ckeditor/ckeditor5-essentials \
         @ckeditor/ckeditor5-basic-styles \
         @ckeditor/ckeditor5-link \
         @ckeditor/ckeditor5-paragraph \
         @ckeditor/ckeditor5-theme-lark

For the sake of this article I'll activate CKEditor in my pack so it can be used application-wide.

// app/javascript/packs/application.js

import CKEditor from '@ckeditor/ckeditor5-vue';
import Vue from 'vue/dist/vue.esm';

Vue.use(CKEditor);

// ... the rest of the pack

From here we can use the <ckeditor> component anywhere in our Vue app.

<template>
  <div id="app">
    <ckeditor
      v-model="editorData"
      :config="editorConfig"
      :editor="editor"
    />
  </div>
</template>

<script>
import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';

import BoldPlugin from '@ckeditor/ckeditor5-basic-styles/src/bold';
import EssentialsPlugin from '@ckeditor/ckeditor5-essentials/src/essentials';
import ItalicPlugin from '@ckeditor/ckeditor5-basic-styles/src/italic';
import LinkPlugin from '@ckeditor/ckeditor5-link/src/link';
import ParagraphPlugin from '@ckeditor/ckeditor5-paragraph/src/paragraph';

export default {
  data: () => ({
    editor: ClassicEditor,
    editorData: '<p>Content of the editor.</p>',
    editorConfig: {
      plugins: [
        BoldPlugin,
        EssentialsPlugin,
        ItalicPlugin,
        LinkPlugin,
        ParagraphPlugin,
      ],

      toolbar: {
        items: [
          'bold',
          'italic',
          'link',
          'undo',
          'redo',
        ],
      },
    },
  }),
};
</script>

And that's it. Now go create!

Discussion

markdown guide