Skip to content

Commit

Permalink
update readme and add ?singleton=false mode
Browse files Browse the repository at this point in the history
  • Loading branch information
developit committed Jan 14, 2020
1 parent 3f817f7 commit 265e419
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 11 deletions.
74 changes: 69 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,13 @@ npm install -D comlink-loader

The goal of `comlink-loader` is to make the fact that a module is running inside a Worker nearly transparent to the developer.

In the example below, the sole difference between running `MyClass` on a Worker thread instead of the main thread is that instantiation and method calls must be prefixed with `await`. This is required because Worker interactions are inherently asynchronous.
### Factory Mode (default)

In the example below, there are two changes we must make in order to import `MyClass` within a Worker via `comlink-loader`.

1. instantiation and method calls must be prefixed with `await`, since everything is inherently asynchronous.
2. the value we import from `comlink-loader!./my-class` is now a function that returns our module exports.
> Calling this function creates a new instance of the Worker.
**my-class.js**: _(gets moved into a worker)_

Expand All @@ -33,7 +39,7 @@ In the example below, the sole difference between running `MyClass` on a Worker
import rnd from 'random-int';

// Export as you would in a normal module:
export function meaningOfLife(){
export function meaningOfLife() {
return 42;
}

Expand All @@ -54,18 +60,76 @@ export class MyClass {
**main.js**: _(our demo, on the main thread)_

```js
import worker from 'comlink-loader!./my-class';
const inst = worker();
import MyWorker from 'comlink-loader!./my-class';

// instantiate a new Worker with our code in it:
const inst = new MyWorker();

// our module exports are exposed on the instance:
await inst.meaningOfLife(); // 42

const obj = await new inst.MyClass(42); // notice the await
// instantiate a class in the worker (does not create a new worker).
// notice the `await` here:
const obj = await new inst.MyClass(42);

await obj.increment();

await obj.getValue(); // 43
```

### Singleton Mode

Comlink-loader also includes a `singleton` mode, which can be opted in on a per-module basis using Webpack's inline loader syntax, or globally in Webpack configuration. Singleton mode is designed to be the easiest possible way to use a Web Worker, but in doing so it only allows using a single Worker instance for each module.

The benefit is that your module's exports can be used just like any other import, without the need for a constructor. It also supports TypeScript automatically, since the module being imported looks just like it would were it running on the main thread. The only change that is required in order to move a module into a Worker using singleton mode is to ensure all of your function calls use `await`.

First, configure `comlink-loader` globally to apply to all `*.worker.js` files (or whichever pattern you choose). Here we're going to use TypeScript, just to show that it works out-of-the-box:

**webpack.config.js**:

```js
module.exports = {
module: {
rules: [
{
test: /\.worker\.(js|ts)$/i,
use: [{
loader: 'comlink-loader',
options: {
singleton: true
}
}]
}
]
}
}
```

Now, let's write a simple module that we're going to load in a Worker:

**greetings.worker.ts**:

```ts
export async function greet(subject: string): string {
return `Hello, ${subject}!`;
}
```

We can import our the above module, and since the filename includes `.worker.ts`, it will be transparently loaded in a Web Worker!

**index.ts**:

```ts
import { greet } from './greetings.worker.ts';

async function demo() {
console.log(await greet('dog'));
}

demo();
```


## License

Apache-2.0
23 changes: 17 additions & 6 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,19 +39,30 @@ loader.pitch = function (request) {

const remainingRequest = JSON.stringify(workerLoader + '!' + request);

if (singleton) {
// ?singleton mode: export an instance of the worker
if (singleton === true) {
return `
module.exports = require('comlink').wrap(require(${remainingRequest})());
module.exports.__esModule = true;
${options.module === false ? '' : 'module.exports.__esModule = true;'}
`.replace(/\n\s*/g, '');
}

// ?singleton=false mode: always return a new worker from the factory
if (singleton === false) {
return `
module.exports = function () {
return require('comlink').wrap(require(${remainingRequest})());
};
`.replace(/\n\s*/g, '');
}

return `
import {wrap} from 'comlink';
var inst, Worker = require(${remainingRequest});
export default function f() {
var wrap = require('comlink').wrap,
Worker = require(${remainingRequest}),
inst;
module.exports = function f() {
if (this instanceof f) return wrap(Worker());
return inst || (inst = wrap(Worker()));
}
};
`.replace(/\n\s*/g, '');
};

0 comments on commit 265e419

Please sign in to comment.