ckeditor / ckeditor5

Powerful rich text editor framework with a modular architecture, modern integrations, and features like collaborative editing.
https://ckeditor.com/ckeditor-5
Other
9.44k stars 3.69k forks source link

Provide instructions for Quasar framework #6389

Open gioppoluca opened 4 years ago

gioppoluca commented 4 years ago

Using from source in Quasar

The documentation explains what to do when is needed to use a custom build editor in Vue.js, but many times users do not use pure vue approach.

What is the purpose and what should be changed?

Since Quasar is a framework growing in popularity it could be useful to have a description, similar to the "Using CKEditor from source" actually present for Vue. My need is to use the "Mention" plugin but I'm not able to navigate through the webpack stuff needed by all these framework.

Probably for you could be simpler to provide the right documentation.

FilipTokarski commented 4 years ago

Hi, thanks for the report. I managed to succesfully integrate CKEditor5 with Mention plugin into Quasar app. Here are my steps:

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

module.exports = {
  pluginOptions: {                    // I added this pluginOptions object
    quasar: {                         // with Quasar config
      importStrategy: 'kebab',
      rtlSupport: false
    }
  },
  transpileDependencies: [
    /ckeditor5-[^/\\]+[/\\]src[/\\].+\.js$/,
    'quasar'                          // I added this line
  ],
  configureWebpack: {
    plugins: [
      new CKEditorWebpackPlugin( {
        language: 'en'
      } )
    ]
  },
  chainWebpack: config => {
    const svgRule = config.module.rule( 'svg' );
    svgRule.exclude.add( path.join( __dirname, 'node_modules', '@ckeditor' ) );
    config.module
      .rule( 'cke-svg' )
      .test( /ckeditor5-[^/\\]+[/\\]theme[/\\]icons[/\\][^/\\]+\.svg$/ )
      .use( 'raw-loader' )
      .loader( 'raw-loader' );
    config.module
      .rule( 'cke-css' )
      .test( /ckeditor5-[^/\\]+[/\\].+\.css$/ )
      .use( 'postcss-loader' )
      .loader( 'postcss-loader' )
      .tap( () => {
        return styles.getPostCssConfig( {
          themeImporter: {
            themePath: require.resolve( '@ckeditor/ckeditor5-theme-lark' ),
          },
          minify: true
        } );
      } );
  }
};

And it works like a charm. Please let me know if this helps and in case of any further problems, I will need to see your error messages, editor config, detailed steps to reproduce issue, etc.

gioppoluca commented 4 years ago

Will check, but I used the Quasar CLI since it produces a project more managed and there is a quasar.conf.json that is slightly different than the vue one.

kennyrafael commented 4 years ago

Same situation, I have a Quasar project on going and need this as well. =/

ajmas commented 4 years ago

