Bootstrap

【git】如何实现规范git commit -m的格式

.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>
 )

;