快来免费体验ChatGpt plus版本的,我们出的钱 体验地址:https://chat.waixingyun.cn
在这篇文章中,作者讨论了如何在 CSS 模块中使用类型安全。由于 CSS 模块在运行时生成类名并在构建之间更改,因此很难以类型安全的方式使用它们。一种解决方案是使用 TypeScript 定义文件为每个 CSS 模块手动创建类型,但更新这些文件非常繁琐。文章提出了一个问题,即假设在 CSS 模块中添加或删除了一个类名。
下面是正文~
使用TypeScript的好处之一是它显著减少了特定错误的发生,例如拼写错误;它甚至使访问原型方法和执行重构更加容易。在编译时捕获的错误可以提高正常运行时间,让客户更加满意,并减少开发人员的紧急呼叫压力。
使用TypeScript,很容易为我们的应用程序的业务逻辑和控制流程进行类型标注,但如果我们也能使CSS类安全,那该多好呢?确保正确的CSS类名已经就位可以确保所需的样式应用于给定的组件,从而防止由于排版错误而导致样式错位。
在本文中,我们将讨论CSS模块是什么,探讨它们的开发者体验缺陷,并学习如何通过使用TypeScript自动化来解决这些问题。让我们开始吧!
什么是CSS模块?
CSS模块提供了一种在现代Web应用程序中编写模块化和作用域CSS样式的方法。这些样式特定于你的应用程序的特定组件或模块。你可以使用常规CSS编写CSS模块。
在构建时,使用 Vite 或其他类似的工具,CSS 模块为 CSS 文件中定义的每个类生成唯一的类名。然后在 JavaScript 中使用生成的类名来引用 CSS,从而使 CSS 模块化和可重用,避免类名冲突或不必要的重复。
在撰写本文时,CSS类名不再是全局的,解决了许多像BEM这样的方法论旨在解决的问题,但无需手动努力。然而,在CSS模块中遵循BEM仍然取决于用例而有益。
将 CSS 模块添加到你的项目中
如果你想在下一个 TypeScript 应用程序中使用 CSS 模块,则有几个选项。
现代构建工具如 Vite 和 Snowpack 支持 CSS 模块化,但如果你使用的是 webpack,可能需要包含一些小的配置。
一旦构建设置完成,可以按照CSS模块约定添加带有 module.css
扩展名的CSS文件:
// button.module.css
.green {
background-color: 'green';
}
.blue {
background-color: 'blue';
}
.red {
background-color: 'red';
}
为了应用这些样式并利用上述好处,我们应该从 TypeScript 文件中导入 CSS 模块并绑定 HTML。请记住,下面的示例是用 React 编写的,但语法与其他 UI 库非常相似:
代码语言:javascript复制// Component.tsx
import styles from './button.module.css'
const Component = () => (
<>
<button className={styles.green}>I am green!</button>
<button className={styles.blue}>I am blue!</button>
<button className={styles.red}>I am red!</button>
</>
)
如果你在本地运行上面的代码,您会注意到返回的 styles
没有被严格限制类型。相反,它们被视为任何类型。此外,TypeScript
编译器不会在类名不存在时通知你。
开发者体验的改进
CSS模块是一个很好的工具,但由于类名是在运行时生成的并且在构建之间发生更改,因此很难以类型安全的方式使用它们。
你可以使用TypeScript定义文件手动为每个CSS模块创建类型,但更新它们很繁琐。假设从CSS模块中添加或删除了一个类名。在这种情况下,必须手动更新类型,否则类型安全性将无法按预期工作。
对于上面的例子,输入应该如下:
代码语言:javascript复制declare const styles: {
readonly green: string;
readonly blue: string;
readonly red: string;
};
export default styles;
这些类型在我们修改相关的CSS模块之前都能很好地工作。一旦我们修改了它,我们就必须更新类型。如果我们忘记手动更新类型,可能会出现一些讨厌的UI错误。
我们忘记修改相关的类型文件:
代码语言:javascript复制// button.module.css.d.ts
declare const styles: {
readonly green: string;
readonly blue: string;
readonly red: string;
we forgot to update the types!
};
export default styles;
// Component.tsx
import styles from './button.module.css'
const Component = () => (
<>
<button className={styles.green}>I am green!</button>
<button className={styles.blue}>I am blue!</button>
<button className={styles.red}>I am red!</button>
</>
)
在这个例子中展示的情况可能看起来不相关,但随着代码库和贡献者数量的增长,这种重复和容易出错的过程将会阻碍对类型系统的信任。引用不存在或打错字的 CSS 类将无法按预期样式化 HTML,这可能很快演变成开发人员失去对工具的信任。让我们学习如何自动化它!
自动化
在这种情况下,自动化解决方案很简单。我们将自动生成类型,而不是手动创建,并提供一个脚本来验证生成的类型是否最新,以避免不正确的 CSS 模块类型泄漏到编译步骤中。
有多种方法可以实现这一点。例如,我们可以构建一个将 CSS 转换为 TypeScript 定义的提取器。但是,为了避免重复造轮子,我们将利用开源包 typed-css-modules。
使用 npm i typed-css-modules
在你的项目中安装包,然后将类型生成添加到你的主开发脚本中的 package.json
脚本中:
"watch": "vite & tcm --watch .",
添加检查最新类型的功能。如果生成的类型在 package.json
脚本中不正确,则会失败:
"check:up-to-date-types": "tcm --listDifferent .",
有了这两个脚本,现在可以自动保持 CSS 模块类型定义的同步,并检查类型是否保持最新。
根据项目的不同,你可能更喜欢在本地或服务器上运行这些脚本,可能作为你的 CI 流水线的一部分。为了完善示例,我们将描述如何使用 husky
将它们作为 Git Hook 运行。
使用 npx husky-init && npm install
安装并设置 Git Hook runner
。要设置在每次提交之前运行 CSS 模块类型检查的 pre-commit Hook
,请将 .husky/pre-commit
文件修改为以下内容:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npm run check:up-to-date-types
在每次提交之前,钩子将运行并验证类型是否最新。
总结
在TypeScript生态系统中工作具有巨大的潜力,但是,当过度依赖手动流程时,很容易破坏类型系统的信任或产生不必要的摩擦。
CSS模块非常棒,通过一些额外的配置,很容易为生成的类添加类型安全性。您应该自动化繁琐的工作,以便你的团队可以专注于构建出色的产品。
代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug。