vite: Bad handle of (dynamic) optional dependencies during dependency pre-bundling

Describe the bug

Hello,

First of all, thank you for developping this awesome tool. I use it on many projects now as the replacement of my old but stable toolchain.

Let’s get into this issue: I’m maintainer of the library svelte-query which uses an optional dependency (broadcast-channel) to provide an opt-in feature.

When developers install the library on a vite project, vite is throwing an error: Failed to resolve import "broadcast-channel" (SvelteStack/svelte-query#63).

However, this dependency is imported dynamically only when the developper actually use the associated feature.

I think, there are two options to resolve this issue:

  1. Delay the pre-bundling of dynamic imports when they are actually imported (best IMHO)
  2. If solution 1 is not acceptable, maybe we could only delay pre-bundling of dynamic imports that are referenced in optionalDependencies in the package.json.

The only workaround I found is to install the optional dependency even if it’s not used. I tried to include @sveltestack/svelte-query, broadcast-channel or both in optimizeDeps.exclude but it’s not enough to workaround this issue.

I’m not familiar with vite code but I’m happy to help if needed.

Reproduction

1/ Start by creating a fresh project using create-vite:

$ npm init vite
✔ Project name: … vite-project
✔ Select a framework: › svelte
✔ Select a variant: › svelte-ts

$ cd vite-project
$ npm install

2/ Install svelte-query dependency:

$ npm install @sveltestack/svelte-query

3/ Use it in your code (eg: App.svelte):

<script lang="ts">
  // append this at the end of imports
  import { QueryClientProvider } from "@sveltestack/svelte-query";
</script>

<QueryClientProvider>
  <!-- The content of the page -->
</QueryClientProvider>

4/ Run the project:

$ npm run dev

System Info

System:
    OS: Linux 5.10 Ubuntu 20.04.3 LTS (Focal Fossa)
    CPU: (8) x64 Intel(R) Core(TM) i7-1065G7 CPU @ 1.30GHz
    Memory: 1.63 GB / 7.57 GB
    Container: Yes
    Shell: 5.0.17 - /bin/bash
  Binaries:
    Node: 16.13.0 - ~/.nvm/versions/node/v16.13.0/bin/node
    Yarn: 1.22.5 - /usr/bin/yarn
    npm: 8.1.0 - ~/.nvm/versions/node/v16.13.0/bin/npm
  npmPackages:
    vite: ^2.7.0 => 2.7.1

Used Package Manager

npm

Logs

[vite] Internal server error: Failed to resolve import "broadcast-channel" from "node_modules/@sveltestack/svelte-query/svelte/queryCore/broadcastQueryClient-experimental/index.js". Does the file exist?
  Plugin: vite:import-analysis
  File: /projects/vite-project/node_modules/@sveltestack/svelte-query/svelte/queryCore/broadcastQueryClient-experimental/index.js
  1  |  import '../core';
  2  |  export async function broadcastQueryClient({ queryClient, broadcastChannel = 'svelte-query', }) {
  3  |      const { BroadcastChannel } = await import('broadcast-channel');
     |                                                ^
  4  |      let transaction = false;
  5  |      const tx = (cb) => {
      at formatError (/projects/vite-project/node_modules/vite/dist/node/chunks/dep-3daf770c.js:42587:46)
      at TransformContext.error (/projects/vite-project/node_modules/vite/dist/node/chunks/dep-3daf770c.js:42583:19)
      at normalizeUrl (/projects/vite-project/node_modules/vite/dist/node/chunks/dep-3daf770c.js:80909:26)
      at async TransformContext.transform (/projects/vite-project/node_modules/vite/dist/node/chunks/dep-3daf770c.js:81049:57)
      at async Object.transform (/projects/vite-project/node_modules/vite/dist/node/chunks/dep-3daf770c.js:42803:30)
      at async doTransform (/projects/vite-project/node_modules/vite/dist/node/chunks/dep-3daf770c.js:57478:29)

Validations

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 15
  • Comments: 18 (11 by maintainers)

Commits related to this issue

Most upvoted comments

I’m having this exact same issue in a SvelteKit project! Even in a try catch, we get the same error about vite:import-analysis

let dependency;

try {
    dependency = (await import('@org/dependency')).default;
} catch {
    //
}

We recently migrated from rollup to Vite and now our old code doesn’t work which is super annoying.

@IanVS thanks again for your suggestion. I wound up using a different work-around – inspired by another issue you opened: #5728 [Feature request] Allow import.meta.glob from node_modules (addressed by PR #6056).

I am now loading the optional dep using:

const modules = import.meta.glob('/node_modules/chartiq/{js,css}/*.{js,css}');

…and then checking Object.keys(modules).length / importing the modules I need if available. Works great / no vite:import-analysis errors.

My only slight hesitancy with this approach is that it’s a Vite-specific feature. But given that it’s a work-around to a Vite-specific issue … and this is in a SvelteKit app (no real likelihood of moving away from Vite) … I’m fine with that.

@kenkunz this is the workaround I arrived at, in addition to optimizeDeps.exclude: https://github.com/storybookjs/builder-vite/pull/320/files#diff-53261c79d121de43b9341f7d87ba28d33c2cdac416c10b0ccf5022f767937e91R68-R75.

Basically, inside a plugin, I have:

resolveId(source) {
      // Avoid error in react < 18 projects
      if (source === 'react-dom/client') {
        try {
          return require.resolve('react-dom/client', { paths: [projRoot] });
        } catch (e) {
          // This is not a react 18 project, need to stub out to avoid error
          return path.resolve(__dirname, '..', 'input', 'react-dom-client-placeholder.js');
        }
      }
    },

Where the react-dom-client-placeholder.js is an actual real file, but is empty. I get a warning about generating an empty chunk during build, but it doesn’t cause any problems as far as I can tell.