大型项目必须通过构建工具(如Webpack、Vite)管理CSS,因其支持tree-shaking、作用域隔离、条件注入和关键CSS提取;而@import阻塞串行加载,手动<link>无法保障顺序、脱离构建流程、丧失模块化能力。

大型项目中不建议直接在 HTML 里 <link rel="stylesheet"> 引入 CSS,而是必须通过构建工具(如 Webpack、Vite、Rollup)抽离和管理——因为只有构建阶段才能做 tree-shaking、作用域隔离、条件注入、关键 CSS 提取这些事,运行时做不到。
为什么 @import 和手动 <link> 在大型项目里会失控
构建工具之外的引入方式,本质是放弃控制权:
-
@import在 CSS 文件里写,会阻塞并串行加载,浏览器必须等前一个 CSS 解析完才发起下一个请求,首屏时间直线上升 - 手动
<link>到多个 CSS 文件,无法保证加载顺序:比如reset.css如果后加载,所有组件样式都会被重置规则覆盖 - 第三方库的 CSS(如
node_modules/antd/dist/reset.css)若直接<link>,就脱离了构建流程,没法做 PurgeCSS、postcss-preset-env 或变量注入 - 没有模块化上下文,
scoped、modules、css.preprocessorOptions.sass.additionalData这些机制全部失效
webpack 的 MiniCssExtractPlugin 和 vite 的 css.codeSplit 干了什么
它们不是“把 CSS 拆出来就完事”,而是在打包期完成三件事:
- 识别哪些 CSS 是全局基础(
reset、variables、fonts),合并进base.css并内联到 HTML<head> - 识别哪些是异步路由/组件的 CSS,生成独立 chunk,配合
import('./Page').then(...)动态加载 - 对每个 CSS chunk 做 scope 隔离:CSS Modules 会把
.button编译成.Button_button__abc123;vue-style-scope会加[data-v-xxx]属性选择器
没构建工具,这些都得手写 loader、自己 parse AST、手动注入 hash —— 不现实。
立即学习“前端免费学习笔记(深入)”;
抽离 CSS 后,tailwind.config.js 和 sass 变量怎么生效
关键点在于:变量注入必须发生在编译器读取组件样式之前。比如 Vite 中:
-
css.preprocessorOptions.sass.additionalData是唯一能确保所有<style lang="scss" scoped>都能访问$spacing-unit的位置 - 路径必须真实存在且被
resolve.alias支持,比如@/styles/variables.scss要配alias: { '@': path.resolve(__dirname, 'src') } -
additionalData字符串末尾必须带\n,否则会和组件第一行样式连成一句,报Invalid CSS after "" - 不能在
additionalData里写@use "xxx",Sass 会因重复 forward 报错;应统一用@forward+@use模块系统管理依赖
真正容易被忽略的是:抽离不是为了“让 CSS 文件变少”,而是为了让每一段样式都可追溯、可剔除、可隔离——当一个组件被 git rm 删除时,它的样式也必须 100% 消失,不多也不少。


















