Ckeditor toolbar item is unavailable in Vue (Laravel)

Viewed 2911

I'm using Ckeditor5 for vue in Laravel. Following documentation I have installed modules using npm install --save @ckeditor/ckeditor5-vue @ckeditor/ckeditor5-build-classic and enabled Ckeditor in resources/js/app.js file

import CKEditor from '@ckeditor/ckeditor5-vue';
Vue.use( CKEditor );
const app = new Vue({
    el: '#app',
});

After that I have imported ClassicEdditor in vue component

<template>
 // A lot of code here
 <div class="editor">
    <ckeditor :editor="editor" v-model="editorData" :config="editorConfig"></ckeditor>
 </div>
</template>

<script>
  import Swal from 'sweetalert2';
  import ClassicEditor from '@ckeditor/ckeditor5-build-classic';
  import FontFamily from '@ckeditor/ckeditor5-font/src/fontfamily'; // <----- Here is the error
  export default {
    props: ['groups'],

    mounted(){

    },
    data: function(){
      return {
        // My data
        editor: ClassicEditor,
        editorData: '',
        editorConfig: {
          // The configuration of the editor.
          toolbar: {
            items: [
              'FontFamily',
              '|',
              'bold',
              'italic',
              'underline',
              'subscript',
              'superscript',
              '|',
              'List',
              'Code',
              'EasyImage',
              'ImageUpload',
              '|',
              'link',
              'undo',
              'redo'
            ]
          }
        }
      }
    },
    methods: {
      // My methods here
    }
</script>

After that ckeditor show warning in console

toolbarview-item-unavailable: The requested toolbar item is unavailable {name: "FontFamily"}

In Error Codes page it says that

There was a problem processing the configuration of the toolbar. The item with the given name does not exist so it was omitted when rendering the toolbar.

So I have decided to install plugin via npm and import in Vue component, but after

import FontFamily from '@ckeditor/ckeditor5-font/src/fontfamily';

Ckeditor throw an error

Uncaught CKEditorError: ckeditor-duplicated-modules: Some CKEditor 5 modules are duplicated

I have reinstalled ckeditor - same issue

2 Answers

Looks like you're importing an existing build while you should create a build from source. Have a look at this link, where you can find this example:

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

<script>
    // ⚠️ NOTE: We don't use @ckeditor/ckeditor5-build-classic any more!
    // Since we're building CKEditor from source, we use the source version of ClassicEditor.
    import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';

    import EssentialsPlugin from '@ckeditor/ckeditor5-essentials/src/essentials';
    import BoldPlugin from '@ckeditor/ckeditor5-basic-styles/src/bold';
    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 {
        name: 'app',
        data() {
            return {
                editor: ClassicEditor,
                editorData: '<p>Content of the editor.</p>',
                editorConfig: {
                    plugins: [
                        EssentialsPlugin,
                        BoldPlugin,
                        ItalicPlugin,
                        LinkPlugin,
                        ParagraphPlugin
                    ],

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

To build from source in Laravel, you should add this code to your webpack.mix.js file (source: here, edited the style-loading singleton to cope with the API change they made)

const CKEditorWebpackPlugin = require('@ckeditor/ckeditor5-dev-webpack-plugin');
const CKEStyles = require('@ckeditor/ckeditor5-dev-utils').styles;
const CKERegex = {
  svg: /ckeditor5-[^/\\]+[/\\]theme[/\\]icons[/\\][^/\\]+\.svg$/,
  css: /ckeditor5-[^/\\]+[/\\]theme[/\\].+\.css/,
};

Mix.listen('configReady', webpackConfig => {
  const rules = webpackConfig.module.rules;
  const targetSVG = /(\.(png|jpe?g|gif|webp)$|^((?!font).)*\.svg$)/;
  const targetFont = /(\.(woff2?|ttf|eot|otf)$|font.*\.svg$)/;
  const targetCSS = /\.css$/;

  // exclude CKE regex from mix's default rules
  for (let rule of rules) {
    if (rule.test.toString() === targetSVG.toString()) {
      rule.exclude = CKERegex.svg;
    }
    else if (rule.test.toString() === targetFont.toString()) {
      rule.exclude = CKERegex.svg;
    }
    else if (rule.test.toString() === targetCSS.toString()) {
      rule.exclude = CKERegex.css;
    }
  }
});

mix.webpackConfig({
  plugins: [
    new CKEditorWebpackPlugin({
      language: 'nl',
      addMainLanguageTranslationsToAllAssets: true
    }),
  ],
  module: {
    rules: [
      {
        test: CKERegex.svg,
        use: ['raw-loader'],
      },
      {
        test: CKERegex.css,
        use: [
          {
            loader: 'style-loader',
            options: {
              injectType: "singletonStyleTag",
            },
          },
          {
            loader: 'postcss-loader',
            options: CKEStyles.getPostCssConfig({
              themeImporter: {
                themePath: require.resolve('@ckeditor/ckeditor5-theme-lark'),
              },
              minify: true,
            }),
          },
        ],
      },
    ],
   },
});

Make sure to npm install the loaders (raw-loader, style-loader, postcss-loader) and the modules you want to use in your CKEditor.

Updated J.Otten's answer for Laravel Mix v.6 (Webpack v.5) and CKEditor v.32.

const CKEditorWebpackPlugin = require('@ckeditor/ckeditor5-dev-webpack-plugin');
const CKEditorStyles = require('@ckeditor/ckeditor5-dev-utils').styles;
//Includes SVGs and CSS files from "node_modules/ckeditor5-*" and any other custom directories
const CKEditorRegex = {
    svg: /ckeditor5-[^/\\]+[/\\]theme[/\\]icons[/\\][^/\\]+\.svg$/, //If you have any custom plugins in your project with SVG icons, include their path in this regex as well.
    css: /ckeditor5-[^/\\]+[/\\].+\.css$/,
};

//Exclude CKEditor regex from mix's default rules
Mix.listen('configReady', config => {
    const rules = config.module.rules;
    const targetSVG = (/(\.(png|jpe?g|gif|webp|avif)$|^((?!font).)*\.svg$)/).toString();
    const targetFont = (/(\.(woff2?|ttf|eot|otf)$|font.*\.svg$)/).toString();
    const targetCSS = (/\.p?css$/).toString();

    rules.forEach(rule => {
        let test = rule.test.toString();
        if ([targetSVG, targetFont].includes(rule.test.toString())) {
            rule.exclude = CKEditorRegex.svg;
        } else if (test === targetCSS) {
            rule.exclude = CKEditorRegex.css;
        }
    });
});

mix.webpackConfig({
    plugins: [
        new CKEditorWebpackPlugin({
            language: 'en',
            addMainLanguageTranslationsToAllAssets: true
        }),
    ],
    module: {
        rules: [
            {
                test: CKEditorRegex.svg,
                use: ['raw-loader']
            },
            {
                test: CKEditorRegex.css,
                use: [
                    {
                        loader: 'style-loader',
                        options: {
                            injectType: 'singletonStyleTag',
                            attributes: {
                                'data-cke': true
                            }
                        }
                    },
                    'css-loader',
                    {
                        loader: 'postcss-loader',
                        options: {
                            postcssOptions: CKEditorStyles.getPostCssConfig({
                                themeImporter: {
                                    themePath: require.resolve('@ckeditor/ckeditor5-theme-lark')
                                },
                                minify: true
                            })
                        }
                    }
                ]
            }
        ]
    }
});
Related