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

ESbuild loader Plugin: Dynamic Imports do not contain "with" information #3797

Closed
tiagomta opened this issue Jun 8, 2024 · 3 comments
Closed

Comments

@tiagomta
Copy link

tiagomta commented Jun 8, 2024

Hi,

I've noticed when using a custom plugin for esbuild dynamic imports behave differently from static imports, not sure if this is per design or a bug, so posting here.
I was expecting this two lines of code to behave the same

import env from "./env.txt" with { type: "env" }; // uses the .env instead of txt
const env2 = (await import("./env.txt", { with: { type: "env" }, }))?.default; // Uses the default for txt which is text
I've checked and the On-load arguments comes has: [Arguments] { '0': { path: '***', namespace: 'file', suffix: '', pluginData: undefined, with: {} } }

@evanw
Copy link
Owner

evanw commented Jun 9, 2024

How do you reproduce this? Here's what I tried:

require('esbuild').build({
  bundle: true,
  write: false,
  stdin: {
    contents: `
      import 'foo' with { type: 'foo' }
      import('bar', { with: { type: 'bar' } })
    `,
  },
  plugins: [{
    name: 'example',
    setup(build) {
      build.onResolve({ filter: /./ }, args => {
        return { path: args.path, namespace: 'temp' }
      })
      build.onLoad({ filter: /./ }, args => {
        console.log({ path: args.path, with: args.with })
        return { contents: args.path }
      })
    },
  }],
})

That prints this, which seems to work fine:

{ path: 'bar', with: { type: 'bar' } }
{ path: 'foo', with: { type: 'foo' } }

Marking as unactionable because the issue reporting instructions weren't followed (no reproduction instructions were provided).

@tiagomta
Copy link
Author

tiagomta commented Jun 9, 2024

Hi @evanw,

Yeah, the example to this is a bit more complex than that, but I was able to reproduce this using a example like that.
I've found out that this only happens when the path is dynamic, here is an example:

import { build } from "esbuild";
import path from "path";
import { readFileSync } from "fs";

const { outputFiles } = await build({
  entryPoints: ["./code.js"],
  bundle: true,
  write: false,
  format: "esm",
  plugins: [
    {
      name: "demo",
      setup: (build) => (
        build.onResolve({ filter: /.*/ }, resolve.bind(this)),
        build.onLoad({ filter: /.*/ }, load.bind(this))
      ),
    },
  ],
});

function resolve(args) {
  return { path: path.resolve(args.path) }
}

function load(args) {
  if (args.with.type === "reader") return { contents: readFileSync(args.path, "utf8") };
  return { contents: readFileSync(args.path, "utf8"), loader: "js" };
}

this is the main script, then we have the "code.js":

import "./README.md" with { type: "reader" };
const target = "example";
const test = await import(`./${target}/README.md`, {
  with: { type: "reader" },
});
console.log(test);

Then for this to behave unexpectedly, I had multiple folders with a README.md file, and when the esbuild tries to parse them, it does not use the "with reader", uses the default javascript

@evanw evanw removed the unactionable label Jun 9, 2024
@evanw
Copy link
Owner

evanw commented Jun 9, 2024

Thanks, I can reproduce the issue. Glob-style imports should support import attributes. This problem also affects uses of glob-style imports that don't involve plugins at all.

@evanw evanw closed this as completed in 953dae9 Jun 9, 2024
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

2 participants