Skip to content

Commit 29165b6

Browse files
authored
Merge pull request #275 from AykutSarac/feat/elkjs-web-worker
Feat/elkjs web worker
2 parents bb053dd + 1f2d4e2 commit 29165b6

File tree

5 files changed

+110
-21
lines changed

5 files changed

+110
-21
lines changed

copy-elk-storybook.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import fs from 'fs';
2+
import path from 'path';
3+
4+
// Copy elk-worker.min.js from node_modules to storybook-static/assets directory
5+
const sourceFile = 'node_modules/elkjs/lib/elk-worker.min.js';
6+
const targetDir = 'storybook-static/assets';
7+
const targetFile = path.join(targetDir, 'elk-worker.min.js');
8+
9+
// Create assets directory if it doesn't exist
10+
if (!fs.existsSync(targetDir)) {
11+
fs.mkdirSync(targetDir, { recursive: true });
12+
}
13+
14+
// Copy the file
15+
if (fs.existsSync(sourceFile)) {
16+
const content = fs.readFileSync(sourceFile);
17+
fs.writeFileSync(targetFile, content);
18+
console.log('Successfully copied elk-worker.min.js to storybook-static/assets directory');
19+
} else {
20+
console.error('Error: Could not find elk-worker.min.js in node_modules');
21+
}

package-lock.json

Lines changed: 23 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"scripts": {
66
"build": "vite build --mode library",
77
"build:watch": "vite build --watch --mode library",
8-
"build-storybook": "storybook build",
8+
"build-storybook": "storybook build && node copy-elk-storybook.js",
99
"prettier": "prettier --loglevel warn --write 'src/**/*.{ts,tsx,js,jsx}'",
1010
"lint": "eslint --ext js,ts,tsx",
1111
"lint:fix": "eslint --ext js,ts,tsx --fix src",
@@ -52,11 +52,11 @@
5252
"calculate-size": "^1.1.1",
5353
"classnames": "^2.3.2",
5454
"d3-shape": "^3.0.1",
55-
"elkjs": "^0.8.2",
55+
"elkjs": "^0.10.0",
5656
"ellipsize": "^0.2.0",
57-
"motion": "^12.4.2",
5857
"kld-affine": "^2.1.1",
5958
"kld-intersections": "^0.7.0",
59+
"motion": "^12.4.2",
6060
"p-cancelable": "^3.0.0",
6161
"reablocks": "^8.7.6",
6262
"react-cool-dimensions": "^2.0.7",
@@ -110,7 +110,8 @@
110110
"vite-plugin-dts": "^3.3.1",
111111
"vite-plugin-svgr": "^3.2.0",
112112
"vite-tsconfig-paths": "^4.2.0",
113-
"vitest": "^0.33.0"
113+
"vitest": "^0.33.0",
114+
"web-worker": "^1.5.0"
114115
},
115116
"lint-staged": {
116117
"src/**/*.{js,jsx,ts,tsx}": [

src/layout/elkLayout.ts

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { EdgeData, NodeData } from '../types';
2-
import ELK, { ElkNode } from 'elkjs/lib/elk.bundled.js';
2+
import type { ELK, ElkNode } from 'elkjs';
33
import PCancelable from 'p-cancelable';
44
import { formatText, measureText } from './utils';
55

@@ -321,14 +321,45 @@ function postProcessNode(nodes: any[]): any[] {
321321
return nodes;
322322
}
323323

324+
const isBrowser = typeof window !== 'undefined' && typeof Worker !== 'undefined';
325+
let elkInstance: ELK | null = null;
326+
327+
const getElk = async () => {
328+
if (elkInstance) return elkInstance;
329+
330+
if (!isBrowser) {
331+
const ELKModule = await import('elkjs/lib/elk.bundled.js');
332+
elkInstance = new ELKModule.default({
333+
algorithms: ['layered']
334+
});
335+
336+
return elkInstance;
337+
} else {
338+
const ELKModule = await import('elkjs/lib/elk-api');
339+
let workerPath = await import.meta.resolve('./elk-worker.min.js');
340+
if (import.meta.env.DEV) {
341+
workerPath = '/node_modules/elkjs/lib/elk-worker.min.js';
342+
}
343+
344+
elkInstance = new ELKModule.default({
345+
algorithms: ['layered'],
346+
workerFactory: () => {
347+
return new Worker(workerPath);
348+
}
349+
});
350+
351+
return elkInstance;
352+
}
353+
};
354+
324355
export const elkLayout = (nodes: NodeData[], edges: EdgeData[], options: ElkCanvasLayoutOptions) => {
325-
const graph = new ELK();
326-
const layoutOptions: ElkCanvasLayoutOptions = {
327-
...defaultLayoutOptions,
328-
...options
329-
};
356+
return new PCancelable<ElkNode>(async (resolve, reject) => {
357+
const graph = await getElk();
358+
const layoutOptions: ElkCanvasLayoutOptions = {
359+
...defaultLayoutOptions,
360+
...options
361+
};
330362

331-
return new PCancelable<ElkNode>((resolve, reject) => {
332363
graph
333364
.layout(
334365
{

vite.config.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,26 @@ import { resolve } from 'path';
99
import external from 'rollup-plugin-peer-deps-external';
1010
import dts from 'vite-plugin-dts';
1111
import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js';
12+
import fs from 'fs';
13+
14+
// Custom plugin to copy elk-worker.min.js to the output directory
15+
const copyElkWorker = () => {
16+
return {
17+
name: 'copy-elk-worker',
18+
closeBundle() {
19+
const sourceFile = 'node_modules/elkjs/lib/elk-worker.min.js';
20+
const targetFile = 'dist/elk-worker.min.js';
21+
22+
if (fs.existsSync(sourceFile)) {
23+
const content = fs.readFileSync(sourceFile);
24+
fs.writeFileSync(targetFile, content);
25+
console.log('Successfully copied elk-worker.min.js to dist directory');
26+
} else {
27+
console.error('Error: Could not find elk-worker.min.js in node_modules');
28+
}
29+
}
30+
};
31+
};
1232

1333
export default defineConfig(({ mode }) =>
1434
mode === 'library'
@@ -24,7 +44,8 @@ export default defineConfig(({ mode }) =>
2444
}),
2545
checker({
2646
typescript: true
27-
})
47+
}),
48+
copyElkWorker()
2849
],
2950
test: {
3051
globals: true,
@@ -44,7 +65,7 @@ export default defineConfig(({ mode }) =>
4465
external({
4566
includeDependencies: true
4667
})
47-
]
68+
],
4869
}
4970
}
5071
}

0 commit comments

Comments
 (0)