Skip to content

Commit

Permalink
Remove web worker replacement (#976)
Browse files Browse the repository at this point in the history
  • Loading branch information
HarelM authored Feb 10, 2022
1 parent 9c2bb48 commit 0263cc0
Show file tree
Hide file tree
Showing 9 changed files with 120 additions and 108 deletions.
26 changes: 8 additions & 18 deletions build/readme.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,31 @@
# Build Scripts
This folder holds common build scripts accessed via the various `npm run` commands.

Codegen is executed when calling `npm install` in order to generate all artifacts needed for the build to pass
## Bundeling all the code

The bundeling process can be split into several steps:

`npx run tsc`
This command will transpile all the typescript files into javascript files and place them in the `rollup/build` folder.

`npm run build-glsl`
This command will copy all the shader files to the build output and convert the shaders into strings that can be imported to javascript.

`npm run build-css`
This command will compile the css code and create the css file.

`npm run build-prod` or `npm run build-prod-min` or `npm run build-dev`
These commands will use rollup to bundle the code. This is where the magic happens and uses some files in this folder.

`banner.js` is used to create a banner at the beginning of the output file
`banner.ts` is used to create a banner at the beginning of the output file

`rollup_plugins.js` is used to define common plugins for rollup configurations
`rollup_plugins.ts` is used to define common plugins for rollup configurations

`rollup_plugin_minify_style_spec.js` is used to specify the plugin used in style spec bundeling
`rollup_plugin_minify_style_spec.ts` is used to specify the plugin used in style spec bundeling

In the `rollup` folder there are some files that are used as linking files as they link to other files for rollup to pick when bundling.
Rollup also has a configuration in the `package.json` file to signal which files it needs to replace when bundling for the browser, this is where `web_worker_replacement.js` is used - as it replaces the node mocking of web worker that is present in the source code.

Rollup is generating 3 files throughout the process of bundling:

`index.js` a file containing all the code that will run in the main thread.
`index.ts` a file containing all the code that will run in the main thread.

`shared.js` a file containing all the code shared between the main and worker code.
`shared.ts` a file containing all the code shared between the main and worker code.

`worker.js` a file containing all the code the will run in the worker threads.
`worker.ts` a file containing all the code the will run in the worker threads.

These 3 files are then referenced and used by the `bundle_prelude.js` file. It allows loading the web wroker code automatically in web workers without any extra effort from someone who would like to use the library, i.e. it simply works.

Expand All @@ -55,8 +48,5 @@ Generates `style-spec/types.ts` based on the content of `v8.json`. This provides
<hr>

### Generate Release Nodes
The following files are being used to generate release notes:

`release-notes.js` Used to generate release notes when releasing a new version

`release-notes.md.ejs` Used for the generation as a template file
`release-notes.js` Used to generate release notes when releasing a new version
3 changes: 1 addition & 2 deletions build/rollup_plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ import {Plugin} from 'rollup';

export const nodeResolve = resolve({
browser: true,
preferBuiltins: false,
extensions: ['.mjs', '.js', '.json', '.node', '.ts']
preferBuiltins: false
});

export const plugins = (minified: boolean, production: boolean): Plugin[] => [
Expand Down
5 changes: 0 additions & 5 deletions build/web_worker_replacement.ts

This file was deleted.

5 changes: 4 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,8 @@ export default {
transformIgnorePatterns: [
'/node_modules/@mapbox/jsonlint-lines-primitives/lib/jsonlint.js'
],
setupFiles: ['jest-canvas-mock'],
setupFiles: [
'jest-canvas-mock',
'./test/unit/lib/web_worker_mock.ts'
],
};
3 changes: 0 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,6 @@
"ts-node": "^10.5.0",
"typescript": "^4.5.5"
},
"browser": {
"./src/util/web_worker.ts": "./build/web_worker_replacement.ts"
},
"scripts": {
"generate-shaders": "node --loader ts-node/esm --experimental-specifier-resolution=node build/generate-shaders.ts",
"generate-struct-arrays": "node --loader ts-node/esm --experimental-specifier-resolution=node build/generate-struct-arrays.ts",
Expand Down
51 changes: 41 additions & 10 deletions src/util/actor.test.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,42 @@
import Actor from './actor';
import workerFactory from './web_worker';
import {MessageBus} from '../../test/unit/lib/web_worker_mock';

const originalWorker = global.Worker;

function setTestWorker(MockWorker: { new(...args: any): any}) {
(global as any).Worker = function Worker(_: string) {
const parentListeners = [];
const workerListeners = [];
const parentBus = new MessageBus(workerListeners, parentListeners);
const workerBus = new MessageBus(parentListeners, workerListeners);

parentBus.target = workerBus;
workerBus.target = parentBus;

new MockWorker(workerBus);

return parentBus;
};
}

describe('Actor', () => {
afterAll(() => {
global.Worker = originalWorker;
});

test('forwards responses to correct callback', done => {
jest.spyOn(workerFactory, 'Worker').mockImplementation(function Worker(self) {
this.self = self;
this.actor = new Actor(self, this);
this.test = function (mapId, params, callback) {
setTestWorker(class MockWorker {
self: any;
actor: Actor;
constructor(self) {
this.self = self;
this.actor = new Actor(self, this);
}
test(mapId, params, callback) {
setTimeout(callback, 0, null, params);
};
} as any);
}
});

const worker = workerFactory();

Expand Down Expand Up @@ -38,10 +65,14 @@ describe('Actor', () => {
test('targets worker-initiated messages to correct map instance', done => {
let workerActor;

jest.spyOn(workerFactory, 'Worker').mockImplementation(function Worker(self) {
this.self = self;
this.actor = workerActor = new Actor(self, this);
} as any);
setTestWorker(class MockWorker {
self: any;
actor: Actor;
constructor(self) {
this.self = self;
this.actor = workerActor = new Actor(self, this);
}
});

const worker = workerFactory();

Expand Down
72 changes: 4 additions & 68 deletions src/util/web_worker.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
// When Rollup builds the main bundle this file is replaced with ./build/web_worker_replacement.js
// See package.json 'browser' field and rollup documentation.
// This file is intended for use in the GL-JS test suite when they run on node since node doesn't support workers.
// It implements a MessageBus main thread interface

import MaplibreWorker from '../source/worker';
import maplibregl from '../index';

import type {WorkerSource} from '../source/worker_source';

type MessageListener = (
export type MessageListener = (
a: {
data: any;
target: any;
}
) => unknown;

// The main thread interface. Provided by Worker in a browser environment,
// and MessageBus below in a node environment.
export interface WorkerInterface {
addEventListener(type: 'message', listener: MessageListener): void;
removeEventListener(type: 'message', listener: MessageListener): void;
Expand All @@ -34,64 +28,6 @@ export interface WorkerGlobalScopeInterface {
registerRTLTextPlugin: (_: any) => void;
}

class MessageBus implements WorkerInterface, WorkerGlobalScopeInterface {
addListeners: Array<MessageListener>;
postListeners: Array<MessageListener>;
target: MessageBus;
registerWorkerSource: any;
registerRTLTextPlugin: any;

constructor(addListeners: Array<MessageListener>, postListeners: Array<MessageListener>) {
this.addListeners = addListeners;
this.postListeners = postListeners;
}

addEventListener(event: 'message', callback: MessageListener) {
if (event === 'message') {
this.addListeners.push(callback);
}
}

removeEventListener(event: 'message', callback: MessageListener) {
const i = this.addListeners.indexOf(callback);
if (i >= 0) {
this.addListeners.splice(i, 1);
}
}

postMessage(data: any) {
setTimeout(() => {
try {
for (const listener of this.postListeners) {
listener({data, target: this.target});
}
} catch (e) {
console.error(e);
}
}, 0);
}

terminate() {
this.addListeners.splice(0, this.addListeners.length);
this.postListeners.splice(0, this.postListeners.length);
}

importScripts() { }
}

export default function workerFactory(): WorkerInterface {
const parentListeners = [],
workerListeners = [],
parentBus = new MessageBus(workerListeners, parentListeners),
workerBus = new MessageBus(parentListeners, workerListeners);

parentBus.target = workerBus;
workerBus.target = parentBus;

new workerFactory.Worker(workerBus);

return parentBus;
export default function workerFactory() {
return new Worker(maplibregl.workerUrl);
}

// expose to allow stubbing in unit tests
workerFactory.Worker = MaplibreWorker;
2 changes: 1 addition & 1 deletion test/integration/render/suite_implementation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import fs from 'fs';
import path, {dirname} from 'path';
import customLayerImplementations from './custom_layer_implementations';
import {fileURLToPath} from 'url';

import '../../unit/lib/web_worker_mock';
// @ts-ignore
const __dirname = dirname(fileURLToPath(import.meta.url));
let now = 0;
Expand Down
61 changes: 61 additions & 0 deletions test/unit/lib/web_worker_mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import type {WorkerInterface, WorkerGlobalScopeInterface, MessageListener} from '../../../src/util/web_worker';
import MaplibreWorker from '../../../src/source/worker';

export class MessageBus implements WorkerInterface, WorkerGlobalScopeInterface {
addListeners: Array<MessageListener>;
postListeners: Array<MessageListener>;
target: MessageBus;
registerWorkerSource: any;
registerRTLTextPlugin: any;

constructor(addListeners: Array<MessageListener>, postListeners: Array<MessageListener>) {
this.addListeners = addListeners;
this.postListeners = postListeners;
}

addEventListener(event: 'message', callback: MessageListener) {
if (event === 'message') {
this.addListeners.push(callback);
}
}

removeEventListener(event: 'message', callback: MessageListener) {
const i = this.addListeners.indexOf(callback);
if (i >= 0) {
this.addListeners.splice(i, 1);
}
}

postMessage(data: any) {
setTimeout(() => {
try {
for (const listener of this.postListeners) {
listener({data, target: this.target});
}
} catch (e) {
console.error(e);
}
}, 0);
}

terminate() {
this.addListeners.splice(0, this.addListeners.length);
this.postListeners.splice(0, this.postListeners.length);
}

importScripts() { }
}

(global as any).Worker = function Worker(_: string) {
const parentListeners = [];
const workerListeners = [];
const parentBus = new MessageBus(workerListeners, parentListeners);
const workerBus = new MessageBus(parentListeners, workerListeners);

parentBus.target = workerBus;
workerBus.target = parentBus;

new MaplibreWorker(workerBus);

return parentBus;
};

0 comments on commit 0263cc0

Please sign in to comment.