Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

importScripts for libflac in React #4

Open
arherzf8er opened this issue Oct 14, 2019 · 6 comments
Open

importScripts for libflac in React #4

arherzf8er opened this issue Oct 14, 2019 · 6 comments

Comments

@arherzf8er
Copy link

Trying to import the script into worker and getting this:

export default () => {
  console.log(location)
  onerror = err => console.log(err)
  importScripts('libflac4-1.3.2.min.js');
  console.log(location)
}

image
Same for all other script versions

Looks like I am missing something here, could you please help?

@russaa
Copy link
Contributor

russaa commented Oct 16, 2019

Could you provide some more details?
E.g. the details/other fields and stack trace of the error, and the script code of the worker itself?

@arherzf8er
Copy link
Author

@russaa Thanks, it's all in React being called like this:

import WebWorker from '../../utils/WebWorker';
import flacworker from '../../utils/flacworker.js';

componentDidMount = async () => {
  this.flacworker = new WebWorker(flacworker);
  this.flacworker.onmessage = event => {
   const { cmd, buf } = event.data;
   console.log(cmd, buf);
  }
}

WebWorker.js

export default class WebWorker {
  constructor(worker) {
    const code = worker.toString();
    const blob = new Blob(['('+code+')()']);
    return new Worker(URL.createObjectURL(blob));
  }
}

flacworker.js (libflac is located in the same folder)

export default () => {
  console.log(location)
  onerror = err => console.log(err)
  importScripts('libflac4-1.3.2.min.js');
  console.log(location)
}

I'm using this construction for loading scripts in other workers without issues
Where can I get the stack trace to debug this kind of things?

@russaa
Copy link
Contributor

russaa commented Oct 18, 2019

so, I am not a react expert, but it seems to me, that this problem is related to the build process you are using:

I tried to create a skeleton project with react and use your code snippets, and the example project that is create by npx create-react-app ... which uses react-scripts for building the app.

And react-scripts uses webpack:
in another project I was able to integrate libflac.js via webpack, but it did require some specific configuration.

Anyway, the default configuration of react-scripts does not seem to be able to handle the inclusion correctly:

  • for the "single file" variants of libflac.js, e.g. libflac4-1.3.2.js and libflac4-1.3.2.dev.js, I get various build-warnings related to the fact that libflac.js is an UMD library and internally checks, if it is run in node or in a browser (or in a WebWorker), or loaded as an AMD module...
    but the webpack configuration of react-scripts does not seem to handle this well, and throws build errors for supposedly undefined variables etc -> to suppress this, you'd need to modify the webpack build configuration
    => could you check/confirm, if/that there are build errors when your app is compiled?
  • for the other library variants, like the min or wasm versions that have an additional binary file, you'd actually need to configure webpack to include the binary file(s)

Although at some point I would like to, I currently do not have the time to further look into the react build process to find out, what exactly needs to be done to get it to work.

However, in another project, I did use a webpack configuration to accomplish this, but I do not know, if it would work with react.
The basic steps for this are:

  • use webpack plugin worker-loader for WebWorkers
  • for variants with binary files, use webpack plugin file-loader to include the "raw" binary files
  • for suppressing webpack problems due the UMD mechanism, you may need to configure the node setting for webpack (e.g. setting path and fs to false, and crypto to false or "empty")

@arherzf8er
Copy link
Author

Thank you for such a thorough answer, will use it on the weekend and report you back!

@russaa
Copy link
Contributor

russaa commented Oct 18, 2019

OK, I had another look, and found a solution for react-scripts when ejecting, i.e. you'd need to run

npm run eject

first (this makes later updates for react etc somewhat more complicated)

after running eject you get the webpack configuration in

config/webpack.config.js

where you'd need to modify the webpack's module.rules array (for me it was somewhere around line 335):
insert somewhere at the beginning of the array the following configuration:

  {
    //this must match the file-name of the worker script:
    test:  /\bflacworker\.js$/i,
    use: {
      loader: 'worker-loader',
      options: { name: 'worker-[name].[hash].js' }
    }
  },
  //OPTIONALLY if .wasm or .min variant: for including the binary file
  {
    test: /\.(wasm|mem)$/i,
    use: {
      loader: 'file-loader',
      options: {
        //NOTE binary file must be included with its original file name,
        //     so that libflac.js lib can find it:
        name: function(file) {
          return path.basename(file)
        }
      }
    },
  },

And then you'd need to change, how the Web Worker is included:
instead of using the helper module ../../utils/WebWorker, directly require the worker script and invoke it as a constructor, e.g.

//import WebWorker from '../../utils/WebWorker';
//import flacworker from '../../utils/flacworker.js';

componentDidMount = async () => {
  //this.flacworker = new WebWorker(flacworker);
  this.flacworker = require('../../utils/flacworker.js')();
  this.flacworker.onmessage = event => {
   const { cmd, buf } = event.data;
   console.log(cmd, buf);
  }
}

Then in the worker script itself, include the libflac.js library with require() instead of importScript()
(also: the webpack configuration above will not compile the worker script any more, so I used "pure javascript", but with some time and effort you could probably figure out, how to pass the worker script to the babel-compiler again):

//flacworker.js
//export default () => {
  self.console.log(location)
  self.onerror = function(err){ console.log(err) };
  //importScripts('libflac4-1.3.2.min.js');
  
  //for including a "single file variant" of libflac.js, e.g. the standard version:
  var Flac = require('./libflac4-1.3.2.js');

  //or: for including a .wasm variant, e.g standard-wasm (for binary of min-version include its *.mem file):
  require.resolve('./libflac4-1.3.2.wasm.wasm') // <- force webpack to include the binary file
  var Flac = require('./libflac4-1.3.2.wasm.js')

  self.console.log(Flac)
//}

@russaa
Copy link
Contributor

russaa commented Oct 18, 2019

... if you install libflac.js e.g.

npm install git+https://github.com/mmig/libflac.js.git

you can use its module ID in the require statements (and don't need to include/copy the files into the source directories):
the compiled javascript files of libflac.js are located in its dist/ directory, so the require-strings from above would change to:

  require.resolve('libflacjs/dist/libflac4-1.3.2.wasm.wasm')
  var Flac = require('libflacjs/dist/libflac4-1.3.2.wasm.js')

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants