Skip to content

Instantly share code, notes, and snippets.

@0xdevalias
Last active March 12, 2025 05:28
Show Gist options
  • Save 0xdevalias/37a189cac102ff53d5c8f10357ac6a83 to your computer and use it in GitHub Desktop.
Save 0xdevalias/37a189cac102ff53d5c8f10357ac6a83 to your computer and use it in GitHub Desktop.
Deep Dive into `import.meta` support in `pkgroll` / `esbuild`

Deep Dive into import.meta support in pkgroll / esbuild

Table of Contents

Overview

Originally posted here:

Related:

Shared on socials/etc here:

tl;dr

The root cause of this is likely having your esbuild --target set to lower than es2020 (or an equivalent engine version alias (eg. node9)).

If you set your --target to something higher than that, it should transpile correctly, and leave import.meta as is; e.g.

esbuild app.js --target=es2020

If you can't change your --target, then you can override the individual feature support using --supported; e.g. to tell esbuild that import.meta is supported:

esbuild app.js --supported:import-meta=true

Deep Dive

I came across this issue recently while debugging a strange build failure due to a pkgroll update (which uses esbuild under the hood), which I ended up making a minimal reproduction of, for this bug report:

node:internal/modules/cjs/loader:1762
    throw new ERR_INVALID_ARG_VALUE('filename', filename, createRequireError);
          ^

TypeError [ERR_INVALID_ARG_VALUE]: The argument 'filename' must be a file URL object, file URL string, or absolute path string. Received undefined
    at createRequire (node:internal/modules/cjs/loader:1762:11)
    at file:///Users/devalias/dev/tmp/humanify/dist/index.mjs:1374:18 {
  code: 'ERR_INVALID_ARG_VALUE'
}

The root cause of that bug appears as though it may be the same as the issues being seen here.

esbuild transforms import.meta when the --target is below es2020:

These syntax features are conditionally transformed for older browsers depending on the configured language target:

..snip..

  • Syntax transform | Transformed when --target is below | Example
  • ..snip..
  • import.meta | es2020 | import.meta
  • ..snip..

..snip..

Since the repo I was debugging was using es2017, that explains why it wasn't working there.


While I'm not sure what target Sergio was using in their original question, we can see that James was using node16 in theirs.

While many of the usual sources of JavaScript / browser compatibility data don't seem to have entries for import.meta.url / import.meta.filename / import.meta.dirname; we can see that node has supported the basic import.meta since 10.4.0 (which also includes support for import.meta.url according to the node 10.x docs); and from node 20.x, support for import.meta.dirname and import.meta.filename exists; which seems to have been added in this PR, and released in node 21.2.0, which was later backported to node 20.11.0.

We can see that this esbuild compat-table combines data from kangax, caniuse, mdn, etc, along with manual data for things such as es2020's js.ImportMeta. We can also see that this internal/compat/js_table.go file shows ImportMeta support since Node 10.4.0 and ES 2020.

So at least in theory, I would have expected node16 to have worked with import.meta correctly. Looking at the online esbuild playground, we can see that import.meta with --target=node16 worked as far back as esbuild version 0.8.27:

esbuild 0.8.27 supports import.meta with --target=node16

But that esbuild version 0.8.26 didn't support it:

esbuild 0.8.26 doesn't support import.meta with --target=node16

Options:

{target: ['node16']}

Input:

console.log(import.meta.url)

Output:

const import_meta = {};
console.log(import_meta.url);
 > <stdin>:1:12: warning: "import.meta" is not available in the configured target environment and will be empty
    1 │ console.log(import.meta.url)
      ╵             ~~~~~~~~~~~

For these versions we need to go back to esbuild's CHANGELOG-2020.md; where in version 0.8.27 we see:

Mark import.meta as supported in node 10.4+ (#626)

It was previously marked as unsupported due to a typo in esbuild's compatibility table, which meant esbuild generated a shim for import.meta even when it's not necessary. It should now be marked as supported in node 10.4 and above so the shim will no longer be included when using a sufficiently new target environment such as --target=node10.4.


If we can't set a --target to es2020 or above; then we can still override the feature at an individual level using esbuild's --supported option:

If you need to customize the set of supported syntax features at the individual feature level in addition to or instead of what target provides, you can do that with the supported setting.

This setting lets you customize esbuild's set of unsupported syntax features at the individual syntax feature level. Usually this is configured for you when you use the target setting, which you should typically be using instead of this setting. If the target is specified in addition to this setting, this setting will override whatever is specified by the target.

Syntax features are specified using esbuild-specific feature names. The full set of feature names is as follows:

JavaScript:

  • ..snip..
  • import-meta
  • ..snip..

So you could tell esbuild that import.meta is supported and should be left as-is with:

esbuild app.js --supported:import-meta=true

Using the online esbuild playground, we can see that when we set target to less than es2020, we get a warning:

Options:

{target: ['es2019']}

Input:

console.log(import.meta.url)

Output:

const import_meta = {};
console.log(import_meta.url);
▲ [WARNING] "import.meta" is not available in the configured target environment ("es2019") and will be empty [empty-import-meta]

    <stdin>:1:12:
      1 │ console.log(import.meta.url)
        ╵             ~~~~~~~~~~~

But if we change that to also use supported, it works as expected and there is no warning:

Options:

{target: ['es2019'], supported: {'import-meta': true}}

Input:

console.log(import.meta.url)

Output:

console.log(import.meta.url);

As for esbuild's import.meta shim being an empty object, there are a number of issues on the esbuild GitHub repo about this/related, including:

See Also

My Other Related Deepdive Gist's and Projects

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment