Code Monkey home page Code Monkey logo

Comments (16)

ddebarros avatar ddebarros commented on August 30, 2024 32

CRA uses eslint so just suppress that rule for the import line.

import worker from 'workerize-loader!./foo'; // eslint-disable-line import/no-webpack-loader-syntax

from workerize-loader.

wilcoxmd avatar wilcoxmd commented on August 30, 2024 21

I think I found another solution here as well, by using a hook for each worker I create. Using some of your tips above about the jest config, and some tips from here, I have the following that works for me and allows typed usage:

src/workers/sampleWorker.worker.ts

export function foo(a: number, b: number) {
  return `Worker result: ${a + b}`;
}

src/workers/workerDeclarations.d.ts

declare module 'workerize-loader!*' {
  type AnyFunction = (...args: any[]) => any;
  type Async<F extends AnyFunction> = (
    ...args: Parameters<F>
  ) => Promise<ReturnType<F>>;

  type Workerized<T> = Worker &
    { [K in keyof T]: T[K] extends AnyFunction ? Async<T[K]> : never };

  function createInstance<T>(): Workerized<T>;
  export = createInstance;
}

src/hooks/useSampleWorker.ts

// eslint-disable-next-line import/no-webpack-loader-syntax
import createWorker from 'workerize-loader!../workers/sampleWorker.worker';
import * as SampleWorker from '../workers/sampleWorker.worker';

const sampleWorker = createWorker<typeof SampleWorker>();

export const useSampleWorker = () => sampleWorker;

Component.tsx

import {useSampleWorker} from '../hooks/useSampleWorker';

function Component(props) { 
    const sampleWorker = useSampleWorker();
    
    // ...
    sampleWorker.foo(1000, 1000).then(result => console.log(result)) // result is of type 'string'
}

then to make tests work....
src/workers/mocks/sampleWorker.mock.ts

import { foo } from '../sampleWorker.worker';

export default () => ({
  foo,
});

package.json

"jest": {
    "moduleNameMapper": {
      "workerize-loader!../workers/sampleWorker.worker": "<rootDir>/src/workers/mocks/sampleWorker.mock.ts"
    }
}

from workerize-loader.

wilcoxmd avatar wilcoxmd commented on August 30, 2024 11

Has anyone gotten workerize-loader to work with create-react-app and typescript?

I'm using react-scripts version 3.2, so should have the PR related to facebook/create-react-app#7741 included in my build. However, I keep running into a typescript error: Cannot find module 'workerize-loader!./example.worker'.

I'm importing like so:

// in ./Component.tsx
import ExampleWorker from 'workerize-loader!./example.worker'; // eslint-disable-line import/no-webpack-loader-syntax

// ./example.worker.ts
interface IWorkerMessage {
  message: string;
  time: number;
}

export const sayHi = async ({ message, time }: IWorkerMessage) => {
  console.log('in worker function!, got message, ', message);
  const start = Date.now();
  let count: number = 0;
  while (Date.now() - start < time) {
    count++;
  }
  return count;
};

Anyone else seen this error / overcome it?

from workerize-loader.

aeroxy avatar aeroxy commented on August 30, 2024 7

Cannot find module 'workerize-loader!./workerize'.ts(2307)

TypeScript also doesn't like it.

from workerize-loader.

MikeSpitz avatar MikeSpitz commented on August 30, 2024 4

The above comment works great but I'm running into issues with jest when I use the shim. Without the shim jest works fine but typescript doesn't 😢

Edit
I was able to get this running without the shim by using require:

Component.tsx

const Worker = require( "workerize-loader!../../workers/workerFileName"); // eslint-disable-line import/no-webpack-loader-syntax

src/workers/workerFileName.js

export async function doStuff(data) {
    // Worker code here
}

package.json

jest {
     "moduleNameMapper": {
       "workerize-loader!../../workers/workerFileName":"<rootDir>/src/workers/workerFileName.mock.js"
    },
}

src/workers/workerFileName.mock.js

class WorkerFileName {

}

module.exports = WorkerFileName;

Now I have the following:

  • Workers work in create-react-app with typescript
  • Components that include the workerize-loader file no longer fail in jest

from workerize-loader.

lukesmurray avatar lukesmurray commented on August 30, 2024 4

src/workers/workerDeclarations.d.ts

declare module 'workerize-loader!*' {
type AnyFunction = (...args: any[]) => any;
type Async = (
...args: Parameters
) => Promise<ReturnType>;

type Workerized = Worker &
{ [K in keyof T]: T[K] extends AnyFunction ? Async<T[K]> : never };

function createInstance(): Workerized;
export = createInstance;
}

Using a flattened promise so async methods aren't double nested as Promise<Promise<return value>>

declare module "workerize-loader!*" {
  type FlattenedPromise<T> = unknown extends T
    ? Promise<T>
    : T extends Promise<infer U>
    ? T
    : Promise<T>;

  type AnyFunction = (...args: any[]) => any;
  type Async<F extends AnyFunction> = (
    ...args: Parameters<F>
  ) => FlattenedPromise<ReturnType<F>>;

  type Workerized<T> = Worker &
    { [K in keyof T]: T[K] extends AnyFunction ? Async<T[K]> : never };

  function createInstance<T>(): Workerized<T>;
  export = createInstance;
}

from workerize-loader.

developit avatar developit commented on August 30, 2024 3

Eek! That's a surprisingly draconian lint rule.. maybe try with require?

const worker = require('workerize-loader!Workers/Worker')

from workerize-loader.

wilcoxmd avatar wilcoxmd commented on August 30, 2024 2

@kentcdodds No problem! This one has bugged me for a bit because I've really wanted to use this package :)

I had a little trouble getting jest.mock to work for me. What were you picturing? If I try to use jest.mock in my tests I was getting more 'unresolved' module errors.

An alternative, more flexible option I did think of though is to better use the regex in the moduleNameMapper....

  "jest": {
    "moduleNameMapper": {
      "^workerize-loader!(.*)/workers(.*)": "<rootDir>/src/workers/__mocks__$2"
    }
  }

and to make the actual mock file more easy to work with...
in src/workers/__mocks__/sampleWorker.worker.ts

import * as SampleWorker from '../sampleWorker.worker';

export default () => SampleWorker

That way any worker you add into the /workers directory just needs a corresponding mock like the one above and you shouldn't really have to touch it again?

from workerize-loader.

rdgfuentes avatar rdgfuentes commented on August 30, 2024 2

Fixed it following @wilcoxmd's solution described above and also applied the alternative option but with a slightly tweak in the moduleNameMapper regexp :

  "jest": {
    "moduleNameMapper": {
      "^workerize-loader(\\?.*)?!(.*)/([^/]*)$": "$2/__mocks__/$3"
    }
  }

with the purpose of loading mocks from a file with the same name that the worker but located in the ./__mocks__ folder where the worker file is (Eg: <workerFolder>/__mocks__/<workerFilename>) since we want to have the workers and its mocks next to the other files organized by features. Our files structure looks like this:

├── src/
│   └── features/
│       └── foo/
│           ├── FooBar.worker.ts 
│           └── __mocks__
│               └── FooBar.worker.ts
├── App.tsx
└── App.test.tsx

from workerize-loader.

developit avatar developit commented on August 30, 2024

Hmm - you shouldn't need any resolution config at all to use this.

npm i -D workerize-loader
import worker from 'workerize-loader!./foo';

from workerize-loader.

craigcoles avatar craigcoles commented on August 30, 2024

I did try that, but CRA has rules setup:

Unexpected '!' in 'workerize-loader!Workers/Worker'. Do not use import syntax to configure webpack loaders

from workerize-loader.

developit avatar developit commented on August 30, 2024

Perfect! Thanks for the tip, closing this issue then.

from workerize-loader.

kentcdodds avatar kentcdodds commented on August 30, 2024

Related: facebook/create-react-app#7741

from workerize-loader.

stevenmcdonald avatar stevenmcdonald commented on August 30, 2024

@wilcoxmd
It's not pretty, but I was able to get it to work using a shim js file to load the worker and export it to the TS file:

// in ./ComponentWorkerShim.js
import ExampleWorker from 'workerize-loader!./example.worker'; // eslint-disable-line import/no-webpack-loader-syntax

export default ExampleWorker
// in ./Component.tsx
import ExampleWorker from './ComponentWorkerShim';

// ...

Then you have type issues to deal with when calling the worker, but at least it works.

from workerize-loader.

kentcdodds avatar kentcdodds commented on August 30, 2024

Awesome. Instead of moduleNameMapper I'd probably just do jest.mock. Glad you got that working and thanks for coming back here to show us how you did it.

from workerize-loader.

Download avatar Download commented on August 30, 2024

CRA uses eslint so just suppress that rule for the import line.

When I do, it works in development.
However when I then build the project, it fails without errors. It just doesn't generate anything.
Took me a few hours to figure out why.
Uncommenting the workerize loader import fixed the build right away.
So think twice before using this.

from workerize-loader.

Related Issues (20)

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.