.husky/commit-msg
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"yarn commitlint --edit $1
.vscode/settings.json
"ahooks","aliyuncs","antd","commitlint", // 新增"deadcode","denormalize","echarts","EDITMSG", // 新增"favicons","iconfont","IIFE",
commitlint.config.ts
import type { UserConfig } from '@commitlint/types';
import { RuleConfigSeverity } from '@commitlint/types';
import dotenv from 'dotenv';
import fs from 'fs';
import path from 'path';dotenv.config({ path: path.resolve(__dirname, '.env.local') });const Configuration: UserConfig = {extends: ['@commitlint/config-conventional'],rules: {'type-case': [RuleConfigSeverity.Error, 'always', ['lower-case']],'type-enum': [RuleConfigSeverity.Error, 'always', ['feat', 'fix', 'docs', 'style', 'refactor', 'perf', 'test', 'build', 'ci', 'chore', 'revert']],'subject-rule': [RuleConfigSeverity.Error, 'always']},plugins: [{rules: {'type-enum': ({ type }) => {const typeList = ['feat', 'fix', 'docs', 'style', 'refactor', 'perf', 'test', 'build', 'ci', 'chore', 'revert'];return [typeList.includes(type || ''), `类型错误,只允许提交类型为【${typeList}】的 commit, 例如:feat: 【1112223334445556667】xxx`];},'subject-rule': ({ type, subject }) => {let _subject = subject || '';const regRex = /^【[0-9]{19}】(?!\s*$).+/;if (process.env.TASK_NO && !regRex.test(_subject)) {const commitEditMsgPath = path.resolve(process.cwd(), '.git', 'COMMIT_EDITMSG');const commitMsgContent = fs.readFileSync(commitEditMsgPath, 'utf-8');const lines = commitMsgContent.split('\n');_subject = `【${process.env.TASK_NO}】${subject}`;if (lines.length > 0) {lines[0] = `${type}: ${_subject}`;}fs.writeFileSync(commitEditMsgPath, lines.join('\n'));}return [regRex.test(_subject), '提交格式不符合规范,需要包含19位任务ID,且包含基础的 commit 信息, 例如:feat: 【1112223334445556667】xxx'];}}}]
};export default Configuration;
package.json
"devDependencies": {"@commitlint/cli": "^17.8.1", // 新增"@commitlint/config-conventional": "^17.8.1", // 新增"@types/lodash": "^4.14.202","@types/node": "^20.11.6","@types/react": "^18.0.33","@types/react-dom": "^18.0.11","chalk": "^4.1.2","cross-env": "^7.0.3","dotenv": "^16.4.5", // 新增"eslint": "^8.54.0","eslint-config-prettier": "^9.0.0","eslint-import-resolver-alias": "^1.1.2",...
}
.env.local
# .env 的本地版本,这里配置的环境变量会覆盖 .env 中的变量。
APP_ENV=sz-test1
# APP_ENV=sz-dev
# TASK_NO=1788498654317685432
TASK="[{"release/2024-07-18" : "1807622818796223578"}]"
.env
# 对应测试环境,值从 config/server.ts 中的 key 中选
# 开发时请在本地根目录新建一个 `.env.local` 文件,自行修改为需要的开发环境
# APP_ENV=sz-test# 多语言相关接口的域名。
# 各环境统一走 生产jk.cc.cn 域名(环境由接口的env参数做区分)
# 这个值基本不会动,除非服务端需要调试特定环境的多语言接口。
# 在使用时:
# 1. 当 APP_ENV=production 时,不使用当前变量,固定走生产的域名 jk.cc.cn。
# 2. 测试环境用当前变量指定的域名,而不是随环境对应的域名。
# 3. 本地开发会忽略该变量,走本地开发域名以mock本地语料# 自动添加任务编号到 Commit, TASK_NO 根据自己要求填写
# TASK_NO=1803607484162225644
README.md
# 运营平台前端项目## yarn- 统一使用 yarn 作为包管理工具## 配置本地开发环境- 切换环境请按 `.env` 中关于 `APP_ENV` 的注释,在`.env.local` 中配置 `APP_ENV` 变量区分连接的环境。
- `yarn install` 时会自动创建一个空白的 `.env.local` 文件## 代码校验macos用户,需要在 `yarn install`之后,于项目目录下执行下面两行命令。使 husky 生效。```sh
chmod ug+x .husky/*
chmod ug+x .git/hooks/*
UI库
- 依赖antd 4.24.x版本,但是不要直接从antd引入, UI相关的组件从核心库引入
// 错误引入方式:
import { Button } from 'antd';// 正确引入方式
import { Button } from '@/component';
权限
- 抛弃umi的authority配置。菜单直接在路由里面配置权限code,具体权限code是什么,需要找后端
开发须知
- 请运行:
git config --global core.autocrlf false
去除 git 进入暂存区时自动转换为crlf
- 请运行:
git config --global core.ignorecase false
去除 git 忽略大小写 - 编辑器必须开启 eslint 检测和保存自动修复功能(具体配置详细看:编辑器配置 Eslint)
- master 是主分支,feature+版本号是开发分支,release+版本号是预发布分支
- 统一使用 yarn 作为包管理工具
野火本地开发
- 修改 hosts
172.22.3.196 im.jk.cn
不同环境 ip 不同
business 和 test 服务修改 hosts 即可成功连接本地联调只有 workdev 环境可连接成功 ( 请求头 Origin 为 localhost 造成连接失败, 连接非 dev 的服务连接会被拒绝 )
其他
参考umi开发文档 Umi
styled-components 使用方法
基础
// Create a Title component that'll render an <h1> tag with some styles
const Title = styled.h1`font-size: 1.5em;text-align: center;color: #BF4F74;
`;// Create a Wrapper component that'll render a <section> tag with some styles
const Wrapper = styled.section`padding: 4em;background: papayawhip;
`;// Use Title and Wrapper like any other React component – except they're styled!
render(<Wrapper><Title>Hello World!</Title></Wrapper>
);
根据属性进行调整
const Button = styled.button<{ $primary?: boolean; }>`/* Adapt the colors based on primary prop */background: ${props => props.$primary ? "#BF4F74" : "white"};color: ${props => props.$primary ? "white" : "#BF4F74"};font-size: 1em;margin: 1em;padding: 0.25em 1em;border: 2px solid #BF4F74;border-radius: 3px;
`;render(<div><Button>Normal</Button><Button $primary>Primary</Button></div>
);
扩展样式
// The Button from the last section without the interpolations
const Button = styled.button`color: #BF4F74;font-size: 1em;margin: 1em;padding: 0.25em 1em;border: 2px solid #BF4F74;border-radius: 3px;
`;// A new component based on Button, but with some override styles
const TomatoButton = styled(Button)`color: tomato;border-color: tomato;
`;render(<div><Button>Normal Button</Button><TomatoButton>Tomato Button</TomatoButton></div>
);
伪元素、伪选择器和嵌套
const Thing = styled.div.attrs((/* props */) => ({ tabIndex: 0 }))`color: blue;&:hover {color: red; // <Thing> when hovered}& ~ & {background: tomato; // <Thing> as a sibling of <Thing>, but maybe not directly next to it}& + & {background: lime; // <Thing> next to <Thing>}&.something {background: orange; // <Thing> tagged with an additional CSS class ".something"}.something-else & {border: 1px solid; // <Thing> inside another element labeled ".something-else"}
`render(<React.Fragment><Thing>Hello world!</Thing><Thing>How ya doing?</Thing><Thing className="something">The sun is shining...</Thing><div>Pretty nice day today.</div><Thing>Don't you think?</Thing><div className="something-else"><Thing>Splendid.</Thing></div></React.Fragment>
);
强制样式提升
const Thing = styled.div`&& {color: blue;}`const GlobalStyle = createGlobalStyle`div${Thing} {color: red;}`render(<React.Fragment><GlobalStyle /><Thing>I'm blue, da ba dee da ba daa</Thing></React.Fragment>)