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

Webpack support #139

Closed SplicePHP closed 6 years ago

SplicePHP commented 8 years ago

A great deal of javascript developers are going the direction of webpack, myself included. There seems to be no way of properly implementing any version of ckeditor I have tried into webpack as far as I can tell. I can't even find any discussions on the matter. Will ckeditor5 have support for webpack? Is there a way to integrate the current ckeditor 4 into webpack that I am not aware of? If not, I would suggest making this a priority or a lot of people will be forced to find an editor that is compatible. If there are any discussions surrounding this topic please point me in the right direction.

Thanks.

Reinmar commented 8 years ago

EDIT: There's been a major overhaul in how CKEditor 5 needs to be built since I wrote this message. Jump to https://github.com/ckeditor/ckeditor5/issues/139#issuecomment-276876222 if you're interested in more up to date information :)

tl;dr: There's full support for Webpack.


Hey,

As for CKEditor 4 I don't know if there's any way to bundle it. I think there should be but I can't say for sure because CKEditor 4 does some magic under the hood to load assets and maybe you can't disable some of this magic. Dunno.

And as for CKEditor 5, things are much different here. Most importantly we decided that magic is no good. In CKEditor 4 it was aimed at simplifying adding CKEditor to your page but nowadays it's not necessary. It's the opposite – magic makes it harder to integrate with other tools.

So, releasing CKEditor 5 will be done in couple of steps:

  1. Building – preparing the code found in multiple packages to be run together. This step is currently implemented in gulp build and simply gathers all the code and produces an output in build/ directory. At this stage the code (JS and SCSS) is transpiled and some additional work around themes is done. Most likely, a meta files (such as dependency map) will be produced as well, which will allow to optimise the bundled package.
  2. Bundling – this step isn't yet implemented and the plan is to leave this open to developers. Most likely we'll implement couple of bundling scenarios (e.g. with r.js, Rollup or even Webpack). We assume that developers will be able to use other bundlers as well, simply because what the builder produces in the first step is a set of JS and CSS files.

I hope that this answers your question and is fine with you. Any feedback is welcomed here, as it was really hard for us to figure out what are the scenarios and, more importantly, how to deal with them, taken the complexity of the project.

You can read more details in:

Thanks!

SplicePHP commented 8 years ago

Thanks for the feedback. I managed to figure out how to implement ck4 in webpack using scriptjs.

Install scriptjs: npm install scriptjs --save-dev

Example call:

var $s = require('scriptjs');
$s('./vendor/ckeditor/ckeditor.js', function(){
    CKEDITOR.replace('editor1');
});

Note that this will only work with the minified version of the editor. I got everything working properly on a simple test page but noticed some inexplicable errors when implementing this method into my framework. ( I think the issue is related to my framework though and will post an update here if the bug is related to the implementation method )

I will do a bit of research regarding the topic and write an update here if I find a better solution.

Good luck with the project. I know how much work goes into updating a project of this magnitude.

SplicePHP commented 8 years ago

Quick update on the last comment. The method described looks like it works on my framework now. I think the reason I had errors was due to the fact that requirejs was still being used in my project. The second I removed it, my problems seems to have vanished.

pjasiun commented 8 years ago

we'll implement couple of bundling scenarios (e.g. with r.js, Rollup or even Webpack).

Note that Webpack is not a simple Rollup replacement. It is a Grunt/Gulp replacement in many cases. With a vast number of Webpack plugins you can configure it to handle whole building process, including cleanup , find and replace and upload on a server.

Now, expecting that CKEditor 5 transpiling will be done outside Webpack is strange for users who handle building with Webpack. Also, in the environment where even the bundle is not stored on the hard drive (using webpack dev server), the fact that you need to generate and save your CKEditor 5 compilation in strange.

This is why I think there should be a ckeditor5-webpack plugin where you can define expected format of CKEditor classes and in automatically do all you need. Something like this:

// package.json
{
  "dependencies": {
    // ... 
    "ckeditor5-editor-classic": "ckeditor/ckeditor5-editor-classic",
    "ckeditor5-headings": "ckeditor/ckeditor5-headings",
    "ckeditor5-paragraph": "ckeditor/ckeditor5-paragraph",
    "ckeditor5-typing": "ckeditor/ckeditor5-typing",
    "ckeditor5-undo": "ckeditor/ckeditor5-undo",
    "ckeditor5-webpack": "ckeditor/ckeditor5-webpack"
    // ...
  }
}
// webpack.config.js
module.exports = {
  // ... 
  module: {
    loaders: [
      {
        loader: 'ckeditor5',
        query: {
          path: '/lib/ckeditor5'
          format: 'esnext'
        }
      }
    ]
  }
}

