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

Same module imported and intialized twice #135

Closed
cdellacqua opened this issue Aug 6, 2021 · 8 comments
Closed

Same module imported and intialized twice #135

cdellacqua opened this issue Aug 6, 2021 · 8 comments
Labels
bug Something isn't working

Comments

@cdellacqua
Copy link

Describe the bug

When using a library that contains Svelte components a module can get initialized twice. This happens only when running Vite in development mode.

The bug occurs when you have:

  • a library containing module.js and Component.svelte. Note that Component imports module.js
  • a Svelte app that depends on that library and imports both Component and module.js

Running Vite in development mode results in module.js getting executed/initialized twice, thus causing reference mismatches and all sort of strange behavior.

On the other hand, when running Vite for bundling for production the module resolution process correctly detects that module.js has already been imported and does not replicate it in the output bundle.

Reproduction

A reproduction of this bug can be found at this repository:

https://github.com/cdellacqua/svelte-vite-double-import-demo

The repository contains an app directory with a minimal example based on the template obtained by running npm init vite@latest test-vite-svelte -- --template svelte.

It also contains svelte-vite-double-import-lib which is a minimal library that can cause this behavior.

Steps to reproduce:

  • download the repository
  • open the app directory
  • run npm install
  • run npm run dev
  • open a browser at http://localhost:3000
  • open the javascript console, you should see "module initialized" two times

Logs

> test-vite-svelte@0.0.0 dev
> vite

  vite:config native esm config loaded in 54ms URL {
  href: 'file:///home/carlo/Downloads/svelte-vite-double-import-demo-master/app/vite.config.js',
  origin: 'null',
  protocol: 'file:',
  username: '',
  password: '',
  host: '',
  hostname: '',
  port: '',
  pathname: '/home/carlo/Downloads/svelte-vite-double-import-demo-master/app/vite.config.js',
  search: '',
  searchParams: URLSearchParams {},
  hash: ''
} +0ms
  vite:vite-plugin-svelte default options for development {
  extensions: [ '.svelte' ],
  hot: { injectCss: false },
  emitCss: true,
  compilerOptions: { format: 'esm', css: false, dev: true }
} +0ms
  vite:vite-plugin-svelte no svelte config found at /home/carlo/Downloads/svelte-vite-double-import-demo-master/app +0ms
  vite:vite-plugin-svelte additional vite config {
  optimizeDeps: {
    exclude: [
      'svelte/animate',
      'svelte/easing',
      'svelte/internal',
      'svelte/motion',
      'svelte/store',
      'svelte/transition',
      'svelte',
      'svelte-hmr/runtime/hot-api-esm.js',
      'svelte-hmr/runtime/proxy-adapter-dom.js',
      'svelte-hmr'
    ]
  },
  resolve: {
    mainFields: [ 'svelte', 'module', 'jsnext:main', 'jsnext' ],
    dedupe: [
      'svelte/animate',
      'svelte/easing',
      'svelte/internal',
      'svelte/motion',
      'svelte/store',
      'svelte/transition',
      'svelte',
      'svelte-hmr/runtime/hot-api-esm.js',
      'svelte-hmr/runtime/proxy-adapter-dom.js',
      'svelte-hmr'
    ]
  }
} +0ms
  vite:vite-plugin-svelte resolved options {
  extensions: [ '.svelte' ],
  hot: { injectCss: false },
  emitCss: true,
  compilerOptions: { format: 'esm', css: false, dev: true },
  experimental: {},
  root: '/home/carlo/Downloads/svelte-vite-double-import-demo-master/app',
  isProduction: false,
  isBuild: false,
  isServe: true,
  preprocess: [ { style: [Function: style] } ]
} +3ms
  vite:config using resolved config: {
  vite:config   server: { fs: { strict: true, allow: [Array] } },
  vite:config   base: '/',
  vite:config   plugins: [
  vite:config     'vite:pre-alias',
  vite:config     'alias',
  vite:config     'vite-plugin-svelte',
  vite:config     'vite:dynamic-import-polyfill',
  vite:config     'vite:resolve',
  vite:config     'vite:html',
  vite:config     'vite:css',
  vite:config     'vite:esbuild',
  vite:config     'vite:json',
  vite:config     'vite:wasm',
  vite:config     'vite:worker',
  vite:config     'vite:asset',
  vite:config     'vite:define',
  vite:config     'vite:css-post',
  vite:config     'vite:client-inject',
  vite:config     'vite:import-analysis'
  vite:config   ],
  vite:config   optimizeDeps: {
  vite:config     exclude: [
  vite:config       'svelte/animate',
  vite:config       'svelte/easing',
  vite:config       'svelte/internal',
  vite:config       'svelte/motion',
  vite:config       'svelte/store',
  vite:config       'svelte/transition',
  vite:config       'svelte',
  vite:config       'svelte-hmr/runtime/hot-api-esm.js',
  vite:config       'svelte-hmr/runtime/proxy-adapter-dom.js',
  vite:config       'svelte-hmr'
  vite:config     ],
  vite:config     esbuildOptions: { keepNames: undefined }
  vite:config   },
  vite:config   resolve: {
  vite:config     dedupe: [
  vite:config       'svelte/animate',
  vite:config       'svelte/easing',
  vite:config       'svelte/internal',
  vite:config       'svelte/motion',
  vite:config       'svelte/store',
  vite:config       'svelte/transition',
  vite:config       'svelte',
  vite:config       'svelte-hmr/runtime/hot-api-esm.js',
  vite:config       'svelte-hmr/runtime/proxy-adapter-dom.js',
  vite:config       'svelte-hmr'
  vite:config     ],
  vite:config     mainFields: [ 'svelte', 'module', 'jsnext:main', 'jsnext' ],
  vite:config     alias: [ [Object] ]
  vite:config   },
  vite:config   configFile: '/home/carlo/Downloads/svelte-vite-double-import-demo-master/app/vite.config.js',
  vite:config   configFileDependencies: [],
  vite:config   inlineConfig: {
  vite:config     root: undefined,
  vite:config     base: undefined,
  vite:config     mode: undefined,
  vite:config     configFile: undefined,
  vite:config     logLevel: undefined,
  vite:config     clearScreen: undefined,
  vite:config     server: {}
  vite:config   },
  vite:config   root: '/home/carlo/Downloads/svelte-vite-double-import-demo-master/app',
  vite:config   publicDir: '/home/carlo/Downloads/svelte-vite-double-import-demo-master/app/public',
  vite:config   cacheDir: '/home/carlo/Downloads/svelte-vite-double-import-demo-master/app/node_modules/.vite',
  vite:config   command: 'serve',
  vite:config   mode: 'development',
  vite:config   isProduction: false,
  vite:config   build: {
  vite:config     target: [ 'es2019', 'edge88', 'firefox78', 'chrome87', 'safari13.1' ],
  vite:config     polyfillDynamicImport: false,
  vite:config     outDir: 'dist',
  vite:config     assetsDir: 'assets',
  vite:config     assetsInlineLimit: 4096,
  vite:config     cssCodeSplit: true,
  vite:config     sourcemap: false,
  vite:config     rollupOptions: {},
  vite:config     commonjsOptions: { include: [Array], extensions: [Array] },
  vite:config     dynamicImportVarsOptions: { warnOnError: true, exclude: [Array] },
  vite:config     minify: 'terser',
  vite:config     terserOptions: {},
  vite:config     cleanCssOptions: {},
  vite:config     write: true,
  vite:config     emptyOutDir: null,
  vite:config     manifest: false,
  vite:config     lib: false,
  vite:config     ssr: false,
  vite:config     ssrManifest: false,
  vite:config     brotliSize: true,
  vite:config     chunkSizeWarningLimit: 500,
  vite:config     watch: null
  vite:config   },
  vite:config   env: { BASE_URL: '/', MODE: 'development', DEV: true, PROD: false },
  vite:config   assetsInclude: [Function: assetsInclude],
  vite:config   logger: {
  vite:config     hasWarned: false,
  vite:config     info: [Function: info],
  vite:config     warn: [Function: warn],
  vite:config     warnOnce: [Function: warnOnce],
  vite:config     error: [Function: error],
  vite:config     clearScreen: [Function: clearScreen]
  vite:config   },
  vite:config   createResolver: [Function: createResolver]
  vite:config } +7ms
  vite:deps Hash is consistent. Skipping. Use --force to override. +0ms

  vite v2.4.4 dev server running at:

  > Local: http://localhost:3000/
  > Network: use `--host` to expose

  ready in 197ms.

  vite:spa-fallback Rewriting GET / to /index.html +0ms
  vite:time 24ms  /index.html +0ms
  vite:resolve 1ms   /home/carlo/Downloads/svelte-vite-double-import-demo-master/app/node_modules/vite/dist/client/client -> /home/carlo/Downloads/svelte-vite-double-import-demo-master/app/node_modules/vite/dist/client/client.mjs +0ms
  vite:resolve 3ms   /@vite/client -> /home/carlo/Downloads/svelte-vite-double-import-demo-master/app/node_modules/vite/dist/client/client.mjs +1ms
  vite:resolve 0ms   /src/main.js -> /home/carlo/Downloads/svelte-vite-double-import-demo-master/app/src/main.js +3ms
  vite:load 3ms   [fs] /@vite/client +0ms
  vite:resolve 0ms   ./env -> /home/carlo/Downloads/svelte-vite-double-import-demo-master/app/node_modules/vite/dist/client/env.mjs +11ms
  vite:resolve 0ms   /node_modules/vite/dist/client/env.mjs -> /home/carlo/Downloads/svelte-vite-double-import-demo-master/app/node_modules/vite/dist/client/env.mjs +0ms
  vite:transform 10ms  /@vite/client +0ms
  vite:time 20ms  /@vite/client +44ms
  vite:load 12ms  [fs] /src/main.js +12ms
  vite:resolve 1ms   ./App.svelte -> /home/carlo/Downloads/svelte-vite-double-import-demo-master/app/src/App.svelte +4ms
  vite:resolve 0ms   /src/App.svelte -> /home/carlo/Downloads/svelte-vite-double-import-demo-master/app/src/App.svelte +0ms
  vite:transform 1ms   /src/main.js +2ms
  vite:time 15ms  /src/main.js +2ms
  vite:load 1ms   [fs] /node_modules/vite/dist/client/env.mjs +9ms
  vite:rewrite 0ms   [no imports] node_modules/vite/dist/client/env.mjs +0ms
  vite:transform 2ms   /node_modules/vite/dist/client/env.mjs +9ms
  vite:time 4ms   /node_modules/vite/dist/client/env.mjs +9ms
  vite:load 2ms   [fs] /src/App.svelte +2ms
  vite:vite-plugin-svelte setting cssHash s-XsEmFtvddWTw for /src/App.svelte +3s
  vite:vite-plugin-svelte transform returns compiled js for /home/carlo/Downloads/svelte-vite-double-import-demo-master/app/src/App.svelte +38ms
  vite:resolve 2ms   svelte/internal -> /home/carlo/Downloads/svelte-vite-double-import-demo-master/app/node_modules/svelte/internal/index.mjs?v=b9b912b2 +50ms
  vite:resolve 0ms   /node_modules/svelte/internal/index.mjs?v=b9b912b2 -> /home/carlo/Downloads/svelte-vite-double-import-demo-master/app/node_modules/svelte/internal/index.mjs?v=b9b912b2 +1ms
  vite:resolve 0ms   @cdellacqua/svelte-vite-double-import-lib -> /home/carlo/Downloads/svelte-vite-double-import-demo-master/app/node_modules/.vite/@cdellacqua_svelte-vite-double-import-lib.js?v=b9b912b2 +0ms
  vite:resolve 0ms   /node_modules/.vite/@cdellacqua_svelte-vite-double-import-lib.js?v=b9b912b2 -> /home/carlo/Downloads/svelte-vite-double-import-demo-master/app/node_modules/.vite/@cdellacqua_svelte-vite-double-import-lib.js?v=b9b912b2 +0ms
  vite:resolve 0ms   /node_modules/svelte-hmr/runtime/hot-api-esm.js -> /home/carlo/Downloads/svelte-vite-double-import-demo-master/app/node_modules/svelte-hmr/runtime/hot-api-esm.js +1ms
  vite:resolve 0ms   /node_modules/svelte-hmr/runtime/proxy-adapter-dom.js -> /home/carlo/Downloads/svelte-vite-double-import-demo-master/app/node_modules/svelte-hmr/runtime/proxy-adapter-dom.js +0ms
  vite:hmr [self-accepts] src/App.svelte +0ms
  vite:transform 44ms  /src/App.svelte +44ms
  vite:time 49ms  /src/App.svelte +46ms
  vite:load 1ms   [fs] /node_modules/svelte-hmr/runtime/hot-api-esm.js +53ms
  vite:resolve 0ms   ../runtime/index.js -> /home/carlo/Downloads/svelte-vite-double-import-demo-master/app/node_modules/svelte-hmr/runtime/index.js +10ms
  vite:resolve 0ms   /node_modules/svelte-hmr/runtime/index.js -> /home/carlo/Downloads/svelte-vite-double-import-demo-master/app/node_modules/svelte-hmr/runtime/index.js +0ms
  vite:transform 0ms   /node_modules/svelte-hmr/runtime/hot-api-esm.js +9ms
  vite:time 1ms   /node_modules/svelte-hmr/runtime/hot-api-esm.js +7ms
  vite:load 2ms   [fs] /node_modules/svelte-hmr/runtime/proxy-adapter-dom.js +1ms
  vite:resolve 0ms   ./overlay.js -> /home/carlo/Downloads/svelte-vite-double-import-demo-master/app/node_modules/svelte-hmr/runtime/overlay.js +2ms
  vite:resolve 0ms   /node_modules/svelte-hmr/runtime/overlay.js -> /home/carlo/Downloads/svelte-vite-double-import-demo-master/app/node_modules/svelte-hmr/runtime/overlay.js +0ms
  vite:transform 1ms   /node_modules/svelte-hmr/runtime/proxy-adapter-dom.js +2ms
  vite:time 3ms   /node_modules/svelte-hmr/runtime/proxy-adapter-dom.js +2ms
  vite:resolve 1ms   /node_modules/@cdellacqua/svelte-vite-double-import-lib/Component.svelte -> /home/carlo/Downloads/svelte-vite-double-import-demo-master/app/node_modules/@cdellacqua/svelte-vite-double-import-lib/Component.svelte +1ms
  vite:load 0ms   [fs] /node_modules/@cdellacqua/svelte-vite-double-import-lib/Component.svelte +2ms
  vite:vite-plugin-svelte setting cssHash s-rPsNWTPCWvCv for /node_modules/@cdellacqua/svelte-vite-double-import-lib/Component.svelte +17ms
  vite:vite-plugin-svelte transform returns compiled js for /home/carlo/Downloads/svelte-vite-double-import-demo-master/app/node_modules/@cdellacqua/svelte-vite-double-import-lib/Component.svelte +13ms
  vite:resolve 0ms   ./utils -> /home/carlo/Downloads/svelte-vite-double-import-demo-master/app/node_modules/@cdellacqua/svelte-vite-double-import-lib/utils.js +14ms
  vite:resolve 0ms   /node_modules/@cdellacqua/svelte-vite-double-import-lib/utils.js -> /home/carlo/Downloads/svelte-vite-double-import-demo-master/app/node_modules/@cdellacqua/svelte-vite-double-import-lib/utils.js +0ms
  vite:hmr [self-accepts] node_modules/@cdellacqua/svelte-vite-double-import-lib/Component.svelte +28ms
  vite:transform 15ms  /node_modules/@cdellacqua/svelte-vite-double-import-lib/Component.svelte +16ms
  vite:load 1ms   [fs] /node_modules/svelte-hmr/runtime/index.js +16ms
  vite:resolve 0ms   ./hot-api.js -> /home/carlo/Downloads/svelte-vite-double-import-demo-master/app/node_modules/svelte-hmr/runtime/hot-api.js +3ms
  vite:resolve 0ms   /node_modules/svelte-hmr/runtime/hot-api.js -> /home/carlo/Downloads/svelte-vite-double-import-demo-master/app/node_modules/svelte-hmr/runtime/hot-api.js +0ms
  vite:transform 1ms   /node_modules/svelte-hmr/runtime/index.js +2ms
  vite:time 2ms   /node_modules/svelte-hmr/runtime/index.js +18ms
  vite:time 18ms  /node_modules/@cdellacqua/svelte-vite-double-import-lib/Component.svelte +0ms
  vite:load 1ms   [fs] /node_modules/svelte-hmr/runtime/overlay.js +1ms
  vite:rewrite 0ms   [no imports] node_modules/svelte-hmr/runtime/overlay.js +76ms
  vite:transform 0ms   /node_modules/svelte-hmr/runtime/overlay.js +1ms
  vite:time 2ms   /node_modules/svelte-hmr/runtime/overlay.js +1ms
  vite:load 1ms   [fs] /node_modules/svelte-hmr/runtime/hot-api.js +7ms
  vite:resolve 1ms   ./proxy.js -> /home/carlo/Downloads/svelte-vite-double-import-demo-master/app/node_modules/svelte-hmr/runtime/proxy.js +8ms
  vite:resolve 0ms   /node_modules/svelte-hmr/runtime/proxy.js -> /home/carlo/Downloads/svelte-vite-double-import-demo-master/app/node_modules/svelte-hmr/runtime/proxy.js +0ms
  vite:transform 1ms   /node_modules/svelte-hmr/runtime/hot-api.js +7ms
  vite:time 3ms   /node_modules/svelte-hmr/runtime/hot-api.js +7ms
  vite:load 2ms   [fs] /node_modules/@cdellacqua/svelte-vite-double-import-lib/utils.js +1ms
  vite:rewrite 0ms   [no imports] node_modules/@cdellacqua/svelte-vite-double-import-lib/utils.js +7ms
  vite:transform 0ms   /node_modules/@cdellacqua/svelte-vite-double-import-lib/utils.js +0ms
  vite:time 3ms   /node_modules/@cdellacqua/svelte-vite-double-import-lib/utils.js +1ms
  vite:load 1ms   [fs] /node_modules/svelte-hmr/runtime/proxy.js +4ms
  vite:resolve 0ms   ./svelte-hooks.js -> /home/carlo/Downloads/svelte-vite-double-import-demo-master/app/node_modules/svelte-hmr/runtime/svelte-hooks.js +5ms
  vite:resolve 0ms   /node_modules/svelte-hmr/runtime/svelte-hooks.js -> /home/carlo/Downloads/svelte-vite-double-import-demo-master/app/node_modules/svelte-hmr/runtime/svelte-hooks.js +0ms
  vite:transform 1ms   /node_modules/svelte-hmr/runtime/proxy.js +6ms
  vite:time 3ms   /node_modules/svelte-hmr/runtime/proxy.js +5ms
  vite:load 0ms   [fs] /node_modules/svelte-hmr/runtime/svelte-hooks.js +6ms
  vite:transform 0ms   /node_modules/svelte-hmr/runtime/svelte-hooks.js +4ms
  vite:time 2ms   /node_modules/svelte-hmr/runtime/svelte-hooks.js +5ms

System Info

System:
    OS: Linux 5.11 Pop!_OS 21.04
    CPU: (16) x64 AMD Ryzen 7 2700X Eight-Core Processor
    Memory: 8.07 GB / 15.64 GB
    Container: Yes
    Shell: 3.2.2 - /usr/bin/fish
  Binaries:
    Node: 14.16.1 - /usr/bin/node
    Yarn: 1.22.10 - /usr/bin/yarn
    npm: 7.10.0 - /usr/bin/npm
  Browsers:
    Chrome: 92.0.4515.107
    Firefox: 90.0

Severity

blocking all usage of vite-plugin-svelte

@cdellacqua cdellacqua added bug Something isn't working triage Awaiting triage by a project member labels Aug 6, 2021
@bluwy
Copy link
Member

bluwy commented Aug 7, 2021

Same underlying issue as #124, the workaround now is to add that library to optimizeDeps.exclude. There's a feature request to automate this at #125. The real issue is within Vite and is tracked in vitejs/vite#3910.

@cdellacqua
Copy link
Author

Thank you. When adding the library I'm using to optimizeDeps.exclude this bug doesn't occur, though I understand it's not a perfect solution.

I was wondering if excluding all possible dependencies could prevent weird behavior from ever happening (it's better to have longer build time than a buggy output), so I did this:

import {svelte} from '@sveltejs/vite-plugin-svelte';
import {readFileSync} from 'fs';

const pkg = JSON.parse(readFileSync('package.json'));

const exclude = [
	...Object.keys(pkg.devDependencies || {}),
	...Object.keys(pkg.peerDependencies || {}),
	...Object.keys(pkg.dependencies || {}),
];

export default defineConfig({
	base: './',
	plugins: [svelte()],
	optimizeDeps: {
		exclude,
	},
});

And it works most of the time, except when using import 'path/to/some-module' because then I get "Uncaught SyntaxError: The requested module '/node_modules/... does not provide an export named '...'" inside some-module.

After some testing I found out that replacing import 'path/to/some-module' with import {} from 'path/to/some-module' solves the problem, but I guess this should be another issue

@bluwy
Copy link
Member

bluwy commented Aug 7, 2021

Excluding all isn't recommended since Vite needs to pre-bundle CJS-only packages to ESM (Explanation). You might be lucky with your setup of having all its dependencies obediently exports ESM code.

Re "Uncaught SyntaxError: The requested module '/node_modules/... does not provide an export named '...'", that could be an issue of not prebundling CJS to ESM, I'm not sure why using import {} would work around that though.

@benmccann
Copy link
Member

You have to turn of source maps to use the debugger on this (otherwise they both get mapped to utils.js). The two files being loaded are:

http://localhost:3000/src/main.js
http://localhost:3000/src/App.svelte
http://localhost:3000/node_modules/.vite/@cdellacqua_svelte-vite-double-import-lib.js?v=04d0ce69 (one console.log is here)

http://localhost:3000/src/main.js
http://localhost:3000/src/App.svelte
http://localhost:3000/node_modules/.vite/@cdellacqua_svelte-vite-double-import-lib.js?v=04d0ce69
http://localhost:3000/node_modules/@cdellacqua/svelte-vite-double-import-lib/Component.svelte
http://localhost:3000/node_modules/@cdellacqua/svelte-vite-double-import-lib/utils.js (one console.log is here)

So this bug resides within the single optimized module. The optimized module should not be importing things from the non-optimized module.

@dominikg dominikg removed the triage Awaiting triage by a project member label Aug 12, 2021
@bluwy
Copy link
Member

bluwy commented Aug 17, 2021

Should we close this in favor of #125?

@cdellacqua
Copy link
Author

#125 suggests adding svelte libraries to the exclude rule, but it shares the same underline problem, so it's fine by me to close this issue in favor of it

@dominikg
Copy link
Member

automatic handling of svelte dependencies optimizeDeps has been released.

Please check if that fixes your issue https://github.com/sveltejs/vite-plugin-svelte/blob/main/packages/vite-plugin-svelte/CHANGELOG.md#100-next19

@cdellacqua
Copy link
Author

Hi @dominikg , yes it does! Awesome!

spiffytech added a commit to spiffytech/forgo that referenced this issue Jan 13, 2022
When debugging Forgo using `npm link`, Vite's pre-bundling optimization executes the `forgo` module twice ([Vite bug](vitejs/vite#3910), [Svelte bug with workarounds](sveltejs/vite-plugin-svelte#135 (comment))). It doesn't happen when using the package from npm.

This results in different code paths holding references to two different `Fragment` symbols, causing renders to fail because the two symbols aren't comparable using `===`. Using `Symbol.for()` makes all symbols named `FORGO_FRAGMENT` comparable, no matter where they come from.

Alternatively, there's a workaround to have Vite disable pre-bundling optimizations for `forgo`, but this patch makes that unnecessary.
jeswin pushed a commit to forgojs/forgo that referenced this issue Jan 14, 2022
When debugging Forgo using `npm link`, Vite's pre-bundling optimization executes the `forgo` module twice ([Vite bug](vitejs/vite#3910), [Svelte bug with workarounds](sveltejs/vite-plugin-svelte#135 (comment))). It doesn't happen when using the package from npm.

This results in different code paths holding references to two different `Fragment` symbols, causing renders to fail because the two symbols aren't comparable using `===`. Using `Symbol.for()` makes all symbols named `FORGO_FRAGMENT` comparable, no matter where they come from.

Alternatively, there's a workaround to have Vite disable pre-bundling optimizations for `forgo`, but this patch makes that unnecessary.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants