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

import.meta behavior inconsistency between targets #2294

Open
sapphi-red opened this issue Jun 2, 2022 · 4 comments
Open

import.meta behavior inconsistency between targets #2294

sapphi-red opened this issue Jun 2, 2022 · 4 comments

Comments

@sapphi-red
Copy link
Contributor

sapphi-red commented Jun 2, 2022

import.meta has different instances when target is below es2020. But it has same instance if target is same or above es2020.

If it is intented to be unmodified (#208 (comment)) (import.meta's scope is the output file), I think it needs to point the same instance.

current behaviors

Without bundle

main.mjs

import { sub } from './sub.mjs'

import.meta.url = 'main'

const main = () => {
  console.log(import.meta.url)
}

main()
sub()

sub.mjs

import.meta.url = 'sub'

export const sub = () => {
  console.log(import.meta.url)
}

When I run node main.mjs, it outputs:

main
sub

With bundle (es2020)

After I bundle this with esbuild --bundle --format=esm --target=es2020 main.mjs, it becomes:

// sub.mjs
import.meta.url = "sub";
var sub = () => {
  console.log(import.meta.url);
};

// main.mjs
import.meta.url = "main";
var main = () => {
  console.log(import.meta.url);
};
main();
sub();

When I run this, it outputs:

main
main

With bundle (es2015)

After I bundle this with esbuild --bundle --format=esm --target=es2015 main.mjs, it becomes:

// sub.mjs
var import_meta = {};
import_meta.url = "sub";
var sub = () => {
  console.log(import_meta.url);
};

// main.mjs
var import_meta2 = {};
import_meta2.url = "main";
var main = () => {
  console.log(import_meta2.url);
};
main();
sub();

When I run this, it outputs:

main
sub
@susiwen8
Copy link
Contributor

susiwen8 commented Jun 3, 2022

ac97be7
You can see the reason in change log

@sapphi-red
Copy link
Contributor Author

Thanks. I know the reason. I think the output of es2015 bundle would be better to be the code below. This has more consistency with es2020 bundle output.

// sub.mjs
var import_meta = {};
import_meta.url = "sub";
var sub = () => {
  console.log(import_meta.url);
};

// main.mjs
import_meta.url = "main";
var main = () => {
  console.log(import_meta.url);
};
main();
sub();

@susiwen8
Copy link
Contributor

susiwen8 commented Jun 3, 2022

Oh, sorry, I see

@hyrious
Copy link

hyrious commented Jun 4, 2022

There is an existing workaround in tsup/cjs_shims.js by injecting import.meta.url manually:

esbuild main.mjs --bundle --define:import.meta.url=importMetaUrl --inject:cjs_shims.js --format=esm

// cjs_shims.js
var getImportMetaUrl = () => typeof document === "undefined" ? new URL("file:" + __filename).href : document.currentScript && document.currentScript.src || new URL("main.js", document.baseURI).href;
var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();

// sub.mjs
importMetaUrl = "sub";
var sub = () => {
  console.log(importMetaUrl);
};

// main.mjs
importMetaUrl = "main";
var main = () => {
  console.log(importMetaUrl);
};
main();
sub();

But in fact import.meta is from ES2020. I'm not sure what's the correct behavior before that target. esbuild is replacing it with a simple object to prevent syntax error (likewise import() becomes new Promise((r) => r(require()))). But we still have to handle it at the most of the time, and some of them cannot be handled easily.

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

3 participants