Then you can call in your code:

import ClassicEditor from '/lib/ckeditor5/editor-classic/classic.js';

ClassicEditor.create( document.querySelector( '#editor' ), {
    features: [ 'typing', 'paragraph', 'undo', 'headings' ],
    toolbar: [ 'headings', 'undo', 'redo' ]
} );
Reinmar commented 8 years ago

Thanks for the feedback, @pjasiun.

I didn't mean of course that Webpack integration will work in the same way as Rollup's. We need something which feels familiar to developers using Webpack and the solution with a specialized loader sounds great.

BTW, it may turn out that if we switch to Karma, we'll start using the Webpack integration for everything and that it will replace the current builder. That will be a bit sad, cause we've spent a lot of time writing the builder and perhaps some pieces will be hard to port, but maintaining a separate builder which duplicates Webpack's options if we're not using Bender anymore may be pointless.

IAMtheIAM commented 8 years ago

As software progresses, the need to let go of old software becomes more necessary, regardless of how much time was spend into creating it. For example. Angular 2 scrapped everything from Angular 1 and started fresh.

I suggest the same, because modern front end developers use webpack or similar tools, and build our own scripts. All this legacy js software are so hard to integrate into modern modular apps.

Reinmar commented 8 years ago

We've done the same as Angular did. CKEditor 5 was rewritten from scratch and we're open to every tool.

Recently, we decided to finally switch to Karma+Webpack for development. However, CKEditor source code is split into multiple repositories and requires a compilation step which gathers all the files. After compilation, you can then bundle the code or do whatever you want – e.g. build it into your source code like you'd normally do in more modern architecture. There are two things, though, which makes us unsure which direction to take.

  1. Right now the compilation step is performed by our tool. This makes CKEditor independent of a build tool, which feels future proof (we're talking here about 10y+ perspective...). However, we're duplicating features of the Webpack a bit and e.g. it's super tricky how to load external libraries (perhaps the most tricky thing resolved by Webpack). So we could base the entire setup on Webpack, but again... this doesn't feel safe and may give less flexibility. Cause...
  2. ... CKEditor is used in so many various setups and environments that even now we've seen that our idealistic approach that you compile CKEditor and build it into your project by importing what you need doesn't work for some people. It was already requested that we should make bundles more powerful. So far we've been saying – a bundle should export a single Editor.create() function and nothing more. If you want more – use a source version of the editor. Reality verified this already.

Anyway, we'll definitely have Webpack integration. We're just unsure yet how big part of CKEditor building process will be based on Webpack and how much on our custom tools.

Reinmar commented 7 years ago

I reported a ticket which is a bit related to this one, because it also concerns Webpack support: https://github.com/ckeditor/ckeditor5/issues/345. We're trying to figure out how to use Webpack for testing environment and enable loading external resources, while preserving the current custom compiler.

Reinmar commented 7 years ago

(Corrected ticket number in my previous comment.)

manuelfink commented 7 years ago

Opinionated I believe the future of web development will be in an reactive component driven way of building web applications. Thus I would really appreciate a strong webpack integration and also providing builded version making it easy to integrate the editor into modern web application frameworks like angular 2 or react.

Reinmar commented 7 years ago

Thanks for the feedback. I totally agree and I think we all do. Webpack is our main point of interest, also because it will allow us to solve many issues at once. Still, we don't want to totally base CKEditor compilation on it, cause it will narrow down the integration scenarios. Hence, the intermediate form (produced by CKEditor's compilator) which is just a bunch of source files in the format of your choice (ES6, AMD, CJS).

Thus I would really appreciate (...) providing builded version making it easy to integrate the editor into modern web application frameworks like angular 2 or react.

By builded version do you mean a single file like ckeditor.js or a set of files (which I mentioned above)? Cause the latter is what we feel is the best way to actually integrate CKEditor. It's a framework with dozens of features and a single bundle would be huge in terms of size. If you use a source version, you import only the modules that you need and you can produce highly optimised builds.

I haven't researched this yet, but I guess that if you, in your project, use Webpack, then basically you don't care how CKEditor is released. You simply base on the integration (guess – loader) and Webpack's ability to produce small, optimal bundles. But as I wrote above – we don't want to satisfy the Webpack case only, so... yeah, it requires from us analysing every possible and reasonable integration scenario. Tricky :D.

As for Angular 2 and React – I've seen you reported https://github.com/ckeditor/ckeditor5/issues/347. I'll reply about the whole "component" thing there.

Reinmar commented 7 years ago

Related topic: https://github.com/ckeditor/ckeditor5/issues/362. I started thinking on whether we need the compilation step, but according to my (unresearched) thought experiment, we still do. If we have time, it'd be good to have this a bit better researched.

IlyaSemenov commented 7 years ago

Since this ticket appears first in Google search results for "ckeditor5 webpack", and there's no official docs yet, I will share my findings.

This doesn't add up much to the discussion above (and the ticket itself), it's just to save time for people who are starting to adopt the project.

To add ckeditor5 beta to your existing webpack (2.x) project

1) Install ckeditor5 packages (a reasonable set to start with):

npm i -D @ckeditor/ckeditor5-basic-styles \
    @ckeditor/ckeditor5-editor-classic \
    @ckeditor/ckeditor5-enter \
    @ckeditor/ckeditor5-image \
    @ckeditor/ckeditor5-paragraph \
    @ckeditor/ckeditor5-typing \
    @ckeditor/ckeditor5-undo

2) Install ES2015 and sass transpilers:

npm i -D babel-core babel-loader babel-preset-es2015-webpack2 regenerator-runtime \
    style-loader css-loader sass-loader node-sass

3) In webpack.config.js, add rules for ckeditor5 js and svg (for icons):

