一、项目启动
- 了解需求背景
- 了解业务流程
二、项目搭建初始化
本案例使用脚手架 create-react-app
初始化了项目。此脚手架有利有弊吧,项目目录结构简洁,不需要太关心 webpack
令人头疼的配置;弊端在于,脚手架确实有些庞大,构建时间在 4mins 左右。各位看官择优选择吧,也可以完全自己搭建一个项目。
- 设置淘宝镜像仓库
$ yarn config set registry registry.npm.taobao.org/ -g
$ yarn config set sass_binary_site cdn.npm.taobao.org/dist/node-sass -g
- 工程目录 init
$ create-react-app qpj-web-pc –typescript
$ tree -I “node_modules”
.|-- README.md|-- package.json|-- public| |-- favicon.ico | |-- index.html| |-- logo192.png | |-- logo512.png | |-- manifest.json | `-- robots.txt|-- src| |-- App.css| |-- App.test.tsx | |-- App.tsx| |-- index.css| |-- index.tsx| |-- logo.svg| |-- react-app-env.d.ts| |-- reportWebVitals.ts| `-- setupTests.ts `-- tsconfig.json
yarn build
试试
$ yarn build & tree -I “node_modules”
.|-- README.md|-- build/ # 改造点(由于 `Jenkins` 构建打包脚本有可能已经写死了 `dist` 包名)|-- package.json|-- public| |-- favicon.ico | |-- index.html| |-- logo192.png | |-- logo512.png | |-- manifest.json | `-- robots.txt|-- src| |-- App.css| |-- App.test.tsx | |-- App.tsx| |-- index.css| |-- index.tsx| |-- logo.svg| |-- react-app-env.d.ts| |-- reportWebVitals.ts| `-- setupTests.ts `-- tsconfig.json
- 连接
git
远程仓库
$ git remote add origin yuanmin.zhu%40wetax.com.cn:wd246800mm@gitlab.yunpiaoer.com/front/qpj-web-pc.git
- 添加
.gitignore
$ echo -e ” yarn.lock \n package-lock.json \n /dist \n .idea” >> .gitignore
- 添加
eslint
代码及提交评论校验
$ yarn add husky lint-staged @commitlint/cli @commitlint/config-conventional -D
$ npx husky install
$ npx husky add .husky/pre-commit “npx lint-staged”
$ npx husky add .husky/prepare-commit-msg “npx commitlint -e”
- 项目根目录新建
commitlint.config.js
// commitlint.config.jsmodule.exports = { extends: ['@commitlint/config-conventional'], rules: { 'type-enum': [ 2, 'always', ['feat', 'fix', 'docs', 'style', 'refactor', 'test', 'chore', 'revert'], ], 'subject-full-stop': [0, 'never'], 'subject-case': [0, 'never'], },}
vscode
扩展中搜索ESLint
并安装,项目根目录新建.eslintrc.js
,内容可参考文章配置:zhuanlan.zhihu.com/p/84329603 看第五点- Commit message 格式说明
<type>: <subject>
type
值枚举如下:- feat: 添加新特性
- fix: 修复 bug
- docs: 仅仅修改了文档
- style: 仅仅修改了空格、格式缩进、都好等等,不改变代码逻辑
- refactor: 代码重构,没有加新功能或者修复 bug
- perf: 增加代码进行性能测试
- test: 增加测试用例
- chore: 改变构建流程、或者增加依赖库、工具等
- revert: 当前 commit 用于撤销以前的 commit
subject
是 commit 目的的简短描述,不超过 50 个字符,且结尾不加句号(.)package.json
新加入如下配置:
{ ..., "lint-staged": { "src/**/*.{jsx,txs,ts,js,json,css,md}": [ "eslint --quiet" ] },}
- 可执行
npx eslint [filePath] \--fix
进行格式修复,无法修复的需手动解决
三、项目配置一(功能配置)
- 安装项目常用依赖库
$ yarn add antd axios dayjs qs -S # UI 库 及工具库
$ yarn add react-router-dom redux react-redux redux-logger redux-thunk -S # 路由及状态管理
webpack
配置拓展很有必要
- 根目录新建
config-overrides.js
,详细使用可访问:简书:React 之 config-overrides文件配置 - 安装
- $ yarn add react-app-rewired customize-cra -D
- 修改
package.json
中启动项
// package.json"scripts": { "start": "react-app-rewired start", "build": "react-app-rewired build",}
- 使用
// config-overrides.jsconst { override, // 主函数 fixBabelImports, // 配置按需加载 addWebpackExternals, // 不做打包处理配置 addWebpackAlias, // 配置别名 addLessLoader // lessLoader 配置,可更改主题色等} = require('customize-cra')module.exports = override(/* ... */, config => config)
- 配置按需加载
// config-overrides.js...module.exports = override( fixBabelImports('import', { libraryName: 'antd', libraryDirectory: 'es', // library 目录 style: true, // 自动打包相关的样式 }),)
- 更改主题色
// config-overrides.js...module.exports = override( addLessLoader({ lessOptions: { javascriptEnabled: true, modifyVars: { '@primary-color': '#1890ff', }, } }),)
- 别名配置(
typescript
项目这里有坑)
// config-overrides.jsconst path = require('path')...module.exports = override( addWebpackAlias({ '@': path.resolve(__dirname, 'src'), }),)
- 去除注释、多进程打包压缩
// config-overrides.jsconst UglifyJsPlugin = require('uglifyjs-webpack-plugin')const HardSourceWebpackPlugin = require('hard-source-webpack-plugin')...module.exports = override(/* ... */, config => { config.plugins = [...config.plugins, { new UglifyJsPlugin({ uglifyOptions: { warnings: false, compress: { drop_debugger: true, drop_console: true, }, }, }), new HardSourceWebpackPlugin() }] return config})
- 解决埋下的两个坑
- 修改打包出的文件夹名为
dist
// 修改打包路径除了output,这里也要修改const paths = require('react-scripts/config/paths')paths.appBuild = path.join(path.dirname(paths.appBuild), 'dist')module.exports = override(/* ... */, config => { config.output.path = path.resolve(__dirname, 'dist') return config})
- 解决
typescript
别名配置- 查阅相关资料,需要在
tsconfig.json
中添加一项配置
- 查阅相关资料,需要在
{ ... "extends": "./paths.json"}
- 新建文件
paths.json
{ "compilerOptions": { "baseUrl": "src", "paths": { "@/*": ["*"] } }}
- 配置装饰器写法
{ "compilerOptions": { "experimentalDecorators": true, ... }}
- 配置开发代理
- 在
src
目录新建setupProxy.js
// src/setupProxy.jsconst proxy = require('http-proxy-middleware').createProxyMiddlewaremodule.exports = function(app) { // app 为 Express 实例,此处可以写 Mock 数据 app.use( proxy('/api', { "target": "https://qpj-test.fapiaoer.cn", "changeOrigin": true, "secure": false, // "pathRewrite": { // "^/api": "" // } }) )}
- 加入
polyfill
和antd
组件国际化处理
// src/index.tsximport React from 'react'import ReactDOM from 'react-dom'// 注入 storeimport { Provider } from 'react-redux'import store from '@/store/store'import { ConfigProvider, Empty } from 'antd'import App from './App'import zhCN from 'antd/es/locale/zh_CN'import 'moment/locale/zh-cn'// polyfillimport 'core-js/stable'import 'regenerator-runtime/runtime'ReactDOM.render( <Provider store={store}> <ConfigProvider locale={zhCN} renderEmpty={Empty}> <App /> </ConfigProvider> </Provider>, document.getElementById('root'))
- CSS Modules
create-react-app
自带支持以xxx.module.(c|le|sa)ss
的样式表文件,使用上typescript
项目中要注意:
const styles = require('./index.module.less')retrun ( <div className={`${styles.container}`}> <Table columns={columns} className={`${styles['border-setting']}`} dataSource={props.store.check.items} rowKey={record => record.id} pagination={false} /> <div className="type-check-box"></div> </div>)
// index.module.less.container { padding: 24px; background-color: #fff; height: 100%; overflow: auto; .border-setting { tr { td:nth-child(3) { border-left: 1px solid #F0F0F0; border-right: 1px solid #F0F0F0; } } td { text-align: left !important; } } :global { // 这个标识之后,其子代元素可以不需要使用 `styles['type-check-box']` 的方式,直接写 `className` .type-check-box { .ant-checkbox-wrapper + .ant-checkbox-wrapper{ margin-left: 0; } } }}
- 【新】配置
React jsx
指令式属性r-if
、r-for
、r-model
、r-show
,提升开发效率:
- 安装依赖
$ yarn add babel-react-rif babel-react-rfor babel-react-rmodel babel-react-rshow -D
- 配置
.babelrc
:
// .babelrc{ ..., "plugins": [ "babel-react-rif", "babel-react-rfor", "babel-react-rmodel", "babel-react-rshow", ]}
- 使用示例:
r-if
<div> <h1 r-if={height < 170}>good</h1> <h1 r-else-if={height > 180}>best</h1> <h1 r-else>other</h1></div>
r-for
{/* eslint-disable-next-line no-undef */}<div r-for={(item, index) in [1, 2, 3, 4]} key={index}> 内容 {item + '-' + index}</div>
r-model
<input onChange={this.callback} type="text" r-model={inputVale} />
r-show
<div r-show={true}>内容</div> # 注意:这是 `r-if` 的效果,不会渲染节点
四、项目配置二(优化配置)
- 实现组件懒加载
react-loadable
import Loadable from 'react-loadable'const Loading = (props: any) => { if (props.error) { console.error(props.error) return <div>Error! <Button type="link" onClick={props.retry}>Retry</Button></div> } else if (props.timedOut) { return <div>Timeout! <Button onClick={props.retry}>Retry</Button></div> } else if (props.pastDelay) { return <div>Loading...</div> } else { return null }}const loadable = (path: any) => { return Loadable({ loader: () => import(`@/pages${path}`), loading: Loading, delay: 200, timeout: 10000, })}const Home = loadable('/homePage/Home')
暂无评论内容