React 配置全局 Sass 和 CSS Module

React 配置全局 Sass 和 CSS Module

接下来的业余时间要做个人博客 Wap 端,这次打算尝试一下 TypeScript、持续集成、自动化等以前没有实践过的技术栈...当然大前提还是要把架子搭好,上次记录了一下 Vue 配置全局 Sass 变量的方法,这次把 React 的配置方法记录一下,显然比 Vue-cli 麻烦了一些。

前提

一开始本来打算用微软的TypeScript-React-Starter来创建脚手架,正好省了初始化TypeScript那一套,但是这个 CLI 貌似对CSS Mudule配置不是支持得很好,看了社区一些 hack 方法感觉也不太好用。遂还是用create-react-app创建一个 React 工程,然后把TypeScript-React-Starter的配置拷了过来。

以前用React-app-rewired去给 webpack 添加配置,但总有种隔靴搔痒的感觉,这次决定yarn eject这个工程。

src目录下创建assets文件夹,然后在assets文件夹里创建一个styles文件夹,添加一个 sass 文件叫_color.scss,里面先简单加几个颜色变量,以备测试:

$white: #fff;
$black: #000;
$gray: #666;

下面先说怎么做 CSS Module,然后再往全局 Sass 迁移。

CSS Module

安装配置

首先安装依赖:

yarn add node-sass

使用create-react-app默认会创建一个App.jsApp.css,我们需要将App.css重命名为App.module.css

这点非常关键,只要想做CSS Module,css 文件必须要改成*.module.css的形式。

然后打开App.js文件,引入App.module.css,可以发现引入 css 的方式也和以前不一样了,下面的styles名字随便起,看你个人喜好了:

import styles from './App.module.css';

这里我建议在 class 命名的时候,要以下划线的形式连接每个单词,比如App_common_logo,这也是鹅厂 aotu 实验室推荐的的命名方式,其实这样对使用 CSS Module 也有好处,一会儿会说到。

CSS Module使用图例

使用方法

关于使用方法,这里直接上图吧,实际上就是把以前的className="App_intro"变成了className={styles.App_intro}

我们回到上面 class 命名那个话题,如果你的类名叫做App-intro,那你就得写成className={styles['App-intro']},写多了项目也不清晰了。

我们再看一下 Dev Tool 的渲染情况:

渲染出来的类名

这是 Webpack 的默认配置,默认就是模块名_类名__5位hash,好处一目了然,不会用重复的 class 了,我个人决定在开发环境直接使用 Webpack 的默认配置,在生产环境再做一些改变,打开config/webpack.config.prod.js文件,搜索关键字getLocalIndent,我个人打算 build 之后的类名直接是6位hash,所以配置如下图:

修改Webpack配置

题外话

在使用 CSS Module 的过程中相信你一定会遇到其他的问题,比如一个标签如果有多个 class,以前可以写成className="App_icon App_select",但是 CSS Module 是不允许的,所以需要安装依赖yarn add classnames,使用方式如下:

import cs from 'classnames';

className={cs(styles.social_media_motto, styles.no_user_select)}

此外,如果你的模块里不得不操作 DOM,如果继续用className={styles.App_intro}的方式,document.querySelector('.App_intro')将不会如你所愿,因为此时的 Appintro 已经被被 hash 所“污染,因此你还是需要命名为`className="Appintro"这种形式`。

但是新的问题来了,你在App.mudule.css中给App_intro定义的任何样式将不会起作用,所以需要在 css 里做写文章:

:global(.App_intro) {
    outline: none;
    border-radius: 50%;
  }

Sass 全局变量、函数、Mixin...

如果定义了一个关于颜色变量的 Sass 文件,按以前的做法,那就得在每个模块的 Sass 文件中@import '../assets/styles/_color.scss',显然这种方式很不(e)科(xin)学。尤其在写移动端的时候,肯定得定义一些全局的函数,要是每个文件都要引一次,天啦噜...

首先安装依赖yarn add sass-resources-loader --dev,然后打开config/webpack.config.dev.js,注意是开发环境的 Webpack 配置文件。

检索关键词sass-loader,看下图:

配置全局Sass

下面把代码贴出来,注意一定是../src/assets/styles/_colors.scss',网上教程坑得一逼,全给写成./src/assets/styles/_colors.scss',结果一直报错。

use: [{
  loader: require.resolve('style-loader'),
},
{
  loader: require.resolve('css-loader'),
  options: {
    importLoaders: 2
  },
},
{
  loader: require.resolve('sass-loader'),
},
{
  loader: require.resolve('sass-resources-loader'),
  options: {
    resources: [path.resolve(__dirname, '../src/assets/styles/_colors.scss'), path.resolve(__dirname, '../src/assets/styles/_function.scss')],
  }
}],

因为我们做了 CSS Module,所以我们也要为 CSS Module 支持引入全局 Sass 变量。

为CSS Module配置全局Sass

这时我们将上面的App.mudule.css重命名为App.mudule.scss,然后随便找个 class 添加个颜色,发现生效了:

.App_header {
  display: flex;
  align-items: center;
  justify-content: center;
  color: $gray;
}

最后

在前几个月写 PC 端的博客前台时,已经用上了 CSS Module,但没去考虑全局 Sass 变量,这次也算是一次温故和知新吧。计划 Wap 端会用上 TypeScript,同构个 PWA 什么的,然后尝试用 Trvis 做持续集成和自动化部署,任重道远啊。

明天又要苦逼的加班去了,日了。

以上、よろしく。

聊一聊前端上传那些事

PREVIOUS POST

聊一聊前端上传那些事

React 单页应用添加 GA 埋点

NEXT POST

React 单页应用添加 GA 埋点