How can I use a custom build of CKEditor 5 with React and Vite? - vite

For the past several months, I've been building my app with Create React App.
However, Ionic now supports Vite and I am attempting to migrate my app from CRA to Vite.
Originally, I made a CKEditor 5 Custom Build and set it up in a React app like this:
import React from 'react';
// eslint-disable-next-line #typescript-eslint/ban-ts-comment
// #ts-ignore Ckeditor does not supply TypeScript typings.
import { CKEditor } from '#ckeditor/ckeditor5-react';
// eslint-disable-next-line #typescript-eslint/ban-ts-comment
// #ts-ignore Ckeditor does not supply TypeScript typings.
import Editor from 'ckeditor5-custom-build/build/ckeditor';
Before building my app, I build the custom CKEditor like this:
cd ckeditor5; npm run build
The CKEditor build command is webpack --mode production.
Now, after configuring Vite, when I run npm run build, I get the following error:
'default' is not exported by ckeditor5/build/ckeditor.js, imported by
src/components/contentTypeCard/CKEditorInput.tsx
The CKEditor issue queue has a thread on a lack of documentation on issues with Vite, but there's nothing in particular about how to resolve this issue.
What I tried
I tried building CKEditor in development mode (webpack --mode development) and examining the ckeditor.js file to try to export Editor, but the file has over 100,000 lines of code and I am totally lost.

In my cause its:
"react": "18.2.0",
"vite": "2.9.10",
Here is solution what i found:
package.json
"ckeditor5-custom-build": "file:libs/ckeditor5",
vite.config.ts
export default defineConfig(() => {
return {
plugins: [react()],
optimizeDeps: {
include: ['ckeditor5-custom-build'],
},
build: {
commonjsOptions: { exclude: ['ckeditor5-custom-build'], include: [] },
},
};
});
RichTextEditor.tsx
import { CKEditor, CKEditorProps } from '#ckeditor/ckeditor5-react';
import Editor from 'ckeditor5-custom-build';
export function RichTextEditor({
defaultValue,
...props
}: RichTextEditorProps) {
return (
<EditorContainer>
<CKEditor editor={Editor} data={defaultValue || ''} {...props} />
</EditorContainer>
);
}

Related

How do I use Vite with Yarn Workspaces?

At my workplace we were trying to get Vite working with Yarn Workspaces (in yarn v2).
We wanted to create a test environment where we consumed one of the packages we were publishing from the same repository but a different workspace. To illustrate:
packages
package-a
package-b
The packages are referred to in the main package.json like so:
{
...
"workspaces" : [
"packages/package-a",
"packages/package-b"
]
...
"packageManager": "yarn#3.3.1"
}
Where package-b refers to package-a in package-b's package.json like so:
{
...
"dependencies" : {
...
"package-a-name-in-npm": "workspace:packages/package-a"
...
}
...
}
What we found though, was that when it came to running the application in Vite, the package was not being loaded into the browser. This resulted in errors like:
Uncaught SyntaxError: The requested module ... does not provide an export named ...
At runtime only, but TypeScript and ESLint were perfectly happy with our imports.
See my answer below to find out our solution.
Yarn uses symbolic links to link to local workspaces. Vite doesn't seem to handle this well out of the box.
By setting the preserveSymlinks option in vite.config.ts, we were able to resolve this.
import { defineConfig } from "vite";
import react from "#vitejs/plugin-react";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
resolve: {
preserveSymlinks: true // this is the fix!
}
});

Vite: Cannot use import statement outside a module

