vitejs / vite

Next generation frontend tooling. It's fast!
http://vitejs.dev
MIT License
67.17k stars 6.04k forks source link

bug: Inconsistent path separator in resolveId() on Windows #17715

Closed maxpatiiuk closed 1 month ago

maxpatiiuk commented 1 month ago

Describe the bug

In most places Vite is using POSIX path separators even on Windows (i.e in config.root, file identifiers and etc).

However, there is one place where this is inconsistent and platform path separators are used:

If build.lib.entry includes a virtual file, the resolveId() hook in plugins will be called:

  build: {
    lib: {
      formats: ["es"],
      entry: "virtual-file.js",
    },
  },

The resolveId() is called with an absolute path (process.cwd() + '/virtual-file.js') that uses the platform's path separator (\ on Windows), rather than POSIX path separator

This is inconsistent behavior and lead to a bug in my plugin on Windows.

Reproduction

https://github.com/maxpatiiuk/vite-inconsistent-resolve-id

Steps to reproduce

  1. Use Windows machine

  2. Clone the reproduction repository

    git clone https://github.com/maxpatiiuk/vite-inconsistent-resolve-id
  3. Install dependencies

    npm install
  4. Run build

    npx vite build
  5. See build output show a message like resolveId called with C:\Users\root\... rather than resolveId called with C:/Users/root/...

System Info

System:
    OS: Windows 10 10.0.19045
    CPU: (2) x64 Intel(R) Xeon(R) Gold 6342 CPU @ 2.80GHz
    Memory: 3.27 GB / 7.50 GB
  Binaries:
    Node: 20.14.0 - C:\Program Files\nodejs\node.EXE     
    npm: 10.7.0 - C:\Program Files\nodejs\npm.CMD        
  Browsers:
    Edge: Chromium (126.0.2592.102)
    Internet Explorer: 11.0.19041.4355

Used Package Manager

npm

Logs

