GithubHelp home page GithubHelp logo

alewin / useworker Goto Github PK

View Code? Open in Web Editor NEW
2.9K 22.0 99.0 2.33 MB

⚛️ useWorker() - A React Hook for Blocking-Free Background Tasks

Home Page: https://useworker.js.org/

License: MIT License

HTML 4.18% JavaScript 64.62% CSS 7.25% TypeScript 22.61% Dockerfile 1.35%
react hooks web-worker-react useworker web-workers background thread hook web-worker typescript-library

useworker's Introduction


useWorker

Use web workers with react hook
https://useworker.js.org/
Tweet

Bytes Newsletter

GitHub size GitHub TypeScript Support


🎨 Features

  • Run expensive function without blocking UI (Show live gif)
  • Supports Promises pattern instead of event-messages
  • Size: less than 3KB!
  • Clear API using hook
  • Typescript support
  • Garbage collector web worker instance
  • Remote dependencies option
  • timeout option

💾 Install

  • @latest
npm install --save @koale/useworker

🔨 Import

import { useWorker, WORKER_STATUS } from "@koale/useworker";

📙 Documents


🍞 Demo


⚙ Web Workers

Before you start using this hook, I suggest you to read the Web Worker documentation.


🐾 Usage

import React from "react";
import { useWorker } from "@koale/useworker";

const numbers = [...Array(5000000)].map(e => ~~(Math.random() * 1000000));
const sortNumbers = nums => nums.sort();

const Example = () => {
  const [sortWorker] = useWorker(sortNumbers);

  const runSort = async () => {
    const result = await sortWorker(numbers); // non-blocking UI
    console.log(result);
  };

  return (
    <button type="button" onClick={runSort}>
      Run Sort
    </button>
  );
};

🖼 Live Demo

useworker demo


🐾 Examples

Edit white-glitter-icji4

More examples: https://github.com/alewin/useWorker/tree/develop/example


🔧 Roadmap

  • Kill Web Worker
  • Reactive web worker status
  • Add timeout option
  • Import and use remote script inside useWorker function
  • support Transferable Objects
  • Testing useWorker #41
  • Import and use local script inside useWorker function #37
  • useWorkers Hook #38
  • useWorkerFile Hook #93

🤔 Motivation and Limitations

Most react projects are initialized through Create React App. CRA unfortunately does not offer support for webworkers, unless you eject and change the webpack configuration manually.

This library allows you to use web workers without having to change the CRA configuration, which is why there are often limitations or particular workarounds.

If you are interested in changing the webpack configuration to manually manage your workers, see: worker-loader


Known issues

There's a known issue related to transpiling tools such as Babel causing Not refereced errors.

Since the approach of this library is moving the entire function passed to the Hook to a worker, if the function gets transpiled, variable definitions used by the transpiling tool may get out of scope when the function gets moved to the worker, causing unexpected reference errors.

If you're experimenting this type of issue, one workaround is wrapping your function declaration inside a function object as a string.

const sum = new Function(`a`, `b`, `return a + b`)

🌏 Contribute? Bug? New Feature?

The library is experimental so if you find a bug or would like to request a new feature, open an issue


💡 Similar Projects


💻 Mantainers

