sveltejs / vite-plugin-svelte

Svelte plugin for https://vite.dev
MIT License
869 stars 106 forks source link

Same module imported and intialized twice #135

Closed cdellacqua closed 3 years ago

cdellacqua commented 3 years ago

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:

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:

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

bluwy commented 3 years ago

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 https://github.com/vitejs/vite/issues/3910.

cdellacqua commented 3 years ago

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 commented 3 years ago

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 commented 3 years ago

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.

bluwy commented 3 years ago

Should we close this in favor of #125?

cdellacqua commented 3 years ago

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 commented 3 years ago

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 commented 3 years ago

Hi @dominikg , yes it does! Awesome!