Skip to content

Commit

Permalink
Merge pull request #68 from cloudnc/feat/webpack-5-support
Browse files Browse the repository at this point in the history
  • Loading branch information
zakhenry authored Apr 24, 2021
2 parents f84d0ef + 0aba7f4 commit 5d741ad
Show file tree
Hide file tree
Showing 22 changed files with 107 additions and 154 deletions.
30 changes: 2 additions & 28 deletions .betterer.results
Original file line number Diff line number Diff line change
@@ -1,26 +1,7 @@
// BETTERER RESULTS V1.
exports[`stricter compilation`] = {
timestamp: 1616658221627,
timestamp: 1619240872304,
value: `{
"projects/observable-webworker/src/lib/from-worker-pool.spec.ts:634732869": [
[288, 33, 33, "Argument of type \'(observer: Observer<number>) => () => void\' is not assignable to parameter of type \'(this: Observable<T>, subscriber: Subscriber<T>) => TeardownLogic\'.\\n Types of parameters \'observer\' and \'subscriber\' are incompatible.\\n Type \'Subscriber<T>\' is not assignable to type \'Observer<number>\'.\\n Types of property \'next\' are incompatible.\\n Type \'(value?: T | undefined) => void\' is not assignable to type \'(value: number) => void\'.\\n Types of parameters \'value\' and \'value\' are incompatible.\\n Type \'number\' is not assignable to type \'T | undefined\'.", "1166033031"]
],
"projects/observable-webworker/src/lib/from-worker.spec.ts:2047567224": [
[92, 4, 20, "Cannot invoke an object which is possibly \'null\'.", "650422727"],
[171, 4, 20, "Cannot invoke an object which is possibly \'null\'.", "650422727"],
[177, 4, 20, "Cannot invoke an object which is possibly \'null\'.", "650422727"]
],
"projects/observable-webworker/src/lib/from-worker.ts:4009652202": [
[28, 56, 11, "Argument of type \'Input | undefined\' is not assignable to parameter of type \'Input\'.\\n \'Input\' could be instantiated with an arbitrary type which could be unrelated to \'Input | undefined\'.\\n Type \'undefined\' is not assignable to type \'Input\'.\\n \'Input\' could be instantiated with an arbitrary type which could be unrelated to \'undefined\'.", "1574273654"]
],
"projects/observable-webworker/src/lib/run-worker.ts:4122498212": [
[4, 65, 7, "Rest parameter \'args\' implicitly has an \'any[]\' type.", "3622679692"],
[51, 38, 26, "Cannot invoke an object which is possibly \'undefined\'.", "4028913799"],
[51, 65, 18, "Argument of type \'O | undefined\' is not assignable to parameter of type \'O\'.\\n \'O\' could be instantiated with an arbitrary type which could be unrelated to \'O | undefined\'.\\n Type \'undefined\' is not assignable to type \'O\'.\\n \'O\' could be instantiated with an arbitrary type which could be unrelated to \'undefined\'.", "3307950093"]
],
"src/app/file-hash.worker.ts:1230899360": [
[0, 21, 8, "Could not find a declaration file for module \'js-md5\'. \'./node_modules/js-md5/src/md5.js\' implicitly has an \'any\' type.\\n Try \`npm install @types/js-md5\` if it exists or add a new declaration (.d.ts) file containing \`declare module \'js-md5\';\`", "3516231053"]
],
"src/app/google-charts.service.ts:1308226900": [
[3, 29, 15, "Could not find a declaration file for module \'google-charts\'. \'./node_modules/google-charts/dist/googleCharts.js\' implicitly has an \'any\' type.\\n Try \`npm install @types/google-charts\` if it exists or add a new declaration (.d.ts) file containing \`declare module \'google-charts\';\`", "2535818334"]
],
Expand All @@ -30,15 +11,8 @@ exports[`stricter compilation`] = {
[13, 9, 5, "Property \'color\' has no initializer and is not definitely assigned in the constructor.", "176948952"],
[18, 44, 17, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "463397358"]
],
"src/app/multiple-worker-pool/multiple-worker-pool.component.ts:3101768987": [
[40, 55, 17, "Property \'timelineComponent\' has no initializer and is not definitely assigned in the constructor.", "964610961"],
"src/app/multiple-worker-pool/multiple-worker-pool.component.ts:1042385498": [
[90, 9, 14, "Type \'Observable<{ millisSinceLast: number | null; file?: string | undefined; timestamp: Date; message: string; thread: Thread; fileEventType: FileHashEvent | null; }[]>\' is not assignable to type \'Observable<HashWorkerMessage[]>\'.\\n Type \'{ millisSinceLast: number | null; file?: string | undefined; timestamp: Date; message: string; thread: Thread; fileEventType: FileHashEvent | null; }[]\' is not assignable to type \'HashWorkerMessage[]\'.\\n Type \'{ millisSinceLast: number | null; file?: string | undefined; timestamp: Date; message: string; thread: Thread; fileEventType: FileHashEvent | null; }\' is not assignable to type \'HashWorkerMessage\'.\\n Types of property \'millisSinceLast\' are incompatible.\\n Type \'number | null\' is not assignable to type \'number | undefined\'.\\n Type \'null\' is not assignable to type \'number | undefined\'.", "463576723"]
],
"src/app/single-worker/single-worker.component.ts:228104130": [
[25, 22, 6, "Parameter \'$event\' implicitly has an \'any\' type.", "3058907597"]
],
"src/readme/worker-pool-hash.worker.ts:2220989309": [
[0, 21, 8, "Could not find a declaration file for module \'js-md5\'. \'./node_modules/js-md5/src/md5.js\' implicitly has an \'any\' type.\\n Try \`npm install @types/js-md5\` if it exists or add a new declaration (.d.ts) file containing \`declare module \'js-md5\';\`", "3516231053"]
]
}`
};
69 changes: 38 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ yarn add observable-webworker

