Skip to content

Commit

Permalink
feat(*): update worker importing
Browse files Browse the repository at this point in the history
  • Loading branch information
neki-dev committed Jul 24, 2024
1 parent 727bac9 commit 51d8641
Show file tree
Hide file tree
Showing 19 changed files with 132 additions and 64 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.git
.idea
node_modules/
.temp
.DS_Store
46 changes: 3 additions & 43 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ Fast node.js pathfinding on workers for grid-based games.
Documentation

* [Install](https://github.com/neki-dev/pathfinding-worker?tab=readme-ov-file#install)
* [Configuration](https://github.com/neki-dev/pathfinding-worker?tab=readme-ov-file#configuration)
* [General](https://github.com/neki-dev/pathfinding-worker?tab=readme-ov-file#general)
* [Layers](https://github.com/neki-dev/pathfinding-worker?tab=readme-ov-file#layers)
* [Finding](https://github.com/neki-dev/pathfinding-worker?tab=readme-ov-file#finding)
Expand All @@ -29,26 +28,6 @@ npm i pathfinding-worker

.

## Configuration

### ⚡️ Store module worker
Add new entry in your webpack.config to store module worker in project dist. Or you may use [webpack 5 workers import](https://webpack.js.org/guides/web-workers/) / [copy-webpack-plugin](https://webpack.js.org/plugins/copy-webpack-plugin/)
```ts
// webpack.config.js

module.exports = {
entry: {
// Add new entry
'pathfinding.worker': path.resolve(
__dirname,
'node_modules/pathfinder-worker/dist/worker.js',
),
},
};
```

.

## General

### ⚡️ Create worker thread
Expand All @@ -61,8 +40,8 @@ const pathfinding = new Pathfinding(

| Prop | Description | Default |
| ---- | ----------- | ------- |
| rate | Finding loop rate | 200 ms |
| workerPath | Path to worker file | ./pathfinder.worker.js |
| loopRate | Finding loop rate | 200 ms |
| workerPath | Custom path to worker file | ./pathfinder.worker.js |

### ⚡️ Terminate worker thread
```ts
Expand Down Expand Up @@ -190,8 +169,7 @@ const weight = pathfinder.getWeight(
// index.ts

const pathfinding = new Pathfinding({
rate: 500,
workerPath: path.resolve(__dirname, 'worker.entry.js'),
loopRate: 500,
});

pathfinding.addLayer('basic', [
Expand All @@ -210,21 +188,3 @@ pathfinder.createTask({
console.log('Total cost:', cost);
})
```
```ts
// webpack.config.js

module.exports = {
// ...
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
},
entry: {
'app': path.resolve(__dirname, 'index.ts'),
'worker.entry': path.resolve(
__dirname,
'node_modules/pathfinder-worker/dist/worker.js',
),
},
}
```
2 changes: 1 addition & 1 deletion dist/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export declare class Pathfinding {
*
* @param config - Pathfinding configuration
*/
constructor({ workerPath, rate, }?: PathfindingConfig);
constructor({ workerPath, loopRate, }?: PathfindingConfig);
/**
* Terminate worker thread.
*/
Expand Down
2 changes: 1 addition & 1 deletion dist/index.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/process/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export declare class PathfindingProcess {
private weights;
private taskQueue;
private timer;
constructor(rate?: number);
constructor(loopRate?: number);
destroy(): void;
createTask(task: PathfindingTask): void;
cancelTask(idTask: number): void;
Expand Down
6 changes: 6 additions & 0 deletions dist/runtime/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export declare class PathfindingRuntime {
readonly workerPath: string;
constructor(workerPath: string);
workerExists(): boolean;
createWorker(): void;
}
4 changes: 2 additions & 2 deletions dist/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
export type PathfindingConfig = {
/**
* Finding loop rate
* Finding process loop rate
* Default: 200 ms
*/
rate?: number;
loopRate?: number;
/**
* Path to worker file
* Default: ./pathfinder.worker.js
Expand Down
1 change: 0 additions & 1 deletion dist/worker.js

This file was deleted.

10 changes: 6 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "pathfinding-worker",
"description": "Fast node.js pathfinding on workers for grid-based games",
"version": "0.1.1",
"version": "1.0.0",
"keywords": [
"astar",
"dijkstra",
Expand All @@ -22,8 +22,9 @@
},
"main": "./dist/index.js",
"scripts": {
"build": "webpack --mode production",
"watch": "webpack --mode development --watch --stats-children",
"build": "yarn build:worker && yarn build:entrypoint",
"build:worker": "webpack --config ./webpack/worker.config.js --mode production",
"build:entrypoint": "webpack --config ./webpack/entrypoint.config.js --mode production",
"test": "jest",
"lint": "eslint \"./src/**/*.ts\" --fix"
},
Expand All @@ -44,7 +45,8 @@
"typescript": "5.5.3",
"typescript-eslint": "7.16.1",
"webpack": "5.93.0",
"webpack-cli": "5.1.4"
"webpack-cli": "5.1.4",
"wrapper-webpack-plugin": "^2.2.2"
},
"repository": {
"type": "git",
Expand Down
12 changes: 9 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Worker } from 'worker_threads';
import { PATHFINDING_DEFUALT_WORKER_FILE_NAME } from './const';
import { PathfindingEvents } from './events';
import { PathfindingEvent } from './events/types';
import { PathfindingRuntime } from './runtime';

import type { PathfindingTaskCallback } from './task/types';
import type { PathfindingGrid, PathfindingTaskConfig, PathfindingPosition, PathfindingConfig } from './types';
Expand All @@ -27,10 +28,15 @@ export class Pathfinding {
*/
constructor({
workerPath = PATHFINDING_DEFUALT_WORKER_FILE_NAME,
rate,
loopRate,
}: PathfindingConfig = {}) {
this.worker = new Worker(workerPath, {
workerData: { rate },
const runtime = new PathfindingRuntime(workerPath);
if (!runtime.workerExists()) {
runtime.createWorker();
}

this.worker = new Worker(runtime.workerPath, {
workerData: { loopRate },
});

this.events = new PathfindingEvents(this.worker);
Expand Down
4 changes: 2 additions & 2 deletions src/process/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ export class PathfindingProcess {

private timer: NodeJS.Timeout;

constructor(rate: number = PATHFINDING_PROCESS_LOOP_RATE) {
constructor(loopRate: number = PATHFINDING_PROCESS_LOOP_RATE) {
this.timer = setInterval(() => {
try {
this.next();
} catch (error) {
console.error('Pathfinding process error:', error);
}
}, rate);
}, loopRate);
}

public destroy(): void {
Expand Down
21 changes: 21 additions & 0 deletions src/runtime/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import fs from 'fs';
import path from 'path';

// Import pre-builded inline worker as string
import INLINE_WORKER from '../../.temp/worker.inline.js';

export class PathfindingRuntime {
public readonly workerPath: string;

constructor(workerPath: string) {
this.workerPath = path.resolve(__dirname, workerPath);
}

public workerExists() {
return fs.existsSync(this.workerPath);
}

public createWorker() {
fs.writeFileSync(this.workerPath, INLINE_WORKER);
}
}
4 changes: 2 additions & 2 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
export type PathfindingConfig = {
/**
* Finding loop rate
* Finding process loop rate
* Default: 200 ms
*/
rate?: number;
loopRate?: number;

/**
* Path to worker file
Expand Down
4 changes: 4 additions & 0 deletions src/typings.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
declare module '*.inline.js' {
const content: string;
export default content;
}
2 changes: 1 addition & 1 deletion src/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ if (!parentPort) {
}

const events = new PathfindingEvents(parentPort);
const process = new PathfindingProcess(workerData.rate);
const process = new PathfindingProcess(workerData.loopRate);

events.on(PathfindingEvent.CreateTask, (payload) => {
const task = new PathfindingTask(payload, (result) => {
Expand Down
7 changes: 4 additions & 3 deletions webpack.config.js → webpack/entrypoint.config.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
const path = require('path');

const root = path.resolve(__dirname, '..');

module.exports = {
target: 'node',
resolve: {
extensions: ['.ts', '.js'],
},
entry: {
index: path.resolve(__dirname, 'src/index.ts'),
worker: path.resolve(__dirname, 'src/worker.ts'),
index: path.resolve(root, 'src/index.ts'),
},
output: {
path: path.resolve(__dirname, 'dist'),
path: path.resolve(root, 'dist'),
chunkFilename: '[name].js',
filename: '[name].js',
libraryTarget: 'commonjs2',
Expand Down
30 changes: 30 additions & 0 deletions webpack/worker.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const path = require('path');

const InjectWorkerPlugin = require('./worker.plugin');

const root = path.resolve(__dirname, '..');

module.exports = {
target: 'node',
resolve: {
extensions: ['.ts', '.js'],
},
entry: path.resolve(root, 'src/worker.ts'),
output: {
path: path.resolve(root, '.temp'),
filename: 'worker.inline.js',
libraryTarget: 'commonjs2',
clean: true,
},
plugins: [
new InjectWorkerPlugin(),
],
module: {
rules: [
{
test: /\.ts$/,
use: 'ts-loader',
},
],
},
};
33 changes: 33 additions & 0 deletions webpack/worker.plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/* eslint-disable no-undef */
/* eslint-disable @typescript-eslint/no-var-requires */

const ModuleFilenameHelpers = require('webpack/lib/ModuleFilenameHelpers');

class InjectWorkerPlugin {
apply(compiler) {
const ConcatSource = compiler.webpack.sources.ConcatSource;
const tester = { test: this.test };

compiler.hooks.compilation.tap('InjectWorkerPlugin', (compilation) => {
compilation.hooks.afterOptimizeChunkAssets.tap('InjectWorkerPlugin', (chunks) => {
for (const chunk of chunks) {
for (const fileName of chunk.files) {
if (ModuleFilenameHelpers.matchObject(tester, fileName)) {
wrapFile(compilation, fileName);
}
}
}
});
});

function wrapFile(compilation, fileName) {
compilation.assets[fileName] = new ConcatSource(
'module.exports = `',
compilation.assets[fileName],
'`;',
);
}
}
}

module.exports = InjectWorkerPlugin;
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3984,6 +3984,11 @@ wrap-ansi@^7.0.0:
string-width "^4.1.0"
strip-ansi "^6.0.0"

wrapper-webpack-plugin@^2.2.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/wrapper-webpack-plugin/-/wrapper-webpack-plugin-2.2.2.tgz#a950b7fbc39ca103e468a7c06c225cb1e337ad3b"
integrity sha512-twLGZw0b2AEnz3LmsM/uCFRzGxE+XUlUPlJkCuHY3sI+uGO4dTJsgYee3ufWJaynAZYkpgQSKMSr49n9Yxalzg==

wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
Expand Down

0 comments on commit 51d8641

Please sign in to comment.