Click to expand! ```shell vite:config bundled config file loaded in 173.20ms +0ms vite:config using resolved config: { vite:config build: { vite:config target: [ 'es2020', 'edge88', 'firefox78', 'chrome87', 'safari14' ], vite:config cssTarget: [ 'es2020', 'edge88', 'firefox78', 'chrome87', 'safari14' ], vite:config outDir: 'dist', vite:config assetsDir: 'assets', vite:config assetsInlineLimit: 4096, vite:config cssCodeSplit: false, vite:config sourcemap: false, vite:config rollupOptions: {}, vite:config minify: 'esbuild', vite:config terserOptions: {}, vite:config write: true, vite:config emptyOutDir: null, vite:config copyPublicDir: true, vite:config manifest: false, vite:config lib: { formats: [Array], entry: 'virtual-file.js' }, vite:config ssr: false, vite:config ssrManifest: false, vite:config ssrEmitAssets: false, vite:config reportCompressedSize: true, vite:config chunkSizeWarningLimit: 500, vite:config watch: null, vite:config commonjsOptions: { include: [Array], extensions: [Array] }, vite:config dynamicImportVarsOptions: { warnOnError: true, exclude: [Array] }, vite:config modulePreload: { polyfill: true }, vite:config cssMinify: true vite:config }, vite:config plugins: [ vite:config 'vite:build-metadata', vite:config 'vite:watch-package-data', vite:config 'vite:pre-alias', vite:config 'alias', vite:config 'vite:modulepreload-polyfill', vite:config 'vite:resolve', vite:config 'vite:html-inline-proxy', vite:config 'vite:css', vite:config 'vite:esbuild', vite:config 'vite:json', vite:config 'vite:wasm-helper', vite:config 'vite:worker', vite:config 'vite:asset', vite:config 'resolve-id', vite:config 'vite:wasm-fallback', vite:config 'vite:define', vite:config 'vite:css-post', vite:config 'vite:build-html', vite:config 'vite:worker-import-meta-url', vite:config 'vite:asset-import-meta-url', vite:config 'vite:force-systemjs-wrap-complete', vite:config 'commonjs', vite:config 'vite:data-uri', vite:config 'vite:dynamic-import-vars', vite:config 'vite:import-glob', vite:config 'vite:build-import-analysis', vite:config 'vite:esbuild-transpile', vite:config 'vite:terser', vite:config 'vite:reporter', vite:config 'vite:load-fallback' vite:config ], vite:config configFile: 'C:/Users/mak13180/Documents/arcgis-web-components/packages/test-packages/vite-inconsistent-resolve-id/vite.config.ts', vite:config configFileDependencies: [ vite:config 'C:/Users/mak13180/Documents/arcgis-web-components/packages/test-packages/vite-inconsistent-resolve-id/vite.config.ts' vite:config ], 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 build: {} vite:config }, vite:config root: 'C:/Users/mak13180/Documents/arcgis-web-components/packages/test-packages/vite-inconsistent-resolve-id', vite:config base: '/', vite:config rawBase: '/', vite:config resolve: { vite:config mainFields: [ 'browser', 'module', 'jsnext:main', 'jsnext' ], vite:config conditions: [], vite:config extensions: [ vite:config '.mjs', '.js', vite:config '.mts', '.ts', vite:config '.jsx', '.tsx', vite:config '.json' vite:config ], vite:config dedupe: [], vite:config preserveSymlinks: false, vite:config alias: [ [Object], [Object] ] vite:config }, vite:config publicDir: 'C:/Users/mak13180/Documents/arcgis-web-components/packages/test-packages/vite-inconsistent-resolve-id/public', vite:config cacheDir: 'C:/Users/mak13180/Documents/arcgis-web-components/packages/test-packages/vite-inconsistent-resolve-id/node_modules/.vite', vite:config command: 'build', vite:config mode: 'production', vite:config ssr: { vite:config target: 'node', vite:config optimizeDeps: { noDiscovery: true, esbuildOptions: [Object] } vite:config }, vite:config isWorker: false, vite:config mainConfig: null, vite:config bundleChain: [], vite:config isProduction: true, vite:config css: { lightningcss: undefined }, vite:config esbuild: { jsxDev: false }, vite:config server: { vite:config preTransformRequests: true, vite:config sourcemapIgnoreList: [Function: isInNodeModules$1], vite:config middlewareMode: false, vite:config fs: { vite:config strict: true, vite:config allow: [Array], vite:config deny: [Array], vite:config cachedChecks: undefined vite:config } vite:config }, vite:config preview: { vite:config port: undefined, vite:config strictPort: undefined, vite:config host: undefined, vite:config https: undefined, vite:config open: undefined, vite:config proxy: undefined, vite:config cors: undefined, vite:config headers: undefined vite:config }, vite:config envDir: 'C:/Users/mak13180/Documents/arcgis-web-components/packages/test-packages/vite-inconsistent-resolve-id', vite:config env: { BASE_URL: '/', MODE: 'production', DEV: false, PROD: true }, 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 hasErrorLogged: [Function: hasErrorLogged] vite:config }, vite:config packageCache: Map(1) { vite:config 'fnpd_C:/Users/mak13180/Documents/arcgis-web-components/packages/test-packages/vite-inconsistent-resolve-id' => { vite:config dir: 'C:/Users/mak13180/Documents/arcgis-web-components/packages/test-packages/vite-inconsistent-resolve-id', vite:config data: [Object], vite:config hasSideEffects: [Function: hasSideEffects], vite:config webResolvedImports: {}, vite:config nodeResolvedImports: {}, vite:config setResolvedCache: [Function: setResolvedCache], vite:config getResolvedCache: [Function: getResolvedCache] vite:config }, vite:config set: [Function (anonymous)] vite:config }, vite:config createResolver: [Function: createResolver], vite:config optimizeDeps: { vite:config holdUntilCrawlEnd: true, vite:config esbuildOptions: { preserveSymlinks: false } vite:config }, vite:config worker: { format: 'iife', plugins: '() => plugins', rollupOptions: {} }, vite:config appType: 'spa', vite:config experimental: { importGlobRestoreExtension: false, hmrPartialAccept: false }, vite:config getSortedPlugins: [Function: getSortedPlugins], vite:config getSortedPluginHooks: [Function: getSortedPluginHooks] vite:config } +57ms vite v5.3.1 building for production... resolveId called with: C:\Users\mak13180\Documents\arcgis-web-components\packages\test-packages\vite-inconsistent-resolve-id\virtual-file.js ✓ 1 modules transformed. dist/vite-project.js 0.03 kB │ gzip: 0.05 kB ✓ built in 285ms ```

Validations

bluwy commented 1 month ago

I'm not sure this is exactly a bug. In the resolveId hook, the given id isn't guaranteed to be normalized (the term used by Vite for forward slash only paths), what Vite guarantees within its plugins and encourages others plugins to do so, is that resolved ids (returned from resolveId hook) are normalized.

Non-normalized path can also happen if user writes imports like import "foo\\bar" or import "C:\\foo\\bar", which they will be passed to resolveId as is.

Your plugin should be updated in this case to handle backslashes.