-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
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
Parcel breaks import.meta.url
in worker entry files
#7623
Comments
In addition, writing the code this way means Parcel is not aware that it will run in a worker environment, which is important for things like runtime loading. Writing the code in this form is how Parcel can determine that: let worker = new Worker(new URL('worker.js', import.meta.url)); However, it looks like you are trying to work around the same origin restriction with workers by using a blob url. Parcel actually does this automatically by default. Here's an example. If you inspect the code, you can see that if the worker origin is different from the page origin, we apply this exact workaround. Hopefully this solves your issue. |
Unfortunately, it can't. :-/
It looks like |
I would argue that passing Parcel matches webpack's behavior here. Webpack also compiles |
I certainly agree with this sentence, so I guess it comes down to which semantics should be preserved. Given our tradeoffs, we currently have no choice but to instantiate the worker this way — If Parcel can't address this, should we recommend that folks shouldn't use Parcel to build applications using our library? Footnotes
|
const workerURL = (await import("./worker.js")).WORKER_ENTRY_FILE_URL; This is a strange approach. It will result in the module being executed twice: once in the main thread, and again in the worker. Why not do something like this? const workerURL = new URL('worker.js', import.meta.url); This works natively and in most bundlers (e.g. Webpack, Vite, Parcel).
Yes, because it isn't bundled. Once bundled, the source module doesn't exist anymore, it's embedded in the bundle, so there's no individual URL to refer to. Referring to the entire bundle is incorrect. For example: a.js import './b.js';
console.log(import.meta.url); b.js console.log(import.meta.url); These should log two different results, but if bundled and untransformed, they would log the same result. That would break many things. |
Also, apologies if I sound really cranky about this. I'm a little annoyed at myself for not noticing this sooner. I thought that this worked in all bundlers, given that it was passing our test against Parcel in CI — but unfortunately it turns out that this was because of our super blunt workaround of serializing an entire worker source to a 1MB string. This situation is not Parcel's fault, and Parcel in fact has done more than most bundlers to make workers less painful. But I'm determined to remove all workarounds as soon as module workers are available in Firefox (which looks like it will hopefully happen soon), and this is the closest to a universal approach that seems possible. I don't want to leave Parcel compatibility behind. 😔 |
This does not work in |
Hmm, I think esbuild is the odd one out here then. As I linked above in an edit, most other bundlers support this syntax and it is supported natively as well. I would hope that esbuild would add support for it as well. |
That may be — I've been trying to get |
Anyway, I think the approach proposed in the original issue will also have problems in webpack, which seems like a pretty big target to exclude for a library too. https://webpack.js.org/api/module-variables/#importmetaurl |
Then I consider this a serious compatibility bug in Webpack as well. 🤷 In any case, I have often used — and still recommend — Parcel. I'm not nearly as concerned with Webpack compat. |
I'm not sure what else to tell you, sorry! esbuild's behavior is incorrect here. You should open an issue with them to support the |
Sounds like we just fundamentally disagree on whether Parcel should break this code. 🤷 I've left another comment on the |
I know you're frustrated, but please try to understand how it works. I feel like I've tried to explain it a few times now. Think about it: where do your source files exist? How do you refer to them? From Parcel's perspective, while building your code, your files are on the file system. There's no URL to link to if a module is bundled into the same file with other modules. Let me extend your example a little. // index.js
const workerURL = (await import("./worker.js")).WORKER_ENTRY_FILE_URL;
const blob = new Blob([`import "${workerURL}";`], { type: "text/javascript" });
new Worker(URL.createObjectURL(blob), { type: "module" });
// worker.js
export {LIBRARY_URL as WORKER_ENTRY_FILE_URL} from "./library.js";
// library.js
export const LIBRARY_URL = import.meta.url; If you load this in a browser, Therefore, |
I think you make a good argument that this makes sense for applications that rely in However, in practice bundlers all seem to preserve dynamic imports for code splitting, and |
@devongovett I opened an issue that may be related (#7643), but I guess I'm still a bit confused (apologies for my n00bliness!). It seems like lgarron wants the I'm wondering whether this is due to the fact that the file lgarron is serving is a worker file and therefore, a .js file. Given that, I would imagine that parcel might have difficulty differentiating which files should be incorporated into the initial bundle and which should be served later. If that holds, wouldn't the bundler handle filetypes like videos differently, though? I would imagine that images/videos aren't included in the bundled chunks, and therefore would be serve-able after the fact from the server? One final question -- in development, given that If they will always be broken in development, would it be worthwhile adding a feature/flag that would enable them to be served from build machine using either an absolute path in development or from localhost? Thanks in advance for your patience, time, and consideration! |
@devongovett I just wanted to circle back and ask about this, as I'm currently having to do a hacky work-around to get a similar-sounding issue resolved in my app. I was hoping whether you might be able to help me better understand about |
@devongovett ping? |
@devongovett ping again? |
I have read throughout this conversation and I do understand the maintainers and the users point of view somehow. I just want to share some insights from using webpack for a similar issue. we wanted to develop the worker script in typescript rather than in javascript. so webpack/tsc needs to transpile the typescript into javascript first and than provide a link to that javascript file, that works within a deployed environment - so no file:/// links. also we out-sourced the shared worker into it's own library, so multiple applications can use it, instead of having the same shared worker file duplicated. instance SharedWorker: return new SharedWorker(
new URL(
'@my/api/shared-worker',
import.meta.url
) /* webpackChunkName: 'shared-worker' */,
{
type: 'module',
name: 'My Shared Worker',
}
); the interessting part here is, that the combination it seems webpack handles to the combination of (Shared)Worker and URL specially to just fullfill the usecase. https://webpack.js.org/guides/web-workers/ more from the example - in case someone stumbles across this. tsconfig.ts ...
"@my/api/shared-worker": [
"libs/api/worker/shared-worker.ts"
],
... api module`s index.ts ....
// May not be exported because otherwise the worker will not be executed in the web worker context.
// But must be imported so that the file is compiled.
import * as SharedWorker from '@my/api/shared-worker'; shared-worker.ts imports ...
export default self.onconnect = (event: MessageEvent<any>) => {
const [port] = event.ports;
start(port);
};
if ('DedicatedWorkerGlobalScope' in self) start(self as unknown as MessagePort);
function start(port: MessagePort) {
// do worker stuff
port.postMessage({ data: 'data' })
port.onmessage = (e: MessageEvent) => {
messageHandler(e, port, subscriptions, dpConnectSubs);
};
} |
though perhaps old, this is still relevant |
Yeah, it's been over a year and the choice continues to be:
With both approaches it's "obvious" how to maintain correctness with standard code splitting, so it's a matter of the ecosystem settling on a cross-compatible solution. For now, we've given up on Parcel compatibility, given that this issue is stalled. |
This is still a breaking issue with Parcel for us, at least unless/until #8924 is implemented. |
As far as I know, this is still relevant. |
I'm going to unsubscribe from this issue, as I don't see any hope of it being addressed and I have given up on writing Parcel-compatible code as a result. As noted in the first post, all other major bundlers properly maintain the path resolution semantics in the example, and have continued to do so for over 2.5 years. I would still highly recommend that Parcel changes its design decisions to match them for this kind of code. I've made sure that https://github.com/lgarron/parcel-import-meta-url-bug still serves as a reproduction case, in case you still wish to address this. |
🐛 bug report
Parcel breaks trampoline code for worker instantiation:
🤔 Expected Behavior
The worker is instantiated properly, as it does when the source code is served either directly or with other tools:
npx serve
(or any static file server)npx vite
npx wmr
npx esbuild src/index.js --format=esm --bundle --splitting --servedir=src
😯 Current Behavior
Parcel errors with:
💁 Possible Solution
There should be a way to preserve the semantics of
import.meta.url
.At the very least, it would be sufficient in our case if
import.meta.url
is left untransformed when it is assigned to an export.🔦 Context
We maintain a library that:
node
and on the web (in particular, is available from a CDN), andnpm
.Unfortunately, instantiating workers in a portable way is challenging. The trampoline approach is the closest to a universal approach.
💻 Code Sample
See https://github.com/lgarron/parcel-import-meta-url-bug for a runnable repro:
🌍 Your Environment
2.2.1
v17.4.0
npm
8.3.1
The text was updated successfully, but these errors were encountered: