vuejs/vue · 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 @vue/compiler-sfc's compileScript() when the SFC descriptor passed in has neither a <script> nor a <script setup> block. The compiler needs at least one script block to produce bindings and script AST metadata; without one it cannot proceed. This indicates either a malformed SFC or that compileScript was invoked on a descriptor produced from a template-only or style-only .vue file.
Source
Thrown at packages/compiler-sfc/src/compileScript.ts:138
plugins.push('jsx')
} else {
// If don't match the case of adding jsx, should remove the jsx from the babelParserPlugins
if (options.babelParserPlugins)
options.babelParserPlugins = options.babelParserPlugins.filter(
n => n !== 'jsx'
)
}
if (options.babelParserPlugins) plugins.push(...options.babelParserPlugins)
if (isTS) {
plugins.push('typescript')
if (!plugins.includes('decorators')) {
plugins.push('decorators-legacy')
}
}
if (!scriptSetup) {
if (!script) {
throw new Error(`[@vue/compiler-sfc] SFC contains no <script> tags.`)
}
if (scriptLang && !isTS && scriptLang !== 'jsx') {
// do not process non js/ts script blocks
return script
}
try {
let content = script.content
let map = script.map
const scriptAst = _parse(content, {
plugins,
sourceType: 'module'
}).program
const bindings = analyzeScriptBindings(scriptAst.body)
if (cssVars.length) {
content = rewriteDefault(content, DEFAULT_VAR, plugins)
content += genNormalScriptCssVarsCode(
cssVars,
bindings,View on GitHub (pinned to 9e88707940)
Solutions
- Check the SFC descriptor before calling compileScript: if (!descriptor.script && !descriptor.scriptSetup) skip compilation and return early.
- Add a <script> or <script setup> block to the .vue file, even an empty export default {} is sufficient.
- If the file is intentionally script-less, route it through compileTemplate/compileStyle instead of compileScript.
Example fix
// before
const script = compileScript(descriptor, { id: 'data-v-xxx' })
// after
if (!descriptor.script && !descriptor.scriptSetup) {
throw new Error(`${descriptor.filename} has no <script> block; nothing to compile`)
}
const script = compileScript(descriptor, { id: 'data-v-xxx' }) Defensive patterns
Strategy: validation
Validate before calling
import type { SFCDescriptor } from '@vue/compiler-sfc'
function canCompileScript(descriptor: SFCDescriptor): boolean {
return Boolean(descriptor.script || descriptor.scriptSetup)
}
// before calling compileScript:
if (!canCompileScript(descriptor)) {
console.warn(`${descriptor.filename}: no <script> block, skipping compileScript`)
return null
}
const script = compileScript(descriptor, { id: 'data-v-xxx' }) Type guard
function hasScriptBlock(descriptor: SFCDescriptor): descriptor is SFCDescriptor & { script: SFCScriptBlock } {
return descriptor.script != null
}
function hasScriptSetup(descriptor: SFCDescriptor): descriptor is SFCDescriptor & { scriptSetup: SFCScriptBlock } {
return descriptor.scriptSetup != null
} Try / catch
try {
const script = compileScript(descriptor, opts)
} catch (e) {
if (e.message.includes('SFC contains no <script> tags')) {
// script-less SFC: skip compilation gracefully
return null
}
throw e
} Prevention
- Gate compileScript behind a descriptor.script || descriptor.scriptSetup check.
- Differentiate script-less SFCs early in the pipeline and route them to compileTemplate/compileStyle.
- Write a unit test that feeds a template-only .vue through your build step to confirm it does not throw.
When it happens
Trigger: Calling compileScript(descriptor, { id }) where descriptor.script and descriptor.scriptSetup are both null/undefined. This happens when a .vue file contains only <template> and/or <style> blocks, when parseComponent was given empty source, or when an integration (e.g. vue-loader plugin) routes a non-script SFC through compileScript.
Common situations: A toolchain or custom build plugin unconditionally calls compileScript on every SFC descriptor. Template-only or style-only components (rare but valid for some design-system use cases) hit this. Also triggered when an SFC is generated programmatically and the <script> tag is omitted or stripped.
Related errors
- [@vue/compiler-sfc] <script> and <script setup> must have th
- [@vue/compiler-sfc] ${msg}\n\n${filename}\n${generateCodeFra
- \n\nVue packages version mismatch:\n\n- vue@${vueVersion}\n-
- Invalid JSON bundle file: ${bundle}
- Cannot locate bundle file: ${bundle}
AI-assisted analysis of vuejs/vue@9e88707940 (2026-08-11).
Data as JSON: /api/errors/85e1abe32bd97418.
Report an issue: GitHub.