Cannot set property 'ckeFiller' of undefined in Angular 8 Universal Server Side Rending. [CKEditor]

Viewed 357

i am getting warning of ckeditor convert angular 8 App in Angular Universal Server Side Rending.

server.ts:

// These are important and needed before anything else
import 'zone.js/dist/zone-node';
import 'reflect-metadata';

import { enableProdMode } from '@angular/core';

import * as express from 'express';
import { join } from 'path';
import { NgwWowService } from 'ngx-wow';
import 'localstorage-polyfill'

const domino = require('domino');
const fs = require('fs');
const path = require('path');
const template = fs
  .readFileSync(path.join('dist/browser', 'index.html'))
  .toString();
const window = domino.createWindow(template);
window.Object = Object;
window.Math = Math;

(global as any).WOW = NgwWowService;
(global as any).window = window;
(global as any).document = window.document;
(global as any).Event = window.Event;
(global as any).KeyboardEvent = window.KeyboardEvent;
(global as any).MouseEvent = window.MouseEvent;
(global as any).FocusEvent = window.FocusEvent;
(global as any).PointerEvent = window.PointerEvent;
(global as any).HTMLElement = window.HTMLElement;
(global as any).HTMLElement.prototype.getBoundingClientRect = () => {
    return {
      left: '',
      right: '',
      top: '',
      bottom: ''
  };
};


// If using IgxIconService to register icons
(global as any).XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;

// Other optional depending on your application configuration
(global as any).object = window.object;
(global as any).navigator = window.navigator;
(global as any).DOMTokenList = window.DOMTokenList;
global['localStorage'] = localStorage;

// Faster server renders w/ Prod mode (dev mode never needed)
enableProdMode();

// Express server
const app = express();

const PORT = process.env.PORT || 4000;
const DIST_FOLDER = join(process.cwd(), 'dist');

// * NOTE :: leave this as require() since this file is built Dynamically from webpack
const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/server/main');

// Express Engine
import { ngExpressEngine } from '@nguniversal/express-engine';
// Import module map for lazy loading
import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';

app.engine('html', ngExpressEngine({
  bootstrap: AppServerModuleNgFactory,
  providers: [
    provideModuleMap(LAZY_MODULE_MAP)
  ]
}));

app.set('view engine', 'html');
app.set('views', join(DIST_FOLDER, 'browser'));

// TODO: implement data requests securely
app.get('/api/*', (req, res) => {
  res.status(404).send('data requests are not supported');
});

// Server static files from /browser
app.get('*.*', express.static(join(DIST_FOLDER, 'browser')));

// All regular routes use the Universal engine
app.get('*', (req, res) => {
  res.render('index', { req });
});

// Start up the Node server
app.listen(PORT, () => {
  console.log(`Node server listening on http://localhost:${PORT}`);
});

webpack.server.config.js:

const path = require('path');
const webpack = require('webpack');

module.exports = {
  entry: { server: './server.ts' },
  resolve: { extensions: ['.js', '.ts'] },
  target: 'node',
  mode: 'none',
  externals: [/node_modules/],
  output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name].js'
  },
  module: {
    rules: [{ test: /\.ts$/, loader: 'ts-loader' }]
  },
  plugins: [
    new webpack.ContextReplacementPlugin(
      /(.+)?angular(\\|\/)core(.+)?/,
      path.join(__dirname, 'src'),
      {}
    ),
    new webpack.ContextReplacementPlugin(
      /(.+)?express(\\|\/)(.+)?/,
      path.join(__dirname, 'src'),
      {}
    )
  ]
};

warning in server:

ERROR Error: Uncaught (in promise): TypeError: Cannot set property 'ckeFiller' of undefined                                               
TypeError: Cannot set property 'ckeFiller' of undefined                
at Fo (D:\Raj\Projects\ANGULAR-PROJECT\green-spa\green_spa_web\dist\server.js:282177:181676)

Waring of CKEditor

1 Answers

How I resolved this issue was by first importing the class in as a required file using required. Then I used isPlatformBroswer() to check rather the class is being loaded client or server side.

if (this.seoService.isPlatformBrowser()) {
  const ClassicEditor = require('@ckeditor/ckeditor5-build-classic');
  this.Editor = ClassicEditor;
}

SEOService

  constructor(private title: Title, private meta: Meta,
              protected injector: Injector, @Inject(PLATFORM_ID) platformId: object,
              @Inject(DOCUMENT) private doc: Document) {
    this.platformId = platformId;
  }

  isPlatformBrowser() {
    if (isPlatformBrowser(this.platformId)) {
      return true;
    }
    return false;
  }
Related