Skip to content

Inconsistent compilation of CSS Modules between dev and build commands when using ?url query param #13416

Description

@stefanmaric

Describe the bug

Hi everyone 👋

I'm trying to workaround #13401 by manually listing CSS Modules I want to manipulate on the client-side but the contents of the transformed asset differs between vite dev and vite build, to be more specific, in dev the CSS class names are property hashed as I would expect for a .module.css file but they are not after vite build.

For the reproduction project, I have an Isolated.module.css file:

.ImportantText {
  color: red;
  font-weight: bold;
}

Which I'm importing as follows:

import IsolatedUrl from './Isolated.module.css?url';

Then I'm logging the URL string, fetching such file, and redering its contents on the page:

// log the URL string to the console
console.log(IsolatedUrl);

// Get the contents for the URL string
fetch(IsolatedUrl, { headers: { Accept: 'text/css' } })
  .then(async (response) => {
    const content = await response.text();

    // Simply render it pretty on the page for easy debugging
    const container = document.createElement('div');
    container.innerHTML = `
<pre style="max-width: 28rem; overflow: auto; text-align: left;">
  <code>
${content}
  </code>
</pre>
  `;

    document.querySelector('#app').appendChild(container);
  })
  .catch(console.error);

Reproduction

https://stackblitz.com/edit/vitejs-vite-pj3wxw?file=main.js

Steps to reproduce

Open the reproduction project.

You will see the content of the CSS Module on the page. CSS Class Names will be hashed, e.g.:

._ImportantText_yuz6n_1 {
  color: red;
  font-weight: bold;
}

Open a new Terminal in the StackBlitz UI and run the preview script:

npm run preview

It will compile and serve the compiled project on port 4173 and StackBlitz should replace the browser view on the right side to point to the new port automatically.

On the new page you will see that the CSS Class Names are not hashed, e.g.:

.ImportantText {
  color: red;
  font-weight: bold;
}

System Info

System:
    OS: Linux 5.0 undefined
    CPU: (8) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
    Memory: 0 Bytes / 0 Bytes
    Shell: 1.0 - /bin/jsh
  Binaries:
    Node: 16.14.2 - /usr/local/bin/node
    Yarn: 1.22.19 - /usr/local/bin/yarn
    npm: 7.17.0 - /usr/local/bin/npm
  npmPackages:
    vite: ^4.3.9 => 4.3.9

Used Package Manager

npm

Logs

$ vite build --debug
  vite:config bundled config file loaded in 244.44ms +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: true,
  vite:config     sourcemap: true,
  vite:config     rollupOptions: {},
  vite:config     minify: false,
  vite:config     terserOptions: {},
  vite:config     write: true,
  vite:config     emptyOutDir: null,
  vite:config     copyPublicDir: true,
  vite:config     manifest: true,
  vite:config     lib: false,
  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     cssMinify: false,
  vite:config     commonjsOptions: { include: [Array], extensions: [Array] },
  vite:config     dynamicImportVarsOptions: { warnOnError: true, exclude: [Array] },
  vite:config     modulePreload: { polyfill: true }
  vite:config   },
  vite:config   optimizeDeps: {
  vite:config     disabled: 'build',
  vite:config     force: undefined,
  vite:config     esbuildOptions: { preserveSymlinks: false }
  vite:config   },
  vite:config   configFile: '/home/projects/vitejs-vite-pj3wxw/vite.config.ts',
  vite:config   configFileDependencies: [ '/home/projects/vitejs-vite-pj3wxw/vite.config.ts' ],
  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     optimizeDeps: { force: undefined },
  vite:config     build: {}
  vite:config   },
  vite:config   root: '/home/projects/vitejs-vite-pj3wxw',
  vite:config   base: '/',
  vite:config   rawBase: '/',
  vite:config   resolve: {
  vite:config     mainFields: [ 'module', 'jsnext:main', 'jsnext' ],
  vite:config     browserField: true,
  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: '/home/projects/vitejs-vite-pj3wxw/public',
  vite:config   cacheDir: '/home/projects/vitejs-vite-pj3wxw/node_modules/.vite',
  vite:config   command: 'build',
  vite:config   mode: 'production',
  vite:config   ssr: {
  vite:config     format: 'esm',
  vite:config     target: 'node',
  vite:config     optimizeDeps: { disabled: true, esbuildOptions: [Object] }
  vite:config   },
  vite:config   isWorker: false,
  vite:config   mainConfig: null,
  vite:config   isProduction: true,
  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     '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:manifest',
  vite:config     'vite:reporter',
  vite:config     'vite:load-fallback'
  vite:config   ],
  vite:config   esbuild: { jsxDev: false },
  vite:config   server: {
  vite:config     preTransformRequests: true,
  vite:config     sourcemapIgnoreList: [Function: isInNodeModules],
  vite:config     middlewareMode: false,
  vite:config     fs: { strict: true, allow: [Array], deny: [Array] }
  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: '/home/projects/vitejs-vite-pj3wxw',
  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_/home/projects/vitejs-vite-pj3wxw' => {
  vite:config       dir: '/home/projects/vitejs-vite-pj3wxw',
  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   worker: {
  vite:config     format: 'iife',
  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       '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:worker-post',
  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:load-fallback'
  vite:config     ],
  vite:config     rollupOptions: {},
  vite:config     getSortedPlugins: [Function: getSortedPlugins],
  vite:config     getSortedPluginHooks: [Function: getSortedPluginHooks]
  vite:config   },
  vite:config   appType: 'spa',
  vite:config   experimental: { importGlobRestoreExtension: false, hmrPartialAccept: false },
  vite:config   getSortedPlugins: [Function: getSortedPlugins],
  vite:config   getSortedPluginHooks: [Function: getSortedPluginHooks]
  vite:config } +18ms
vite v4.3.9 building for production...
transforming (1) index.html  vite:esbuild 334.94ms tsconfck init /home/projects/vitejs-vite-pj3wxw +0ms
✓ 9 modules transformed.
dist/manifest.json                   0.41 kB │ gzip: 0.19 kB
dist/index.html                      0.45 kB │ gzip: 0.30 kB
dist/assets/javascript-8dac5379.svg  1.00 kB │ gzip: 0.60 kB
dist/assets/index-c8247773.css       1.63 kB │ gzip: 0.75 kB
dist/assets/index-d9330be8.js        2.95 kB │ gzip: 1.29 kB │ map: 3.06 kB
✓ built in 720ms

Validations

Metadata

Metadata

Assignees

No one assigned

    Labels

    inconsistencyInconsistency between dev & buildp3-minor-bugAn edge case that only affects very specific usage (priority)

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    Has plan

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions