vuejs/core · error · Error

[@vue/compiler-sfc] `modules` option is not supported in the

Error message

[@vue/compiler-sfc] `modules` option is not supported in the browser build.

What it means

Thrown by doCompileStyle in @vue/compiler-sfc when the CSS Modules `modules` option is requested in a browser build (__GLOBAL__ or __ESM_BROWSER__). CSS Modules need postcss-modules and a filesystem-aware resolver that the in-browser bundle does not ship. The guard at compileStyle.ts:124 hard-fails before postcssModules is ever pushed onto the plugin list.

Source

Thrown at packages/compiler-sfc/src/compileStyle.ts:124

    ? preProcessedSource.map
    : options.inMap || options.map
  const source = preProcessedSource ? preProcessedSource.code : options.source

  const shortId = id.replace(/^data-v-/, '')
  const longId = `data-v-${shortId}`

  const plugins = (postcssPlugins || []).slice()
  plugins.unshift(cssVarsPlugin({ id: shortId, isProd }))
  if (trim) {
    plugins.push(trimPlugin())
  }
  if (scoped) {
    plugins.push(scopedPlugin(longId))
  }
  let cssModules: Record<string, string> | undefined
  if (modules) {
    if (__GLOBAL__ || __ESM_BROWSER__) {
      throw new Error(
        '[@vue/compiler-sfc] `modules` option is not supported in the browser build.',
      )
    }
    if (!options.isAsync) {
      throw new Error(
        '[@vue/compiler-sfc] `modules` option can only be used with compileStyleAsync().',
      )
    }
    plugins.push(
      postcssModules({
        ...modulesOptions,
        getJSON: (_cssFileName: string, json: Record<string, string>) => {
          cssModules = json
        },
      }),
    )
  }

View on GitHub (pinned to a2b40db9a8)

Solutions

  1. Move style compilation to a build step (Vite, webpack + vue-loader) that uses the Node build of @vue/compiler-sfc, where modules is supported.
  2. If you must compile in the browser, drop the `modules` option and pre-extract the class map at build time, injecting it as data.
  3. Ensure your bundler resolves @vue/compiler-sfc to the Node CJS entry, not the *-esm-browser entry.

Example fix

// before (browser build)
import { compileStyle } from '@vue/compiler-sfc'
compileStyle({ filename: 'x.css', source: '.a{color:red}', modules: true })

// after — run in Node build during bundling
import { compileStyleAsync } from '@vue/compiler-sfc'
const { code, modules } = await compileStyleAsync({
  filename: 'x.css',
  source: '.a{color:red}',
  modules: true,
})
Defensive patterns

Strategy: validation

Validate before calling

// Reject the modules option in browser builds before compiling.
const isBrowserBuild = typeof __ESM_BROWSER__ !== 'undefined' || typeof __GLOBAL__ !== 'undefined'
function safeCompileStyle(opts) {
  if (opts.modules && (isBrowserBuild || isBrowserBundle())) {
    throw new Error('CSS modules require the Node build of @vue/compiler-sfc')
  }
  return compileStyle(opts)
}

Type guard

function isNodeCompilerSfc(): boolean {
  // True when the resolved entry is the CJS/Node build, not *-esm-browser / global.
  return typeof process !== 'undefined' && !!process.versions?.node && !__ESM_BROWSER__ && !__GLOBAL__
}

Prevention

When it happens

Trigger: Calling compileStyle({ modules: true }) from the @vue/compiler-sfc browser/global build; loading the esm-browser or global entry of compiler-sfc in the browser and requesting CSS Modules.

Common situations: Trying to do full SFC compilation (including <style module>) in the browser; shipping the browser build of compiler-sfc to a client that expects Node-grade compilation.

Related errors


AI-assisted analysis of vuejs/core@a2b40db9a8 (2026-08-12). Data as JSON: /api/errors/6ce4fb718031741c. Report an issue: GitHub.