💻 Contributors

  • Thanks to:
  • @zant (test, CI, RFC, bugfixes, localdependencies feature, ...)
  • @101arrowz ( isoworker packages proposal )
  • @z4o4z (Typescript implementation, Discussion of RFC)
  • @IljaDaderko (Typescript support, Discussion of RFC)
  • @ophirg (Typescript support)
  • @Pigotz (Discussion of RFC)
  • @gubo97000 (Fix #108)

How to contribute?

Read CONTRIBUTE.md


📜 License

MIT


Netlify Status

useworker's People

Contributors

ahmadawais avatar alewin avatar ashish-r avatar dependabot-preview[bot] avatar dependabot[bot] avatar fkhadra avatar gubo97000 avatar iljadaderko avatar juzhiyuan avatar matamatanot avatar orkideh avatar z4o4z avatar zant avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

useworker's Issues

Proposals for 3.0.0

These are 3/4 braking changes that I would like to introduce in version: 3.0.0

I chose to transcribe them so if someone wants to participate or give an opinion we can discuss it together 😃@iljadaderko @Pigotz @gonzachr @JonatanSalas @z4o4z


PROPOSAL 1 - remove killWorker

remove killWorker from the values returned by thehook, and manage the status through a controller

Before:

const [sortWorker, workerStatus, killWorker] = useWorker(sortDates);
const res = await sortWorker()
function onButtonClick = () => workerController.killWorker()

After

 const [sortWorker, workerController] = useWorker(sortDates);
 const res = await sortWorker()
 function onButtonClick = () => workerController.killWorker()

PROs 👍

  • we can add any functionality through the controller without introducing breaking changes

CONS 👎:

  • Anywhing?

PROPOSAL 2- remove workerStatus

remove workerStatus from the values returned by thehook, and manage the status through a controller

Before:

  const [sortWorker, workerStatus, killWorker] = useWorker(sortDates);

  // workerStatus WORKER_STATUS.PENDING
  try{
    const res = await sortWorker()
    // workerStatus WORKER_STATUS.SUCCESS
  }catch(status, e){
     // workerStatus WORKER_STATUS.ERROR or WORKER_STATUS.TIMEOUT_EXPIRED
  }

After

 const [sortWorker, workerController] = useWorker(sortDates);

  let workerStatus = workerController.getStatus() // WORKER_STATUS.PENDING
  try{
    const res = await sortWorker()
    workerStatus = workerController.getStatus() // WORKER_STATUS.SUCCESS
  }catch(status, e){
    workerStatus = workerController.getStatus() // WORKER_STATUS.ERROR or WORKER_STATUS.TIMEOUT_EXPIRED
  }

PROs 👍

  • we can add any functionality through the controller without introducing breaking changes

CONS 👎:

  • the state of the worker will no longer be reactive through the react life cycle since it will no longer be a state but a simple variable)

PROPOSAL 3 - Inline dependencies

currently the worker dependencies are urls that will be injected through importScripts, since react-scripts still does not support web workers, we could allow to inject functions and objects into the worker

