React , TypeScript, CSS Module , Less , Antd 遇到的坑
<h1>序 </h1><p>因为React 本身的脚手架自身在webpack中已经做了对CSS Module 的配置,因最近遇到了很多坑,所以从头整理了一遍</p>
<p> </p>
<h2>使用版本</h2>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">"react": "^16.13.1",
"antd": "^4.4.0",
"typescript": "~3.7.2",
"webpack": "4.42.0",
"less": "^3.11.3",
"less-loader": "5.0.0",
</pre>
</div>
<p> </p>
<h2 id="安装和初始化" data-scrollama-index="0">一. 安装和初始化---React and TypeScript<br></h2>
<p>请确保电脑上已经安装了最新版的 yarn 或者 npm。</p>
<p> </p>
<p>使用 yarn 创建 cra-template-typescript 项目。</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">$ yarn create react-app antd-demo-ts --template typescript
</pre>
</div>
<p>如果你使用的是 npm(接下来我们都会用 yarn 作为例子,如果你习惯用 npm 也没问题)。</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">$ npx create-react-app antd-demo-ts --typescript
</pre>
</div>
<p> </p>
<p>然后我们进入项目并启动。</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">$ cd antd-demo-ts
$ yarn start
</pre>
</div>
<p> </p>
<h2>二. CSS Module的使用</h2>
<p>1.在src目录下新建 css/index.module.css 文件</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;"><span style="color: rgba(0, 0, 255, 1)">.red{
color: red;
}
</span></pre>
</div>
<p>2. 打开APP.tsx 文件新增以下代码 </p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">import React from 'react';
<span style="color: rgba(0, 0, 255, 1)">import styles from './css/index.module.css'</span>
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<span style="color: rgba(0, 0, 255, 1)"><div className={styles.red}>哈哈啊哈</div></span>
</header>
</div>
);
}
export default App;
</pre>
</div>
<p> </p>
<p>3. 你会发现style代码可以通过Js方式来使用,棒棒的</p>
<p> </p>
<p>4. 因为React脚手架自身支持.css, .Scss, .Sass 文件做了配置,所以如果有用scss的小伙伴可以直接使用scss,如想使用less,可查看后面</p>
<p> </p>
<p>5. 在src目录下新建 css/index.module.scss 文件,App.tsx 中引用,发现报错以下,提示需要安装Sass文件</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">/src/css/index.module.scss (./node_modules/css-loader/dist/cjs.js??ref--6-oneOf-6-1!./node_modules/postcss-loader/src??postcss!./node_modules/resolve-url-loader??ref--6-oneOf-6-3!./node_modules/sass-loader/dist/cjs.js??ref--6-oneOf-6-4!./src/css/index.module.scss)
To import Sass files, you first need to install node-sass.
Run <span style="color: rgba(0, 0, 255, 1)">`npm install node-sass` or `yarn add node-sass`</span> inside your workspace.
Require stack:
</pre>
</div>
<p> </p>
<p>5. 安装Sass和node-sass</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">`npm install node-sass` or `yarn add node-sass`
</pre>
</div>
<p> </p>
<p> </p>
<h2>三. Less的使用----打开隐藏的webpack配置文件</h2>
<p>1. 查看webpack内部配置</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">npm run eject
</pre>
</div>
<p> </p>
<p>2. 如果发现报错以下信息,表示你需要上传到git上面后再进行<span style="color: rgba(255, 102, 0, 1)">eject</span>操作</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;collapse:true;;gutter:true;">This git repository has untracked files or uncommitted changes:
.CFUserTextEncoding
.DS_Store
.***-NG/
.***/
.Trash/
.android/
.ant-devtool.json
.anyproxy/
.bash_history
.bash_profile
.bash_sessions/
.cocoapods/
.config/
.fancy/
.gitconfig
.kaitian/
.lesshst
.local/
.mysql_history
.node-gyp/
.npm/
.npminstall_tarball/
.nvm/
.putty/
.rncache/
.sh_history
.ssh/
.taro/
.taro2/
.v8flags.7.0.276.38-node.19.e8d369a76bd6a0858b87990e6b1a3cfd.json
.viminfo
.vscode-react-native/
.vscode/
.vue-cli-ui/
.vuerc
.vuxrc/
.wallaby/
.yarnrc
Applications/
Desktop/
Documents/
Downloads/
Library/
Logs/
Movies/
Music/
Pictures/
Public/
UI/
WeChatProjects/
gulpfile.js
"iCloud \344\272\221\347\233\230\357\274\210\345\275\222\346\241\243\357\274\211/"
image/
mysql/
workSpace/
"\344\277\241\346\201\257\350\265\204\346\226\231/"
"\345\216\237\345\236\213/"
"\351\241\271\347\233\256\346\226\207\344\273\266/"
Remove untracked files, stash or commit any changes, and try again.
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! react-demo@0.1.0 eject: `react-scripts eject`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the react-demo@0.1.0 eject script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
</pre>
</div>
<p> </p>
<p>3. 在webpack中可以看到,webpack中已经配置了 CSS, SCSS, SASS 的Module,后续无需自己配置,</p>
<p> </p>
<p>4. 如果你想使用Less还需要自己去配置,以下是Less的操作步骤</p>
<p> </p>
<h2>四. 安装 Less 和 Less-loader</h2>
<p>使用 yarn</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">$ yarn add less less-loader</pre>
</div>
<p>或者使用 npm </p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">$ cnpm i less less-loader
</pre>
</div>
<p> </p>
<h2>五. webpack中配置Less</h2>
<p>1. 在第二步的时候我们已经打开了config中webpack的配置,打开 config 文件夹,修改 webpack.config.js</p>
<p>2. 搜索 cssRegex ,找到后添加两行代码</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">const cssRegex = /\.css$/;
const cssModuleRegex = /\.module\.css$/;
const sassRegex = /\.(scss|sass)$/;
const sassModuleRegex = /\.module\.(scss|sass)$/;
<span style="color: rgba(0, 0, 255, 1)">const lessRegex = /\.less$/;
const lessModuleRegex = /\.module\.less$/;
</span></pre>
</div>
<p>3.修改 getStyleLoaders 函数,添加代码</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">// common function to get style loaders
const getStyleLoaders = (cssOptions, <span style="color: rgba(0, 0, 255, 1)">lessOptions</span>, preProcessor) => {
const loaders = [
isEnvDevelopment && require.resolve('style-loader'),
isEnvProduction && {
loader: MiniCssExtractPlugin.loader,
options: shouldUseRelativeAssetPaths ? { publicPath: '../../' } : {},
},
{
loader: require.resolve('css-loader'),
options: cssOptions,
},
<span style="color: rgba(0, 0, 255, 1)"> {
loader: require.resolve('less-loader'),
options: lessOptions,
},</span>
{
// Options for PostCSS as we reference these options twice
// Adds vendor prefixing based on your specified browser support in
// package.json
loader: require.resolve('postcss-loader'),
</pre>
</div>
<p>4. 搜索 cssRegex ,在 css 配置下添加 less 配置 </p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">{
test: cssRegex,
exclude: cssModuleRegex,
use: getStyleLoaders({
importLoaders: 1,
sourceMap: isEnvProduction && shouldUseSourceMap,
}),
// Don't consider CSS imports dead code even if the
// containing package claims to have no side effects.
// Remove this when webpack adds a warning or an error for this.
// See https://github.com/webpack/webpack/issues/6571
sideEffects: true,
},
// Adds support for CSS Modules (https://github.com/css-modules/css-modules)
// using the extension .module.css
{
test: cssModuleRegex,
use: getStyleLoaders({
importLoaders: 1,
sourceMap: isEnvProduction && shouldUseSourceMap,
modules: true,
getLocalIdent: getCSSModuleLocalIdent,
}),
},
<span style="color: rgba(0, 0, 255, 1)">{
test: lessRegex,
exclude: lessModuleRegex,
use: getStyleLoaders(
{
importLoaders: 1,
sourceMap: isEnvProduction
? shouldUseSourceMap
: isEnvDevelopment,
},
'less-loader'
),
sideEffects: true,
},
{
test: lessModuleRegex,
use: getStyleLoaders(
{
importLoaders: 1,
sourceMap: isEnvProduction
? shouldUseSourceMap
: isEnvDevelopment,
modules:{<br></span> <span style="color: rgba(0, 0, 255, 1)">getLocalIdent: getCSSModuleLocalIdent,<br></span><span style="color: rgba(0, 0, 255, 1)"> },</span></pre>
<pre class="brush:javascript;gutter:true;"><span style="color: rgba(0, 0, 255, 1)"> },
'less-loader'
),
},
</span></pre>
</div>
<p>5. 保存后,重新启动项目</p>
<p> </p>
<p>6. 在src目录下新建 css/index.module.less 文件</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">.red{
color: yellow;
}
</pre>
</div>
<p> </p>
<p>7. App.tsx 修改</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">import React from 'react';
import logo from './logo.svg';
<span style="color: rgba(0, 0, 255, 1)">import styles from './css/index.module.less'
</span>
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<span style="color: rgba(0, 0, 255, 1)"> <div className={styles.red}>哈哈啊哈</div>
</span>
</header>
</div>
);
}
export default App;</pre>
</div>
<p> </p>
<p>8. 提示:index.module.less 找不到模块</p>
<p>解决:修改 src/react-app-env.d.ts 文件,新增一下代码,到底部</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">declare module '*.module.less' {
const classes: { readonly : string };
export default classes;
}
</pre>
</div>
<p> </p>
<p>9. 坑又来了, 提示使用less-loader与API模式不匹配的options对象初始化的Loader更少。 </p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">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 'less-loader'. These properties are valid:
object { lessOptions?, prependData?, appendData?, sourceMap?, implementation? }
</pre>
</div>
<p> </p>
<p>10. 查看以下package.json文件, 目前less 3.11版本与less-loader 6.1版本不匹配,需要将less-loader降到5.0版本才可以</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">"less": "^3.11.3",
"less-loader": "^6.1.3",
</pre>
</div>
<p> </p>
<p>11. less-loader 降版本</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;"><code>// 删除less-loader<br>yarn remove less-loader<br></code>
// 安装5.0版本<br>yarn add less-loader@5.0.0</pre>
</div>
<p> </p>
<p>12. 发现Less成功使用。</p>
<p> </p>
<h2>六. 引入Antd</h2>
<p>1. 安装antd</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">$ yarn add antd
</pre>
</div>
<p> </p>
<p>2. App.tsx 使用</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">import React from 'react';
import logo from './logo.svg';
import './App.css';
import styles from './css/index.module.less'
<span style="color: rgba(0, 0, 255, 1)">import { Button } from 'antd';</span>
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.tsx</code> and save to reload.
</p>
<div className={styles.red}>哈哈哈哈哈</div>
<span style="color: rgba(0, 0, 255, 1)"><Button type="primary">Button</Button></span>
</header>
</div>
);
}
export default App;
</pre>
</div>
<p> </p>
<p>3.修改 <code>src/App.css</code>,在文件顶部引入 antd 的样式。</p>
<p> </p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">@import '~antd/dist/antd.css';
</pre>
</div>
<p> </p>
<p>4. 查看浏览器,发现使用antd组件,报错了</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">index.js:1 Warning: findDOMNode is deprecated in StrictMode. findDOMNode was passed an instance of Wave which is inside StrictMode. Instead, add a ref directly to the element you want to reference. Learn more about using refs safely here: https://fb.me/react-strict-mode-find-node
in button (created by Button)
in Wave (created by Button)
in Button (at App.tsx:17)
in header (at App.tsx:11)
in div (at App.tsx:10)
in App (at src/index.tsx:9)
in StrictMode (at src/index.tsx:8)
</pre>
</div>
<p> </p>
<p>5. 原来是把严格模式加入了版本改动中,详细信息可查看下面</p>
<p><img src="https://img2020.cnblogs.com/blog/1069051/202007/1069051-20200701134651940-1813680823.png"></p>
<p> </p>
<p>6. 找到index.tsx 默认是严格模式,删除<React.StrictMode>标签,关闭严格模式,警告消除了</p>
<p><img src="https://img2020.cnblogs.com/blog/1069051/202007/1069051-20200701134820732-1657829675.png"></p>
<p> </p>
<h2>七. antd按需加载</h2>
<h3 id="1">第一种方法按需加载antd react-app-rewired</h3>
<p> </p>
<p>1. 此时我们需要对 create-react-app 的默认配置进行自定义,这里我们使用 react-app-rewired (一个对 create-react-app 进行自定义配置的社区解决方案)。</p>
<p>引入 react-app-rewired 并修改 package.json 里的启动配置。由于新的 react-app-rewired@2.x 版本的关系,你还需要安装 customize-cra。</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">`cnpm i react-app-rewired customize-cra` or `yarn add react-app-rewired customize-cra`
</pre>
</div>
<p> </p>
<p>2. packjson.js代码:</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
},
</pre>
</div>
<p> </p>
<p>3. 坑又来了,原因是没有找到 react-scripts</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">Error: Cannot find module 'react-scripts/package.json'
Require stack:
</pre>
</div>
<p> </p>
<p>4. 安装 react-scripts</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">`cnpm i react-scripts` or `yarn add react-scripts`
</pre>
</div>
<p> </p>
<p>5. 重启,又报错了,原因是我们需要新建一个 config-overrides文件配置antd的设置</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">Cannot find module '/Users/****/workSpace/antd-demo-ts/config-overrides'
</pre>
</div>
<p> </p>
<p>6.在项目根目录创建一个 config-overrides.js 用于修改默认配置。</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">const { override, fixBabelImports, addLessLoader } = require('customize-cra');
module.exports = override(
fixBabelImports('import', {
libraryName: 'antd',
libraryDirectory: 'es',
style: true,
}),
addLessLoader({
javascriptEnabled: true,
modifyVars: { '@primary-color': 'red' },
}),
);
</pre>
</div>
<p> </p>
<p>7. 又报错了,原因是没有找到 babel-plugin-import 模版</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">Error: Cannot find module 'babel-plugin-import' from '/Users/***/workSpace/antd-demo-ts'
at Array.map (<anonymous>)
</pre>
</div>
<p> </p>
<p>8. 安装 babel-plugin-import</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">`cnpm -s install babel-plugin-import` or `yarn add babel-plugin-import`
</pre>
</div>
<p> </p>
<p>9. 重启,第一种方法成功</p>
<p> </p>
<h6 id="没有生效?" data-scrollama-index="2"><span style="font-size: 15px">10. 没有生效?</span><br></h6>
<p>注意样式必须加载 less 格式,一个常见的问题就是<span style="color: rgba(0, 0, 255, 1)">引入了多份样式,less 的样式被 css 的样式覆盖了。</span></p>
<ul>
<li>
<p>如果你在使用 babel-plugin-import 的 <code>style</code> 配置来引入样式,需要将配置值从 <code>'css'</code> 改为 <code>true</code>,这样会引入 less 文件。</p>
</li>
<li>
<p>如果你是通过 <code>'antd/dist/antd.css'</code> 引入样式的,改为 <code>antd/dist/antd.less</code>。</p>
</li>
</ul>
<p> </p>
<h3>第二种方法 antd 按需加载</h3>
<p>请将第一种方式忽略</p>
<p>1. 首先确认以下,是否完成了上面的第三步骤,webpack隐藏文件的显示</p>
<p> </p>
<p>2. 查看 pageson.js 种是否已安装 <span class="hljs-keyword">babel-<span class="hljs-keyword">plugin-<span class="hljs-keyword">import,如没有安装请安装</span></span></span></p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">`cnpm -s install babel-plugin-import` or `yarn add babel-plugin-import`
</pre>
</div>
<p> </p>
<p>3. 需先完成 第四步,第五步</p>
<p> </p>
<p>4. 修改webpack里面找到babel-loader,因为babel-plugin-import是通过babel的添加一下<span style="color: rgba(0, 0, 255, 1)">蓝色</span>代码:</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;"> oneOf: [
// "url" loader works like "file" loader except that it embeds assets
// smaller than specified limit in bytes as data URLs to avoid requests.
// A missing `test` is equivalent to a match.
{
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
loader: require.resolve('url-loader'),
options: {
limit: imageInlineSizeLimit,
name: 'static/media/..',
},
},
// Process application JS with Babel.
// The preset includes JSX, Flow, TypeScript, and some ESnext features.
{
test: /\.(js|mjs|jsx|ts|tsx)$/,
include: paths.appSrc,
loader: require.resolve('babel-loader'),
options: {
customize: require.resolve(
'babel-preset-react-app/webpack-overrides'
),
plugins: [
[
require.resolve('babel-plugin-named-asset-import'),
{
loaderMap: {
svg: {
ReactComponent:
'@svgr/webpack?-svgo,+titleProp,+ref!',
},
},
},
],
<span style="color: rgba(0, 0, 255, 1)"> [
require.resolve('babel-plugin-import'),// 导入 import 插件
{
libraryName: 'antd', //暴露antd
style: 'css'
}
],</span>
],
// This is a feature of `babel-loader` for webpack (not Babel itself).
// It enables caching results in ./node_modules/.cache/babel-loader/
// directory for faster rebuilds.
cacheDirectory: true,
// See #6846 for context on why cacheCompression is disabled
cacheCompression: false,
compact: isEnvProduction,
},
},
</pre>
</div>
<p> </p>
<p> 4. 主题配置</p>
<p>如果要更改antd主题颜色的话,下面这个style属性值就不能是"css"了。必须改成true,原因是因为值是css时按需加载时加载的就是antd编译后之后的css文件,要更改主题颜色是要更改less变量的,而true标识直接加载antd的less文件</p>
<p> </p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;"> plugins: [
[
require.resolve('babel-plugin-named-asset-import'),
{
loaderMap: {
svg: {
ReactComponent:
'@svgr/webpack?-svgo,+titleProp,+ref!',
},
},
},
],
<span style="color: rgba(0, 0, 255, 1)"> [
require.resolve('babel-plugin-import'),// 导入 import 插件
{
libraryName: 'antd', //暴露antd
<span style="background-color: rgba(204, 153, 255, 1)"> style: true</span>
}</span>
],
],
</pre>
</div>
<p> </p>
<p>5.坑来了,当你设为true时,你会发编译失败,页面中antd组件也会没有样式了,命令行抛出如下异常:</p>
<p> 这是因为你还没配置less-loader的配置项,在之前我复制修改的那个地方只是引入使用了less-loader,并没有添加配置项,导致他就会出现这个异常,那么如何配置这个主题。</p>
<p> <img src="https://img2020.cnblogs.com/blog/1069051/202007/1069051-20200701161203075-1445675786.png"></p>
<p> </p>
<p>6. <span style="color: rgba(0, 0, 255, 1)">删除以下代码</span></p>
<p><img src="https://img2020.cnblogs.com/blog/1069051/202007/1069051-20200701162219956-625506066.png"></p>
<p>7. 在下面这个地方,<span style="color: rgba(0, 0, 255, 1)">去掉灰色框</span>代码,<span style="color: rgba(0, 0, 255, 1)">新增蓝色</span>部分代码</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">if (preProcessor) {
<span style="color: rgba(0, 0, 255, 1)"> let loader = {
loader: require.resolve(preProcessor),
options: {
sourceMap: isEnvProduction && shouldUseSourceMap,
},
}
if (preProcessor === 'less-loader') {
loader.options.modifyVars = {
'primary-color': '#000000',
'link-color': '#1DA57A',
'border-radius-base': '2px',
}
loader.options.javascriptEnabled = true
}
loaders.push(loader);</span>
<span style="background-color: rgba(128, 128, 128, 1)"> loaders.push(
{
loader: require.resolve('resolve-url-loader'),
options: {
sourceMap: isEnvProduction && shouldUseSourceMap,
},
},
{
loader: require.resolve(preProcessor),
options: {
sourceMap: true,
},
}
);</span>
}
</pre>
</div>
<p> </p>
<p>8.重启,完成。</p>
<pre><code id="mycode" class="hljs coffeescript"></code></pre><br><br>
来源:https://www.cnblogs.com/gqx-html/p/13219422.html
頁:
[1]