在项目中使用ts
npx create-react-app 项目名 --template typescript
为什么使用cra呢?因为它会自动安装并配置ts相关的包,以及jest测试包等常用的包,以及一些常用的webpack配置,比如热重载、优化后的打包配置等,还直接配置好了对es6+的各自新特性的支持。而且,如果将来cra增加了新功能,我们可以只修改package.json中react-scripts的版本号,然后运行npm i
或者yarn i
来更新react-scripts,之后我们就可以直接在项目里使用新版本的功能了!
更多细节可以阅读CreateReactApp中文文档,如果你使用cra创建项目,那这就是必读的。
我希望可以像使用vue那样,通过@/component
直接访问到src/component
,而不是在某个层级比较深的文件内写一堆../../../src/component
。
这步操作是为了让编辑器可以在我们输入@
的时候能识别它并且可以给出代码提示。
首先在项目根目录下创建一个名为tsconfig.path.json的文件,然后复制下列内容:
{
"compilerOptions": {
"baseUrl": "src",
"paths": {
"@/*": [
"*"
],
}
}
}
之后,在根目录下的tsconfig.json文件中新增一行配置信息,目的是将tsconfig.path.json文件内的配置合并进来。
{
"extends": "./tsconfig.path.json",
"compilerOptions": {...略},
"include": [...略]
}
为什么不直接将路径配置写在tsconfig.json中呢?因为我的项目是使用cra创建的,每次运行项目的时候tsconfig.json内的paths字段都会被移除掉,于是只好使用extend字段继承额外的配置文件。两个文件里面的配置加载顺序是这样的:在原文件里的配置先被加载,然后被来至继承文件里的配置重写。 如果发现循环引用,则会报错。
现在编辑器做静态分析的过程中可以识别别名了,我们输入@
可以给出提示了。但是webpack在打包的时候仍然不认识这个别名,不信你可以试试运行项目,看看报错信息。我们还需要对webpack做一些配置。不过cra创建的项目默认是没有webpack.config等配置文件的,需要在控制台执行yarn run eject
来将CRA 中的配置全部反编译到当前项目中,但如果我们使用了eject命令,就再也享受不到CRA 升级带来的好处了,因为react-scripts已经是以文件的形式存在于你的项目,而不是以包的形式,所以无法对其升级。
基于上面的原因,我选择使用react-app-rewired来重写部分webpack配置,这样可以做到不弹出webpack配置的前提下,重写webpack配置。
首先命令行执行npm install react-app-rewired --save-dev
或者yarn add react-app-rewired --dev
来安装这个包,之后在项目根目录下创建名为config-overrides.js的文件,文件内容一会儿再说,最后修改package.json的scripts字段,修改后如下:
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test --env=jsdom",
"eject": "react-scripts eject"
},
接下来就可以编写config-overrides.js文件了,不过我们其实没必要编写原生的webpack配置,我选择借助customize-cra这个包的一些工具函数自动生成配置项。
首先安装它yarn add customize-cra -D
,之后开始编写config-overrides.js,内容如下:
const path = require('path');
const {override, addWebpackAlias } = require("customize-cra");
module.exports=override(
addWebpackAlias({
"@": path.resolve(__dirname, 'src')
})
)
保存之后重新执行yarn start
,发现webpack可以找到文件了,项目通过编译。
本以为使用sass需要在config-overrides.js里面配置下sass-loader,可根据cra官方文档的说法,我只需要安装node-sass即可,猜测cra默认已经安装了sass-loader并且已经配置完成。于是创建了一个新项目然后执行npm run eject
弹出webpack.config.js看了下,确实已经对拓展名为.sass
和.scss
的文件使用了sass-loader来加载。
于是如果我想在cra创建的项目中使用sass就简化为只安装node-sass即可。
因为众所周知的原因,我们需要使用镜像源来安装。
npm:npm i node-sass --sass_binary_site=https://npm.taobao.org/mirrors/node-sass/ --save-dev
yarn:yarn config set registry https://registry.npm.taobao.org -g
和yarn add node-sass
祝你好运。
安装: yarn add less less-loader -D
或 npm i less less-loader -D
修改config-overrides.js,如下:
const {override,addLessLoader} = require("customize-cra");
module.exports = override(
addLessLoader({
javascriptEnabled: true,
localIdentName: '[local]--[hash:base64:5]'
})
)
配置好sass之后,根据我的习惯,我喜欢创建两个文件: src/styles/mixin.scss
和src/styles/variables.scss
。然后使用sass-resources-loader
将这两个文件自动引入到其他.scss
文件内,这样我就可以在任何一个.scss
文件内使用这些变量和mixin了。十分方便。
首先,安装sass-resources-loader,yarn add sass-resources-loader --dev
或npm i sass-resources-loader --save-dev
。之后我本打算继续使用reactAppRewrite和customizeCra做配置,但是麻烦事来了。
首先,阅读下cra的webpack默认配置模板可以知道,scss文件要经历四个loader的加载才能最终放置到页面内,按照先后顺序分别是:
sass-loader:用于将scss语法转为css。
postcss-loader:为css添加特定厂商的前缀,就是-moz-
、-webkit-
等等这些。
css-loader:分析@import和url,推导各个css文件之间的关系,把各个css文件合并成一段css。
style-loader:将css添加到index.html的style标签内。
因为sass-resources-loader这个loader是用来处理scss文件的,所以一定是要放在saa-loader之前使用,可我翻遍了customize-cra的文档,也没找到哪个api可以在loader调用链中插入新的loader,于是只好完全重新配置所有css相关loader,并在尾部添加我自己需要的这个sass-resources-loader(loader的调用是从loader列表尾部开始的)。config-overrides.js内容如下:
const path = require('path');
const { override, addWebpackAlias, addWebpackModuleRule } = require("customize-cra");
module.exports = override(
addWebpackAlias({
"@": path.resolve(__dirname, 'src')
}),
addWebpackModuleRule(
{
test: /\.scss$/, use: [
{ loader: 'style-loader' },
{ loader: 'css-loader', options: { sourceMap: true } },
{ loader: 'sass-loader', options: { sourceMap: true } },
{
loader: 'sass-resources-loader',
options: {
sourceMap: true,
resources: ['./src/styles/variables.scss']
}
}]
}
)
)
然而这样太麻烦了,不仅手动把cra配置过的loader重新配了一遍,而且还完全放弃了cra给我们做好的各个loader的options,这样绝对不行,于是我换了种方式,如下:
const path = require('path');
const { override, addWebpackAlias, addWebpackModuleRule } = require("customize-cra");
function overwriteScssLoader(config) {
config.module.rules[2].oneOf[5].use.push({
loader: 'sass-resources-loader',
options: {
sourceMap: true,
resources: ['./src/styles/variables.scss']
}
})
return config
}
module.exports = override(
addWebpackAlias({
"@": path.resolve(__dirname, 'src')
}),
overwriteScssLoader
)
customizeCra会为overwriteScssLoader
函数传入webpack的配置(config参数),我选择直接修改它。但其实这种方式也不行,大家可以看到我是直接使用了下标的方式操作数组,如果将来react把webpack的配置改动了,那我这种写法就失效了。可这已经是我倒腾2个多小时的结果了。当然,大家可以选择在overwriteScssLoader
函数里面加上各种各样的判断语句来增加健壮性,但是!最终我建议,如果需要对webpack做精细的配置还是eject吧!一分钟搞定的事情花十几分钟甚至个把小时去弄实在得不偿失。
安装 mobx: yarn add mobx mobx-react
或npm i mobx mobx-react --save
然后配置装饰器:
首先,安装 yarn add @babel/plugin-proposal-decorators -D
或npm i --save-dev @babel/plugin-proposal-decorators
然后,修改override-config.js文件如下:
const path = require('path');
const {addDecoratorsLegacy, override } = require("customize-cra");
module.exports = override(
addDecoratorsLegacy()
)
如果是非ts项目的话,做到这一步即可,否则还需要修改tsconfig.json。如果不这样做的话,ts会给出警告说装饰器是不稳定的语法balabala什么的,但其实这个语法很多库源码都在用,而且js最终支持不支持无所谓,反正babel是支持的,这就够了。废话有点多了,我们只需在tsconfig.json中添加一条选项即可
{
"compilerOptions": {
"experimentalDecorators": true,
}
}
安装:npm install react-router-dom --save
或yarn add react-router-dom
我们不需要安装react-router这个包,因为 react-router 为了支持 Web 和 React Native 出了两个包—— react-router-dom
和 react-router-native
,我们只关心 Web,所以只需要安装 react-router-dom
。这个 react-router-dom
依赖于 react-router
,所以 react-router
也会被自动安装上。并且react-router-dom
也会导出(动词)react-router
的那些导出(名词)。
如果是非ts项目的话,到这一步安装就结束了,不过对ts项目来说,还需要安装相应的类型声明的包,因为react-router-dom并没有提供.d.ts
文件。至于第三方的类型声明仓库,一般是使用DefinitelyTyped。
DefinitelyTyped 是一个庞大的声明仓库,为没有声明文件的 JavaScript 库提供类型定义。这些类型定义通过众包的方式完成,并由微软和开源贡献者一起管理。—— React官方文档
这是它的官网,你可以直接搜索包名。如果存在其对应的类型声明文件的话,页面会自动跳转到npm中相应包的主页。
react-rouer-dom对应的包为@types/react-router-dom。所以直接安装:npm install --save @types/react-router-dom
或yarn add @types/react-router-dom
。至此react-router就安装完毕了。
安装:yarn add antd
或者npm i antd --save
配置按需引入还需安装babel-plugin-import:npm i --save-dev babel-plugin-import
或yarn add babel-plugin-import -D
。
此外还需要修改config-overrides.js,如下:
const {override,fixBabelImports } = require("customize-cra");
module.exports = override(
fixBabelImports('import', {
libraryName: 'antd',
libraryDirectory: 'es',
style: true,
})
)
注意style选项是true,官方文档给出的style值是’css’,之所以写成true是因为antd源码中样式全部是使用less编写的,当style为true时引入的就是less源文件,而style为’css’的时候引入的是等效的css文件。虽然less文件的体积要比css小很多算是个优点,但其实体积大小不重要,因为最终less文件仍然会被less-loader编译成css,也就是说引入到index.html里面的就是编译出来的css。而我选择引入less而非css的原因是cra配置了对less的优化策略,比起我直接引入css要好一些。
另外,安装less是不会增加打包后的体积的,因为less和sass都是开发环境的工具,它们只在打包过程中发挥作用。它们不会被打包到最终的输出目录中,大家放心大胆的装两个是完全OK的,我自己的项目是less和sass都安装了。
刚刚也说过了,antd的样式是用less写的,其中使用了大量的变量来做到风格的一致性。如果我们想修改less中的变量的话,有两种方案:
第一个方案是配置 less 变量文件,它的优点是配置简单。但这种方式我不推荐,因为这么做会强制导入全部样式,那么之前配置的按需导入样式就失效了。
第二个方案是修改less-loader的配置,让webpack在打包的过程中修改使用到的那些less变量的值,这种方式不会影响到按需导入,推荐!。
只需一步,修改config-overrides.js。在addLessLoader的选项中新增modifyVars属性,然后在其中以键值对方式制定变量和它的新值即可。如下:
const {override,addLessLoader} = require("customize-cra");
module.exports = override(
addLessLoader({
javascriptEnabled: true,
modifyVars: {
'@primary-color': '#1DA57A' //注意这里
},
localIdentName: '[local]--[hash:base64:5]'
})
)
react + typescript 集成mobx和设置别名alias最新解决方案
ts官方文档
CreateReactApp中文文档
Create React App无eject配置(react-app-rewired 和 customize-cra)
babel-plugin-import
less中文文档