React中使用less(use CSS Modules)的两种配置方法

创建日期: 2020年3月2日
Demo源码下载
参考链接:
链接1
链接2
customize-cra API

前言:
如果你想通过不暴露webpack,配置less,并且只想知道步骤,不关心你配置时候为什么不好用,可以直接划到下面看【3.总结】。
如果,你是初学者小白,并没有项目,你需要做如下准备工作:
用create-react-app (CRA)脚手架或者IDE创建React项目。
参考:React入门(1)——我的第一个React.js项目

1.安装less和less-loader

//npm 
$ npm install --save-dev less-loader less
//yarn
$ yarn add less less-loader -D

遗留问题:为什么我按官网的命令去安装less,在package.json里面不会显示,而用上面的方式,就会显示呢?需要查下npm的子命令了。[参考]

安装后,我们会看到package.json文件中,添加了依赖:

  "devDependencies": {
    "less": "^3.11.1",
    "less-loader": "^5.0.0"
  }

Dependencies和devDependencies到底有什么区别呢?[参考链接]

2. 配置

2.1 方法一:暴露webpack

哇啊!好尴尬😅,翻了半天,也没找到网上说的webpack.config.js文件,原因看这个

下面这个命令,谨慎执行,因为不可逆。但是只要做好代码版本管理,可以随意折腾,大不了重头再来版本管理git的使用

2.1.1 yarn eject

$ yarn eject

执行的时候,有提示:NOTE: Create React App 2+ supports TypeScript, Sass, CSS Modules and more without ejecting: https://reactjs.org/blog/2018/10/01/create-react-app-v2.html
因为,执行该命令后会把已构建依赖项、配置文件和脚本复制到程序目录中。该操作是不可逆转的,执行完成后会删除这个命令,也就是说只能执行一次。

插曲:执行的时候,被git给阻挡了,因为是在学习,所以我直接用

$ find . -name ".git" | xargs rm -Rf

用这个命令把git给清除了。如果是项目,自己按照提示,把git相关的commit,stash什么的,处理完毕就好。
执行完毕后,package.json文件被更改了,与此同时,会生成新文件夹config:


config文件夹

2.1.2修改webpack.config.js配置文件。

我们找到sassRegex,模仿它来配置lessRegex。
(1).配置less

// style files regexes
const cssRegex = /\.css$/;
const cssModuleRegex = /\.module\.css$/;
const sassRegex = /\.(scss|sass)$/;
const sassModuleRegex = /\.module\.(scss|sass)$/;
const lessRegex = /\.less$/; //这一句和下一句是新增的less的配置
const lessModuleRegex = /\.module\.less$/;

(2).配置less-loader
找到"test: sassRegex"这个,搜一下即可,然后模仿这个来写less的。

// Adds support for CSS Modules, but using LESS
            {
              test: lessRegex,
              exclude: lessModuleRegex,
              use: getStyleLoaders(
                {
                  importLoaders: 3,
                  modules: true,
                  sourceMap: isEnvProduction && shouldUseSourceMap,
                },
                'less-loader'
              ),
              sideEffects: true,
            },
            {
              test: lessModuleRegex,
              use: getStyleLoaders(
                {
                  importLoaders: 3,
                  sourceMap: isEnvProduction && shouldUseSourceMap,
                  modules: {
                    getLocalIdent: getCSSModuleLocalIdent,
                  },
                },
                'less-loader'
              ),
            },

这里,我先直接copy了sass的配置,然后改成less,运行后不好用。之后,又在lessRegex里加了一句modules: true,才可以运行。致于 importLoaders: 3,这后面的数字,是3,是1,都好用,没有查具体意义。待调查

2.1.3 修改代码

新建styles.less文件:

//styles.less
.title {
  color: red;
}

修改index.js文件:

//index.js
import React from 'react';
import ReactDOM from 'react-dom';
import styles from './styles.less'

const App = () => {
  console.log(styles);//打印一下,是一个对象,对象的元素的key是title
  return(
    <h1 className={styles.title}>Hello world</h1>
  )
}

ReactDOM.render(<App />, document.getElementById('root'));

这里,引入less文件,作为styles,设置className的时候,将原本的双引号,改成花括号。至此,less的引用成功。

参考链接1:样式设置和CSS文件引入
配置的时候请注意:关于 less 配置规则放在 sass 的解析规则下面即可,如果放在了 file-loader 的解析规则下面,less 文件解析不会生效。(这段注意来自于网络,没有验证过)



2.2 配置方法二:无需eject进行配置(不用暴露webpack)

参考1: Create React App无eject配置(react-app-rewired 和 customize-cra)
参考2: create-react-app 优雅定制指南

初学者:因为,eject是一个不可逆的过程,所以,这里,你需要重新创建一个项目来实验。新建项目后,参照上面,修改代码,新建styles.less文件,以及修改inde.js文件。记得要安装less和less-loader。然后,运行。嗯,hello world是黑色的,styles.less的文件没有被成功调用。

下面,我们来进行第二种,相对优雅的设置方案。
react-app-rewired
是 react 社区开源的一个修改 CRA 配置的工具。纯 react-app-rewired 的方式自定义配置,参考 Extended Configuration Options 文档。
注意
react-app-rewired 1.x 配合 create-react-app 1.x
react-app-rewired 2.x 配合 create-react-app 2.x

版本升级导致互不兼容,另外,react-app-rewired 2.x 应该是社区维护了。
react-app-rewired@^2.0.0+ 版本需要搭配 customize-cra 使用

在 react-app-rewired 1.x 的版本中,它除了提供覆盖配置的方法,还体用了一些 helpers,例如 rewireLess、rewirePreact 等,2.x 版本只保留了核心功能。
另外一个工具帮我们实现了这些,customize-cra.

customize-cra
这次我们使用 customize-cra 协助自定义,参考 Using the plugins 文档。

2.2.1 安装

yarn add react-app-rewired customize-cra -D

2.2.2 修改package.json文件

//package.json
"scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test --env=jsdom",
    "eject": "react-scripts eject"
  },

2.2.3 在项目根目录新建config-overrides.js

//config-overrides.js
const { override } = require('customize-cra');
module.exports = {};

2.2.4 配置less (在react使用JavaScript语言下)

在第一部分中,我们已经安装了less和less-loader依赖,这里我们开始配置。
这个过程中,笔者找了很多文章来看,大部分都是依赖react-app-rewired来做的,但是,文章比较老,现在版本更新,我们需要[customize-cra]来协助。
customize-cra API docs
addLessLoader(loaderOptions)
我们来修改config-overrides.js文件:

//config-overrides.js
const { override, addLessLoader } = require('customize-cra');

module.exports = override(
  
  addLessLoader({
    strictMath: true,
    noIeCompat: true,
    localIdentName: "[local]--[hash:base64:5]" // if you use CSS Modules, and custom `localIdentName`, default is '[local]--[hash:base64:5]'.
  }),
)

好了,less配置成功,来运行你的代码吧!
😱😱😱,什么???不好用???
没错,确实不好用!笔者也在这里卡住了,读了数十篇文章,依然没有找到解决方案,最终,还是回归官网的文档,才搞明白缘由。
其实,CRA生成的React项目,是可以直接用css modules的,但是,css文件的命名是有规则的,例如:styles.module.css。同理依赖css modules的less,文件名的命名规则也如此:styles.module.less。
好了,我们修改下文件名及index.js里的引用,再运行一次代码。
报错:


image.png

至此,我已哭死!!!调查后,发现是因为css-loader更新到3.0以后,出现的这个问题,也因此,之前博客的方法,都不起作用。

参考1: https://github.com/arackaf/customize-cra/issues/201
我们先将"customize-cra": "^1.0.0-alpha.0"升级,此时,用的就是这个版本的,
然后参考:https://github.com/rails/webpacker/issues/2197的gyurcigyurma说的,将config-overrides.js文件改成如下:(此时,使用的是styles.module.less文件名)

//config-overrides.js
const { override, addLessLoader } = require('customize-cra');

module.exports = override(
  addLessLoader({
    strictMath: true,
    noIeCompat: true,
    loader: "css-loader",
    options: {
      modules: {
        localIdentName: "[name]__[local]___[hash:base64:5]",
      },
      sourceMap: true
    }
  }),
)

好了,我看到红色的Hello world了,终于可以正确运行了。。。

2.2.5 配置less(在react使用TypeScript语言下)

用IDE新建项目,比如webStorm,新建时,选择支持TypeScript。参考上面的1~4,进行一次,less文件用styles.modules.less这种.modules.less命名规则。我们也要更新customize-cra的版本。
除此之外,还有修改react-app-env.d.ts文件:

//react-app-env.d.ts
declare module "*.module.less"

笔者第二次执行时,运行一直出错,提示:

./src/styles.module.less (./node_modules/css-loader/dist/cjs.js??ref--6-oneOf-8-1!./node_modules/postcss-loader/src??postcss!./node_modules/resolve-url-loader??ref--6-oneOf-8-3!./node_modules/less-loader/dist/cjs.js??ref--6-oneOf-8-4!./src/styles.module.less)
ValidationError: Invalid options object. Less Loader has been initialized using an options object that does not match the API schema.
 - options has an unknown property 'options'. These properties are valid:
   object { lessOptions?, prependData?, appendData?, sourceMap? }

笔者修改了config-overrides.js:

const { override, addLessLoader } = require('customize-cra');

module.exports = override(
  addLessLoader({
    strictMath: true,
    noIeCompat: true,
    localIdentName: "[local]--[hash:base64:5]" // if you use CSS Modules, and custom `localIdentName`, default is '[local]--[hash:base64:5]'.
  }),
)

