{"record":{"id":"85e1abe32bd97418","repo":"vuejs/vue","slug":"vue-compiler-sfc-sfc-contains-no-script-tags","errorCode":null,"errorMessage":"[@vue/compiler-sfc] SFC contains no <script> tags.","messagePattern":"\\[@vue/compiler-sfc\\] SFC contains no <script> tags\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/compiler-sfc/src/compileScript.ts","lineNumber":138,"sourceCode":"    plugins.push('jsx')\n  } else {\n    // If don't match the case of adding jsx, should remove the jsx from the babelParserPlugins\n    if (options.babelParserPlugins)\n      options.babelParserPlugins = options.babelParserPlugins.filter(\n        n => n !== 'jsx'\n      )\n  }\n  if (options.babelParserPlugins) plugins.push(...options.babelParserPlugins)\n  if (isTS) {\n    plugins.push('typescript')\n    if (!plugins.includes('decorators')) {\n      plugins.push('decorators-legacy')\n    }\n  }\n\n  if (!scriptSetup) {\n    if (!script) {\n      throw new Error(`[@vue/compiler-sfc] SFC contains no <script> tags.`)\n    }\n    if (scriptLang && !isTS && scriptLang !== 'jsx') {\n      // do not process non js/ts script blocks\n      return script\n    }\n    try {\n      let content = script.content\n      let map = script.map\n      const scriptAst = _parse(content, {\n        plugins,\n        sourceType: 'module'\n      }).program\n      const bindings = analyzeScriptBindings(scriptAst.body)\n      if (cssVars.length) {\n        content = rewriteDefault(content, DEFAULT_VAR, plugins)\n        content += genNormalScriptCssVarsCode(\n          cssVars,\n          bindings,","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/vuejs/vue/blob/9e88707940088cb1f4cd7dd210c9168a50dc347c/packages/compiler-sfc/src/compileScript.ts#L120-L156","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nconst script = compileScript(descriptor, { id: 'data-v-xxx' })\n\n// after\nif (!descriptor.script && !descriptor.scriptSetup) {\n  throw new Error(`${descriptor.filename} has no <script> block; nothing to compile`)\n}\nconst script = compileScript(descriptor, { id: 'data-v-xxx' })","handlingStrategy":"validation","validationCode":"import type { SFCDescriptor } from '@vue/compiler-sfc'\n\nfunction canCompileScript(descriptor: SFCDescriptor): boolean {\n  return Boolean(descriptor.script || descriptor.scriptSetup)\n}\n\n// before calling compileScript:\nif (!canCompileScript(descriptor)) {\n  console.warn(`${descriptor.filename}: no <script> block, skipping compileScript`)\n  return null\n}\nconst script = compileScript(descriptor, { id: 'data-v-xxx' })","typeGuard":"function hasScriptBlock(descriptor: SFCDescriptor): descriptor is SFCDescriptor & { script: SFCScriptBlock } {\n  return descriptor.script != null\n}\n\nfunction hasScriptSetup(descriptor: SFCDescriptor): descriptor is SFCDescriptor & { scriptSetup: SFCScriptBlock } {\n  return descriptor.scriptSetup != null\n}","tryCatchPattern":"try {\n  const script = compileScript(descriptor, opts)\n} catch (e) {\n  if (e.message.includes('SFC contains no <script> tags')) {\n    // script-less SFC: skip compilation gracefully\n    return null\n  }\n  throw e\n}","preventionTips":["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."],"tags":["vue","compiler-sfc","sfc","script-setup","validation"],"analyzedSha":"9e88707940088cb1f4cd7dd210c9168a50dc347c","analyzedAt":"2026-08-11T22:22:01.295Z","schemaVersion":2},"datasetVersion":"2026-08-12T05:08:24.936Z"}