ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Create React App 样式引入完全指南:在 JavaScript 中 import CSS 的原理与实战

Create React App 样式引入完全指南:在 JavaScript 中 import CSS 的原理与实战 Create React App 样式引入完全指南在 JavaScript 中 import CSS 的原理与实战【免费下载链接】create-react-appSet up a modern web app by running one command.项目地址: https://gitcode.com/gh_mirrors/cr/create-react-app本篇指南围绕 create-react-app 官方文档《Adding a Stylesheet》展开系统讲解如何在 React 组件中通过import ./Button.css的方式引入样式文件并深入源码剖析其背后的 webpack 处理链路开发环境的样式热更新、生产环境的 CSS 提取与压缩、PostCSS 自动加前缀与 Normalize 重置以及src目录边界约束等。读完本文你将掌握 create-react-app 项目中样式文件的标准组织方式并能理解import一个 CSS 文件时底层究竟发生了什么从而在迁移构建工具、排查样式失效或优化打包体积时做到心中有数。核心思想用import表达JavaScript 依赖 CSScreate-react-app 的项目构建完全基于 webpack而 webpack 提供了一种超越 JavaScript 的扩展import概念的自定义方式如果你想让一个 JavaScript 文件依赖某个 CSS 文件只需在该 JavaScript 文件中 import 这个 CSS。这与传统 HTML 中通过link relstylesheet引入样式的思路截然不同——样式不再是独立加载的静态资源而是作为模块依赖的一部分随组件代码一起被构建系统解析、打包。这一设计让一个组件 一份样式的文件组织方式成为可能每个组件的样式与其逻辑代码就近存放、共同进退删除组件时其样式也随之移除不会留下孤儿样式。这种模式在官方文档中给出了一组最小可运行的示例下面完整复现。最小示例从 CSS 文件到组件样式假设你有一个Button.css文件内容如下.Button { padding: 20px; }再创建一个Button.js在其中引入它import React, { Component } from react; import ./Button.css; // 告诉 webpackButton.js 使用了这些样式 class Button extends Component { render() { // 你可以把它们当作普通的 CSS 类名来使用 return div classNameButton /; } }这里的import ./Button.css一行就完成了三件事把Button.css注册为Button.js的依赖webpack 会保证它随该模块一起被处理让Button.css中的类名在运行时生效开发环境注入style标签生产环境提取为独立文件让构建系统能够追踪样式的变化从而在开发时实现热更新。需要特别强调这并不是 React 的要求而是 webpack 提供的能力。React 本身对样式方案没有任何强制规定JSX 中的classNameButton只是一个字符串属性。只是很多开发者觉得组件自带样式这种内聚的组织方式非常方便于是它成为了 create-react-app 的默认支持特性。不过也要清醒地认识到这一做法的代价它让你的代码对 webpack 产生了依赖相比纯 HTML CSS 的方案可移植性会降低——如果未来迁移到其他构建工具或非构建环境这些import ./xxx.css语句需要相应改造。开发与生产同一份 import两条截然不同的处理路径官方文档明确指出同样的import语句在开发与生产两种环境下会有不同的表现开发环境npm start通过这种方式表达的样式依赖在你编辑保存后能够即时热重载无需刷新页面生产环境npm run build所有 CSS 文件会被拼接concatenated成一个经过压缩minified的.css文件出现在构建产物中。这两条路径在源码中有非常清晰的落点。webpack.config.js 中的getStyleLoaders函数根据构建模式动态拼接 loader 链const loaders [ isEnvDevelopment require.resolve(style-loader), isEnvProduction { loader: MiniCssExtractPlugin.loader, options: paths.publicUrlOrPath.startsWith(.) ? { publicPath: ../../ } : {}, }, { loader: require.resolve(css-loader), options: cssOptions, }, { loader: require.resolve(postcss-loader), options: { /* postcssOptions: ... */ }, }, ].filter(Boolean);展开来看这条 loader 链的职责分工如下环境Loader作用开发style-loader把 CSS 转成 JS 模块运行时动态创建style标签注入页面配合 webpack 的文件监听实现编辑即热更新生产MiniCssExtractPlugin.loader把 CSS 从 JS 中抽离出来写入独立文件避免 FOUC无样式内容闪烁并支持按 chunk 拆分两者css-loader解析 CSS 中的url()、import等引用路径把资源作为模块依赖处理两者postcss-loader应用 PostCSS 插件链详见下文自动后处理一节生产环境下抽取后的文件命名与产物路径在 webpack.config.js 中定义new MiniCssExtractPlugin({ filename: static/css/[name].[contenthash:8].css, chunkFilename: static/css/[name].[contenthash:8].chunk.css, });即所有样式最终合并输出到build/static/css/目录文件名携带 8 位内容哈希contenthash内容变化时文件名随之变化从而让浏览器缓存策略更可靠。而压缩则由CssMinimizerPlugin完成见同一文件的 optimization.minimizer 段。此外还有一个容易被忽视的细节配置中给普通 CSS 规则显式设置了sideEffects: true见 webpack.config.js。这是因为 webpack 的 tree-shaking 默认会把声称无副作用的包中的死代码移除而 CSS 导入本身就是副作用必须显式声明否则打包时样式可能被错误地摇树删除。真实模板App.css与index.css是怎么组织的上面的最小示例在 create-react-app 的官方模板中就有活生生的体现。使用npx create-react-app my-app创建项目后模板源码位于 cra-template/templatesrc目录下默认包含index.css和App.css两个样式文件src/index.css 存放全局基础样式例如重置body的margin、设定字体栈与字体平滑body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }src/index.js 作为入口在顶部import ./index.css确保全局样式最先被应用import React from react; import ReactDOM from react-dom/client; import ./index.css; import App from ./App;src/App.js 则在组件层面import ./App.css配合模板自带的.App-header、.App-logo等类名使用。可见全局样式入index.css、组件样式就近放正是官方推荐的默认组织方式。项目里的 kitchensink 测试夹具 也验证了这一模式组件import ./assets/style.css后正常渲染其配套测试 CssInclusion.test.js 断言引入 CSS 的组件渲染不崩溃作为 webpack 功能回归的守护。保守方案把全部样式放进src/index.css如果你对 webpack 特有的语义import非 JS 文件心存顾虑官方文档给出了一个更保守的替代方案把全部 CSS 直接写进src/index.css它仍然由src/index.js引入——这与模板默认行为完全一致。这样做的价值在于将来如果迁移到其他构建工具你只需要删除src/index.js中的那一个import ./index.css语句即可而不必逐个组件清理样式引用。这是官方文档明示的低耦合撤退路径。边界约束为什么样式必须放在src目录在 folder-structure.md 中有一条重要说明为了更快的重建速度webpack 只处理src目录内的文件任何 JS 和 CSS 文件都必须放进src否则 webpack 根本看不到它们。这是引入样式时最常见的踩坑点——把 CSS 放在src之外的顶层目录例如styles/运行时会报模块找不到。这一约束在源码层面由ModuleScopePlugin强制实施见 webpack.config.jsnew ModuleScopePlugin(paths.appSrc, [ paths.appPackageJson, /* ... 其他白名单模块 ... */ ]),该插件会拦截所有从src之外导入的请求node_modules与少数白名单模块除外提前暴露这类错误而不是等到打包失败。其背后的原因在 paths.js 中也能看到appSrc被解析为项目根目录下的srcbabel 与样式 loader 的include都锚定在这一目录上。因此组件样式与src/index.css都必须待在src之内这是使用本文所有特性的前提。引入样式时自动发生的后处理当你import一个 CSS 文件时它并非原样进入产物而是会先经过postcss-loader配置的插件链处理见 webpack.config.js其中包含三个默认插件postcss-flexbugs-fixes修复 flexbox 在旧浏览器中的已知 bugpostcss-preset-env根据package.json中的browserslist配置自动添加厂商前缀autoprefixer 以flexbox: no-2009模式运行stage 3并 polyfill 部分新 CSS 特性postcss-normalize引入 modern-normalize 风格的重置样式且尊重你的browserslist配置按需输出对应浏览器的 reset 规则。这意味着你在源码中写的.App { display: flex; flex-direction: row; align-items: center; }经构建后可能变成带前缀的版本例如.App { display: -webkit-box; display: -ms-flexbox; display: flex; -webkit-box-orient: horizontal; -webkit-box-direction: normal; -ms-flex-direction: row; flex-direction: row; -webkit-box-align: center; -ms-flex-align: center; align-items: center; }此示例与详细说明参见 post-processing-css.md。你无需手写这些前缀只需在package.json中维护browserslist字段来声明目标浏览器范围。另外需要注意CSS Grid 的自动前缀默认关闭且不会剥离手写前缀如需启用需在 CSS 文件顶部添加/* autoprefixer grid: autoplace */注释。更进一步CSS Modules 与 Sass 的衔接掌握了JS import CSS的机制后可以无缝衔接两个进阶特性CSS Modules文件以.module.css结尾时例如Button.module.csswebpack 配置会自动切换为局部作用域模式生成[filename]_[classname]__[hash]形式的唯一类名从而允许不同文件中出现同名类而不冲突。其实现同样位于 webpack.config.js使用getCSSModuleLocalIdent来自react-dev-utils生成类名。详细用法见 adding-a-css-modules-stylesheet.mdSass/SCSS若需要预处理器先按 adding-a-sass-stylesheet.md 安装sass依赖然后通过getStyleLoaders的preProcessor分支见 webpack.config.js在现有 loader 链末尾追加resolve-url-loader与sass-loader文件扩展名相应变为.scss/.sass或.module.scss/.module.sass。两条路径共用本文所述的同一套 loader 基础设施理解import 即依赖声明这一核心模型后扩展只是文件扩展名与配置分支的区别。小结在 create-react-app 中引入样式的核心可以归纳为三点依赖即 import通过import ./Button.css在 JS 中声明样式依赖这是 webpack 扩展了import语义的结果而非 React 的要求环境分治开发环境由style-loader注入style实现热更新生产环境由MiniCssExtractPlugin抽取并合并为static/css/下带内容哈希的压缩文件边界与后处理样式必须位于src内由ModuleScopePlugin强制引入后自动经postcss-flexbugs-fixes、postcss-preset-env含 autoprefixer与postcss-normalize处理并受package.json中browserslist约束。如果想保留迁移灵活性把全部样式收敛到src/index.css并由src/index.js统一引入是最低耦合的选择若追求组件级样式内聚则Button.css就近 import 是官方推荐的默认路径。掌握这套机制无论后续使用 CSS Modules、Sass 还是迁移构建工具你都能清楚地知道自己的代码依赖了什么、产物会变成什么样。【免费下载链接】create-react-appSet up a modern web app by running one command.项目地址: https://gitcode.com/gh_mirrors/cr/create-react-app创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表