accessible-worker
v0.0.1-dev-11
Published
Make web worker more accessible
Downloads
11
Maintainers
Readme
Accessible Worker (experimental )
accessible-worker aim to make web worker more accessible in TypeScipt and meet oop(Object Oriented Programing) style
What it does?
- Use TypeScript decorator & acorn compile class into web worker source code.
| Accessible Worker Define | Compiled Web Worker Souce Codes | | ------------------------------------------------------------ | ------------------------------------------------------------ | | | | | | |
Demo
- A demo is provided, accessible-worker-demo / online with codesandbox
Getting Started
Install,
npm install accessible-worker -s
oryarn add accessible-worker
Update
tsconfig.json
, for useaccessible-worker
in your project, you shold add"experimentalDecorators":true
option incompilerOptions
, look like this:{ ... "compilerOptions":{ ... "experimentalDecorators":true ... } ... }
Channel Worker
Channel Worker is designed as Sever-Client style based on event communication
Define Server I/O events like this:
// events for server to listen on type InputEvents = { COMBINE_MESSAGE: (name: { name: string }) => void, BEGIN_COUNT: () => void } // events for server to emit type OutputEvents = { COMBINED_MESSAGE: (message: string) => void, SEND_COUNT: (count: number) => void }
Implement your own Channel Worker extends
ChannelWorkerDefinition
like this:// Define Accessible Worker Description Class @AccessibleWorker() class MyAccessibleWorker extends ChannelWorkerDefinition<InputEvents, OutputEvents> { constructor() { super() this.prefix = 'Hi' } @GlobalVariable<string>() prefix: string = 'Hello' @GlobalVariable<number>() count = 0 @GlobalVariable<any>() timer: any @SubscribeMessage<InputEvents>('COMBINE_MESSAGE') async combineMessage(data: InferParams<InputEvents, 'COMBINE_MESSAGE'>) { console.log(MyOwnModule.a + MyOwnModule.b) this.emit('COMBINED_MESSAGE', `${this.prefix} ${data.name}`) } @SubscribeMessage<InputEvents>('BEGIN_COUNT') async onCount() { clearInterval(this.timer) this.count = 0 this.timer = setInterval(() => { this.count++ this.emit('SEND_COUNT', this.count) }, 1000) } }
Register your own Channel Worker with
AccessibleWorkerFactory
:// register Channel Worker const channelWorkerClient = await AccessibleWorkerFactory.registerChannelWorker<InputEvents, OutputEvents>(MyAccessibleWorker)
Now, you can use your own Channel Worker:
channelWorkerClient.on('COMBINED_MESSAGE', (msg: string) => { console.log(msg) // output // hi, okay6 }) channelWorkerClient.on('SEND_COUNT', count => { console.log(count) // output // 1 // 2 // 3 // 4 // ... }) client.emit('COMBINE_MESSAGE', {name: 'okay6'}) client.emit('BEGIN_COUNT'))
Functional Worker
Functional Worker will make a function run in web worker by proxy
Define you own function set:
const functionSet = { add: (a: number, b: number): number => { return a + b }, sub: (a: number, b: number): Promise<number> => Promise.resolve(a - b) }
Register your own function set with
AccessibleWorkerFactory
:// register Functional Worker const functionalWorker = await AccessibleWorkerFactory.registerFunctionSet(functionSet)
Now, you can your own function worker:
functionalWorker.sub(3, 1).then(res => { console.log(res) // output // 2 }) functionalWorker.add(1, 3).then(res => { console.log(res) // output // 4 })
Use third library
Cause accessible-worker is inline-worker (Javascript codes is dynamicilly created inner Blob), Same origin policy will block some request like
import {module} from 'lib'
andimportscripts
, so if we wanna use third library, we have to merge library code into web worker.accessible-worker provides a schema for integrate third library into yourt own web worker.(Now,only tested on webpack5)
First, define a module which export all you need in one constant like this:
// worker_module.ts import {v4 as uuidv4} from 'uuid' import _ from "lodash"; export const MyOwnModule = { uuid: uuidv4, endWith: _.endsWith }
Then, define your own Channel Worker or Function Worker:
import { AccessibleWorker, AccessibleWorkerFactory, ChannelWorkerDefinition, GlobalVariable, InferParams, SubscribeMessage } from "accessible-worker"; import {MyOwnModule} from "./worker_module"; type InputEvents = { IS_END_WITH: (param: {str:string, suffix:string}) => void } type OutputEvents = { END_WITH_RES: (res: boolean) => void } @AccessibleWorker({ module: { name: 'MyOwnModule', relativePath: 'accessible_worker_module' } }) class MyAccessibleWorker extends ChannelWorkerDefinition<InputEvents, OutputEvents> { @SubscribeMessage<InputEvents>('IS_END_WITH') async combineMessage(data: InferParams<InputEvents, 'IS_END_WITH'>) { this.emit('END_WITH_RES', MyOwnModule.endWith(data.str,data.suffix)) } } const functionSet = { uuid: (): string => MyOwnModule.uuid(), }
Register your own channel worker or function worker:
// register Channel Worker const channelWorkerClient = await AccessibleWorkerFactory.registerChannelWorker<InputEvents, OutputEvents>(MyAccessibleWorker) // register Functional Worker const functionalWorker = await AccessibleWorkerFactory.registerFunctionSet(functionSet,{ module: { name: 'MyOwnModule', relativePath: 'accessible_worker_module' } })
You should compile
worker_module.ts
into single js file for load, in webpack5, we can do it like this, add a new webpack config:const TerserPlugin = require("terser-webpack-plugin"); module.exports = { entry: { "accessible_worker_module": "./project/worker_module.ts", }, experiments: { outputModule: true, }, optimization: { minimize: true, minimizer: [ new TerserPlugin({ extractComments: false }), ], }, output: { publicPath: './dist/', filename: '[name].js', chunkFilename: '[name].[chunkhash].js', library: { type: "module" } }, resolve: { extensions: [".ts", ".js"], }, module: { rules: [ { test: /\.tsx?$/, use: "ts-loader", exclude: "/node-modules/" }, ] }, mode: "production" }
Add build script in
package.json
:{ ... "scripts": { ... "awm": "webpack --config webpack.aw.config.js", ... } ... }
For compile worker_module.ts once code updated, we can use webpack hook plugin
hook-shell-script-webpack-plugin
inwebpack.config.js
:module.exports = { ... plugins: [ ... new HookShellScriptPlugin({ afterEmit: ['npm run awm'] }) ... ], ... }
!!! So far, accessible-worker is experimental and only tested on webpack5
Todo
- [ ] Complete codes comments
- [ ] Complete API docs
- [ ] Support expection catch in web web worker
ChangeLog
License
Copyright (c) 2023-present, HongXiang Li