module.exports = {
    ...
    module: {
        rules: [
            {
                test: /\.js$/,
                include: [
                    path.resolve(__dirname, "assets"), // your scripts
                    path.resolve(__dirname, "node_modules/@ckeditor")
                ],
                use: [{
                    loader: 'babel-loader',
                    options: {
                        presets: ['es2015-webpack2'],
                        cacheDirectory: true
                    }
                }]
            },
            {test: /\.css$/, loader: ExtractTextPlugin.extract({fallbackLoader: 'style-loader', loader: 'css-loader'})},
            {test: /\.s[ac]ss$/, loader: ExtractTextPlugin.extract({fallbackLoader: 'style-loader', loader: 'css-loader!sass-loader'})},
            {test: /\/ckeditor5-.*\.svg$/, loader: 'raw-loader'}
            // NOTE: if you have other *.svg rule(s), add {exclude: /\/ckeditor5-/} option to them
        ]
    }
  1. In your entrypoint (before you ever import ckeditor):
import 'regenerator-runtime/runtime'; // for CKEditor

Alternatively, include the runtime right in webpack.config.js:

module.exports = {
    ...
    entry: {
        main: ['regenerator-runtime/runtime', './assets/main']
    }
  1. Now, you can actually init CKeditor5:
// assets/js/myckeditor.js
import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classic';

import Enter from '@ckeditor/ckeditor5-enter/src/enter';
import Typing from '@ckeditor/ckeditor5-typing/src/typing';
import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
import Undo from '@ckeditor/ckeditor5-undo/src/undo';
import Bold from '@ckeditor/ckeditor5-basic-styles/src/bold';
import Italic from '@ckeditor/ckeditor5-basic-styles/src/italic';
import Image from '@ckeditor/ckeditor5-image/src/image';

ClassicEditor.create(document.getElementById("editor"), {
    plugins: [ Enter, Typing, Paragraph, Undo, Bold, Italic, Image ],
    toolbar: [ 'bold', 'italic', 'undo', 'redo' ]
});
Reinmar commented 7 years ago

That's awesome! :) Thanks for writing this down. I was actually working yesterday on our own setup for Webpack here: https://github.com/CKEditor5/ckeditor5.github.io/tree/master (it's for https://ckeditor5.github.io where we've been using Rollup previously). Our setups are pretty much identical with that difference that I didn't split CSSs out of the bundle.

We've made several big changes to the project infrastructure during the last 2 months and they result in a very different way of building editor than before. Before, we hoped to be able to encapsulate CKEditor specific work in a pre-bundling step called "compilation". It's all gone now, you can read more in https://github.com/ckeditor/ckeditor5-design/issues/171.

So, currently, support for Webpack (and Rollup, once this issue is fixed: https://github.com/rollup/rollup-plugin-node-resolve/issues/67#issuecomment-270358007) are native and the CKEditor specific things will be handled by plugins for these tools.

Our plans for Webpack:

  1. We'll propose a CKEditor plugin for Webpack. It will handle the CKEditor specific things:
  2. We'll create presets for CKEditor so you don't have to install so many packages and import so many modules yourself. (A preset will simply be a plugin which requires a set of other plugins.)
ssougnez commented 7 years ago

Hi,

thanks a lot for this configuration. I tried it on a bare new project and it works well (actually I used this one: https://github.com/CKEditor5/ckeditor5.github.io/blob/master/webpack.config.js but it's quite the same). However, I'm trying to include ckeditor in my angular4 project so I replicates this configuration in my webpack.config.js but unfortunately, I get the following error:

Error: Uncaught (in promise): TypeError: emitter.on is not a function TypeError: emitter.on is not a function at FocusTracker.listenTo

As this configuration works on a new project, I guess that mixing up angular with ckeditor creates some conflicts. I don't really know if you care about that so soon in the development of ckeditor but anyway, worse case scenario, you just lost 30" of your time :-)

Here is the webpack.config.js that I'm using:

var webpack = require('webpack');
var path = require('path');
var extractTextPlugin = require('extract-text-webpack-plugin');
var htmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: {
    'polyfills': './src/polyfills.ts',  
    'vendor': './src/vendor.ts',
    'app': './src/main.ts'
  }, 
  resolve: {
    extensions: [ '.ts', '.js' ]
  },
  output: {
    path: 'dist', 
    publicPath: '/',
    filename: '[name].bundle.js'
  },
  module: {
    rules: [

      {
        test: /\.ts$/,
        use: [{
          loader: 'awesome-typescript-loader',
          options: { configFileName: './tsconfig.json' }
        } , 'angular2-template-loader']
      },
      {
        test: /\.html$/,
        use: [ 'html-loader' ]
      },
      {
        test: /\.(png|jpe?g|gif|ico)$/,
        use: [ 'file-loader?name=assets/[name].[ext]' ]
      },
      {
        test: /\.css$/,
        include: './src/app',
        use: [ 'raw-loader' ]
      },
      {
        test: /\.css$/,
        exclude: './src/app',
        use: extractTextPlugin.extract({ 
            fallback: 'style-loader', 
            use: 'css-loader'
          })
      },
      { 
        test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, 
        use: [ "url-loader?limit=10000&mimetype=application/font-woff" ]
      },
      { 
        test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, 
        exclude: /\/ckeditor5-/,
        use: [ "file-loader" ]
      },
      {
          test: /\.js$/,
          include: path.resolve(__dirname, "node_modules/@ckeditor"),
          use: [{
              loader: 'babel-loader',
              options: {
                  presets: ['es2015-webpack2'],
                  cacheDirectory: true
              }
          }]
      },      
            {
        test: /\/ckeditor5-.*\.svg$/,
                use: [ 'raw-loader' ]
            },
      {
        test: /\.scss$/,
                use: [
                    'style-loader',
                    {
                        loader: 'css-loader',
                        options: {
                            minimize: true
                        }
                    },
                    'sass-loader'
                ]
            }
    ]
  },
  plugins: [
    new webpack.ContextReplacementPlugin(/angular(\\|\/)core(\\|\/)(esm(\\|\/)src|src)(\\|\/)linker/, './src', {}),
    new webpack.optimize.CommonsChunkPlugin({
      name: [ 'app', 'vendor', 'polyfills' ]
    }),
    new extractTextPlugin('[name].css'),
    new htmlWebpackPlugin({ template: './src/index.html' })
  ]
}

And here is the beginning of the callstack:

TypeError: emitter.on is not a function at FocusTracker.listenTo (http://localhost:8083/vendor.bundle.js:10240:11) at FocusTracker.listenTo (http://localhost:8083/vendor.bundle.js:33143:75) at FocusTracker.add (http://localhost:8083/vendor.bundle.js:62453:9) at new ClassicEditorUI (http://localhost:8083/vendor.bundle.js:80744:21) at new ClassicEditor (http://localhost:8083/vendor.bundle.js:42375:14)

Thanks for your attention.

Reinmar commented 7 years ago

Hi, thanks for the report.

This seems to be a problem of integration with Angular itself. As you mentioned, the bare build works fine. Please report a separate question for this issue. However, to be able to do something, we'll need to see more code or we may even need to be able to reproduce the issue. Let's start with the code though. My guess is that you don't pass the element to the editor's create() method or something similar.

You can also check these places:

ssougnez commented 7 years ago

Hi, I just create a new bare project for Angular2 then tried to include ckeditor and I've been able to reproduce this issue. I'll open a new question with this.

Thanks

Reinmar commented 7 years ago

Thanks! That's it: https://github.com/ckeditor/ckeditor5/issues/413.

ssougnez commented 7 years ago

Exactly. Thanks

deanvaessen commented 7 years ago

I have gone through the very helpful suggestions above and I feel like I am close, but am left with the following error still:

classiceditorui.js?a89d:86 Uncaught (in promise) TypeError: this.view.toolbar.fillFromConfig is not a function
    at view.init.then (eval at <anonymous> (app.7025678….js:2833), <anonymous>:88:39)
    at <anonymous>
view.init.then  @   classiceditorui.js?a89d:86

This sounds similar to what ssougnez was experiencing, but I am not using Angular or any sort of large framework.

Could I ask if the error rings any bells for anyone?

IlyaSemenov commented 7 years ago

@deanvaessen Searching on GitHub reveals that fillFromConfig is a recent refactoring. You probably need to pull the latest ckeditor5-ui package (related change).

Reinmar commented 7 years ago

Yes, it's fresh. That was my thought too. Both packages (ckeditor5-ui and ckeditor5-editor-classic) were released together so their latest releases should contain those changes:

And the editor-classic package requires the ui package in the right version: https://github.com/ckeditor/ckeditor5-editor-classic/blob/master/package.json#L10.

If you install from npm and npm i doesn't help, I'd recommend doing rm -rf node_modules/\@ckeditor/ and npm i again :).

If you use the dev versions through mgit you'll need to do mgit update && lerna bootstrap.

deanvaessen commented 7 years ago

Thank you both. I didn't install the UI package as I didn't see it in the post's:

Step 1 - Install ckeditor5 packages

I didn't think to add it myself, many thanks for the help! :)

Quick additional comment that I had to change this: {test: /\/ckeditor5-.*\.svg$/, loader: 'raw-loader'}

to this:

{test: /\.svg$/, loader: 'raw-loader'}

If I added the ckeditor5- prefix, I ran into trouble with:

  1. ERROR in ./~/@ckeditor/ckeditor5-core/theme/icons/low-vision.svg
  2. ERROR in ./~/@ckeditor/ckeditor5-undo/theme/icons/undo.svg
  3. ERROR in ./~/@ckeditor/ckeditor5-basic-styles/theme/icons/bold.svg
  4. ERROR in ./~/@ckeditor/ckeditor5-basic-styles/theme/icons/italic.svg
ssougnez commented 7 years ago

Hi,

I ran into the same issues and I fixed it like this:

{
  test: /\.svg$/,
  include: path.resolve(__dirname, "node_modules/@ckeditor"),
  use: [ 'raw-loader' ]
}

This only handles SVG for ckeditor. It was necessary for me because I'm using font-awesome which has to load SVG with a different loader. I also added the include property for SCSS and JS files:

/*************************** CKEDITOR JavaScript files ***************************/
{
    test: /\.js$/,
    include: path.resolve(__dirname, "node_modules/@ckeditor"),
    use: [{
        loader: 'babel-loader',
        options: {
            presets: ['es2015-webpack2'],
            cacheDirectory: true
        }
    }]
},
/*************************** CKEDITOR SVG files ***************************/
{
  test: /\.svg$/,
  include: path.resolve(__dirname, "node_modules/@ckeditor"),
  use: [ 'raw-loader' ]
},
/*************************** CKEDITOR SCSS files ***************************/
{
  test: /\.scss$/,
  include: path.resolve(__dirname, "node_modules/@ckeditor"),
  use: [
    'style-loader',
    {
      loader: 'css-loader',
      options: {
        minimize: true
      }
    },
    'sass-loader'
  ]
}

Regards

LintonBlack commented 7 years ago

You made my day @ssougnez :)

Reinmar commented 6 years ago

I think there's nothing we can add in this ticket. CKEditor 5 is built with webpack so we support it natively. We also offer guides how to integrate CKEditor 5 with your webpack setup:

g7crservice-Binni-kumari commented 7 months ago

@ssougnez where to add these codes, I am facing the same issue in my angular project.

ssougnez commented 7 months ago

Sorry but... It was seven years ago... I didn't even remember this thread ^^