Before:

 const [sortWorker, sortWorkerStatus, killWorker] = useWorker(sortDates, {
    dependencies: [
      "https://cdnjs.cloudflare.com/ajax/libs/date-fns/1.30.1/date_fns.js"
    ],
  }
 const res = await sortWorker(dates)

After

const utils = {
    manipulate: { ....}
    add: {...}
}

const  sortDates = (date) => {
   var foo = utils.manipulate(date)
   return foo
}

 const [sortWorker, sortWorkerStatus, killWorker] = useWorker(sortDates, {
    remoteDependencies: [
      "https://cdnjs.cloudflare.com/ajax/libs/date-fns/1.30.1/date_fns.js"
    ],
   localDependencies: [{ utils: utils }]
  }
 const res = await sortWorker(dates)

Doubts 🤔:

  • it is probably useless because we could pass the utils object to the function

Example:

 const res = await sortWorker(dates, utils)

PROPOSAL 4 - useWorkers hook

Manage multiple workers with a new hook: useWorkers

Before:

const [sortWorker1, workerStatus1, killWorker1] = useWorker(sortDates);
const [numbersWorker, workerStatus2, killWorker2] = useWorker(sortNumbers);
const [sortWorke2r, workerStatus3, killWorker3] = useWorker(sortDates);

 const res1 = await sortWorker1(dates)
 const res2 = await numbersWorker(numbers)
 const res3 = await sortWorker2(dates)

function onButtonClick = () => killWorker2.killWorker()

After using Array

 const [workers] = useWorkers([sortDates, sortNumber, sortDates], options); // array or object?

 const res1 = await workers[0](dates)
 const res2 = await workers[1](numbers)
 const res3 = await workers[2](dates)

function onButtonClick = () => workers[1].killWorker()

After using Object

 const [workers] =  useWorkers({ sort1: sortDates, sort2: sortNumber, sort3: sortDates }, options);  // array or object?

 const res1 = await workers.sort1(dates)
 const res2 = await workers.sort2(numbers)
 const res3 = await workers.sort3(dates)

function onButtonClick = () => workers[1].killWorker()

Doubts 🤔:

  • should the first parameter be an array or an object?

PROs 👍

CONS 👎:

  • Anywhing?

PROPOSAL 5 - No-Hook

Allow the use and generation of a webworker without having to use a hook

PROs 👍

  • use of webworkers also within normal functions, or sagas

CONS 👎:

  • Anywhing?

Other proposals are welcome :)

Add another example to solve 'variable not defined' error caused by transpiling

Is your feature request related to a problem? Please describe.
I had a pure function that has no external dependencies that worked well in development, but throws a 'l is not defined' error in production. After some debugging that transpiling the code was the cause of this error, as it inlined some dependency inside the body of my function. This was the function:

function getHistory(
  readings: Reading[],
): History {
  const countPerTime = readings.reduce((accumulator, {time, value}) => {
    if (!accumulator[time]) {
      accumulator[time] = 0;
    }

    accumulator[time] += Number(value);

    return accumulator;
  }, {} as {[time: string]: number});

  return Object.entries(countPerTime).map(([time, count]) => ({
    time: new Date(time).valueOf(),
    count,
  }));
}

Describe the solution you'd like
The solution was to replace my function declaration with this:

const getHistory = new Function(
  'readings',
  `
const countPerTime = readings.reduce((accumulator, {time, value}) => {
  if (!accumulator[time]) {
    accumulator[time] = 0;
  }

  accumulator[time] += Number(value);

  return accumulator;
}, {});

return Object.entries(countPerTime).map(([time, count]) => ({
  time: new Date(time).valueOf(),
  count,
}));
`,
) as (readings: Reading[]) => History;

Which prevented the transpiler from altering my code, and it worked. Please add it to your documentation, as it may help other fellow strugglers.

Guidance on how to use local dependencies?

Proposal 3 on #36 mentions local dependencies

I would like to use local dependencies to avoid having long functions which are hard to test / debug.

I've tried to use the functionality but I get an object can not be cloned error.

Guidance or an example on how use local dependencies would be helpful. Thank you.

Code below — https://codesandbox.io/s/hopeful-night-l6vw6?file=/src/App.js

import React, { useState } from "react";
import "./styles.css";
import { useWorker } from "@koale/useworker";

export default function App() {
  const [message, setMessage] = useState("waiting for go...");
  const [processTextWorker] = useWorker(fnWithLocalDependency, {
    localDependencies: [{ util: util }]
  });
  const handleClick = _ => {
    setMessage("working...");
    processTextWorker("blah", util).then(setMessage);
  };
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <button onClick={handleClick}>go!</button>
      <p>{message}</p>
    </div>
  );
}

const fnWithLocalDependency = text => {
  const a = util.fn1(text);
  const b = util.fn2(text);
  return JSON.stringify({ a, b });
};
const util = {
  fn1: text => `the text is '${text}'`,
  fn2: text => `:${text}:`
};

[Proposal] migrate library to TypeScript

Would you consider migrating this library to typescript to ensure better type safety and prevent some bugs from future contributors? I've started using this hook and am in ❤️with how simple it is.

In order to do this following "Todos" are probably required:

  • Re-write source in TypeScript
  • Configure something like rollup to build js files for non typescript users
  • Find a way to serve ts files to TypeScript users and built js files to other users
  • Configure CI to build js files for releases

I can start helping out with Re-write source in TypeScript if you agree to proceed 👍

Error in RemoteDependencies with more than one

Hello,

I was trying put to run my worker with more than one RemoteDependencies like below

image

I got this error from console:

image

with just one RemoteDependencies it works
For now my workaround is create two work with one dependency

Thanks 😀

Testing useWorker

Since they are plans to add new features (#36) I started to work in adding some tests for the hook. I initially setup Jest with react-hooks-testing-library. But found that Jest (which uses jsdom) does not have an implementation for URL.createObjectURL nor Web Workers.

So I had to dig a bit on the internet 🌈to find potential workarounds, and it seems that they're two approaches to test workers (afaik) that we can use.

Options

  • Test with karma on headless chrome, this approach is used by comlink which is a wrapper for Web Workers. I did try this and it worked nicely, the one downside I see is the tooling (needs a preprocessor like webpack with babel to bundle everything for the test, as it's going to be tested in a browser) but at the end they're just devDependencies so it will not affect bundle size.
  • Mock the Web Worker with something like jsdom-worker (although looks like is not actively maintained). This package also comes with a URL.createObjectURL mock :).

Imo, I prefer karma since it will provide reliable behavior for the tests. What do you guys think? 😄

For reference, this is the test I tried with Karma:

import React from "react";
import { useWorker } from "../dist/index";
import { renderHook } from "@testing-library/react-hooks";

it("Basic Test", async () => {
  const sum = (a, b) => a + b;
  const { result } = renderHook(() => useWorker(sum));
  const [sumWorker] = result.current;
  const res = await sumWorker(1, 2);
  assert.equal(res, 3);
});

Proposal: Inline dependencies options

Main thread #36

Inline dependencies

currently the worker dependencies are urls that will be injected through importScripts, since react-scripts still does not support web workers, we could allow to inject functions and objects into the worker

Before:

 const [sortWorker, sortWorkerStatus, killWorker] = useWorker(sortDates, {
    dependencies: [
      "https://cdnjs.cloudflare.com/ajax/libs/date-fns/1.30.1/date_fns.js"
    ],
  }
 const res = await sortWorker(dates)

After

const utils = {
    manipulate: { ....}
    add: {...}
}

const  sortDates = (date) => {
   var foo = utils.manipulate(date)
   return foo
}

 const [sortWorker, sortWorkerStatus, killWorker] = useWorker(sortDates, {
    remoteDependencies: [
      "https://cdnjs.cloudflare.com/ajax/libs/date-fns/1.30.1/date_fns.js"
    ],
   localDependencies: [{ utils: utils }]
  }
 const res = await sortWorker(dates)

When will localDependencies return

Migrating my app to NextJS I decided to move from comlink-loader to useWorker counting from the documentation that it had support for local dependencies; but I just found out that it was actually removed few weeks ago.
When can we expect to see this feature back? I really need it otherwise useWorker doesn't do it for me.

EXPORT DEFAULT ISSUE

WRONG:

import useWorker, {
  WORKER_STATUS
} from "@koale/useworker";

SOLUTION:

import useWorker, {
  WORKER_STATUS
} from "@koale/useworker/dist/index.module.js";

async function error

[Required] Describe the bug
异步函数报错

[Optional] To Reproduce

import React from 'react';
import { useWorker } from '@koale/useworker';

const Example = () => {
  const numbers = [...Array(5000000)].map(e => ~~(Math.random() * 1000000));
  const sortNumbers = async (nums: number[]) => {
    // test async
    const res = await nums.sort();
    return res;
  };
  const [sortWorker] = useWorker(sortNumbers);

  const runSort = async () => {
    const result = await sortWorker(numbers); // non-blocking UI
    console.log('End.');
  };

  return (
    <button type="button" onClick={runSort}>
      Run Sort
    </button>
  );
};

export default Example;

image

how inject dependence for worker function

I have a dependency property in a function that depends on methods in other modules.
I found the localDependency property in the documentation, but it does not solve my problem.
So I checked the source code of the useWorker and found that the localDependency property is commented out

// e.g
import {
  diff
} from '@/utils';

import { getConfig } from '@/config';

// my worker function
export default function foo(arr,arr2){
// error, it does not work
//  diff  is not defined
	return diff(arr,arr2);
}

How can I use api calls in useWorker?

[Required] Describe the bug
I need to get data from backend and store that large amount of data to indexeddb , But issue is when iam using axios or fetch iam getting error , is there any other option to invoke api calls ?

"Uncaught ReferenceError: axios__WEBPACK_IMPORTED_MODULE_2___default is not defined" --- this error getting when using axios ,

[Required] Expected behavior
is there any inbuild method to call api ? ot any way to import third party library like axios

[Optional] Screenshots

[Optional] Device (please complete the following information):

  • OS: [Windows]
  • Browser [chrome]

[Optional] context
Add any other context about the problem here.

Bad isoworker import

[Required] Describe the bug
isoworker dependency does not provide a default import so isoworker.createContext raises an error from index.mjs.
I face this bug while using expo-camera bar code scanner on Web.

[Required] Expected behavior
No error.

isoworker should be imported as import * as isoworker from 'isoworker' here

import isoworker from 'isoworker'

At least until isoworker has a default export cf 101arrowz/isoworker#2

Error's with async functions

I was trying to debug this to find out the cause, but was unsuccessful, basically when useWorker is passed a simple function like this everything is working:

function sum(num1: number, num2: number) {
  return num1 + num2;
}
// ...
const [sumWorker] = useWorker(sum);
const result = await sumWorker(1, 2);

However, I was trying to utilise worker to load images in a worker i.e

async function fetchImage(src: string) {
  const response = await fetch(src);
  const blob = await response.blob();
  const objectUrl = URL.createObjectURL(blob);

  return objectUrl;
}

// ...
const [fetchImageWorker] = useWorker(fetchImage);
const result = await fetchImageWorker("https://...");

I am getting a babel / webpack error:

ReferenceError: regeneratorRuntime is not defined

Uncaught NetworkError for cron-parser

I want to use cron-parser in my worker but useWorker can't load it, even with the example code like this:

const [sortWorker] = useWorker(sortNumbers, {
  remoteDependencies: [
    'https://cdn.jsdelivr.net/npm/[email protected]/lib/parser.min.js',
  ],
});

Message of ErrorEvent:
Uncaught NetworkError: Failed to execute 'importScripts' on 'WorkerGlobalScope': The script at 'https://cdn.jsdelivr.net/npm/[email protected]/lib/parser.min.js' failed to load."

I can run successfully with the remoteDependencies example. I'm not sure whether it's problem of useWorker or cron-parser bundling.

_toConsumableArray2 ReferenceError in simple codesandbox example

Hi there, I'm problem making a very basic mistake in trying to get useWorker to work. Any hints/pointers would be very helpful. Thank you.

Context:
I'm trying to use useWorker to parse large CSV files. Unfortunately, I've so far been unable to put a small example to work.

Problem:
The code sandbox example below gives the following error: ReferenceError: Can't find variable: _toConsumableArray2

Code:
https://codesandbox.io/s/hungry-einstein-4gsel?file=/src/App.js

import React, { useState } from "react";
import { useWorker } from "@koale/useworker";
import "./styles.css";

const processArray = () => {
  const items = [...Array(1000).map((item, offset) => offset)];
  return items.sort();
};

export default function App() {
  const [data, setData] = useState("ready to start");
  const [processWorker] = useWorker(processArray);

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <button
        onClick={_ => {
          setData("started");
          processWorker().then(_ => setData("finished"));
        }}
      >
        Start
      </button>
      <p>{data}</p>
    </div>
  );
}

Worker runtime errors are not handled

Hey @alewin really cool hook! I specially liked how you managed to pass functions directly to the hook without an intermediate file :)

I was playing a bit and I notice that it's not handling runtime errors that occur inside the worker. Even if I enclose the resulting promise in a try/catch:

 const [mapWorker] = useWorker(mapArray);

  const startSort = async () => {
    try {
      const result = await mapWorker(1);
      console.log(result);
    } catch (e) {
      console.log(e);
    }
  };

Here is a working sandbox.

What happens (locally--the sandbox appear to work in a different manner) is that the error is thrown by the worker but the worker is not terminated, this causes other attempts to run the worker to fail.

Update to react 17

I don't think that description is needed.

I don't mind to do, just update me if you allow.

Thanks.

How to keep global state in a worker ?

Hello,

I'm trying to convert an existing worker using the postMessage API. This worker has some global state that is initialized with the first message, and used in subsequent calls:

import Fuse from 'fuse.js'

let fuse = null // This is the global state
onmessage = function(event) {
	if (event.data.options) // First call we initiate the Fuse object
		fuse = new Fuse(event.data.options) 

	if (event.data.input) { // Second call we use it to search
		let results = fuse.search(event.data.input)
		postMessage(results)
	}
}

The goal is that the search happen in the worker. I've tried writing a high order useWorker function but it's not clear to me what is run in the worker, and what's the best way to write such a flow (first call with the source data, second call with the search query). Thank you for your help!

Proposal: Support for TransferList API

Based on #46.

Introduction

Transferable Objects are objects that can be passed to different contexts. This is useful in cases where we don't want to rely on structured cloning to pass data to a worker. Since this procedure moves data without copying it, it can provide better performance for critical applications (this is normally the case with really large objects).

useWorker currently does not support a way for transferring these objects, since for the objects to get transferred, we need to pass a second argument to postMessage, that is the list of the objects we would like to transfer.

worker.postMessage(message, transferList);

We can see that the current implementation does not support passing a second argument to postMessage.

worker.current?.postMessage([[...fnArgs]])

Solution

Currently, the library provides a really nice way to execute functions inside a worker. Considering how it works:

const addNumber = (arr, number) => return arr.map(el => el + number);

const [addNumberWorker] = useWorker(addNumber)

const arr = new Uint8Array([1, 2, 3, 4, 5]);
// All the arguments we pass go directly to the function in the worker
// So data.buffer will be just another argument instead of being moved to worker context
addNumberWorker(arr, 1, [data.buffer]) // Does not transfer

As we need a way to change the default functionality of the useWorker returned function, we introduce a new option to the options object.

TransferList option

The default will be false, and we opt-in to transferList.

// We pass a new option to the worker
const [addNumberWorker] = useWorker(addNumber, { transferList: true }); 

Usage

Option 1

A first option could be to make the usage similar to how the native postMessage works. So when the worker gets called, we will pass the data property from the MessageEvent to the function.

// Inside the worker
onmessage = e => addNumber(e.data) // Not real implementation

// When we call, we pass arguments as we would with postMessage
const  data = { arr, number: 1 }
addNumberWorker(data, transferList);

However, this will restrict function implementations to just one argument, and so, developers will need to refactor a bit the implementation of the function if they want to opt-in:

// Just one argument, they'll have to destructure it
const addNumber = ({arr, number}) => arr.map(el => el + number)

So we can consider this other approach.

Option 2

// Passing the arguments as elements of an array
addNumberWorker([arr, 1], [arr.buffer]);

With the above, we do not pass the data object to the function they provide, instead we collect the elements of the array and pass them as arguments of the function they provide. This way, developers can use the same function without any code changes with the added functionality to pass a transferList.

But we can also argue that it feels weird to pass arguments as an array, besides, it's not really a wide used pattern on Javascript. So we can consider something else.

Option 3

const addNumber = (arr, number) => return arr.map(el => el + number);

const [addNumberWorker] = useWorker(addNumber, { transferList: true })

const arr = new Uint8Array([1, 2, 3, 4, 5]);
/// Using as we do today with an added argument
addNumberWorker(arr, 1, [arr.buffer]);

Where the last argument will always be the transferList, when using the optional argument. I think this will be a familiar approach for current users. However, we really need to think about edge cases, as relying on argument can be a little fragile if not implemented carefully.

Conclusion

As you can see, I haven't get to a conclusion myself. Although I personally like Option 3 more, there are some consideration we need to make to introduce this feature in a way that both makes sense for developers, and doesn't feels foreign to how the hook works today.

I'd love to hear your thoughts! Thanks for reading!

Note: Besides browser compatibility seems to be fine we may want to provide feature detecting errors so we can spot bugs on older versions and relieve that burden from developers who use this hook.

Reference:

Uncaught DOMException: Failed to execute 'postMessage' on 'Worker': An object could not be cloned

A clear and concise description of what the bug is.

Uncaught (in promise) DOMException: Failed to execute 'postMessage' on 'Worker': capacityList => {
console.log(capacityList);
const capacityMap = {
Total: {}
};
let i = 0;

for (......
} could not be cloned.
at http://localhost:8089/js/modules/npm.koale.bundle-1600196980210.js:16:3150
at new Promise ()
at http://localhost:8089/js/modules/npm.koale.bundle-1600196980210.js:16:2782
at http://localhost:8089/js/modules/npm.koale.bundle-1600196980210.js:16:3619
at runReport (http://localhost:8089/js/app.bundle-1600196980210.js:54075:26)
at http://localhost:8089/js/app.bundle-1600196980210.js:54105:5
at commitHookEffectListMount (http://localhost:8089/js/modules/npm.react-dom.bundle-1600196980210.js:23796:26)
at commitPassiveHookEffects (http://localhost:8089/js/modules/npm.react-dom.bundle-1600196980210.js:23834:11)
at HTMLUnknownElement.callCallback (http://localhost:8089/js/modules/npm.react-dom.bundle-1600196980210.js:4253:14)
at Object.invokeGuardedCallbackDev (http://localhost:8089/js/modules/npm.react-dom.bundle-1600196980210.js:4302:16)
at invokeGuardedCallback (http://localhost:8089/js/modules/npm.react-dom.bundle-1600196980210.js:4357:31)
at flushPassiveEffectsImpl (http://localhost:8089/js/modules/npm.react-dom.bundle-1600196980210.js:26918:9)
at unstable_runWithPriority (http://localhost:8089/js/modules/npm.scheduler.bundle-1600196980210.js:1024:12)
at runWithPriority$1 (http://localhost:8089/js/modules/npm.react-dom.bundle-1600196980210.js:15104:10)
at flushPassiveEffects (http://localhost:8089/js/modules/npm.react-dom.bundle-1600196980210.js:26885:12)
at performSyncWorkOnRoot (http://localhost:8089/js/modules/npm.react-dom.bundle-1600196980210.js:25802:3)

How to cancel de previous execution?

I'm trying to use fuzzy search in a worker, but I'm having the following error:

[useWorker] You can only run one instance of the worker at a time, if you want to run more than one in parallel, create another instance with the hook useWorker()

Code:

import debounce from 'lodash.debounce'
import { useWorker, WORKER_STATUS } from "@koale/useworker";

const fuseSearch = ({ list, query, limit, options }) => {
  // my fuse search
}

const MyComponent = () => {
  const [search, controller] = useWorker(fuseSearch)
  
  const handleInputChange = debounce(async value => {
    controller.kill()
    
    setLoading(true)
    try {
      const data = await search({ list: fundos, query: value, limit: 10, options })
      setLoading(false)
      setResultados(data)
    } catch (err) {
      if (err?.message) {
        setLoading(false)
        console.error(err)
      }
    }
  }, 300)
}

Queue tasks or abort current task and start new task

So I'm just getting my head around a problem I'm having with the useWorker hook. I currently call the worker in a useEffect hook but when the useEffect hook is triggered multiple times while the worker hasn't finished yet I'm getting the following error in the log:

[useWorker] You can only run one instance of the worker at a time, if you want to run more than one in parallel, create another instance with the hook useWorker(). Read more: https://github.com/alewin/useWorker 

The problem is I'm no longer interested in the result if the useEffect hook is triggered again so the worker should just abort the current task and start processing the new task. Or if that's not possible I want to queue a task for the worker to process next. Really curious if this can be achieved with the current hook or if I'm overlooking something.

RFC: Inline dependencies

Hey everyone! I'm on my way to implement the Inline Dependencies feature from #37, which I decided to implement after a discussion on #69. (Details there).

I just finished the actual code and it's working just fine. However, there are small points on which I will be really glad to hear some opinions.

The first one is related to the way users will be accessing to the actual utils object, this is an example of how it works right now in my code:

const foo = (data) => {
  // Works just fine
  console.log(utils.fn())
  return data;
};

const utils = {
  fn: (val) => console.log(val)
};

const App = () => {
  const [worker, { terminateWorker }] = useWorker(foo, {
    transferable: "auto",
    localDependencies: utils, // Note how we the utils pass it directly
  });
}

This works because I'm inlining whatever object localDependencies is, and inserting it into the blob code, this is how it looks:

const utils = {fn: val => console.log(val),}

As you can see, it's named utils and that's the reason why it works inside foo. It's important to note that the utils object called inside foo is not the object with the same name declared below. This is important because of the following.

There can be the case in which the object passed to localDependencies isn't available in the scope of the foo function declaration, in which we will need to add a linter ignore rule, this of course, assuming that you're using a linter, which is fairly possible since CRA and most React libraries come with linters, as it almost required in modern development workflows.

const foo = (data) => {
  // eslint-disable-next-line no-undef
  console.log(utils.fooUtils.fn())
  return data;
};

const fooUtils = {
  fn: (val) => console.log(val)
};

const App = () => {
  const [worker, { terminateWorker }] = useWorker(foo, {
    transferable: "auto",
    localDependencies: { fooUtils },
  });
}

The above will still work, but as you can see, accessing correctly the properties inside the utils object, which lives in worker land:

// Trailing commas are in case there is more than one prop
const utils = {fooUtils: {fn: val => console.log(val),},}

That's really all of it, what do you think?

IMO, it's fairly understandable because the object is really not living on the function declaration's scope, so I think it gives clarity to what's going on under the hood, and can also be nicely integrated with a coincidentally good naming of your utils
object.

Another option could also be to pass the object as the last argument of foo, but I think that can be annoying since it will be really hidden under the hood.

Also, is utils a nice name for the inlined object in the worker? maybe localDependencies is a better suite?

P.D.: For reference, the implementation is at branch feature/27

NPM Error

When I try to install the package I get this error:
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR!
npm ERR! While resolving: [email protected]
npm ERR! Found: [email protected]
npm ERR! node_modules/react
npm ERR! react@"^18.2.0" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer react@"^16.8.0" from @koale/[email protected]
npm ERR! node_modules/@koale/useworker
npm ERR! dev @koale/useworker@"*" from the root project
npm ERR!
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR!
npm ERR! See C:\Users\obaag\AppData\Local\npm-cache\eresolve-report.txt for a full report.

npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users\obaag\AppData\Local\npm-cache_logs\2023-03-15T13_08_14_208Z-debug-0.log

please resolve ASAP

Uncaught ReferenceError: _toConsumableArray2 is not defined/

[Required] Describe the bug
Bug happens when using spread syntax in the function passed to useWorker.

[Optional] To Reproduce
Steps to reproduce the behavior:

  1. Write a function that uses spread syntax
  2. Pass that function to useWorker to create a worker
  3. Run worker
  4. See error

[Required] Expected behavior
The worker to run normally without errors.

[Optional] Screenshots
If applicable, add screenshots to help explain your problem.

[Optional] Device (please complete the following information):

  • OS: Windows
  • Browser chrome
  • Version 84.0.4147.125 (Official Build) (64-bit)

[Optional] context
Here's the Codesandbox:
https://codesandbox.io/s/testing-useworker-9rw9j

Compatability Issue with [email protected]

I'm using react ^17.0.2 and when I attempted to do the install i'm getting the following error
$ npm install --save @koale/useworker
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR!
npm ERR! While resolving: [email protected]
npm ERR! Found: [email protected]
npm ERR! node_modules/react
npm ERR! react@"^17.0.2" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer react@"^16.8.0" from @koale/[email protected]
npm ERR! node_modules/@koale/useworker
npm ERR! @koale/useworker@"*" from the root project
npm ERR!
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.

Is this meant to work with react version 17+ or would I need to go back to version 16?

Uncaught ReferenceError: p is not defined

[Required] Describe the bug
A clear and concise description of what the bug is.
The dependency is working as expected when testing locally but when I test the application for prod using yarn build I got this error:
Uncaught ReferenceError: p is not defined

[Optional] To Reproduce
Steps to reproduce the behavior:

  1. Run 'yarn build'
  2. Run 'serve -s build'
  3. Execute the web worker
  4. See the error in console.

[Required] Expected behavior
Run web worker without problems in prod

Why on each call to the worker the dependencies are re-fetched?

Hi! First of all thanks for this awesome library!

I would like to ask something that I don't clearly understand. It's related to how the useWorker manages external dependencies.

I clearly don't understand why, but, when I make a recall to the function given from the useWorker hook, for some reason it re-calls o re-imports the dependencies array.

This behavior is also present in the external scripts example: https://icji4.csb.app/external

If you open the network inspector, you can see when you click the button for Sorting Dates.

Here you can see:

Captura de Pantalla 2020-04-11 a la(s) 14 57 05

What I would like to understand is that if this behavior is expected from the library and why? In case that not, I would submit a PR to fix this!

Anyway, thanks again for your library!

How to test a custom hook using useWorker?

I've been playing with useWorker, and it has been working on the browser.

I tried to create a test for a custom hook that is using the useWorker and got many errors.
I've tried to install jsdom-worker, but I keep receiving errors.

I'm going to share the errors:
image
☝️ with jsdom-worker

image

☝️ without `jsdom-worker`

What kind of setup do I need to do to make it work using jest?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.