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

@mediapipe/selfie_segmentation npm package can be bundled by Rollup, but raises an error in runtime. #2883

Closed
sile opened this issue Dec 13, 2021 · 15 comments
Assignees
Labels
legacy:selfie segmentation Issues related to selfie segmentation platform:javascript MediaPipe Javascript issues type:research Model specific questions

Comments

@sile
Copy link

sile commented Dec 13, 2021

First of all, thank you for publishing this great library.
I'm new to this library and TypeScript, so not sure that this is actually a bug.
Please let me know if you have any misunderstandings 🙏

System information (Please provide as much relevant information as possible)

Describe the current behavior:

Failed to instantiate the SelfieSegmentation class from a JavaScript file bundled by Rollup.

The screenshot below shows the error message (please refer to the following Standalone code to reproduce the issue section about what is the context of index.html):
screenshot0

Describe the expected behavior:

Be able to instantiate SelfieSegmentatoin class without errors (the Hello World! message below is emitted after the instantiation).
screenshot1

Standalone code to reproduce the issue:

I created a small example package, that provides a class only instantiating SelfieSegmentation, to reproduce this issue.

// Files.
$ ls
index.html index.ts package.json rollup.config.js

// Build this package.
$ npm install
$ npm run build

// Open `index.html` on a browser (Chrome in my case).
// The result has been shown at the first screenshot.
$ open index.html

index.html:

<html>
  <head>
    <meta charset="utf-8">
    <title>Example</title>
  </head>
  <body>
    <script src="bundle.js"></script>
    <script>
      const selfie = new window.Example.SelfieSegmentationWrapper();
      console.log("Hello World!");
    </script>
  </body>
</html>

index.ts:

import {SelfieSegmentation} from "@mediapipe/selfie_segmentation";

class SelfieSegmentationWrapper {
    private inner: SelfieSegmentation;

    constructor() {
        this.inner = new SelfieSegmentation({
            locateFile: (file: string) => {
                return `"https://cdn.jsdelivr.net/npm/@mediapipe/selfie_segmentation/${file}`;
            },
        });
        this.inner.setOptions({
            modelSelection: 1,
        });
    }
}

export { SelfieSegmentationWrapper };

package.json:

{
  "name": "example",
  "version": "0.0.0",
  "scripts": {
    "build": "rollup -c ./rollup.config.js"
  },
  "devDependencies": {
    "@rollup/plugin-commonjs": "^21.0.1",
    "@rollup/plugin-node-resolve": "^13.0.6",
    "@rollup/plugin-typescript": "^8.3.0",
    "rollup": "^2.61.1",
    "typescript": "^4.5.3"
  },
  "dependencies": {
    "@mediapipe/selfie_segmentation": "^0.1.1632777926"
  }
}

rollup.config.js:

import typescript from '@rollup/plugin-typescript';
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';

export default {
    input: 'index.ts',
    plugins: [
        typescript(),
        commonjs(),
        resolve()
    ],
    output: {
        sourcemap: false,
        file: 'bundle.js',
        format: 'umd',
        name: 'Example',
    }
};

Other info / Complete Logs :

I don't exactly know why it works but if the line exports.SelfieSegmentation = SelfieSegmentation; is appended to selfie_segmentation.js, the problem is disappeared:

$ echo 'exports.SelfieSegmentation = SelfieSegmentation;' >> node_modules/@mediapipe/selfie_segmentation/selfie_segmentation.js
$ npm run build

// Now, the "Hello World!" message is printed as shown in the second screenshot.
$ open index.html
@sile sile added the type:bug Bug in the Source Code of MediaPipe Solution label Dec 13, 2021
@sgowroji sgowroji added platform:javascript MediaPipe Javascript issues legacy:selfie segmentation Issues related to selfie segmentation stat:awaiting googler Waiting for Google Engineer's Response type:research Model specific questions and removed type:bug Bug in the Source Code of MediaPipe Solution labels Dec 13, 2021
@sgowroji sgowroji assigned tyrmullen and unassigned sgowroji Dec 13, 2021
@englishtom
Copy link

englishtom commented Dec 29, 2021

Just adding that I am experiencing the same issue with the @mediapipe/hands package. Using the package installed via npm works fine but if I compile it with Rollup then I am given TypeError: JT.Hands is not a constructor.

You can see the same issue with the CDN version of the package using this standalone script:

<html>
<head>
    <script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/hand-pose-detection"></script>
    <script src="https://cdn.jsdelivr.net/npm/@mediapipe/hands"></script>
</head>

<body>
    <img id="myImg" src="https://victordibia.com/handtrack.js/images/samples/0.jpg"/>

    <script>
        const img = document.getElementById('myImg');
        const model = handPoseDetection.SupportedModels.MediaPipeHands;
        const detectorConfig = {
            runtime: 'mediapipe',
            modelType: 'full',
            solutionPath: 'https://cdn.jsdelivr.net/npm/@mediapipe/hands@0.4.1635986972',
        };

        const detector = handPoseDetection.createDetector(model, detectorConfig).then(() => {
            console.log('Ready to detect', detector);

            detector.estimateHands(img).then((hands) => {
                console.log('Got results!', hands);  
            });
        });

    </script>
</body>
</html>

@tyrmullen
Copy link

@englishtom Does @sile's workaround of adding exports.Hands = Hands work for you?

I'm not familiar with Rollup myself, so I don't really have any insights to offer here.

@tyrmullen tyrmullen assigned mhays-google and unassigned tyrmullen Jan 20, 2022
@englishtom
Copy link

@tyrmullen It does not, however, using the Hands library directly without TensorFlow works well for me so that is the approach I have moved forwards with.

@utileetdulce
Copy link

