docs(start): clarify verbatimModuleSyntax must be disabled#7806
docs(start): clarify verbatimModuleSyntax must be disabled#7806galaxykhh wants to merge 3 commits into
Conversation
The build-from-scratch guides only said to keep `verbatimModuleSyntax` disabled without showing how, and didn't mention that `tsc --init` (TypeScript 5.9+ and 6.0) now generates `"verbatimModuleSyntax": true`. Add `"verbatimModuleSyntax": false` to the example tsconfig and clarify that the compiler default is still `false` while the init template opts in. Co-authored-by: Cursor <cursoragent@cursor.com>
📝 WalkthroughWalkthroughTanStack Start documentation, skills guidance, and React and Solid counter examples now explicitly configure ChangesverbatimModuleSyntax configuration
Estimated code review effort: 1 (Trivial) | ~5 minutes Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Clarify that verbatimModuleSyntax can be used but may leak server-only code into client bundles when importing types from mixed modules. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/start/framework/solid/build-from-scratch.md`:
- Line 48: Revise the `verbatimModuleSyntax` warning to clarify that only
`import type` statements are elided; inline type-only imports such as `import {
type ... }` still emit an import statement. State that regular imports used for
type-only dependencies from server-only modules can leak server code into client
bundles, while keeping the recommendation to disable the option.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 720056ae-68c9-40f7-8514-ac0bd07320db
📒 Files selected for processing (2)
docs/start/framework/react/build-from-scratch.mddocs/start/framework/solid/build-from-scratch.md
🚧 Files skipped from review as they are similar to previous changes (1)
- docs/start/framework/react/build-from-scratch.md
|
|
||
| > [!NOTE] | ||
| > Enabling `verbatimModuleSyntax` can result in server bundles leaking into client bundles. It is recommended to keep this option disabled. | ||
| > Enabling `verbatimModuleSyntax` can result in server-only code leaking into client bundles when types are imported from modules that also contain server-only code. It is recommended to keep this option disabled. |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
sed -n '35,60p' docs/start/framework/solid/build-from-scratch.md && printf '\n---\n' && python3 - <<'PY'
import urllib.request
url='https://www.typescriptlang.org/tsconfig/verbatimModuleSyntax.html'
print(urllib.request.urlopen(url, timeout=20).read().decode('utf-8')[:5000])
PYRepository: TanStack/router
Length of output: 3773
🏁 Script executed:
python3 - <<'PY'
from pathlib import Path
p=Path('docs/start/framework/solid/build-from-scratch.md')
print(p.exists(), p)
PYRepository: TanStack/router
Length of output: 207
🏁 Script executed:
sed -n '44,52p' docs/start/framework/solid/build-from-scratch.mdRepository: TanStack/router
Length of output: 669
🌐 Web query:
TypeScript verbatimModuleSyntax import type inline type specifiers erased regular imports server-only code
💡 Result:
The verbatimModuleSyntax compiler option in TypeScript (introduced in 5.0) mandates that TypeScript performs no automatic elision (removal) of import or export statements [1][2]. By default, TypeScript heuristically determines which imports are types and removes them during compilation [3][4]. When verbatimModuleSyntax is enabled, TypeScript emits import and export statements exactly as written in the source code [2][5]. Key implications include: 1. Explicit Syntax Requirements: Developers must explicitly use the type modifier for type-only imports and exports (e.g., import type { T } from 'mod' or import { type T } from 'mod') [2][4]. If an import is not marked as type, TypeScript assumes it is a value import and will include it in the emitted JavaScript, regardless of whether it is used only as a type in your TypeScript code [2][5]. 2. Handling Inline Type Specifiers: An important nuance is that when you use inline type specifiers—such as import { type A } from 'mod'—verbatimModuleSyntax ensures the type part is erased, but the import statement itself remains in the emitted code [6]. If an import declaration contains no value imports and only inline type specifiers, the resulting JavaScript will still contain an empty import (e.g., import {} from 'mod'), which effectively functions as a side-effect import [6][7]. 3. Server-Only Code and Runtime Safety: Because verbatimModuleSyntax preserves imports that are not explicitly marked as type-only, it prevents unintentional runtime errors where TypeScript might have otherwise elided an import that was actually needed at runtime [2][5]. Conversely, it can cause issues in environments like Next.js where importing from a server-only module into a client component is strictly prohibited [7]. If you import a type from a server-only file using an import declaration that contains side effects (or is not strictly a type-only import), the build tool may incorrectly flag the file as a client-side dependency, leading to errors [7]. 4. Compatibility with Node.js Type Stripping: As of 2026, verbatimModuleSyntax is recommended when working with modern Node.js environments that support native "type stripping" (or erasable syntax), as it enforces the explicit syntax required for Node.js to safely strip types without breaking runtime code execution [8][9][10].
Citations:
- 1: https://www.typescriptlang.org/tsconfig/verbatimModuleSyntax.html
- 2: https://betterstack.com/community/guides/scaling-nodejs/ts-verbatimmodulesyntax/
- 3: https://www.typescriptlang.org/tsconfig/
- 4: https://www.typescriptlang.org/docs/handbook/modules/reference
- 5: https://mergify.com/blog/typescripts-import-type-the-flag-that-makes-builds-honest/
- 6: Rule proposal: warn against import declarations with no value specifiers and only inline type specifiers typescript-eslint/typescript-eslint#6382
- 7: Importing types from "server-only" w/
"verbatimModuleSyntax": trueerrors after #90907 vercel/next.js#92025 - 8: https://nodejs.org/api/typescript.html
- 9: https://nodejs.org/docs/latest/api/typescript.html
- 10: https://www.sitepoint.com/typescript-58-erasable-syntax-running-ts-directly-in-nodejs/
🌐 Web query:
site:typescriptlang.org verbatimModuleSyntax inline type specifiers import {} from module emitted code
💡 Result:
When the verbatimModuleSyntax compiler option is enabled in TypeScript, the compiler adopts a strict policy regarding imports and exports: it does not transform or elide any import or export statements unless they are explicitly marked with the type modifier [1][2]. For imports and exports containing inline type specifiers, the behavior is as follows: 1. Type-only imports and exports: Any import or export statement that exclusively uses the type modifier (e.g., import type { A } from "a") is erased entirely from the emitted JavaScript code [1]. 2. Mixed imports and exports: If an import or export statement contains both value references and type-only references, the statement is rewritten to remove only the type-only parts [1]. 3. Imports and exports that become empty: If an import or export statement consists entirely of type specifiers (or becomes empty after removing those marked with type), the resulting import or export will be emitted as an empty declaration, such as import {} from "xyz" [1]. This behavior ensures that the emitted code remains consistent with the module format specified by your configuration, preventing TypeScript from implicitly rewriting or eliding code in ways that might conflict with your target module system [1][3].
Citations:
- 1: https://www.typescriptlang.org/tsconfig/verbatimModuleSyntax.html
- 2: https://www.typescriptlang.org/docs/handbook/compiler-options.html
- 3: https://www.typescriptlang.org/docs/handbook/modules/theory.html
🌐 Web query:
TypeScript verbatimModuleSyntax "import { type" emitted import {} from module
💡 Result:
The verbatimModuleSyntax compiler option in TypeScript (introduced in version 5.0) mandates that all import and export statements are emitted exactly as written, with no automatic elision [1][2][3]. Under this setting, TypeScript stops trying to guess whether an import is used as a value or just a type, and instead relies strictly on whether you use the type modifier [2][4]. Regarding the behavior with import { type... } and empty imports: 1. Import Transformation: When you use the type modifier on named imports, TypeScript removes only the type-specific parts during compilation [2]. 2. Emitted Empty Braces: If an import statement consists entirely of type-only named imports, such as import { type T } from "module", TypeScript will rewrite it to import {} from "module" in the emitted JavaScript [5][2]. 3. Why this happens: This behavior is a direct consequence of the verbatim principle—preserving the original module syntax as much as possible [5]. Because the statement was an import declaration, the output retains the import structure even if the named imports are empty, which effectively becomes a side-effect-only import [5][2]. This approach ensures consistency and forces developers to be explicit about their intentions regarding module usage and side effects, rather than having the compiler silently elide code [2][4]. Because it is more predictable and easier to explain, it replaces the older and more complex flags importsNotUsedAsValues and preserveValueImports [6][2].
Citations:
- 1: https://www.typescriptlang.org/tsconfig/verbatimModuleSyntax.html
- 2: https://fxzer.github.io/tsdoc-vitepress/en/tsconfig-reference/options/verbatimModuleSyntax
- 3: https://betterstack.com/community/guides/scaling-nodejs/ts-verbatimmodulesyntax/
- 4: https://www.totaltypescript.com/workshops/typescript-pro-essentials/configuring-typescript/verbatim-module-syntax-enforces-import-type
- 5:
verbatimModuleSyntaxleaves empty curly brackets in the JS output microsoft/TypeScript#62239 - 6: Add
verbatimModuleSyntax, deprecateimportsNotUsedAsValuesandpreserveValueImportsmicrosoft/TypeScript#52203
Clarify that only import type is elided. This warning can read as if any type import is safe, but import { type ... } still emits an import statement. Rephrase it to say the issue is using regular imports for type-only dependencies from server-only modules.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/start/framework/solid/build-from-scratch.md` at line 48, Revise the
`verbatimModuleSyntax` warning to clarify that only `import type` statements are
elided; inline type-only imports such as `import { type ... }` still emit an
import statement. State that regular imports used for type-only dependencies
from server-only modules can leak server code into client bundles, while keeping
the recommendation to disable the option.
Summary
"verbatimModuleSyntax": falsein the exampletsconfig.jsonfalse, whiletsc --init(TypeScript 5.9+ and 6.0) generates"verbatimModuleSyntax": trueas a recommended optionstart-counterexamples (linked from the React guide) and the Start core skill doc with the same guidanceProblem
The build-from-scratch guides warn that enabling
verbatimModuleSyntaxcan cause server-only code to leak into client bundles, but they:tsconfig.jsontsc --initnow generates"verbatimModuleSyntax": true(tsc --init update microsoft/TypeScript#61813)This is especially relevant for TypeScript 6 users who run
tsc --initbefore following the guide, since the generated config opts intoverbatimModuleSyntaxeven though the compiler default remainsfalse.Changes
docs/start/framework/react/build-from-scratch.md"verbatimModuleSyntax": falseto example tsconfig; expand NOTEdocs/start/framework/solid/build-from-scratch.mdexamples/react/start-counter/tsconfig.json"verbatimModuleSyntax": falseexamples/solid/start-counter/tsconfig.jsonpackages/start-client-core/skills/start-core/SKILL.mdtsc --initbehaviorTest plan
tsconfig.jsonfiles remain valid JSONSummary by CodeRabbit
Documentation
verbatimModuleSyntax.false,tsc --initmay set it totrue(TypeScript 5.9+/6.0), sotsconfig.jsonshould explicitly set"verbatimModuleSyntax": false.Configuration
tsconfig.jsonfiles to setverbatimModuleSyntaxtofalse.