{"id":20513852,"url":"https://github.com/webreflection/workway","last_synced_at":"2025-04-07T12:03:59.719Z","repository":{"id":57399341,"uuid":"134376971","full_name":"WebReflection/workway","owner":"WebReflection","description":"A general purpose, Web Worker driven, namespace exporter.","archived":false,"fork":false,"pushed_at":"2023-07-04T16:39:28.000Z","size":97,"stargazers_count":183,"open_issues_count":0,"forks_count":7,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-30T15:36:26.682Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://medium.com/@WebReflection/web-worker-driven-classes-and-methods-8a5a8e9bdb67","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/WebReflection.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2018-05-22T07:26:34.000Z","updated_at":"2025-02-11T15:50:36.000Z","dependencies_parsed_at":"2024-01-10T08:04:12.460Z","dependency_job_id":null,"html_url":"https://github.com/WebReflection/workway","commit_stats":null,"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WebReflection%2Fworkway","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WebReflection%2Fworkway/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WebReflection%2Fworkway/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WebReflection%2Fworkway/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/WebReflection","download_url":"https://codeload.github.com/WebReflection/workway/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247648976,"owners_count":20972945,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-15T21:13:32.010Z","updated_at":"2025-04-07T12:03:59.702Z","avatar_url":"https://github.com/WebReflection.png","language":"JavaScript","readme":"# workway DEPRECATED - See [coincident](https://github.com/WebReflection/coincident#coincidentserver)\n\nA general purpose, Web Worker driven, remote namespace with classes and methods.\n\n\n- - -\n\n## Announcement: Meet proxied-worker \u0026 proxied-node\n\nThere is a new, very similar, yet different, project, in case you're looking to simply drive generic Workers instances, or namespaces, from a client/main thread: [proxied-worker](https://github.com/WebReflection/proxied-worker#readme).\n\nIt has [a NodeJS counterpart module](https://github.com/WebReflection/proxied-node#readme) too!\n\nThe main difference with these projects is:\n\n  * classes have a working constructor\n  * heap is automatically cleaned on both client/server\n  * it uses *Proxy* and *FinalizationRegistry* so these are not as compatible as *workway* is with legacy browsers\n\n- - -\n\n\n## Key Features\n\n  * no eval at all, no scope issues, 100% CSP friendly\n  * no Proxy at all neither, compatible with IE 10, iOS 8, Android 4.4, BB OS 10, and [every other browser](https://webreflection.github.io/workway/test/)\n  * 100LOC client squeezed in about 0.5K once compressed\n  * you expose non blocking namespaces to the main thread, not the other way around\n  * it **works on NodeJS** too 🎉\n\n\n\n## Example \u003csup\u003e\u003csub\u003e(client side only)\u003c/sub\u003e\u003c/sup\u003e\nA basic **firebase.js** client to show the user name.\n```js\nworkway('/workers/firebase.js').then(\n  async function ({worker, namespace}) {\n    await namespace.initializeApp({\n      apiKey: \"\u003cAPI_KEY\u003e\",\n      authDomain: \"\u003cPROJECT_ID\u003e.firebaseapp.com\",\n      databaseURL: \"https://\u003cDATABASE_NAME\u003e.firebaseio.com\",\n      projectId: \"\u003cPROJECT_ID\u003e\",\n      storageBucket: \"\u003cBUCKET\u003e.appspot.com\",\n      messagingSenderId: \"\u003cSENDER_ID\u003e\"\n    });\n    const fb = new namespace.FirebaseUser();\n    const name = await fb.name();\n    console.log(name); // will log the user name, if any\n\n    // the worker can be regularly used like any other worker\n    worker.postMessage('all good');\n  }\n);\n\n// you can also pass in an existing Worker instance (useful if you're using\n// Webpack's worker-loader and don't have access to the output file path):\nimport Worker from 'worker-loader!./Worker.js';\nworkway(new Worker()).then(...\n```\n\nThe **workers/firebase.js** worker that exposes some info.\n```js\n// top import to ensure a transparent communication channel\nimportScripts('https://unpkg.com/workway/worker.js');\n\n// any other needed import for this worker\nimportScripts(...[\n  'app', 'auth', 'database', 'firestore', 'messaging', 'functions'\n].map(name =\u003e `https://www.gstatic.com/firebasejs/5.0.1/firebase-${name}.js`));\n\n// expose a namespaces as an object\n// with any sort of serializable value\n// and also methods or classes\nworkway({\n\n  // any serializable data is OK (nested too)\n  timestamp: Date.now(),\n\n  // methods are OK too, each method\n  // accepts serializable arguments and\n  // can return a value and/or a promise\n  initializeApp(config) {\n    firebase.initializeApp(config);\n  },\n\n  // classes are also fine, as long as\n  // these respect RemoteClass conventions\n  FirebaseUser: class FirebaseUser {\n    constructor() {\n      this.uid = firebase.auth().currentUser.uid;\n    }\n    name() {\n      return firebase.database()\n                .ref('/users/' + this.uid)\n                .once('value')\n                .then(snapshot =\u003e ((\n                  snapshot.val() \u0026\u0026 snapshot.val().username\n                ) || 'Anonymous'));\n    }\n  }\n});\n\n// this worker can be regularly used like any other worker\n// the passed event will never be one handled by `workway`\nself.onmessage = event =\u003e {\n  console.log(event.data);\n};\n```\n\n## Example \u003csup\u003e\u003csub\u003e(NodeJS)\u003c/sub\u003e\u003c/sup\u003e\n\nTo have NodeJS driven workers you need the regular client side `workway.js` file, plus `/pocket.io/pocket.io.js` and `/workway@node.js` that are both handled by this module.\n\n```html\n\u003cscript src=\"/workway.js\"\u003e/* regular workway client file */\u003c/script\u003e\n\u003cscript src=\"/pocket.io/pocket.io.js\"\u003e/* automatically provided by the server */\u003c/script\u003e\n\u003cscript src=\"/workway@node.js\"\u003e/* automatically provided by the server */\u003c/script\u003e\n```\n\nThis is a `js/os.js` file for the client side.\n```js\nworkway('node://os.js').then(({worker, namespace:os}) =\u003e {\n  os.getNetworkInterfaces().then(console.log);\n});\n```\n\nPlease note the client file needs EventTarget, Promise, and WeakMap constructors.\nIf your target browsers don't have these features, you can use the following polyfills on top of your HTML file.\n\n```html\n\u003cscript\u003e\nif(!this.Promise)document.write('\u003cscript src=\"https://cdn.jsdelivr.net/npm/es6-promise@4/dist/es6-promise.auto.min.js\"\u003e\u003c'+'/script\u003e');\nif(!this.WeakMap)document.write('\u003cscript src=\"https://unpkg.com/poorlyfills@0.1.1/min.js\"\u003e\u003c'+'/script\u003e');\ntry{new EventTarget}catch(e){document.write('\u003cscript src=\"https://unpkg.com/event-target@1.2.2/min.js\"\u003e\u003c'+'/script\u003e')}\n\u003c/script\u003e\n```\n\n\nFollowing a `workers/os.js` file to serve via NodeJS.\n```js\n// note: you require a facade here via 'workway'\nvar workway = require('workway');\nworkway(require('os'));\n```\n\nAn express / node based bootstrap.\n```js\nvar express = require('express');\n\n// note: you require the real module as 'workway/node'\nvar workway = require('workway/node');\n// authorize / expose a specific folder\n// that contains web driven workers\nworkway.authorize(__dirname + '/workers');\n\nvar app = workway.app(express());\napp.use(express.static(__dirname + '/www'));\napp.listen(8080);\n```\n\n### NodeJS extra features \u0026 gotchas\n\n  * exact same API (actually exact same code) of the real Web Worker based client side\n  * circular objects are supported out of the box via [flatted](https://github.com/WebReflection/flatted#flatted) on both ways\n  * the `self` global (but sandboxed) variable points at the global\n  * the `self.workway` method is already there, feel free to use it instead of requiring it from workers\n  * the `self.addEventListener` and `self.remoteEventListener` are normalized to work like on the front end side: do not use emitter methods directly with your node workers or messages and errors might not be signaled as expected\n\n\n## The RemoteClass convention\n\nClasses exposed through `workway` namespace must follow these rules:\n\n  * no constructor arguments; use methods to eventually forward extra details from the client\n  * methods can accept only serializable arguments and can return either a serializable value or a promise that will resolve as serializable data\n  * properties set on the **client** side must be serializable and will be **reflected** into related worker instances whenever methods are invoked\n  * properties set in the **worker** will **not** be **reflected** on the client side so that what's defined in the worker, stays in the worker\n  * every method invocation returns a Promise, even if the method returned value is not\n  * multiple methods invocation at once are possible, but there is no guarantee of the order. Use promises features or `await` each call if sequential methods calls depend on previous results.\n\n\n\n## Compatibility\n\nThe code is written in a ES5 friendly syntax, and it's guaranteed to work in IE 10 or above, and mostly every mobile browser on platforms such iOS 8+, Android 4.4+, Blackberry OS 10+, or Windows Phone 8+.\n\nYou can test live your browser through the **[live test page](https://webreflection.github.io/workway/test/index.html)**.\n\nPlease note in IE 10/11 or other old browser cases, you might need to provide polyfills on both client and worker side.\n\nFeel free to choose the polyfill you prefer.\n\nFollowing just as example:\n\n```html\n\u003c!doctype html\u003e\n\u003cscript\u003e\n// needed for IE11\nif(!this.Promise)document.write('\u003cscript src=\"https://cdn.jsdelivr.net/npm/es6-promise@4/dist/es6-promise.auto.min.js\"\u003e\u003c'+'/script\u003e');\n// needed for IE10\nif(!this.WeakMap)document.write('\u003cscript src=\"https://unpkg.com/poorlyfills@0.1.1/min.js\"\u003e\u003c'+'/script\u003e');\n\u003c/script\u003e\n\u003cscript src=\"https://unpkg.com/workway\"\u003e\u003c/script\u003e\n\u003cscript src=\"firebase.js\"\u003e\u003c/script\u003e\n```\n\nOr on top of your generic worker.\n```js\n// import the polyfill you prefer for either IE11 or IE10\nif (!self.Promise) importScripts('https://cdn.jsdelivr.net/npm/es6-promise@4/dist/es6-promise.auto.min.js');\nif (!self.WeakMap) importScripts('https://unpkg.com/poorlyfills@0.1.1/min.js');\n\n// now import workway/worker.js before any other worker script\nimportScripts('https://unpkg.com/workway/worker.js');\n\n// ... the rest of the code ... \n```\n\n\n\n## About Recursive data\n\nIf you need to invoke a method passing an object that might contain recursive data you can serialize it upfront and parse it once received.\n\n```js\n// main thread app.js side\nimport workway from 'https://unpkg.com/workway/esm';\nimport {stringify} from 'https://unpkg.com/flatted/esm';\n\nworkway('analyzer.js').then(({namespace}) =\u003e {\n  const data = {arr: []};\n  data.arr.push(data);\n  data.data = data;\n  namespace.analyze(stringify(data))\n            .then(\n              state =\u003e document.body.textContent = state,\n              console.error\n            );\n});\n\n\n\n// worker side: analyzer.js\nimportScripts(\n  'https://unpkg.com/workway/worker.js',\n  'https://unpkg.com/flatted'\n);\n\nworkway({\n  analyze(circular) {\n    const data = Flatted.parse(circular);\n    return 'OK';\n  }\n});\n```\n\nYou can [test above example right here](https://webreflection.github.io/workway/test/circular/).\n\n\n\n### Extra Info\n\n  * the client side of this package fits in just 100 LOC\n  * the client side of this project weights 0.5K via brotli, 0.6K via gzip\n  * the client side source of truth of this project is its root `./index.js`\n  * the only worker related code is in `./worker.js` root file\n  * the ESM version of this module is in `esm/index.js`\n  * the CJS version of this module is in `cjs/index.js`\n  * the browser version of this module is in `min.js`\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebreflection%2Fworkway","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwebreflection%2Fworkway","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebreflection%2Fworkway/lists"}