vuejs/core · error · Error

[@vue/compiler-sfc] SFC contains no <script> tags.

Error message

[@vue/compiler-sfc] SFC contains no <script> tags.

What it means

Thrown by compileScript in @vue/compiler-sfc when the SFC has neither a <script setup> nor a normal <script> block. compileScript exists to transform script blocks; with nothing to transform it cannot produce a component module. The guard at compileScript.ts:197 fires inside the !scriptSetup / !script branch.

Source

Thrown at packages/compiler-sfc/src/compileScript.ts:197

  const { script, scriptSetup, source, filename } = sfc
  const hoistStatic = options.hoistStatic !== false && !script
  const scopeId = options.id ? options.id.replace(/^data-v-/, '') : ''
  const scriptLang = script && script.lang
  const scriptSetupLang = scriptSetup && scriptSetup.lang
  const isJSOrTS =
    isJS(scriptLang, scriptSetupLang) || isTS(scriptLang, scriptSetupLang)

  if (script && scriptSetup && scriptLang !== scriptSetupLang) {
    throw new Error(
      `[@vue/compiler-sfc] <script> and <script setup> must have the same ` +
        `language type.`,
    )
  }

  if (!scriptSetup) {
    if (!script) {
      throw new Error(`[@vue/compiler-sfc] SFC contains no <script> tags.`)
    }

    // normal <script> only
    if (script.lang && !isJSOrTS) {
      // do not process non js/ts script blocks
      return script
    }

    const ctx = new ScriptCompileContext(sfc, options)
    return processNormalScript(ctx, scopeId)
  }

  if (scriptSetupLang && !isJSOrTS) {
    // do not process non js/ts script blocks
    return scriptSetup
  }

  const ctx = new ScriptCompileContext(sfc, options)

View on GitHub (pinned to a2b40db9a8)

Solutions

  1. If the SFC is intentionally script-less, skip compileScript and rely on compileTemplate/compileStyle only.
  2. Add a <script setup> block (even an empty one) to give the SFC a component module.
  3. In build-tool integration code, gate the compileScript call on sfc.script || sfc.scriptSetup before invoking it.
  4. Verify the SFC source was not corrupted by a preprocessor that removed the script block.

Example fix

// before
<template><div>hi</div></template>
<style>.x{}</style>

// after
<template><div>hi</div></template>
<script setup lang="ts"></script>
<style>.x{}</style>
Defensive patterns

Strategy: validation

Validate before calling

// Only call compileScript when there is something to compile.
function shouldCompileScript(sfc: { script?: unknown; scriptSetup?: unknown }) {
  return !!(sfc.script || sfc.scriptSetup)
}
// usage:
if (shouldCompileScript(sfc)) {
  compileScript(sfc, opts)
}

Type guard

function sfcHasScript(sfc: { script?: unknown; scriptSetup?: unknown }): boolean {
  return Boolean(sfc?.script || sfc?.scriptSetup)
}

Prevention

When it happens

Trigger: Calling compileScript() on an SFC whose source only contains <template> and/or <style>; passing an SFC descriptor that was parsed from a template-only or style-only file.

Common situations: A genuinely script-less SFC being fed through a codegen pipeline that assumes a script block; a build tool (Vite plugin, vue-loader) invoking compileScript unconditionally for every .vue file including ones intended to be template/style only; a malformed SFC where the script tag was stripped by a preprocessor.

Related errors


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