#### Main Thread

💡 Take note! The webworker construction syntax differs for different version of webpack:

#### Webpack < 5

```ts
// src/readme/hello.ts

Expand All @@ -71,18 +75,34 @@ fromWorker<string, string>(() => new Worker('./hello.worker', { type: 'module' }
console.log(message); // Outputs 'Hello from webworker'
});

```
#### Webpack 5

```ts
// src/readme/hello-webpack-5.ts#L2-L12

import { fromWorker } from 'observable-webworker';
import { of } from 'rxjs';

const input$ = of('Hello from main thread');

fromWorker<string, string>(
() => new Worker(new URL('./app.worker', import.meta.url), { type: 'module' }),
input$,
).subscribe(message => {
console.log(message); // Outputs 'Hello from webworker'
});
```

#### Worker Thread

```ts
// src/readme/hello.worker.ts

import { DoWork, ObservableWorker } from 'observable-webworker';
import { DoWork, runWorker } from 'observable-webworker';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

@ObservableWorker()
export class HelloWorker implements DoWork<string, string> {
public work(input$: Observable<string>): Observable<string> {
return input$.pipe(
Expand All @@ -94,35 +114,20 @@ export class HelloWorker implements DoWork<string, string> {
}
}

```

##### Important Note
You **must** export your worker class (`export class ...`) from the file if you're using a minifier. If you don't, your
class will be removed from the bundle, causing your worker to do nothing!

You'll probably need to export the class anyway as you are unit testing it right?!

##### Don't like decorators? Don't use 'em!
runWorker(HelloWorker);

If decorators is not something you use regularly and prefer direct functions, simply
use the `runWorker` function instead.
```

```ts
// src/readme/hello-no-decorator.worker.ts#L5-L16
#### Decorator deprecation notice
Future versions of webpack (Webpack 5) minify webworkers overly aggressively, causing
the `@ObservableWorker()` decorator pattern to no longer function. This decorator
has now been deprecated, and will be removed in the next major version of this library.

class HelloWorker implements DoWork<string, string> {
public work(input$: Observable<string>): Observable<string> {
return input$.pipe(
map(message => {
console.log(message); // outputs 'Hello from main thread'
return `Hello from webworker`;
}),
);
}
}
To migrate from decorators, simply remove the decorator, and invoke the `runWorker`
with your class passed as argument (see example above).

runWorker(HelloWorker);
```
Make sure you **don't forget to remove the decorator** when you add the `runWorker(...)`
function, otherwise the worker will be run twice, each acting on any message sent.

## Transferable

Expand Down Expand Up @@ -209,11 +214,10 @@ export function computeHashes(files: File[]): Observable<string> {
// src/readme/worker-pool-hash.worker.ts

import * as md5 from 'js-md5';
import { DoWorkUnit, ObservableWorker } from 'observable-webworker';
import { DoWorkUnit, runWorker } from 'observable-webworker';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

@ObservableWorker()
export class WorkerPoolHashWorker implements DoWorkUnit<File, string> {
public workUnit(input: File): Observable<string> {
return this.readFileAsArrayBuffer(input).pipe(map(arrayBuffer => md5(arrayBuffer)));
Expand All @@ -239,6 +243,8 @@ export class WorkerPoolHashWorker implements DoWorkUnit<File, string> {
}
}

runWorker(WorkerPoolHashWorker);

```

