1、项目创建
// 1、安装脚手架 建议使用淘宝镜像源(https://registry.npmmirror.com),可安装nrm(npm 源管理器,允许你快速地在 npm源间切换)管理镜像源
npm install -g create-react-app
// 2、创建项目 (ts)
create-react-app my-react-ts-app --template typescript
2、安装yarn
npm install -g yarn
3、配置eslint和Prettier
3.1、安装依赖
这里同时使用eslint和Prettier来统一代码风格,由于create react-app已经安装了eslint,所以我们需要安装Prettier
//根据 Prettier官方建议,Prettier版本升级之后可能会有风格变化,故应当锁定 Prettier 的版本号:
yarn add prettier --save-dev --save-exact
同时使用eslint和Prettier会存在冲突,因此使用eslint-plugin-prettier和eslint-config-prettier两个依赖来解决冲突,其中:
eslint-plugin-prettier将 Prettier 的规则设置到 ESLint 的规则中。eslint-config-prettier关闭 ESLint 中与 Prettier 中会发生冲突的规则。
最后形成优先级:Prettier 配置规则 > ESLint 配置规则。
//安装eslint-plugin-prettier、eslint-config-prettier
yarn add eslint-config-prettier eslint-plugin-prettier --save-dev
3.2、配置文件
删除package.json中的eslintConfig属性,在根目录下新建.eslintrc.js(与 package.json 文件同级)并添加如下代码
module.exports = {
extends: ["react-app", "plugin:prettier/recommended"],
rules: {
// allow debugger during development
"no-debugger": process.env.NODE_ENV === "production" ? "error" : "off",
"no-console": 0,
"prettier/prettier": [
"error",
{
singleQuote: false, //使用单引号
trailingComma: "all", //有效的尾随逗号(对象、数组等)
bracketSameLine: true,
endOfLine: "auto",
},
],
"react/self-closing-comp": ["error"], // 自动闭合标签
},
};
注意:ESLint 的配置文件,可以是: .eslintrc.js、.eslintrc.cjs、.eslintrc.yaml、.eslintrc.yml、.eslintrc.json、 .eslintrc(已弃用)或者 package.json(第一种方法),优先级依次递减,层叠配置使用离要检测的文件最近的 .eslintrc 文件作为最高优先级,然后才是父目录里的配置文件,以此类推。
在根目录下新建.prettierrc.js(与 package.json 文件同级)并添加如下代码
module.exports = {
singleQuote: false, //使用单引号
trailingComma: "all", //有效的尾随逗号(对象、数组等)
bracketSameLine: true,
};
在根目录下新建.prettierignore(与 package.json 文件同级)并添加如下代码
# Ignore artifacts:
build
config
node_modules
public
README.md
package.json
yarn.lock
3.3、 运行项目时增加风格验证
在package.json中script下添加如下代码:
"format": "prettier --write src"**/*.+(js|jsx|json|css|md)""
注意: 此处的src表示只使用Prettier格式src下文件代码 在终端执行: yarn format 就可以安装Prettier规则去格式化代码风格
安装concurrently,可以在运行 yarn start同时运行 yarn format
yarn add concurrently
修改package.json中script,最终结果:
"build": "react-scripts build",
"test": "react-scripts test",
"format": "prettier --write src\"**/*.+(js|jsx|json|css|md)\"",
"start": "concurrently \"yarn format\" \"yarn dev\"",
"dev": "react-scripts start"
4、使用craco
使用craco可以在不运行npm run eject 下配置webpack
安装
yarn add @craco/craco
// 或者
npm install @craco/craco --save
修改package.json
"scripts": {
"build": "craco build",
"test": "craco test",
"format": "prettier --write src\"**/*.+(js|jsx|json|css|md)\"",
"start": "concurrently \"yarn format\" \"yarn dev\"",
"dev": "craco start"
},
安装依赖
yarn add compression-webpack-plugin uglifyjs-webpack-plugin simple-progress-webpack-plugin craco-less
在项目根目录下创建craco.config.js文件
const CompressionWebpackPlugin = require("compression-webpack-plugin");
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const SimpleProgressWebpackPlugin = require("simple-progress-webpack-plugin");
const CracoLessPlugin = require("craco-less");
const { loaderByName } = require("@craco/craco");
const path = require("path");
// 是否是生产环境
const isProduction = process.env.NODE_ENV === "production";
const commonPlugins = [
{
plugin: CracoLessPlugin,
options: {
lessLoaderOptions: {
lessOptions: {
modifyVars: {
"@primary-color": "#00A2FF",
"@link-color": "#00A2FF",
},
javascriptEnabled: true,
},
},
modifyLessModuleRule: (lessModuleRule, context) => {
lessModuleRule.test = /\.less$/;
lessModuleRule.exclude = /node_modules/;
const cssLoader = lessModuleRule.use.find(loaderByName("css-loader"));
cssLoader.options.modules = {
exportLocalsConvention: "camelCase",
localIdentName: "[local]_[hash:base64:5]",
};
return lessModuleRule;
},
modifyLessRule: (lessRule, context) => {
lessRule.test = /\.less$/;
lessRule.include = /node_modules/;
lessRule.exclude = undefined;
return lessRule;
},
},
},
];
const productionPlugins = [
// 打包进度
new SimpleProgressWebpackPlugin(),
// 打压缩包
new CompressionWebpackPlugin({
filename: "[path].gz[query]", // 目标资源名称。[file] 会被替换成原资源。[path] 会被替换成原资源路径,[query] 替换成原查询字符串
algorithm: "gzip", // 算法
test: new RegExp("\\.(js|css)$"), // 压缩 js 与 css
threshold: 10240, // 只处理比这个值大的资源。按字节计算
minRatio: 0.8, // 只有压缩率比这个值小的资源才会被处理
}),
// 压缩ES6
new UglifyJsPlugin({
parallel: true,
uglifyOptions: {
// 在UglifyJs删除没有用到的代码时不输出警告
warnings: false,
// debug false
output: {
comments: false,
beautify: false,
// debug true
},
compress: {
// 删除所有的 `console` 语句
// 还可以兼容ie浏览器
drop_console: isProduction ? true : false,
// 内嵌定义了但是只用到一次的变量
collapse_vars: true,
// 提取出出现多次但是没有定义成变量去引用的静态值
reduce_vars: true,
},
},
}),
];
const devPlugins = [];
module.exports = {
webpack: {
// 别名
alias: {
"@": path.resolve("src"),
},
},
plugins: isProduction
? [...productionPlugins, ...commonPlugins]
: [...devPlugins, ...commonPlugins],
// 代理
devServer: {
proxy: {
"/api": {
target: "http://localhost:3001",
changeOrigin: true,
pathRewrite: {
"^/api": "/api",
},
},
},
},
};