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

Errors with vite #58

Closed
jlarmstrongiv opened this issue Nov 18, 2023 · 30 comments
Closed

Errors with vite #58

jlarmstrongiv opened this issue Nov 18, 2023 · 30 comments
Labels
question Further information is requested

Comments

@jlarmstrongiv
Copy link

In dev mode

Failed to resolve entry for package "/Users/user/projects/astro-vips/node_modules/.vite/deps". The package may have incorrect main/module/exports specified in its package.json.
9:04:39 PM [vite] Internal server error: Failed to resolve entry for package "/Users/user/projects/astro-vips/node_modules/.vite/deps". The package may have incorrect main/module/exports specified in its package.json.
  Plugin: vite:asset-import-meta-url
  File: /Users/user/projects/astro-vips/node_modules/.vite/deps/wasm-vips.js?v=c3cd4bc3
      at packageEntryFailure (file:///Users/user/projects/astro-vips/node_modules/vite/dist/node/chunks/dep-bb8a8339.js:28725:11)
      at resolvePackageEntry (file:///Users/user/projects/astro-vips/node_modules/vite/dist/node/chunks/dep-bb8a8339.js:28722:5)
      at tryCleanFsResolve (file:///Users/user/projects/astro-vips/node_modules/vite/dist/node/chunks/dep-bb8a8339.js:28381:28)
      at tryFsResolve (file:///Users/user/projects/astro-vips/node_modules/vite/dist/node/chunks/dep-bb8a8339.js:28328:17)
      at TransformContext.transform (file:///Users/user/projects/astro-vips/node_modules/vite/dist/node/chunks/dep-bb8a8339.js:43235:32)
      at Object.transform (file:///Users/user/projects/astro-vips/node_modules/vite/dist/node/chunks/dep-bb8a8339.js:44352:62)
      at async loadAndTransform (file:///Users/user/projects/astro-vips/node_modules/vite/dist/node/chunks/dep-bb8a8339.js:55026:29)
      at async viteTransformMiddleware (file:///Users/user/projects/astro-vips/node_modules/vite/dist/node/chunks/dep-bb8a8339.js:64430:32)
09:07:28 PM [astro] Configuration updated. Restarting...

While dev mode starts to work with

optimizeDeps: {
    exclude: ["wasm-vips"],
},

This causes errors in build

vite v4.5.0 building for production...
transforming (11) node_modules/react/cjs/react-jsx-runtime.production.min.jsUnexpected early exit. This happens when Promises returned by plugins cannot resolve. Unfinished hook action(s) on exit:
(commonjs--resolver) resolveId "wasm-vips" "/Users/user/projects/astro-vips/src/components/VipsExample.tsx"
(vite:worker-import-meta-url) transform "/Users/user/projects/astro-vips/node_modules/wasm-vips/lib/vips-es6.js"
✓ 30 modules transformed.
✓ built in 526ms
file:///Users/user/projects/astro-vips/node_modules/rollup/dist/es/shared/node-entry.js:25902
                    reject(new Error(`Unexpected early exit. This happens when Promises returned by plugins cannot resolve. Unfinished hook action(s) on exit:\n` +
                           ^

Error: Unexpected early exit. This happens when Promises returned by plugins cannot resolve. Unfinished hook action(s) on exit:
(commonjs--resolver) resolveId "./vips-es6.js" "/Users/user/projects/astro-vips/node_modules/wasm-vips/lib/vips-es6.worker.js"
(vite:worker-import-meta-url) transform "/Users/user/projects/astro-vips/node_modules/wasm-vips/lib/vips-es6.js"
    at process.handleBeforeExit (file:///Users/user/projects/astro-vips/node_modules/rollup/dist/es/shared/node-entry.js:25902:28)
    at Object.onceWrapper (node:events:629:26)
    at process.emit (node:events:514:28) {
  code: 'PLUGIN_ERROR',
  plugin: 'commonjs--resolver',
  hook: 'resolveId',
  id: '/Users/user/projects/astro-vips/node_modules/wasm-vips/lib/vips-es6.js',
  watchFiles: [
    '\x00astro-entry:/Users/user/projects/astro-vips/src/components/VipsExample',
    '/Users/user/projects/astro-vips/node_modules/@astrojs/react/client.js',
    '/Users/user/projects/astro-vips/src/components/VipsExample.tsx',
    '/Users/user/projects/astro-vips/node_modules/react/index.js',
    '/Users/user/projects/astro-vips/node_modules/react-dom/client.js',
    '/Users/user/projects/astro-vips/node_modules/@astrojs/react/static-html.js',
    '/Users/user/projects/astro-vips/node_modules/react/cjs/react.production.min.js',
    '/Users/user/projects/astro-vips/node_modules/react-dom/index.js',
    '/Users/user/projects/astro-vips/package.json',
    '/Users/user/projects/astro-vips/node_modules/react/jsx-runtime.js',
    '/Users/user/projects/astro-vips/node_modules/wasm-vips/lib/vips-es6.js',
    '\x00commonjsHelpers.js',
    '\x00/Users/user/projects/astro-vips/node_modules/react/index.js?commonjs-module',
    '\x00/Users/user/projects/astro-vips/node_modules/react/cjs/react.production.min.js?commonjs-proxy',
    '\x00/Users/user/projects/astro-vips/node_modules/react/cjs/react.production.min.js?commonjs-exports',
    '/Users/user/projects/astro-vips/node_modules/react-dom/cjs/react-dom.production.min.js',
    '/Users/user/projects/astro-vips/node_modules/react/cjs/react-jsx-runtime.production.min.js',
    '/Users/user/projects/astro-vips/node_modules/scheduler/index.js',
    '\x00/Users/user/projects/astro-vips/node_modules/react/jsx-runtime.js?commonjs-module',
    '\x00/Users/user/projects/astro-vips/node_modules/react/cjs/react-jsx-runtime.production.min.js?commonjs-proxy',
    '\x00/Users/user/projects/astro-vips/node_modules/react/cjs/react-jsx-runtime.production.min.js?commonjs-exports',
    '\x00/Users/user/projects/astro-vips/node_modules/react/index.js?commonjs-proxy',
    '/Users/user/projects/astro-vips/node_modules/scheduler/cjs/scheduler.production.min.js',
    '\x00/Users/user/projects/astro-vips/node_modules/react-dom/client.js?commonjs-exports',
    '\x00/Users/user/projects/astro-vips/node_modules/react-dom/index.js?commonjs-proxy',
    '\x00/Users/user/projects/astro-vips/node_modules/react-dom/index.js?commonjs-module',
    '\x00/Users/user/projects/astro-vips/node_modules/react-dom/cjs/react-dom.production.min.js?commonjs-proxy',
    '\x00/Users/user/projects/astro-vips/node_modules/react-dom/cjs/react-dom.production.min.js?commonjs-exports',
    '\x00/Users/user/projects/astro-vips/node_modules/scheduler/index.js?commonjs-proxy',
    '\x00/Users/user/projects/astro-vips/node_modules/scheduler/index.js?commonjs-module',
    '\x00/Users/user/projects/astro-vips/node_modules/scheduler/cjs/scheduler.production.min.js?commonjs-proxy',
    '\x00/Users/user/projects/astro-vips/node_modules/scheduler/cjs/scheduler.production.min.js?commonjs-exports'
  ]
}

I would love to use wasm-vips, I just need to figure out how to import and use it

@jlarmstrongiv
Copy link
Author

Here’s a reproducible example
astro-vips.zip

@jlarmstrongiv
Copy link
Author

jlarmstrongiv commented Nov 18, 2023

I tried using vite with another popular wasm library ( https://www.npmjs.com/package/@sqlite.org/sqlite-wasm ) and it did build and bundle correctly with

optimizeDeps: {
    exclude: ["@sqlite.org/sqlite-wasm"],
},

Anyway, if you have suggestions on how to get wasm-vips working, please let me know!

EDIT: I’m going to try again tomorrow inside a plain astro component and see if that works any better

@kleisauke kleisauke added the question Further information is requested label Nov 19, 2023
@kleisauke
Copy link
Owner

kleisauke commented Nov 19, 2023

This is due to vitejs/vite#7015. Fortunately, there's a workaround for this that seems to work:

Details

astro.config.mjs:

import { defineConfig } from 'astro/config';

import react from '@astrojs/react';

// https://github.com/vitejs/vite/blob/ec7ee22cf15bed05a6c55693ecbac27cfd615118/packages/vite/src/node/plugins/workerImportMetaUrl.ts#L127-L128
const workerImportMetaUrlRE =
    /\bnew\s+(?:Worker|SharedWorker)\s*\(\s*(new\s+URL\s*\(\s*('[^']+'|"[^"]+"|`[^`]+`)\s*,\s*import\.meta\.url\s*\))/g

// https://astro.build/config
export default defineConfig({
  integrations: [react()],
  server: {
    headers: {
        'Cross-Origin-Embedder-Policy': 'require-corp',
        'Cross-Origin-Opener-Policy': 'same-origin'
    },
  },
  vite: {
    build: {
        target: 'esnext',
    },
    optimizeDeps: {
        esbuildOptions: {
            target: 'esnext'
        }
    },
    worker: {
        format: 'es',
        // https://github.com/vitejs/vite/issues/7015
        // https://github.com/vitejs/vite/issues/14499#issuecomment-1740267849
        plugins: [
            {
                name: 'Disable nested workers',
                enforce: 'pre',
                transform(code, id) {
                    if (code.includes('new Worker') && code.includes('new URL') && code.includes('import.meta.url')) {
                        return code.replace(workerImportMetaUrlRE, `((() => { throw new Error('Nested workers are disabled') })()`);
                    }
                }
            }
        ]
    }
  }
});

However, this would mean that the locateFile handler on the incoming module would have to be overridden to provide support for nested workers, for example when using wasm-vips in a web worker (see: #15 (comment)).

@jlarmstrongiv
Copy link
Author

Thank you @kleisauke! Unfortunately, I’ve tried disabling the nested plugins, and it broke the dev server. It builds just fine though.

Can you describe:

cannot override the locateFile handler on the incoming module

I’m getting that Nested workers are disabled error.

I am using vips in a worker—is that allowed, or does vips spawn it’s own web worker?

Or is the way I’m importing the workers the problem?

// error
const vipsWorker = new Worker(
    new URL("../workers/vips.worker", import.meta.url),
    { type: "module", name: "comlink.worker" },
);

// error 
import vipsWorkerUrl from "../workers/vips.worker?worker&url";
const vipsWorker = new Worker(
    vipsWorkerUrl,
    { type: "module", name: "comlink.worker" },
);
image
import type { PluginOption } from "vite";

// https://github.com/vitejs/vite/blob/ec7ee22cf15bed05a6c55693ecbac27cfd615118/packages/vite/src/node/plugins/workerImportMetaUrl.ts#L127-L128
const workerImportMetaUrlRE =
  /\bnew\s+(?:Worker|SharedWorker)\s*\(\s*(new\s+URL\s*\(\s*('[^']+'|"[^"]+"|`[^`]+`)\s*,\s*import\.meta\.url\s*\))/g;

// https://github.com/vitejs/vite/issues/7015
// https://github.com/vitejs/vite/issues/14499#issuecomment-1740267849
export const disableNestedWorkers: PluginOption = {
  enforce: "pre",
  name: "Disable nested workers",
  transform(code) {
    if (
      code.includes("new Worker") &&
      code.includes("new URL") &&
      code.includes("import.meta.url")
    ) {
      return {
        code: code.replaceAll(
          workerImportMetaUrlRE,
          `((() => { throw new Error('Nested workers are disabled') })()`,
        ),
        // (Disable nested workers plugin) Sourcemap is likely to be incorrect: a plugin (Disable nested workers) was used to transform files, but didn't generate a sourcemap for the transformation. Consult the plugin documentation for help
        // - https://github.com/withastro/astro/pull/6817
        // - https://github.com/withastro/astro/pull/6817/files#diff-2daffa3917247b6251d31ca5525312790f033402a8d48d6616ec7dcf37b78ef6R86
        map: { mappings: "" },
      };
    }
  },
};

@kleisauke
Copy link
Owner

Apologies for the confusion; I mixed it up. You'll need to override the locateFile handler to support nested workers, I clarified my previous post.

I am using vips in a worker—is that allowed, or does vips spawn it’s own web worker?

Using wasm-vips in a worker is allowed. Given that Emscripten's pthreads integration also uses web workers, it can sometimes be tricky to set this up with different module bundlers, as you've noticed.

So, for example, if you initiate wasm-vips in a web worker and not overriding the locateFile handler, this happens:

graph TD
    A["vips-es6.js #40;bundled#41;"] -- "new Worker#40;new URL#40;'vips-es6.worker.js', import.meta.url#41;, {type: 'module'}#41;" --> vips-es6.worker.js
    vips-es6.worker.js --  "import#40;'./vips-es6.js'#41; " --> B["vips-es6.js #40;pre-processed#41;"]
     B["vips-es6.js #40;pre-processed#41;"] --> C["throw new Error#40;'Nested workers are disabled'#41;"]
Loading

But by overriding that handler, this happens:

graph TD
    A["vips-es6.js #40;bundled#41;"] -- "new Worker#40;locateFile#40;'vips-es6.worker.js'#41;, {type: 'module'}#41;" --> vips-es6.worker.js
    vips-es6.worker.js --  "import#40;'./vips-es6.js'#41; " --> B["vips-es6.js #40;pre-processed#41;"]
     B["vips-es6.js #40;pre-processed#41;"] -- "new Worker#40;locateFile#40;'vips-es6.worker.js'#41;, {type: 'module'}#41;" --> vips-es6.worker.js
Loading

@jlarmstrongiv
Copy link
Author

jlarmstrongiv commented Nov 22, 2023

I’m really sorry @kleisauke but do you have a full example using vips in a worker? I feel like I’m missing something important. Am I supposed to have a vips.js or vips-es6.js file? Do I import that from node_modules? What goes in it?

When using importScripts from the example, I get the error:

Uncaught TypeError: Failed to execute 'importScripts' on 'WorkerGlobalScope': Module scripts don't support importScripts().
    at vips.worker.ts:15:6

But, when I switch to classic, I get the error:

Uncaught SyntaxError: Cannot use import statement outside a module (at vips.worker.ts?type=module&worker_file:1:1)

And I need the workers to support ES Modules, so I feel like solving the first error is the way to go.

I also tried await import("./vips.js");, but get the error:

[vite] Internal server error: Failed to resolve import "./vips.js" from "../../core/src/astro/workers/vips.worker.ts?type=module&worker_file". Does the file exist?

Please note that I cannot use top-level await with comlink, so I put the await import("./vips.js"); inside the getVips function.

My worker file looks like:

/// <reference lib="webworker" />

import { expose } from "comlink";
import onetime from "onetime";
// import Vips from "wasm-vips";

// eslint-disable-next-line @typescript-eslint/consistent-type-imports
declare type VipsConstructor = typeof import("wasm-vips");

if (!(typeof importScripts === "function")) {
  // determine environment https://stackoverflow.com/a/23619712
  throw new TypeError(`[example.worker]: ENVIRONMENT_IS_WORKER is false`);
}

importScripts("./vips.js");

// libvips
// - https://www.npmjs.com/package/wasm-vips
// - https://wasm-vips.kleisauke.nl/playground/

const getVips = onetime(
  async () =>
    // @ts-expect-error Cannot find name 'Vips'.
    // eslint-disable-next-line @typescript-eslint/no-unsafe-call
    Vips({
      // @ts-expect-error Parameter 'fileName' implicitly has an 'any' type.
      locateFile: (fileName, scriptDirectory) =>
        `${scriptDirectory}${fileName}`,
      mainScriptUrlOrBlob: "./vips.js",
    }) as Promise<VipsConstructor>,
);

async function getImageUrl(): Promise<string> {
  const vips = await getVips();
  // #C83658 as CIELAB triple
  const start = [46.479, 58.976, 15.052];

  // #D8E74F as CIELAB triple
  const stop = [88.12, -23.952, 69.178];

  // Makes a lut which is a smooth gradient from start colour to stop colour,
  // with start and stop in CIELAB
  // let lut = vips.Image.identity() / 255;
  let lut = vips.Image.identity().divide(255);

  // lut = lut * stop + (1 - lut) * start;
  lut = lut.multiply(stop).add(lut.multiply(-1).add(1).multiply(start));

  lut = lut.colourspace(vips.Interpretation.srgb /* 'srgb' */, {
    source_space: vips.Interpretation.lab, // 'lab'
  });

  const buffer = await fetch("/assets/images/owl.jpg").then(async (resp) =>
    resp.arrayBuffer(),
  );

  let im = vips.Image.newFromBuffer(buffer);

  if (im.hasAlpha()) {
    // Separate alpha channel
    const withoutAlpha = im.extractBand(0, { n: im.bands - 1 });
    const alpha = im.extractBand(im.bands - 1);
    im = withoutAlpha
      .colourspace(vips.Interpretation.b_w /* 'b-w' */)
      .maplut(lut)
      .bandjoin(alpha);
  } else {
    im = im.colourspace(vips.Interpretation.b_w /* 'b-w' */).maplut(lut);
  }

  // Finally, write the result to a blob
  const t0 = performance.now();
  const outBuffer = im.writeToBuffer(".jpg");
  const t1 = performance.now();

  console.log(`Call to writeToBuffer took ${t1 - t0} milliseconds.`);

  const blob = new Blob([outBuffer], { type: "image/jpeg" });
  const blobURL = URL.createObjectURL(blob);

  return blobURL;
}

const workerInterface = {
  getImageUrl,
};

expose(workerInterface);

export type ExposedInterface = typeof workerInterface;

And I’m importing it in this Astro file:

---
// Usage
// <VipsWorker transition:persist />
---

<script>
  import { wrap } from "comlink";
  import type { ExposedInterface } from "../workers/vips.worker";
  import vipsWorkerUrl from "../workers/vips.worker?worker&url";

  // use newer syntax https://v3.vitejs.dev/guide/features.html#import-with-constructors
  const vipsWorker = new Worker(
    // new URL("../workers/vips.worker", import.meta.url),
    vipsWorkerUrl,
    { type: "module", name: "comlink.worker" },
  );
  const vips = wrap<ExposedInterface>(vipsWorker);
  // @ts-expect-error Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature.
  globalThis.vips = vips;
  console.log("vipsWorker", await vips.getImageUrl());
</script>

@kleisauke
Copy link
Owner

do you have a full example using vips in a worker?

Here's a full example of using wasm-vips in a ES6 web worker with vanilla JavaScript: #15 (comment).

I tried to fix your code example above, but it didn't work. I tried this patch:

Details
--- a/src/workers/vips.worker.ts
+++ b/src/workers/vips.worker.ts
@@ -2,33 +2,18 @@
 
 import { expose } from "comlink";
 import onetime from "onetime";
-// import Vips from "wasm-vips";
-
-// eslint-disable-next-line @typescript-eslint/consistent-type-imports
-declare type VipsConstructor = typeof import("wasm-vips");
+import Vips from "wasm-vips";
 
 if (!(typeof importScripts === "function")) {
   // determine environment https://stackoverflow.com/a/23619712
   throw new TypeError(`[example.worker]: ENVIRONMENT_IS_WORKER is false`);
 }
 
-importScripts("./vips.js");
-
 // libvips
 // - https://www.npmjs.com/package/wasm-vips
 // - https://wasm-vips.kleisauke.nl/playground/
 
-const getVips = onetime(
-  async () =>
-    // @ts-expect-error Cannot find name 'Vips'.
-    // eslint-disable-next-line @typescript-eslint/no-unsafe-call
-    Vips({
-      // @ts-expect-error Parameter 'fileName' implicitly has an 'any' type.
-      locateFile: (fileName, scriptDirectory) =>
-        `${scriptDirectory}${fileName}`,
-      mainScriptUrlOrBlob: "./vips.js",
-    }) as Promise<VipsConstructor>,
-);
+const getVips = onetime(async () => Vips());
 
 async function getImageUrl(): Promise<string> {
   const vips = await getVips();

and modified the package.json to include:

  "overrides": {
    "astro": {
      "vite": "^5.0.2"
    }
  }

(this ensures issue vitejs/vite#13367 is not masking issue vitejs/vite#7015)

This will hang indefinitely during astro build, so it seems that the above mentioned workaround is not effective when wasm-vips was imported in a web worker.

There's not much I can do for this, please subscribe to vitejs/vite#7015 for updates related to this.

@jlarmstrongiv
Copy link
Author

Thank you for trying @kleisauke ! I really appreciate your help and recommendations trying to solve this bug. I’ve followed the issue and look forward to when I can try wasm-vips. If you find any workarounds, please let me know and I’ll give them a try.

@kleisauke
Copy link
Owner

Thinking about this further, you might be able to patch vips-es6.js in a similar way as the Vite plugin does. Here's a minimal working example:
astro-vips.zip

Hope this helps.

@jlarmstrongiv
Copy link
Author

Thanks @kleisauke! That worked 🎉 I had to find and fix a few paths for the monorepo, but after studying your example with Vips, cleanup, and patch-package, I was able to get it working 🎉 thank you so much for helping debug vite and providing those extremely helpful examples

@jlarmstrongiv
Copy link
Author

jlarmstrongiv commented Nov 28, 2023

Actually, @kleisauke, I spoke too soon. I am running into CORS errors, even with workaroundCors: true,

Access to script at 'https://typefoundriesdirect.dev/assets/vips-es6-b7b0be19.js' from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

@jlarmstrongiv
Copy link
Author

jlarmstrongiv commented Nov 28, 2023

I was able to get it to work with workaroundCors: true, and mainScriptUrlOrBlob: "https://cdn.jsdelivr.net/npm/[email protected]/lib/vips-es6.js",, but I would love to be able to serve the file locally.

Is the cors error due to loading the worker as a blob, which causes the origin header to be set to null which breaks cors?

@kleisauke
Copy link
Owner

I am running into CORS errors, even with workaroundCors: true,

Unfortunately, workaroundCors: true is no-op for ES6 modules, see: #12 (comment).

Is the cors error due to loading the worker as a blob, which causes the origin header to be set to null which breaks cors?

I think this is indeed the issue. It seems that vips-es6.worker.js is being inlined since its size is smaller than 4 KiB. Fortunately, you could set build.assetsInlineLimit to 0 to disable inlining altogether.

--- a/astro.config.mjs
+++ b/astro.config.mjs
@@ -10,7 +10,8 @@ export default defineConfig({
   },
   vite: {
     build: {
-      target: 'esnext'
+      target: 'esnext',
+      assetsInlineLimit: 0
     },
     optimizeDeps: {
       esbuildOptions: {

@jlarmstrongiv
Copy link
Author

@kleisauke disabling all asset inlining has a pretty big performance impact. Is there another way with vite.worker.rollupOptions.external or vite.build.rollupOptions.external?

@jlarmstrongiv
Copy link
Author

I’ve tried some of those rollup options, but I haven’t quite gotten it to work 🤔

@kleisauke
Copy link
Owner

I couldn't get it work with those Rollup options either. Hopefully sometime in the future this can be controlled with the ?no-inline or ?inline=false query suffixes.

The only two options I can think of to fix this are:

  • serve the Access-Control-Allow-Origin: * HTTP header on vips-es6.js;
  • place vips-es6.js, vips.wasm and vips-es6.worker.js in the public directory.

@jlarmstrongiv
Copy link
Author

You’re right, the easiest solution is that mainScriptUrlOrBlob as vips-es6.js needs to be loaded from the public directory or a cdn

@swissspidy
Copy link

swissspidy commented Dec 16, 2023

@jlarmstrongiv Which solution did you end up finding? I'd love to check it out.

I'm currently trying to get wasm-vips to run in a worker as well, and while #15 (comment) and #58 (comment) are really helpful for trying to understand the problem better, I have yet to get it working on my project (see swissspidy/media-experiments#260)

Might be special because I'm using @shopify/web-worker to load code in a blob worker. I need to load wasm-vips in there or from a CDN (using jsdelivr right now) as I otherwise don't have control to add CORS header.

Anyway, having more examples of wasm-vips in a web worker would be really helpful to me.

Edit: I got it working now! The solution was to load https://cdn.jsdelivr.net/npm/[email protected]/lib/vips.worker.js into a blob and then in the locateFile callback return a blob URL for it.

@jlarmstrongiv
Copy link
Author

@swissspidy I tried @shopify/web-worker and it didn’t work for me, presumably because of its webpack and babel dependencies

This library contains three parts that must be used together:

- The public API of the package provided by @shopify/web-worker
- A babel plugin provided by @shopify/web-worker/babel that identifies uses of createWorkerFactory that need to be processed
- A webpack plugin provided by @shopify/web-worker/webpack that outputs the worker as a dedicated chunk

Did you get it working with a vite-based project?

@swissspidy
Copy link

I‘m not using Vite unfortunately, just React in this case.

@kleisauke
Copy link
Owner

Commit vitejs/vite@4d1342e introduces a new callback functionality to build.assetsInlineLimit, enabling users to selectively opt-in or opt-out for inlining. This enhancement will be available in an upcoming version of Vite, alowing you to do this:

--- a/astro.config.mjs
+++ b/astro.config.mjs
@@ -10,7 +10,9 @@ export default defineConfig({
   },
   vite: {
     build: {
-      target: 'esnext'
+      target: 'esnext',
+      assetsInlineLimit: (filePath) =>
+        filePath.endsWith('.worker.js') ? false : undefined,
     },
     optimizeDeps: {
       esbuildOptions: {

I'll close this as "won't fix" for now, as there's not much I can do for this. Please subscribe to vitejs/vite#7015 for updates related to this.

@kleisauke kleisauke closed this as not planned Won't fix, can't repro, duplicate, stale Jan 12, 2024
@kleisauke
Copy link
Owner

Issue vitejs/vite#7015 is now fixed via PR vitejs/vite#16103, which is included in Vite v5.1.6. This means that the previously mentioned workarounds are no longer needed. 🎉

Here's a minimal working example:
astro-vips.zip

@jlarmstrongiv
Copy link
Author

@kleisauke fantastic news 🎉 thank you so much for the update and example

@jlarmstrongiv
Copy link
Author

jlarmstrongiv commented Mar 25, 2024

@kleisauke it seems that the vite worker no longer works? It appears that vite is attempting to bundle @vite/client with overlay.ts, which fails to due the webworker not having a dom. Other workers like sqlite3 and resvg work fine. Any idea why wasm-vips would be breaking?

@jlarmstrongiv
Copy link
Author

I tried the older workaround, but that doesn’t seem to work either. Did something change in vite?

I also tried the workaround in vitejs/vite#9879, but those didn’t work either

@kleisauke
Copy link
Owner

@jlarmstrongiv This looks like a regression introduced in PR vitejs/vite#15852, I recommend downgrading Vite to v5.1.7 for now.

$ npm install [email protected]

@jlarmstrongiv
Copy link
Author

Fixed in [email protected]

@pepijnolivier
Copy link

Hey @jlarmstrongiv would you mind setting up an example repository using vite and wasm-vips ? I cannot get this to work.

@jlarmstrongiv
Copy link
Author

@pepijnolivier the only thing missing from this example is upgrading all dependencies and adding this option to the config:

  vite: {
    optimizeDeps: {
      exclude: ["wasm-vips"],
    },
  },

@emojiiii
Copy link

import { Plugin } from "vite";
import fs from "fs";
import path from "path";

const hashIgnoreFiles = [
  "vips-es6.js",
  "vips-heif.wasm",
  "vips-jxl.wasm",
  "vips-resvg.wasm",
  "vips.wasm",
];

export function customHeaders(): Plugin {
  let outDir = "";

  return {
    name: "custom-headers",
    configResolved(config) {
      outDir = config.build.outDir;
      if (!config.inlineConfig.build?.ssr) {
        config.build.rollupOptions.output = {
          assetFileNames(chunkInfo) {
            if (
              chunkInfo.type === "asset" &&
              chunkInfo.name &&
              hashIgnoreFiles.includes(chunkInfo.name)
            ) {
              return `assets/${chunkInfo.name}`;
            }
            return `assets/[name]-[hash].[ext]`;
          },
        };
      }

      if (!config.optimizeDeps.exclude) {
        config.optimizeDeps.exclude = ["wasm-vips"];
      } else {
        if (!config.optimizeDeps.exclude.includes("wasm-vips")) {
          config.optimizeDeps.exclude.push("wasm-vips");
        }
      }
    },

    configureServer(server) {
      server.middlewares.use((req, res, next) => {
        if (req.url?.endsWith("lib/vips-es6.js")) {
          res.setHeader("Cross-Origin-Embedder-Policy", "require-corp");
          res.setHeader("Cross-Origin-Opener-Policy", "same-origin");
        }
        next();
      });
    },
    closeBundle() {
      fs.copyFileSync(
        path.join(__dirname, "../node_modules/wasm-vips/lib/vips-jxl.wasm"),
        path.join(outDir, "assets/vips-jxl.wasm")
      );
      fs.copyFileSync(
        path.join(__dirname, "../node_modules/wasm-vips/lib/vips-heif.wasm"),
        path.join(outDir, "assets/vips-heif.wasm")
      );
      fs.copyFileSync(
        path.join(__dirname, "../node_modules/wasm-vips/lib/vips-resvg.wasm"),
        path.join(outDir, "assets/vips-resvg.wasm")
      );
    },
  };
}

export default customHeaders;

This is my vite plugin, for reference only

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

No branches or pull requests

5 participants