This might help to understand the issue:

Rollup CommonJS plugin can't work with obfuscated packages because it relies on static analysis to determine its exports.

@holtwick
Copy link

holtwick commented Mar 7, 2022

By @bluwy :

Note: The core issue of @mediapipe/selfie_segmentation is that exports a non-ESM file in pkg.module, which should be ESM. I'd suggest contacting the package author to fix it, but for now I've documented the difference of dependencies handled in dev and build that might help in debugging the issue. vitejs/vite#4680 (comment)

Does someone have a workaround for this issue?

@sile
Copy link
Author

sile commented Mar 7, 2022

Just FYI, I implemented a custom rollup plugin that appends the line exports.SelfieSegmentation = SelfieSegmentation; to the selfie_segmentation.js during the bundle phase as our workaround: https://github.com/shiguredo/media-processors/blob/develop/packages/virtual-background/rollup.config.js#L73

@holtwick
Copy link

holtwick commented Mar 7, 2022

Just FYI, I implemented a custom rollup plugin that appends the line exports.SelfieSegmentation = SelfieSegmentation; to the selfie_segmentation.js during the bundle phase as our workaround: https://github.com/shiguredo/media-processors/blob/develop/packages/virtual-background/rollup.config.js#L73

Awesome, thanks so much. This works for me!

I use this plugin now in my vite.config.ts under build.rollupOptions.plugins.

@mattrossman
Copy link

Just FYI, I implemented a custom rollup plugin that appends the line exports.SelfieSegmentation = SelfieSegmentation; to the selfie_segmentation.js during the bundle phase as our workaround: https://github.com/shiguredo/media-processors/blob/develop/packages/virtual-background/rollup.config.js#L73

Thanks for sharing. In my case the error was related to MediaPipe Facemesh, so I adjusted the plugin as follows:

function mediapipe_workaround() {
  return {
    name: "mediapipe_workaround",
    load(id) {
      if (path.basename(id) === "face_mesh.js") {
        let code = fs.readFileSync(id, "utf-8")
        code += "exports.FaceMesh = FaceMesh;"
        return { code }
      } else {
        return null
      }
    },
  }
}

@kuaashish
Copy link
Collaborator

Hello @sile,
We are upgrading the MediaPipe Legacy Solutions to new MediaPipe solutions However, the libraries, documentation, and source code for all the MediaPipe Legacy Solutions will continue to be available in our GitHub repository and through library distribution services, such as Maven and NPM.

You can continue to use those legacy solutions in your applications if you choose. Though, we would request you to check new MediaPipe solutions which can help you more easily build and customize ML solutions for your applications. These new solutions will provide a superset of capabilities available in the legacy solutions.

@kuaashish kuaashish added the stat:awaiting response Waiting for user response label Apr 19, 2023
@sile
Copy link
Author

sile commented Apr 20, 2023

@kuaashish Thank you for letting me know about the new solutions. I tried using the Image Segmenter (with label=person) for selfie segmentation purposes. It was able to build without the error shared by this issue.
However, I decided to continue using the legacy selfie segmentation package as the segmentation mask generated by the Image Segmenter seemed too rough (and it took longer wall clock time to process each frame).
I will consider switching to the new solutions once an alternative for the legacy selfie segmentation becomes available.

@google-ml-butler google-ml-butler bot removed the stat:awaiting response Waiting for user response label Apr 20, 2023
@kuaashish
Copy link
Collaborator

@sile,
Thank you checking out our new solutions. Others legacy solutions source code will be available in the Github if you choose.
Further, We need your confirmation to move issue to close if this is no longer issue from your end.

@kuaashish kuaashish added the stat:awaiting response Waiting for user response label Apr 21, 2023
@sile
Copy link
Author

sile commented Apr 21, 2023

@kuaashish I see. It's okay to close this issue 👍

@google-ml-butler google-ml-butler bot removed the stat:awaiting response Waiting for user response label Apr 21, 2023
@spencer17x
Copy link

Maybe you can use vite-plugin-mediapipe:https://github.com/Spencer17x/arca/tree/main/packages/vite-plugin/vite-plugin-mediapipe

@Bersaelor
Copy link

Just FYI, I implemented a custom rollup plugin that appends the line exports.SelfieSegmentation = SelfieSegmentation; to the selfie_segmentation.js during the bundle phase as our workaround: https://github.com/shiguredo/media-processors/blob/develop/packages/virtual-background/rollup.config.js#L73

Thanks for sharing. In my case the error was related to MediaPipe Facemesh, so I adjusted the plugin as follows:

function mediapipe_workaround() {
  return {
    name: "mediapipe_workaround",
    load(id) {
      if (path.basename(id) === "face_mesh.js") {
        let code = fs.readFileSync(id, "utf-8")
        code += "exports.FaceMesh = FaceMesh;"
        return { code }
      } else {
        return null
      }
    },
  }
}

Hey @mattrossman , I'm encountering the exact same issue, trying to bundle mediapipe/facemesh into a vite built application ( also Ik.FaceMesh is not a constructor )

The link you quoted doesn't go anywhere anymore, do you happen to still have a full vite plugin that the method you wrote goes into?

@mattrossman
Copy link

mattrossman commented Aug 25, 2023

@Bersaelor That mediapipe_workaround method in the quoted message is the full plugin, you call it within vite's build.rollupOptions.plugins.

For posterity, here's a permalink to the original by @sile that I based it on (it looks like they just renamed the file extension which broke that other link). And here's where it's used in the config.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
legacy:selfie segmentation Issues related to selfie segmentation platform:javascript MediaPipe Javascript issues type:research Model specific questions
Projects
None yet
Development

No branches or pull requests