The Biome linter rule nursery/noSyncScripts incorrectly flags <script type="module"> tags as synchronous scripts, requesting the addition of defer or async attributes. This is unnecessary and incorrect because module scripts are automatically deferred by specification.
When running Biome with the noSyncScripts rule enabled:
npm run checkOutput:
index.html:10:5 lint/nursery/noSyncScripts
ℹ Unexpected synchronous script.
8 │ <body>
9 │ <div id="root"></div>
> 10 │ <script type="module" src="./src/entrypoint.tsx"></script>
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
11 │ </body>
12 │ </html>
ℹ Synchronous scripts can impact your webpage performance. Add the "async" or
"defer" attribute.
According to the MDN Web Docs - JavaScript Modules:
3. Modules are deferred automatically
Modules are automatically executed in defer mode. This means that:
- Module scripts are downloaded in parallel to parsing the HTML
- Module scripts are executed after the document has been parsed
- The relative order of multiple module scripts is preserved
This behavior is defined in the HTML Standard and is consistent across all modern browsers.
| Script Type | Blocks HTML Parsing | Execution Timing | Needs defer/async |
|---|---|---|---|
<script src="..."> |
✅ Yes | Immediately | ✅ Yes |
<script type="module" src="..."> |
❌ No | After DOM ready (deferred) | ❌ No |
<script defer src="..."> |
❌ No | After DOM ready | N/A |
<script async src="..."> |
❌ No | ASAP (unordered) | N/A |
The noSyncScripts rule should ignore <script> tags that have type="module" because:
- They are inherently non-blocking
- They are automatically deferred by the browser
- Adding
deferorasyncto a module script is redundant and has no effect - Module scripts already provide optimal performance characteristics
npm installnpm run checkYou'll see the false positive warning on line 10 of index.html.
biome.jsonc:
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="./src/entrypoint.tsx"></script>
</body>
</html>The noSyncScripts rule should be updated to:
- Skip validation for
<script>tags withtype="module" - Only flag classic
<script>tags withoutdeferorasyncattributes - Optionally provide an informational message explaining that module scripts are already deferred
- MDN - JavaScript Modules: Other differences between modules and classic scripts (Point #3)
- HTML Living Standard - Script Types
- MDN -
<script>: The Script element
- Biome Version: 2.3.6
- Rule:
nursery/noSyncScripts - Affected Files: HTML files with
<script type="module">
Note: This repository exists solely to demonstrate and document this issue for the Biome team. No workaround or fix is implemented here intentionally, as the rule itself needs to be corrected.
{ "$schema": "https://biomejs.dev/schemas/2.3.6/schema.json", "files": { "includes": ["./index.html"] }, "linter": { "enabled": true, "rules": { "nursery": { "noSyncScripts": "on" } } } }