I know little about bundler and I'm using vite to build project, I got a error when import some package to configure dev server :
SyntaxError: Cannot use import statement outside a module
So here is the thing:
import pinyin from 'pinyin/esm/pinyin-web.js'
export const somePlugin = {
name: 'someplugin',
configureServer(server) {
server.middlewares.use('/somepath', (req, res, next) => {
const foo = pinyin('foo')
next()
})
},
}
I don't use the normal way(import pinyin from 'pinyin') , because that need a package nodejieba which need to install unnecessary node-gyp, so I choose the web version that don't need nodejieba.
I've searched the error, some says add "type": "module" to package.json file. but it already exist in my package.json.
however, I make the change:
// import pinyin from 'pinyin/esm/pinyin-web.js'
import pinyin from 'pinyin/lib/pinyin-web.js'
and problem get solved,I was confused because I thought vite prefer ES module.
So,
1> what cause the problem above?
2> why should I import file with extensions ? eg: import pinyin from 'pinyin/lib/pinyin-web.js'
I have to add extensions .js or it will cause error. while in vite.config.ts I needn't add extensions.
3> I tried to add field optimizeDeps in vite.config.ts like this
export default defineConfig({
plugins: [vue(), somePlugin],
optimizeDeps: {
include: ['pinyin'],
},
})
but it seems to be useless, the offical doc says:
"During development, Vite's dev serves all code as native ESM. Therefore, Vite must convert dependencies that are shipped as CommonJS or UMD into ESM first."
did that work for the frontend part and package "pinyin" is for the dev server so whether add the
field optimizeDeps there is no difference.
codesandbox

How can I test swiper with Jest?

I'm creating unit testing of Swiper using Jest.
Here is my code:
https://codesandbox.io/s/swiper-default-react-forked-v0dnz?file=/src/App.test.jsx
● Test suite failed to run
Cannot find module 'swiper/react' from 'src/App.jsx'
Require stack:
src/App.jsx
src/App.test.jsx
1 | import React from "react";
2 | // Import Swiper React components
> 3 | import { Swiper, SwiperSlide } from "swiper/react";
| ^
4 |
5 | // Import Swiper styles
6 | import "swiper/css";
at Resolver.resolveModule (node_modules/jest-resolve/build/resolver.js:322:11)
at Object.<anonymous> (src/App.jsx:3:1)
This error has been reported all the time, but the program can run normally. Can anyone help me solve this problem?
I suppose you are having issues with Swiper 7 or newer versions because Jest doesn't support ESM packages yet.
So even if it is not the most optimal solution, you can solve it by downgrading it to Swiper 6
Run these commands:
npm uninstall swiper
npm install swiper#6.8.4
And import it this way:
import { Swiper, SwiperSlide } from 'swiper/react'
import 'swiper/swiper-bundle.min.css'
import 'swiper/swiper.min.css'
This seemed to work for me (Swiper v8):
(in package.json)
"jest": {
"moduleNameMapper": {
"swiper/react": "swiper/react/swiper-react.js",
"swiper/css": "swiper/swiper.min.css"
},
"transform": {
"^.+\\.css$": "jest-transform-css"
}
}
(and maybe also add this to transformIgnorePatterns)
'node_modules/(?!(swiper|ssr-window|dom7)/)'
If you don't care about testing Swiper v8 functionality, but want to test some other features in your components, try to add this line in your jest file:
jest.mock('Swiper', () => class Mocked {});
Worked for nextjs, doesn't complain. Maybe not the best way, but in my case it's more than enough.
I'm using Swiper 8.4.2 and this worked for me while using Swiper in Jest.
TL;DR just give me the Jest config
Here is a configuration that worked for me.
/* eslint-disable */
export default {
displayName: "components",
preset: "../../jest.preset.js",
moduleNameMapper: {
// Jest cannot understand this swiper import so we tell it where this points to
"swiper/css": "swiper/swiper.min.css",
},
transform: {
"^(?!.*\\.(js|jsx|ts|tsx|css|json)$)": "#nrwl/react/plugins/jest",
"^.+\\.[tj]sx?$": ["babel-jest", { presets: ["#nrwl/react/babel"] }],
},
moduleFileExtensions: ["ts", "tsx", "js", "jsx"],
coverageDirectory: "../../coverage/libs/components",
setupFilesAfterEnv: ["<rootDir>/jest.setup.js"],
transformIgnorePatterns: ["node_modules/(?!swiper|ssr-window|dom7)"],
};
Important things about config
Some of the things can be ignored because they are specific to this NX controlled monorepo, but couple of things are important here. So ignore "nrwl" and "nx" specifics, because I'm expecting this part about transformers to already be configured for your project whether you are using NX or something else.
What errors was I getting?
So running tests first threw errors "Jest encountered an unexpected token" and "SyntaxError: Unexpected token 'export'" for this line in my code:
import { Navigation } from "swiper";
Actual source of the error was this line in Swiper package:
export { default as Swiper, default } from './core/core.js';
Adding swiper|ssr-window|dom7 to transformIgnorePatterns resolved that issue.
Then after adding that I got the same error, but for this line:
import "swiper/css";
One of the answers above managed to help me with this actually because it involved "moduleNameMapper" property.
So adding this into the config solved the issue with this particular import:
moduleNameMapper: {
// Jest cannot understand this swiper import so we tell it where this points to
"swiper/css": "swiper/swiper.min.css",
},
Hopefully this helps someone with resolving their issue and actually understanding what parts of the config resolved specific issues.

