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

feat(worker): support dynamic worker option fields #19010

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

jamsinclair
Copy link
Contributor

Description

The Problem

Vite has a hard requirement that worker options are defined statically or it throws an error. This prevents some legitimate use cases, such as when a dynamic name is used to differentiate workers. As seen in the Emscripten project (code reference)

worker = new Worker(new URL('target.js', import.meta.url), {
  'type': 'module',
  'name': 'em-pthread-' + PThread.nextWorkerID,
})

This is causing some issues in trying to update Emscripten to support Vite when workers are in use.

Solution

Vite only needs to ensure that the type value is statically defined. Other fields could be dynamically computed with no effect on the Vite bundling process.

A side discussion was started in #18396 (comment) about relaxing the usage of some worker option fields to support this.

This PR hopes to solve this issue in a backwards compatible way that still ensures that Vite can have high confidence in asserting the worker type at compile time.

@jamsinclair jamsinclair changed the title feat(worker): Support dynamic worker option fields feat(worker): support dynamic worker option fields Dec 19, 2024
@jamsinclair
Copy link
Contributor Author

jamsinclair commented Dec 19, 2024

Looks like this change broke the tests in two ways 😅

  • Windows paths aren't resolving nicely with the unit tests
  • It seems to have broken the worker integration tests Solved by 7cf1551

I'll look into fixing these tomorrow.

expect(
await transform('new Worker(new URL("./worker.js", import.meta.url))'),
).toMatchInlineSnapshot(
`"new Worker(new URL(/* @vite-ignore */ "/worker.js?worker_file&type=classic", import.meta.url))"`,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

packages/vite/src/node/__tests__/plugins/workerImportMetaUrl.spec.ts > workerImportMetaUrlPlugin > without worker options

Error: Snapshot `workerImportMetaUrlPlugin > without worker options 1` mismatched

Expected: ""new Worker(new URL(/* @vite-ignore */ "/worker.js?worker_file&type=classic", import.meta.url))""
Received: ""new Worker(new URL(/* @vite-ignore */ "/@fs/D:/a/vite/vite/worker.js?worker_file&type=classic", import.meta.url))""

Is there a way to compensate for this when testing on windows? Or should I add some kind of flag or annotation to skip the tests when isWindows?

Copy link
Collaborator

@hi-ogawa hi-ogawa Dec 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you try setting up an actual fixture? Something like this. You might not need an actual files, but importer being full id probably affects transform behavior.

  const root = path.join(import.meta.dirname, "fixtures/worker")
  const config = await resolveConfig({ configFile: false, root }, 'serve') //// <---- pass root
  ...

    const result = await instance.transform.call(
      { environment, parse: parseAst },
      code,
      path.join(root, 'foo.ts'),  //// <---- pass full id
    )

Copy link
Contributor Author

@jamsinclair jamsinclair Dec 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestion @hi-ogawa.

After debugging further it seems as if there may be a bug or undesired handling for windows paths in this plugin.

  1. The worker file is resolved initially with path.resolve and then tryFsResolve. Both would result in a windows-like path:
D:\\a\\vite\\vite\\packages\\vite\\src\\node\\__tests__\\plugins\\fixtures\\worker\\worker.js
  1. The plugin then tries to turn this into a dev asset url with the function fileToUrl which internally calls fileToDevUrl. However, the function assumes that it is dealing with posix paths. This results in the method always returning an absolute URL, instead of the expected relative URL.

    } else if (id.startsWith(withTrailingSlash(config.root))) {
    // in project root, infer short public path
    rtn = '/' + path.posix.relative(config.root, id)

    The if condition above will always return false when a windows string is presented.

  2. Vite configures the absolute URL as seen in the test failure

Does Vite have any guidelines on handling Windows paths? It feels like at step 1. we should turn the path into a posix path 🤔

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Actually this looks suspicious and we probably want slash(path.resolve(...)) like it's done in assetImportMetaUrlPlugin

if (url[0] === '.') {
file = slash(path.resolve(path.dirname(id), url))
file = tryFsResolve(file, fsResolveOptions) ?? file

I don't use Windows, so I'm just guessing though.

@@ -140,7 +140,6 @@ const genWorkerName = () => 'module'
const w2 = new SharedWorker(
new URL('../url-shared-worker.js', import.meta.url),
{
/* @vite-ignore */
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing the comment as the options can now legitimately be used as defined.

Should we add any explicit tests in the playground or will this suffice?

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

Successfully merging this pull request may close these issues.

2 participants