原生 ESM 不支持 import './style.css',因加载器仅接受 application/javascript 类型,CSS 的 text/css 不可执行;唯一原生方式是 import('./style.css', { assert: { type: 'css' } }),返回 CSSStyleSheet 需手动注入 adoptedStyleSheets,且要求动态 import、现代浏览器、HTTP 服务、正确 MIME 与 CORS。

原生 ESM 不支持 import './style.css',会直接报错
浏览器在模块加载阶段就拒绝执行这行代码,错误不是语法层面的,而是加载器层面的:TypeError: Failed to fetch dynamically imported module 或 MIME type ('text/css') is not executable。根本原因是 ESM 加载器只接受 application/javascript 类型的响应,而 CSS 是 text/css,它不是可执行模块。
import('./style.css', { assert: { type: 'css' } }) 是唯一可行的原生方式
这个语法仅在动态 import() 中有效,且仅限 Chrome 124+、Firefox 125+、Safari 17.4+。它不会返回 JS 对象,而是返回一个 CSSStyleSheet 实例,必须手动注入才能生效:
- 必须在
<script type="module">内调用,否则import()报import() is not a function - HTML 必须通过 HTTP(S) 服务打开(
http://localhost:5173可行,file://协议必挂) - 服务端需返回
Content-Type: text/css和Access-Control-Allow-Origin: *(CORS 头缺失会导致静默失败) - 注入逻辑要合并已有样式表:
document.adoptedStyleSheets = [...document.adoptedStyleSheets, styleSheet.default],否则会覆盖已有的adoptedStyleSheets
Vite/Webpack 等构建工具里的 import './style.css' 是假的“原生”
它们实际没走浏览器原生加载流程,而是把 CSS 提取为 <link rel="stylesheet"> 或内联 <style> 标签注入 DOM。这意味着:
- 开发时能用,是因为构建工具在背后做了重写和注入;生产环境依赖
build.cssCodeSplit(Vite)或MiniCssExtractPlugin(Webpack) - 如果 CSS 文件里含
@import url(...)或外部字体引用,可能被提前合并进主包,失去懒加载效果 - 不配构建工具时,这种写法在纯浏览器环境里根本不会执行,也不会报错——只是静默忽略
真正简单又兼容的替代方案是 @import 写在 CSS 里
这不是 JS 模块化,但它是 CSS 原生支持的模块化机制,无任何运行时限制:
立即学习“前端免费学习笔记(深入)”;
- 在
main.css里写@import './reset.css';,浏览器原生识别并加载 - 无需 HTTP 服务、无需 CORS、无需
type="module",file://下也完全可用 - 不依赖 JS 执行时机,样式加载优先级更高,避免 FOUC
- 缺点是无法按需懒加载(所有
@import都随主 CSS 同步加载)
最容易被忽略的是:即使你写了 assert { type: 'css' },只要不是动态 import() 调用,浏览器就当它不存在;而就算调用了,服务端 MIME 和 CORS 缺一不可——这两个条件在本地开发时最容易漏掉。


















