This commit is contained in:
Anton Lavrevov 2025-08-11 20:34:32 +09:00
parent 8f22d97937
commit e33341d3f6
10 changed files with 94 additions and 82 deletions

View File

@ -14,8 +14,19 @@
".": {
"default": "./lib/index.js"
},
"./setup-node-canvas": {
"default": "./lib/setup-node-canvas.js"
"./lib/*": {
"default": "./lib/*.js"
},
"./lib/*.js": {
"import": "./lib/*.js",
"require": "./lib/*.js",
"default": "./lib/*.js"
},
"./canvas-backend": {
"default": "./lib/canvas-backend.js"
},
"./skia-backend": {
"default": "./lib/skia-backend.js"
}
},
"main": "./lib/index.js",
@ -29,7 +40,6 @@
"test:build": "PARCEL_WORKER_BACKEND=process parcel build ./test/unit-tests.html --dist-dir ./test-build --target none --public-url ./ --no-source-maps",
"test:browser": "npm run test:build && mocha-headless-chrome -f ./test-build/unit-tests.html -a disable-web-security -a no-sandbox -a disable-setuid-sandbox",
"test:watch": "rm -rf ./.parcel-cache && PARCEL_WORKERS=0 parcel serve ./test/unit-tests.html ./test/manual-tests.html ./test/sandbox.html ./test/text-paths.html ./test/bunnies.html",
"test:node:canvas": "rm -rf ./.test-temp && mkdir ./.test-temp && (tsc -p ./test/tsconfig.json --outDir ./.test-temp || true) && node ./rename-imports-test.mjs && mocha './.test-temp/test/unit/**/*.js' -r ./test/node-canvas-global-setup.mjs --exit && rm -rf ./.test-temp && npm run test:import",
"test:node:skia": "rm -rf ./.test-temp && mkdir ./.test-temp && (tsc -p ./test/tsconfig.json --outDir ./.test-temp || true) && node ./rename-imports-test.mjs && mocha './.test-temp/test/unit/**/*.js' -r ./test/node-skia-global-setup.mjs --exit && rm -rf ./.test-temp && npm run test:import",
"test:node": "npm run test:node:canvas && npm run test:node:skia",

View File

@ -2,11 +2,23 @@ import { Konva } from './Global';
import { Context } from './Context';
import { IRect, RGB, Vector2d } from './types';
const NODE_ERROR = `Konva.js unsupported environment.
Looks like you are trying to use Konva.js in Node.js environment. because "document" object is undefined.
To use Konva.js in Node.js environment, you need to use the "canvas-backend" or "skia-backend" module.
bash: npm install canvas
js: import "konva/canvas-backend";
or
bash: npm install skia-canvas
js: import "konva/skia-backend";
`;
const ensureBrowser = () => {
if (typeof document === 'undefined') {
throw new Error(
'document is undefined, this is not a browser environment. For node.js env add `import "konva/register-node"`'
);
throw new Error(NODE_ERROR);
}
};

26
src/canvas-backend.ts Normal file
View File

@ -0,0 +1,26 @@
import { Konva } from './_CoreInternals';
import * as Canvas from 'canvas';
const canvas = Canvas['default'] || Canvas;
global.DOMMatrix = canvas.DOMMatrix;
Konva.Util['createCanvasElement'] = () => {
const node = canvas.createCanvas(300, 300) as any;
if (!node['style']) {
node['style'] = {};
}
return node;
};
// create image in Node env
Konva.Util.createImageElement = () => {
const node = new canvas.Image() as any;
return node;
};
// this line is not part of the public API
// but will be used in tests
Konva.Util['Canvas'] = Canvas;
export default Konva;

View File