Note here that the worker class `implements DoWorkUnit<File, string>`. This is different to before where we implemented
Expand All @@ -254,11 +260,12 @@ from the `workUnit` method.
```ts
// src/app/doc/async-work.worker.ts#L7-L14

@ObservableWorker()
export class FactorizationWorker implements DoWorkUnit<number, number[]> {
public async workUnit(input: number): Promise<number[]> {
return factorize(input);
}
}

```
runWorker(FactorizationWorker);

```
2 changes: 1 addition & 1 deletion karma.conf.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html

module.exports = function(config) {
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
"@types/google.visualization": "0.0.48",
"@types/jasmine": "~3.3.8",
"@types/jasminewd2": "~2.0.3",
"@types/js-md5": "^0.4.2",
"@types/node": "^12.11.1",
"codelyzer": "^6.0.0",
"commitizen": "4.0.3",
Expand All @@ -76,7 +77,7 @@
"karma-jasmine": "~4.0.0",
"karma-jasmine-html-reporter": "^1.5.0",
"ng-packagr": "^10.1.0",
"prettier": "1.18.2",
"prettier": "2.2.1",
"semantic-release": "^17.2.3",
"ts-node": "~7.0.0",
"tslint": "~6.1.0",
Expand Down
2 changes: 1 addition & 1 deletion projects/observable-webworker/karma.conf.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html

module.exports = function(config) {
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { fakeAsync, tick } from '@angular/core/testing';
import { Observable, Observer, Subject, Subscription } from 'rxjs';
import { Observable, Subject, Subscription } from 'rxjs';
import { Notification } from 'rxjs/internal/Notification';
import { reduce } from 'rxjs/operators';
import { fromWorkerPool } from './from-worker-pool';
Expand Down Expand Up @@ -285,14 +285,14 @@ describe('fromWorkerPool', () => {

const operatorSpy = jasmine.createSpy('subscriptionSpy');

function customOperator<T extends number>(outerObservable$: Observable<Observable<T>>): Observable<T> {
return new Observable<T>((observer: Observer<number>) => {
function customOperator(outerObservable$: Observable<Observable<number>>): Observable<number> {
return new Observable<number>(subscriber => {
const innerSubs: Subscription[] = [];

const outerSub = outerObservable$.subscribe(innerObservable$ => {
innerSubs.push(
innerObservable$.subscribe(value => {
observer.next(value * 2);
subscriber.next(value * 2);
operatorSpy();
}),
);
Expand Down
6 changes: 3 additions & 3 deletions projects/observable-webworker/src/lib/from-worker.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ describe('fromWorker', () => {
const subscriptionErrorSpy = jasmine.createSpy('subscriptionErrorSpy');
const sub = stubbedWorkerStream.subscribe({ error: subscriptionErrorSpy });

stubWorker.onmessage(
stubWorker.onmessage!(
new MessageEvent('message', {
data: new Notification('E', undefined, 'Nope!'),
}),
Expand Down Expand Up @@ -169,13 +169,13 @@ describe('fromWorker', () => {
testValue.buffer,
]);

stubWorker.onmessage(
stubWorker.onmessage!(
new MessageEvent('message', {
data: new Notification('N', 1),
}),
);

stubWorker.onmessage(
stubWorker.onmessage!(
new MessageEvent('message', {
data: new Notification('C'),
}),
Expand Down
2 changes: 1 addition & 1 deletion projects/observable-webworker/src/lib/from-worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export function fromWorker<Input, Output>(
materialize(),
tap(input => {
if (selectTransferables && input.hasValue) {
const transferables = selectTransferables(input.value);
const transferables = selectTransferables(input.value as Input);
worker.postMessage(input, transferables);
} else {
worker.postMessage(input);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { take } from 'rxjs/operators';
import { ObservableWorker } from './observable-worker.decorator';
import { DoWork, WorkerMessageNotification } from './observable-worker.types';

describe('@ObservableWorker', () => {
describe('@ObservableWorker (deprecated, remove in next major version)', () => {
it('should automatically run the worker', () => {
const postMessageSpy = spyOn(window, 'postMessage');
postMessageSpy.calls.reset();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { ObservableWorkerConstructor, runWorker } from './run-worker';

/**
* @deprecated - use the `runWorker(YourWorkerClass)` strategy instead, for
* compatibility with future webpack versions, and a slightly smaller bundle
* @see https://github.com/cloudnc/observable-webworker#decorator-deprecation-notice
*/
export function ObservableWorker() {
return <I, O>(workerConstructor: ObservableWorkerConstructor<I, O>): void => {
runWorker(workerConstructor);
Expand Down
8 changes: 3 additions & 5 deletions projects/observable-webworker/src/lib/run-worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { from, fromEvent, Notification, Observable, Subscription } from 'rxjs';
import { concatMap, dematerialize, filter, map, materialize } from 'rxjs/operators';
import { DoTransferableWork, DoWork, DoWorkUnit, WorkerMessageNotification } from './observable-worker.types';

export type ObservableWorkerConstructor<I = any, O = any> = new (...args) => DoWork<I, O> | DoWorkUnit<I, O>;
export type ObservableWorkerConstructor<I = any, O = any> = new (...args: any[]) => DoWork<I, O> | DoWorkUnit<I, O>;

/** @internal */
export type WorkerPostMessageNotification<T> = (message: Notification<T>, tranferables?: Transferable[]) => void;
Expand Down Expand Up @@ -42,14 +42,12 @@ export function runWorker<I, O>(workerConstructor: ObservableWorkerConstructor<I

const incomingMessages$ = fromEvent<WorkerMessageNotification<I>>(self, 'message');

const transferableWorker = workerIsTransferableType(worker);

return getWorkerResult(worker, incomingMessages$).subscribe((notification: Notification<O>) => {
// type to workaround typescript trying to compile as non-webworker context
const workerPostMessage = (postMessage as unknown) as WorkerPostMessageNotification<O>;

if (transferableWorker && notification.hasValue) {
workerPostMessage(notification, worker.selectTransferables(notification.value));
if (workerIsTransferableType(worker) && notification.hasValue) {
workerPostMessage(notification, worker.selectTransferables(notification.value as O));
} else {
workerPostMessage(notification);
}
Expand Down
6 changes: 3 additions & 3 deletions projects/observable-webworker/tsconfig.lib.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
"declaration": true,
"inlineSources": true,
"types": [],
"lib": ["dom", "es2018"]
"lib": ["dom", "es2018"],
"strict": true
},
"angularCompilerOptions": {
"skipTemplateCodegen": true,
// false due to https://github.com/angular/angular/issues/19698
"strictMetadataEmit": false,
"strictMetadataEmit": true,
"fullTemplateTypeCheck": true,
"strictInjectionParameters": true,
"enableResourceInlining": true
Expand Down
3 changes: 2 additions & 1 deletion projects/observable-webworker/tsconfig.spec.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "../../out-tsc/spec",
"types": ["jasmine", "node"]
"types": ["jasmine", "node"],
"strict": true
},
"files": ["src/test.ts"],
"include": ["**/*.spec.ts", "**/*.d.ts"]
Expand Down
5 changes: 3 additions & 2 deletions src/app/doc/async-work.worker.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { DoWorkUnit, ObservableWorker } from 'observable-webworker';
import { DoWorkUnit, runWorker } from 'observable-webworker';

function factorize(input: number): number[] {
return []; // actual implementation left for the reader :)
}

@ObservableWorker()
export class FactorizationWorker implements DoWorkUnit<number, number[]> {
public async workUnit(input: number): Promise<number[]> {
return factorize(input);
}
}

runWorker(FactorizationWorker);
5 changes: 3 additions & 2 deletions src/app/file-hash.worker.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import * as md5 from 'js-md5';
import { ObservableWorker } from 'observable-webworker';
import { runWorker } from 'observable-webworker';
import { Observable, ReplaySubject, Subject } from 'rxjs';
import { map, take, tap } from 'rxjs/operators';
import { DoWorkUnit } from '../../projects/observable-webworker/src/lib/observable-worker.types';
import { FileHashEvent, HashWorkerMessage, Thread } from './hash-worker.types';

@ObservableWorker()
export class FileHashWorker implements DoWorkUnit<File, HashWorkerMessage> {
public workUnit(input: File): Observable<HashWorkerMessage> {
const output$: Subject<HashWorkerMessage> = new ReplaySubject(Infinity);
Expand Down Expand Up @@ -54,3 +53,5 @@ export class FileHashWorker implements DoWorkUnit<File, HashWorkerMessage> {
});
}
}

runWorker(FileHashWorker);
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import TimelineOptions = google.visualization.TimelineOptions;
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MultipleWorkerPoolComponent {
@ViewChild('timeline', { read: ElementRef }) private timelineComponent: ElementRef;
@ViewChild('timeline', { read: ElementRef }) private timelineComponent!: ElementRef;

public multiFilesToHash: Subject<File[]> = new ReplaySubject(1);
public workResult$ = this.multiFilesToHash.pipe(
Expand Down
Loading

0 comments on commit 5d741ad

Please sign in to comment.