创建日期: 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:
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里的引用,再运行一次代码。
报错:
至此,我已哭死!!!调查后,发现是因为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,这个是找答案最快捷的办法。