@ -1,30 +0,0 @@
import { Konva } from './_FullInternals';
import * as Canvas from 'canvas';
const canvas = Canvas['default'] || Canvas;
global.DOMMatrix = canvas.DOMMatrix;
const isNode = typeof global.document === 'undefined';
if (isNode) {
Konva.Util['createCanvasElement'] = () => {
const node = canvas.createCanvas(300, 300) as any;
if (!node['style']) {
node['style'] = {};
}
return node;
};
// create image in Node env
Konva.Util.createImageElement = () => {
const node = new canvas.Image() as any;
return node;
};
// this line is not part of the public API
// but will be used in tests
Konva.Util['Canvas'] = Canvas;
}
export default Konva;

View File

@ -1,40 +0,0 @@
import { Konva } from './_FullInternals';
import { Canvas, DOMMatrix, Image } from 'skia-canvas';
global.DOMMatrix = DOMMatrix as any;
const isNode = typeof global.document === 'undefined';
if (isNode) {
// @ts-ignore
Canvas.prototype.toDataURL = Canvas.prototype.toDataURLSync;
Konva.Util['createCanvasElement'] = () => {
const node = new Canvas(300, 300) as any;
if (!node['style']) {
node['style'] = {};
}
node.toString = () => '[object HTMLCanvasElement]';
const ctx = node.getContext('2d');
// Override the getter to return the canvas node directly
// because in skia-canvas canvas is using weak ref to the canvas node
// and somehow on many tests it fails to get the canvas node
Object.defineProperty(ctx, 'canvas', {
get: () => node,
});
return node;
};
// create image in Node env
Konva.Util.createImageElement = () => {
const node = new Image() as any;
node.toString = () => '[object HTMLImageElement]';
return node;
};
// this line is not part of the public API
// but will be used in tests
Konva.Util['isSkia'] = true;
}
export default Konva;

36
src/skia-backend.ts Normal file
View File

@ -0,0 +1,36 @@
import { Konva } from './_CoreInternals';
import { Canvas, DOMMatrix, Image } from 'skia-canvas';
global.DOMMatrix = DOMMatrix as any;
// @ts-ignore
Canvas.prototype.toDataURL = Canvas.prototype.toDataURLSync;
Konva.Util['createCanvasElement'] = () => {
const node = new Canvas(300, 300) as any;
if (!node['style']) {
node['style'] = {};
}
node.toString = () => '[object HTMLCanvasElement]';
const ctx = node.getContext('2d');
// Override the getter to return the canvas node directly
// because in skia-canvas canvas is using weak ref to the canvas node
// and somehow on many tests it fails to get the canvas node
Object.defineProperty(ctx, 'canvas', {
get: () => node,
});
return node;
};
// create image in Node env
Konva.Util.createImageElement = () => {
const node = new Image() as any;
node.toString = () => '[object HTMLImageElement]';
return node;
};
// this line is not part of the public API
// but will be used in tests
Konva.Util['isSkia'] = true;
export default Konva;

View File

@ -1,6 +1,6 @@
// try to import only core
const Konva = require('../').default;
require('../lib/setup-node-canvas');
require('../lib/canvas-backend');
// just do a simple action
const stage = new Konva.Stage();

View File

@ -6,7 +6,7 @@ function equal(val1, val2, message) {
// try to import only core from built lib
import Konva from '../lib/Core.js';
import '../lib/setup-node-canvas.js';
import '../lib/canvas-backend.js';
import { Rect } from '../lib/shapes/Rect.js';
equal(Rect !== undefined, true, 'Rect is defined');

View File

@ -3,7 +3,7 @@ export async function mochaGlobalSetup() {
// Path from this file (test/) to compiled file (.test-temp/src/...)
try {
await import(
new URL('../.test-temp/src/setup-node-canvas.js', import.meta.url)
new URL('../.test-temp/src/canvas-backend.js', import.meta.url)
);
} catch (e) {
// If not compiled yet or path missing, keep going; tests that need it will fail clearly

View File

@ -1,7 +1,5 @@
export async function mochaGlobalSetup() {
await import(
new URL('../.test-temp/src/setup-node-skia.js', import.meta.url)
);
await import(new URL('../.test-temp/src/skia-backend.js', import.meta.url));
globalThis.Path2D ??= class Path2D {
constructor(path) {