Having run into this issue myself (see issue #135), I found using CK Editor 4 worked without a hitch, so short term will be using that.

In my own project I am going to avoid modifying configuration files more than I need to (fear of maintenance penalties), so I am tempted to look more at the source and try to understand the difference in packaging that may be going on, when compared with version 4.

Update: so in my case it seems to be working now. not really sure what changed, other than maybe having stop and restarted quasar?

For anyone else reading this, I am using Quasr 1.12.2 and created a boot file, which I then registered in quasar.conf.js. The contents of the boot file:

import Vue from 'vue'
import CKEditor from '@ckeditor/ckeditor5-vue'

Vue.use(CKEditor)

and then simply use in my components, per docs:

<template>
  <q-card>
     <ckeditor  v-model="content" :editor="editorForCK" />
  </q-card>
</template>

<script>
import ClassicEditor from '@ckeditor/ckeditor5-build-classic'

export default {
  data () {
    editorForCK: ClassicEditor,
    markdowEditorOptions: {},
    content: ''
  }
}
hognevevle commented 4 years ago

While using the pre-made build also worked for me, a custom build does not. Can't seem to get past the below error:

TypeError: Cannot read property 'getAttribute' of null
    at IconView._updateXMLContent (webpack-internal:///./node_modules/@ckeditor/ckeditor5-ui/src/icon/iconview.js:105)
    at IconView.render (webpack-internal:///./node_modules/@ckeditor/ckeditor5-ui/src/icon/iconview.js:79)
    at IconView.eval (webpack-internal:///./node_modules/@ckeditor/ckeditor5-utils/src/observablemixin.js:254)
    at IconView.fire (webpack-internal:///./node_modules/@ckeditor/ckeditor5-utils/src/emittermixin.js:226)
    at IconView.<computed> [as render]
ajmas commented 4 years ago

@hognevevle can you share the source of the component, in your code, that you see this happening?

DylanMoylan commented 4 years ago

Any updates re: Docs for quasar implementation? We are interested in the track-changes/comments functionality of CKEditor but the process of building from source to add plugins for Vue/Quasar is pretty arcane when you take how Quasar handles webpack into account.

I followed to the best of my ability based on the docs and the issues posted so far, and I am also stuck at "TypeError: Cannot read property 'getAttribute' of null" , same as @hognevevle and others. I would share the source of my component per @ajmas request, but it is identical to the docs; the real culprit is somewhere in quasar.conf.js

I attempted to translate the vue.config.js specified in the docs but I don't really know what I'm doing. It appears most of the webpack configurations are properties of the 'build' object in quasar.conf.js: (quasar docs on webpack)

build: {
      scopeHoisting: true,
      vueRouterMode: "hash", // available values: 'hash', 'history'
      showProgress: true,
      gzip: false,
      analyze: false,
      transpile: true,
      transpileDependencies: [
        /ckeditor5-[^/\\]+[/\\]src[/\\].+\.js$/,
      ],
      // Options below are automatically set depending on the env, set them if you want to override
      // preloadChunks: false,
      // extractCSS: true,
      // https://quasar.dev/quasar-cli/cli-documentation/handling-webpack
      extendWebpack(cfg) { 
        cfg.plugins.push(new CKEditorWebpackPlugin( {
            // The UI language. Language codes follow the https://en.wikipedia.org/wiki/ISO_639-1 format.
            language: 'en'
        } ))
      },

      chainWebpack(chain, { isServer, isClient }) {
        const svgRule = chain.module.rule( 'svg' );
        svgRule.exclude.add( __dirname + '/node_modules/@ckeditor' );
        chain.module
        .rule( 'cke-svg' )
        .test( /ckeditor5-[^/\\]+[/\\]theme[/\\]icons[/\\][^/\\]+\.svg$/ )
        .use( 'raw-loader' )
        .loader( 'raw-loader' );

        chain.module
        .rule( 'cke-css' )
            .test( /ckeditor5-[^/\\]+[/\\].+\.css$/ )
            .use( 'postcss-loader' )
            .loader( 'postcss-loader' )
            .tap( () => {
                return styles.getPostCssConfig( {
                    themeImporter: {
                        themePath: require.resolve( '@ckeditor/ckeditor5-theme-lark' ),
                    },
                    minify: true
                } );
            } );
      }
    },

Perhaps there is a way to build the component from source as a Quasar app extension? My low-level understanding of webpack, Quasar, and CKEditor API isn't really there unfortunately.

viiy commented 2 years ago

Any news on that?

I have two errors,

My quasar.conf.js look like this

build: {
...
    extendWebpack(cfg) {
        cfg.plugins.push(new CKEditorWebpackPlugin({
            language: 'en'
        }))
    },
    chainWebpack(chain) {
        chain
          .plugin("eslint-webpack-plugin")
          .use(ESLintPlugin, [{extensions: ["js", "vue"]}]);

        const svgRule = chain.module.rule('svg');
        svgRule.exclude.add(path.join(__dirname, 'node_modules', '@ckeditor'));
        chain.module
          .rule('cke-svg')
          .test(/ckeditor5-[^/\\]+[/\\]theme[/\\]icons[/\\][^/\\]+\.svg$/)
          .use('raw-loader')
          .loader('raw-loader');
        chain.module
          .rule('cke-css')
          .test(/ckeditor5-[^/\\]+[/\\].+\.css$/)
          .use('postcss-loader')
          .loader('postcss-loader')
          .tap(() => {
            return {
              postcssOptions: styles.getPostCssConfig({
                themeImporter: {
                  themePath: require.resolve('@ckeditor/ckeditor5-theme-lark'),
                },
                minify: true
              })
            };
          });
      },

1) The "path" argument must be of type string. Received undefined [app]/[@ckeditor]/ckeditor5-dev-webpack-plugin/lib/servetranslations.js:47:3

2) TypeError: Cannot read property 'getAttribute' of null

DylanMoylan commented 2 years ago

@viiy I ended up using a different approach. Instead of building from source inside the quasar project:

Then install your package in your quasar project and import it into your component, using CKEditor's Vue wrapper.

I found this guide to be helpful: https://blowstack.com/blog/create-ckeditor-5-custom-build It goes over how to build CKEditor from source and publish to NPM so that it catches updates to the source upstream.

<template>
  <q-card>
     <ckeditor :editor="editor" />
  </q-card>
</template>

<script>
import CKEditor from '@ckeditor/ckeditor5-vue2';
import CustomEditor from '@yourUserName/package-name/build/ckeditor.js' //<-- See here

export default {
 components: { CKEditor },
  data () {
    editor: CustomEditor
  }
}

I hope this helps, maybe it is possible to build from source within the same Quasar project, but this works for me instead.

tothmarci25 commented 1 year ago

@viiy

Finally I managed to build it from source with this quasar.conf build configuration. For me the problem was that chain.module.rule('svg') didn't exist in quasar because svg's were handled with images in a different rule called "images". (Its test regex was: /.(png|jpe?g|gif|svg|webp|avif|ico)(\?.*)?$/)

Besides I had to add an output path because CKEditorWebpackPlugin threw an error when it was nulll.

build: {
        transpile: true,
        transpileDependencies: [
            /ckeditor5-[^/\\]+[/\\]src[/\\].+\.js$/,
        ],

        chainWebpack(chain) {

                // output path must be defined, because CKEditorWebpackPlugin uses it
                chain.output.path(path.join(process.cwd(), 'dist')) 

                chain.plugin('ckEditorWebpackPlugin')
                      .use(CKEditorWebpackPlugin, [{
                          // See https://ckeditor.com/docs/ckeditor5/latest/features/ui-language.html
                          language: 'en',
                          // Append translations to the file matching the `app` name.
                          translationsOutputFile: '/app/',
                      }])

                // svg rule was empty in webpack-chain rules, quasar (my version: v2.7.7) uses images rule for svg too
                const svgRule = chain.module.rule('images') 

                svgRule.exclude.add(path.join(__dirname, 'node_modules', '@ckeditor'))

                chain.module
                      .rule('cke-svg')
                      .test(/[^/\\]*ckeditor5[^/\\]*[/\\]theme[/\\]icons[/\\][^/\\]+\.svg$/)
                      .use('raw-loader')
                      .loader('raw-loader')

                // (2.) Transpile the .css files imported by the editor using PostCSS.
                // Make sure only the CSS belonging to ckeditor5-* packages is processed this way.

                chain.module.rule('cke-css')
                      .test(/ckeditor5-[^/\\]+[/\\].+\.css$/)
                      .use('postcss-loader')
                      .loader('postcss-loader')
                      .tap(() => {
                          return {
                              postcssOptions: styles.getPostCssConfig({
                                  themeImporter: {
                                      themePath: require.resolve('@ckeditor/ckeditor5-theme-lark'),
                                  },
                                  minify: true,
                              }),
                          }
                      })
            },

        },
}
yusuf-ishaku commented 5 months ago

Hello, where's the rest of code?