好了,运行成功,我们看见了红色Hellow world。
因为没有第一次运行时候的demo,所以,笔者并不确定问题具体出在哪,即便,按上面的步骤走,估计也会出错,因为less-loader更新了。。。
为此,笔者贴出自己实验的时候,所用依赖包的信息,仅供参考。

  "devDependencies": {
    "customize-cra": "^1.0.0-alpha.0",
    "less": "^3.11.1",
    "less-loader": "^5.0.0",
    "react-app-rewired": "^2.1.5"
  }

2.2.6 配置less(在react使用TypeScript语言下的优化–––去掉含module的后缀名)

修改config-overrides.js:

const { override, addLessLoader } = require('customize-cra');

module.exports = override(
  addLessLoader({
    strictMath: true,
    noIeCompat: true,
    javascriptEnabled: true,
    cssLoaderOptions: {
      modules: {localIdentName: '[name]_[local]_[hash:base64:5]'},
    }, // .less file used css-loader option, not all CSS file.
  }),
)

修改react-app-env.d.ts文件:

/// <reference types="react-scripts" />

declare module "*.less"

最后,注意也要修改styles.less的文件名以及在indext.tsx的import路径。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.2.6 扩展:引用CSS Module

新建文件styles.module.css

//styles.module.css
.title {
  color: blue;
}

修改index.js文件:

//index.js
import stylesCss from './styles.module.css'
//.......省略
<h1 className={stylesCss.title}>Hello CSS Modules</h1>
//.......省略

运行,成功。

3. 总结

为了方便快速浏览,笔者对第二种比较优雅的配置方法,进行总结。如果上面部分已经看过了,这部分可以忽略,仅仅是对上面陈述的方法二的总结。

3.1 安装依赖

#安装less和less-loader
$yarn add less less-loader -D
#安装react-app-rewired
$yarn add react-app-rewired -D
#安装customize-cra 如果,你安装时的最新版本已经超过这个,可以不用指定版本
$yarn add customize-cra@^1.0.0-alpha.0 -D

3.2 修改package.json文件

//package.json
"scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test --env=jsdom",
    "eject": "react-scripts eject"
  },

3.3 在项目根目录新建config-overrides.js

并对less进行配置:

//config-overrides.js
const { override, addLessLoader } = require('customize-cra');

module.exports = override(
  addLessLoader({
    strictMath: true,
    noIeCompat: true,
    loader: "css-loader",
    options: {
      modules: {
        localIdentName: "[name]__[local]___[hash:base64:5]",
      },
      sourceMap: true
    }
  }),
)

3.4 对于支持TypeScript的项目的配置

修改config-overrides.js:

const { override, addLessLoader } = require('customize-cra');

module.exports = override(
  
  addLessLoader({
    strictMath: true,
    noIeCompat: true,
    localIdentName: "[local]--[hash:base64:5]" // if you use CSS Modules, and custom `localIdentName`, default is '[local]--[hash:base64:5]'.
  }),
)

修改react-app-env.d.ts文件:

//react-app-env.d.ts
declare module "*.module.less"

3.5 对于支持TypeScript的项目的配置的优化(去掉.module的后缀)

修改config-overrides.js:

const { override, addLessLoader } = require('customize-cra');

module.exports = override(
  addLessLoader({
    strictMath: true,
    noIeCompat: true,
    javascriptEnabled: true,
    cssLoaderOptions: {
      modules: {localIdentName: '[name]_[local]_[hash:base64:5]'},
    }, // .less file used css-loader option, not all CSS file.
  }),
)

修改react-app-env.d.ts文件:

/// <reference types="react-scripts" />

declare module "*.less"

最后,注意也要修改styles.less的文件名以及在indext.tsx的import路径。

3.6 测试

注意less文件命名规则,后缀为.module.less

//index.js
import React from 'react';
import ReactDOM from 'react-dom';
import styles from './styles.module.less' 

const App = () => {
  console.log(styles);//打印一下,是一个对象,对象的元素的key是title
  return(
    <h1 className={styles.title}>Hello world</h1>
  )
}

ReactDOM.render(<App />, document.getElementById('root'));
//styles.module.less
.title {
  color: red;
}

3.7 纠错

笔者,在第二次补充的时候,发现又跑不起来了。经调查,发现是因为less-loader版本更新的原因,为此,笔者贴出测试的时候,所用依赖库的版本:

  "devDependencies": {
    "customize-cra": "^1.0.0-alpha.0",
    "less": "^3.11.1",
    "less-loader": "^5.0.0",
    "react-app-rewired": "^2.1.5"
  }

网上,查看各种文档都不好用的时候,包括笔者这篇也被淘汰的时候,建议你看看官网customize-cra API,这个是找答案最快捷的办法。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345

推荐阅读更多精彩内容