Advanced configuration for CKEditor with Strapi - ckeditor

I followed the guide to replace Strapi's WYSIWYG editor with CKEditor. This worked just fine.
After following the guide on how to use CKEditor as React Component from CKEditor site, I expected CKEditor to load and function properly.
However, running npm run build failed with the following error:
Error: Module not found: Error: Can't resolve './#ckeditor/ckeditor5-ui/theme/mixins/_rwd.css' in 'C:\work\myProject\backend\node_modules\#ckeditor\ckeditor5-image\theme'
Code snippets
From package.json:
"dependencies": {
"#ckeditor/ckeditor5-build-classic": "^18.0.0",
"#ckeditor/ckeditor5-react": "^2.1.0",
"#ckeditor/ckeditor5-adapter-ckfinder": "^18.0.0",
"#ckeditor/ckeditor5-alignment": "^18.0.0",
"#ckeditor/ckeditor5-autoformat": "^18.0.0",
"#ckeditor/ckeditor5-basic-styles": "^18.0.0",
"#ckeditor/ckeditor5-block-quote": "^18.0.0",
// ...a lot more additional plugins
From C:\work\myProject\backend\extensions\content-manager\admin\src\components\CKEditor\index.js
import React from 'react';
import PropTypes from 'prop-types';
import CKEditor from '#ckeditor/ckeditor5-react';
import ClassicEditor from '#ckeditor/ckeditor5-build-classic';
import Autoformat from '#ckeditor/ckeditor5-autoformat/src/autoformat.js';
import BlockQuote from '#ckeditor/ckeditor5-block-quote/src/blockquote.js';
import Bold from '#ckeditor/ckeditor5-basic-styles/src/bold.js';
import CKFinder from '#ckeditor/ckeditor5-ckfinder/src/ckfinder.js';
// ...a lot more components imports
...
const editorConfig = {
plugins: [
Autoformat,
BlockQuote,
Bold,
CKFinder,
// ...the rest of the plugins
],
toolbar: {
items: [
'undo',
'redo',
'CKFinder',
'|',
'heading',
'fontFamily',
// ...the rest of the plugins
],
image: {
toolbar: [
'imageTextAlternative',
'imageStyle:full',
'imageStyle:side'
]
},
table: {
contentToolbar: [
'tableColumn',
'tableRow',
'mergeTableCells',
'tableCellProperties',
'tableProperties'
]
},
}
...
const Editor = ({ onChange, name, value }) => {
return (
<Wrapper>
<CKEditor
editor={ClassicEditor}
data={value}
config={editorConfig}
onChange={(event, editor) => {
const data = editor.getData();
onChange({ target: { name, value: data } });
}}
/>
</Wrapper>
);
};
System
Node.js version: 13.5.0
NPM version: 6.13.4
Strapi version: 3.0.0-beta.19.3
Operating system: Windows 10 Pro
The CKEditor guide suggests that I'm using the Advanced Setup. This setup requires a certain Webpack configuration for compiling .css files and .svg icons. But I'm not sure where is the Webpack file that I should edit and how should I do that. Perhaps that is the problem.

You need to change
import CKEditor from '#ckeditor/ckeditor5-react';
To
import { CKEditor } from '#ckeditor/ckeditor5-react';
Reference: https://ckeditor.com/docs/ckeditor5/latest/builds/guides/integration/frameworks/react.html

Related

Laravel Vite with package development

How to use laravel vite with custom package development. I tried to add my path to vite.config.js but am getting an error.
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
export default defineConfig({
plugins: [
laravel({
input: ['resources/css/app.css', 'resources/js/app.js'],
// input: ['../Packages/Plugin/Customers/public/css/styles'],
refresh: true,
}),
],
});
I tried to duplicate this in my package folder but same error. Can you please assist.
I followed Kamlesh login, I was able to create vite.config.js file inside my custom package as shown below.
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
export default defineConfig({
plugins: [
laravel([
'resources/asset/css/settings.css',
'resources/asset/js/custom.js',
'resources/asset/js/ecstore_profile.js',
'resources/asset/js/general_settings.js',
]),
],
resolve: {
alias: {
'settings': '/resources/asset/css/settings.css',
'custom': '/resources/asset/js/custom.s',
'profile': '/resources/asset/js/ecstore_profile.js',
'general': '/resources/asset/js/general_settings.js',
},
},
});
Then I added each file to the vite.config.js file. Then run build inside the custom package and publish this to laravel public folder. all working fine.

How to add custom plugin in CKEditor 5 on Laravel Vue 2

How to add a custom plugin, more specifically the Inline widget plugin as mentioned in the example of the documentation of CKEditor in vue CKEditor ?
I have tried to follow the CKEditor setup process using CKEditor from source.
Since Laravel Vue doesn't have vue.config.js i have copied the same code on webpack.mix.js. Initially it failed to complied with an error
Module not found: Error: Can't resolve './#ckeditor/ckeditor5-ui/theme/mixins/_rwd.css' in '
But after removing some of the plugins such as `LinkPlugin, it complies but it run into another error
app.js?id=00c39e33120645d3026e:82180 TypeError: Cannot read properties of null (reading 'getAttribute')
at IconView._updateXMLContent (app.js?id=00c39e33120645d3026e:63098)
at IconView.render (app.js?id=00c39e33120645d3026e:63074)
at IconView.<anonymous> (app.js?id=00c39e33120645d3026e:80777)
at IconView.fire (app.js?id=00c39e33120645d3026e:78186)
at IconView.<computed> [as render] (app.js?id=00c39e33120645d3026e:80781)
at ViewCollection._renderViewIntoCollectionParent (app.js?id=00c39e33120645d3026e:72022)
at ViewCollection.<anonymous> (app.js?id=00c39e33120645d3026e:71883)
at ViewCollection.fire (app.js?id=00c39e33120645d3026e:78186)
at ViewCollection.addMany (app.js?id=00c39e33120645d3026e:74031)
at ViewCollection.add (app.js?id=00c39e33120645d3026e:73996)
Same issue as mentioned here
https://github.com/ckeditor/ckeditor5-vue/issues/24#issuecomment-947333698
But this solution didn't work for me.
Here is my complete webpack.mix.js file
let mix = require('laravel-mix');
/*
|--------------------------------------------------------------------------
| Mix Asset Management
|--------------------------------------------------------------------------
|
| Mix provides a clean, fluent API for defining some Webpack build steps
| for your Laravel application. By default, we are compiling the Sass
| file for the application as well as bundling up all the JS files.
|
*/
mix.js('resources/assets/js/app.js', 'public/js')
.sass('resources/assets/sass/app.scss', 'public/css')
.version();
const path = require('path');
const CKEditorWebpackPlugin = require('#ckeditor/ckeditor5-dev-webpack-plugin');
const {styles} = require('#ckeditor/ckeditor5-dev-utils');
module.exports = {
// The source of CKEditor is encapsulated in ES6 modules. By default, the code
// from the node_modules directory is not transpiled, so you must explicitly tell
// the CLI tools to transpile JavaScript files in all ckeditor5-* modules.
transpileDependencies: [
/ckeditor5-[^/\\]+[/\\]src[/\\].+\.js$/,
],
configureWebpack: {
plugins: [
// CKEditor needs its own plugin to be built using webpack.
new 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/
})
]
},
// Vue CLI would normally use its own loader to load .svg and .css files, however:
// 1. The icons used by CKEditor must be loaded using raw-loader,
// 2. The CSS used by CKEditor must be transpiled using PostCSS to load properly.
chainWebpack: config => {
// (1.) To handle editor icons, get the default rule for *.svg files first:
const svgRule = config.module.rule('svg');
// More rule
const filesRuleIndex = config.module.rules.findIndex(item => {
return item.test.test('.svg')
})
if (filesRuleIndex !== -1) {
config.module.rules[filesRuleIndex].test = /\.(png|jpe?g|gif|webp)$/
const svgRule = {...config.module.rules[filesRuleIndex]}
svgRule.test = /\.svg/
svgRule.exclude = svgRule.exclude || []
svgRule.exclude.push(path.join(__dirname, 'node_modules', '#ckeditor'))
config.module.rules.push(svgRule)
}
config.module.rules.push({
test: /ckeditor5-[^/\\]+[/\\]theme[/\\]icons[/\\][^/\\]+\.svg$/,
use: ["raw-loader"]
})
// Then you can either:
//
// * clear all loaders for existing 'svg' rule:
//
// svgRule.uses.clear();
//
// * or exclude ckeditor directory from node_modules:
svgRule.exclude.add(path.join(__dirname, 'node_modules', '#ckeditor'));
// Add an entry for *.svg files belonging to CKEditor. You can either:
//
// * modify the existing 'svg' rule:
//
// svgRule.use( 'raw-loader' ).loader( 'raw-loader' );
//
// * or add a new one:
config.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.
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
});
});
},
};
Can anyone please tell me what is the proper way of setting this CKEditor to work with custom plugins
And my vue component script is like this
import CKEditor from '#ckeditor/ckeditor5-vue2';
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';
//Custom Plugin same as in the documentation mentioned above,
//import Placeholder from "../../editor-plugins/Placeholder"; // Commented out
export default {
name: "AddEditDocuments",
props: {},
components:{
ckeditor: CKEditor.component
},
data() {
return {
editor: ClassicEditor,
editorData: '',
editorConfig: {
plugins: [
EssentialsPlugin,
BoldPlugin,
ItalicPlugin,
// LinkPlugin,
ParagraphPlugin
],
toolbar: {
items: [
'bold',
'italic',
'link',
'undo',
'redo'
]
}
},\
}
Packages:
Laravel : 8.76.1
Vue 2
CKEditor 5
Dont use CKEditor5 as it has some bugs in its editor just because of this i was also switch to CKEditor 4. After installing CKeditor using npm use it in the component. No need to configure it globally.
<template>
<ckeditor v-model="obj[name]" :config="editorConfig" ></ckeditor>
</template>
<script>
import CKEditor from 'ckeditor4-vue';
export default {
name: "Ckeditor",
props: {
obj: {
type: Object,
required: true,
},
name: {
type: String,
required: true,
}
},
components: {
ckeditor: CKEditor.component
},
data(){
return {
editorConfig: {
toolbar: [
[
'Bold',
'Italic',
'Link',
'BulletedList',
'NumberedList',
'Undo',
'Redo',
]
],
removePlugins: 'elementspath',
extraPlugins: 'filebrowser,uploadimage',
height: 100,
resize_enabled:false,
}
}
}
}
</script>
<style scoped>
</style>

rollup postcss plugin doesn't seem to work with scss and CSS Modules

The symptom
When are run rollup -c I get a reasonable build, but I get this error if I use the SCSS double slash comments:
CssSyntaxError: //../packages/core/src/styles/layout.module.scss:56:8: Unknown word
You tried to parse SCSS with the standard CSS parser; try again with the postcss-scss parser
As far as I can tell, I have setup the plugin to use sass and to use CSS Modules. When I try to set the parser to "postcss-scss" I get this other error:
[!] (plugin postcss) TypeError: node.getIterator is not a function
rollup.config.js
import url from "#rollup/plugin-url";
import svgr from "#svgr/rollup";
import autoprefixer from "autoprefixer";
import { resolve } from "path";
import postcssNormalize from "postcss-normalize";
import babel from "rollup-plugin-babel";
import peerDepsExternal from "rollup-plugin-peer-deps-external";
import postcss from "rollup-plugin-postcss";
import { nodeResolve } from "#rollup/plugin-node-resolve";
import commonjs from "#rollup/plugin-commonjs";
import typescript from "#rollup/plugin-typescript";
import packageJson from "./package.json";
export default [
{
input: "src/components/index.ts",
output: [
{
file: `${packageJson.main}`,
format: "cjs",
sourcemap: true,
},
{
file: `${packageJson.module}`,
format: "esm",
sourcemap: true,
},
],
plugins: [
// include peer deps in the package
peerDepsExternal(),
// The next 2 allow importing commonjs packages like classnames
commonjs(),
nodeResolve(),
// transform
babel({
exclude: "node_modules/**",
}),
typescript({
typescript: require("typescript"),
tsconfig: "./tsconfig-prod.json",
}),
postcss({
plugins: [autoprefixer(), postcssNormalize()],
// exclude: "src/styles/**/*.scss",
namedExports: true,
sourceMap: true,
extract: false,
// modules: true,
autoModules: true,
minimize: true,
extensions: [".scss"],
use: ["sass"],
// parser: "postcss-scss",
}),
url(),
svgr(),
],
},
};
There are a couple of commented out options, which I have also tried. Yes, I can switch comment type - the sheer number of files notwithstanding, but it bothers me that this setup is not quite working, so any help would be much appreciated.
In the src/components folders I have this folder strcuture pattern for each component:
components ->
> Button ->
> index.ts
> Button.tsx
> Button.module.scss

vuepress local search not showing up [version 2.0.0-beta.22]

I am new to vueppress.
I followed the docs here to create a documentation site. things went well but the search field/input didn't show up. I tried to follow the plugin installation docs here but I got:
I need to install #vuepress/shared-utils
after that I had to install #vue/component-compiler-utils too
but was unable to see the search input. I also tried to add the following to my ./docs/.vuepress/config.ts but still no luck.
plugins: [
[
'#vuepress/plugin-search',
{
searchMaxSuggestions: 10
}
],
]
I don't want to use Algoia search as this is internal documentation.
I had the same issue. Everything was working except the search box was not visible.
The issue was that my ...docs/.vuepress/config.ts was not structured properly. To fix it I followed exactly what the VuePress documentation instructed.
The working config.ts structure
import { defaultTheme } from '#vuepress/theme-default'
import { searchPlugin } from '#vuepress/plugin-search'
module.exports = {
theme: defaultTheme({
...
}),
plugins: [
searchPlugin({
...
})
]
}
Currently I am using VuePress v2.0.0-beta.45
and I used the following to install what I needed:
npm i -D #vuepress/plugin-search#next
npm i -D #vuepress/plugin-register-components#next
Detailed config.ts that is working for me
import { path } from '#vuepress/utils'
import { defaultTheme } from '#vuepress/theme-default'
// Plugins
import { searchPlugin } from '#vuepress/plugin-search'
import { registerComponentsPlugin } from '#vuepress/plugin-register-components'
import navBarItems from './public/navbar'
import sideBar from './public/sidebar'
// SEE: https://v2.vuepress.vuejs.org/reference/default-theme/config.html#config
module.exports = {
// Site Config: https://v2.vuepress.vuejs.org/reference/config.html#site-config
lang: 'en-US',
title: 'Title on Tab and Navbar',
description: '',
// https://v2.vuepress.vuejs.org/reference/default-theme/config.html
theme: defaultTheme({
logo: 'logo-light.png',
logoDark: 'logo-dark.png',
//https://v2.vuepress.vuejs.org/reference/default-theme/config.html#navbar
navbar: navBarItems,
// https://v2.vuepress.vuejs.org/reference/default-theme/config.html#sidebar
sidebar: sideBar
}),
plugins: [
// https://v2.vuepress.vuejs.org/reference/plugin/register-components.html
registerComponentsPlugin({
componentsDir: path.resolve(__dirname, './components')
}),
// https://v2.vuepress.vuejs.org/reference/plugin/search.html#search
searchPlugin({
// getExtraFields: (page) => page.frontmatter.tags,
maxSuggestions: 15,
hotKeys: ['s', '/'],
locales: {
'/': {
placeholder: 'Search',
}
}
})
],
}
Note that I keep my sidebar array and navbar object in different files.
Also I couldn't find any TypeScript reference for the config in VuePress 2x

How to import/use ckeditor 5 from online-builder in Vue 3?

I create custom ckeditor 5 build in https://ckeditor.com/ckeditor-5/online-builder/ (based on "decoupled component" type), at the end i download zip with files. But what I am supposed to do next how to import it in main.js / package.js and finnaly to component ?
All materials I was able to find are https://ckeditor.com/docs/ckeditor5/latest/builds/guides/integration/frameworks/vuejs-v3.html , got decoupled-document preset build working, but wanted to add image resize, so created custom build and am stuck at that point.
Tnx for any response.
This post is maybe longer but its super easy 5min done.
[2022 updated, still works, just config moved in another file, also people may return there because of higher Vue version ckeditor5 toolbar disappear and update/reinstall is needed]
This example is for full document type of ckeditor 5, decoupled-document is almost everything You need, just it lacks image-resize, to add it go to https://ckeditor.com/ckeditor-5/online-builder/ click it all way and add image-resize or all other fun stuff (You do not need premium Ckfinder, but You probably need CKFinder upload adapter for images uplad which is free), and download zip file, do not forget to pick same type in step 1 as one you will use/install.
Install (like in classic guide - https://ckeditor.com/docs/ckeditor5/latest/builds/guides/integration/frameworks/vuejs-v3.html)
npm install --save #ckeditor/ckeditor5-vue #ckeditor/ckeditor5-build-decoupled-document
(if here because of re-install, just remove package.json #ckeditor lines and run above install command again)
In main.js
import CKEditor from '#ckeditor/ckeditor5-vue';
createApp(App)
.use(router)
.use(CKEditor)
.mount("#app");
In your component
import DocumentEditor from '#ckeditor/ckeditor5-build-decoupled-document';
Now add config to data, You can find this config generated inside files you got from online-builder generator its copy/paste so do not freak out :) . You can find it in /src/ckeditor.js in defaultConfig, if you do not set it its possible You'll see an warning about missing "toolbar" options. Do not copy what you see below, use your custom generated config, its only for illustration :
data: function () {
return{
editorConfig: {
ckfinder: {
uploadUrl: 'https://page.com/api/uploadckeditor'
},
toolbar: {
items: [
'heading',
'|',
'bold',
'italic',
'link',
'bulletedList',
'numberedList',
'|',
'outdent',
'indent',
'|',
'imageUpload',
'blockQuote',
'insertTable',
'mediaEmbed',
'undo',
'redo',
'alignment',
'codeBlock',
'fontBackgroundColor',
'fontColor',
'fontFamily',
'fontSize',
'highlight',
'horizontalLine',
'htmlEmbed',
'imageInsert',
'pageBreak',
'removeFormat',
'strikethrough',
'underline',
'style'
]
},
language: 'cs',
image: {
toolbar: [
'imageTextAlternative',
'imageStyle:inline',
'imageStyle:block',
'imageStyle:side',
'imageStyle:alignLeft',
'imageStyle:alignRight',
'imageStyle:alignCenter',
'imageStyle:alignBlockLeft',
'imageStyle:alignBlockRight',
'linkImage'
]
},
table: {
contentToolbar: [
'tableColumn',
'tableRow',
'mergeTableCells',
'tableCellProperties',
'tableProperties'
]
},
fontFamily: {
options: [
'default',
'indieflowerregular',
'Arial, sans-serif',
'Verdana, sans-serif',
'Trebuchet MS',
'Apple Color Emoji',
'Segoe UI Emoji',
'Segoe UI Symbol',
]
},
licenseKey: ''
}
};
}
Now use it in component html
<ckeditor :editor="editor" #ready="onReady" v-model="editorData" :config="editorConfig"></ckeditor>
Decoupled component ckeditor package need #ready="onReady" othervise it will not initialize (classic do not need this)
here is method :
methods: {
onReady( editor ) {
// Insert the toolbar before the editable area.
editor.ui.getEditableElement().parentElement.insertBefore(
editor.ui.view.toolbar.element,
editor.ui.getEditableElement()
);
},
Ok now You have almost everything done just last magic thing to do .
In files you downloaded go to /build folder and COPY all the files into
"node_modules#ckeditor\ckeditor5-build-decoupled-document\build" and override initial decoupled-document. This is key thing to do, even thought it sounds pretty horrible.
Bonus : I wanted to have also image upload so added to config
**ckfinder: {
uploadUrl: 'http://mypage/api/uploadckeditor'
},**
Here is php side implementation its just basic one wit no error handling
$uploaddir = '../www/adminUpload/';
$uploadfile = $uploaddir . basename($_FILES['upload']['name']);
if (move_uploaded_file($_FILES['upload']['tmp_name'], $uploadfile)) {
//$this->sendJson(array("message"=>"sucess"));
} else {
//$this->sendJson(array("message"=>"failed"));
}
$returnArray = array();
$returnArray["uploaded"] = true;
$returnArray["url"] = "http://www.mypage.com/adminUpload/".$_FILES['upload']['name'];
header('Content-type: application/json');
$this->sendJson($returnArray);
$this->terminate();
For last 2 rows they are Nette php framework specific, just send out $returnArray as json response.
Here is how I integrated CKEDITOR with Vue3.js
Install required packages
npm install --save #ckeditor/ckeditor5-vue #ckeditor/ckeditor5-build-classic
main.ts
import CKEditor from '#ckeditor/ckeditor5-vue'
const app = createApp(App)
app.use( CKEditor ).mount('#app')
Then in your component where you wnat to use ckeditor
<template>
<ckeditor :editor="editor" v-model="data.description"></ckeditor>
</template>
<script>
import {onMounted, reactive, computed} from "vue"
import ClassicEditor from '#ckeditor/ckeditor5-build-classic'
export default{
name:'Add',
setup() {
//....
const data = reactive({
description: '',
})
return {
data,
editor: ClassicEditor
}
}
}
</script>
enter code here
I faced a problem image uploading inside ckeditor5-build-classic,
for image uploading I'm using Node.js server and S3, here is how returned the json response from Node.js server, uploaded flag is more important:
exports.upload_file_ckeditor = async(req, res) => {
let obj = {
"uploaded" : true,
"url" : 'http://example.com/upload/xyz.png'
}
return res.send(obj)
}

Resources