How to run electron on a localhost server in Build as well as in Dev

I'm developing with Next.js + Electron + Typescript.
I'm using the npx create-next-app --example with-electron-typescript command to generate code.
npm run dev (the contents are npm run build-electron && electron . ), it seems that the local server is up and running on localhost8000, but when build, the server is not up internally, and it is running by directly accessing the file.
However, some APIs do not work correctly if there is no domain in the location.origin , so it works in Dev, but does not work in Build.
So, if it is possible, I would like to run the server on localhost in the build version as well as in the Dev version.
Is there anything I can do to make it work?
It's not shown in any of the examples, even though someone requested one:
https://github.com/vercel/next.js/issues/28225
It is possible using a custom server:
https://nextjs.org/docs/advanced-features/custom-server
You can follow these steps to create one:
Clone the Electron Next TypeScript example repo:
https://github.com/vercel/next.js/tree/canary/examples/with-electron-typescript
Update ./electron-src/index.ts with the following code:
import isDev from 'electron-is-dev';
import { createServer } from 'http';
import next from 'next';
import { parse } from 'url';
app.on('ready', async () => {
// Use server-side rendering for both dev and production builds
const nextApp = next({
dev: isDev,
dir: app.getAppPath() + '/renderer'
});
const requestHandler = nextApp.getRequestHandler();
// Build the renderer code and watch the files
await nextApp.prepare();
// Create a new native HTTP server (which supports hot code reloading)
createServer((req: any, res: any) => {
const parsedUrl = parse(req.url, true)
requestHandler(req, res, parsedUrl)
}).listen(3000, () => {
console.log('> Ready on http://localhost:3000')
})
mainWindow.loadURL('http://localhost:3000/')
Update ./package.json Electron build configuration to include the renderer src files:
"build": {
"asar": true,
"files": [
"main",
"renderer"
]
}
In ./package.json move next from devDependencies to dependencies. This means it will be available to run in production builds
Then use helpful scripts to unpack the binary and see the files/folder inside:
npx asar extract ./dist/mac/ElectronTypescriptNext.app/Contents/Resources/app.asar ./dist/unpack
Run the unpacked version to debug:
./node_modules/.bin/electron ./dist/unpack
I have created an Express Server version and NextJS versions to prove it is possible:
https://github.com/kmturley/electron-server/tree/feature/express
https://github.com/kmturley/electron-server/tree/feature/next

Problems with vue router (history mode) in development server Vue.js - “Cannot GET /config”

I just wanted to setup my vue project with the full webpack template, use vue router and link different urls to different components.
The src/router/index.html is the following:
import Vue from 'vue';
import Router from 'vue-router';
// eslint-disable-next-line
import Home from '../pages/home.vue';
// eslint-disable-next-line
import Config from '../pages/config.vue';
Vue.use(Router);
export default new Router({
mode: 'hash',
routes: [
{ path: '/', component: Home },
{ path: '/config', component: Config },
],
});
When I run npm run dev and access the above routes, I have the following output:
Up to here, everything is working fine. The problem is when I use the history mode, I can’t access to localhost:8080/config:
And the console doesn’t show any error:
Another thing I tried was switching the mode to history using the simple-webpack template. The worst part is that it worked! So, the problem is in the webpack-template, but I don't know how to make this work.
I'll appreciate any help.

Resources