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

Dynamic import not resolved during build #3764

Open
Paul-Browne opened this issue May 13, 2024 · 1 comment
Open

Dynamic import not resolved during build #3764

Paul-Browne opened this issue May 13, 2024 · 1 comment

Comments

@Paul-Browne
Copy link

I have this simple client-side SPA router that will dynamically import a script based on the url eg. example.com/foo/bar will fire a request for example.com/js/pages/foo/bar.js

I'm handling 404's in the catch statement like so:

const router = async () => {
    const path = window.location.pathname;
    const resourcePath = `/js/pages${path}.js`.replace("/.js", ".js");
    try {
        (await import(resourcePath)).default({ state: window.state });
    } catch {
        console.error(`Page not found: ${resourcePath}`);
        (await import('/js/pages/404.js')).default({ state: window.state });
    }
}

The problem is that the build is trying to resolve the 404 import at build time.
And even thought the file exists, it still doesn't find it...

✘ [ERROR] Could not resolve "/js/pages/404.js"

    src/js/spa_router.js:10:22:
      10 │         (await import('/js/pages/404.js')).default({ state: window.state });
         ╵                       ~~~~~~~~~~~~~~~~~~

Error: Build failed with 1 error:
src/js/spa_router.js:10:22: ERROR: Could not resolve "/js/pages/404.js"

wrapping the 404 import in another try-catch solves the problem and the builder works just fine, but it shouldn't need to be done this way IMO. And I don't understand why it doesn't find the 404.js (yes, very ironic)

const router = async () => {
    const path = window.location.pathname;
    const resourcePath = `/js/pages${path}.js`.replace("/.js", ".js");
    try {
        (await import(resourcePath)).default({ state: window.state });
    } catch {
        console.error(`Page not found: ${resourcePath}`);
        try {
            (await import('/js/pages/404.js')).default({ state: window.state });
        } catch {}
    }
}

This is the build script

await esbuild.build({
    entryPoints: ['src/js/**/*.js'],
    bundle: true,
    minify: true,
    sourcemap: true,
    splitting: true,
    treeShaking: true,
    format: "esm",
    target: "esnext",
    outdir: 'public/js'
})
@hyrious
Copy link

hyrious commented May 13, 2024

This is because "/js/pages/404.js" is an absolute path. esbuild runs its node-behavior resolver against those paths in import(path) and require(path) and includes (bundles) them in the bundle. There's no such file with the absolute path in your file system.

If it is in a single build (i.e. in one esbuild.build() call), you can reference 404.js with relative path, e.g. "./pages/404.js".

On the other hand, you may mark this path as external through a plugin, roughly look like this:

var custom_external_plugin = {
  name: "custom-external",
  setup({ onResolve }) {
    onResolve({ filter: /404\.js$/ }, args => {
      return { path: args.path, external: true }
    })
  }
}

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