Skip to main content

项目框架搭建

info
  • 选择项目结构(Mono-repo)
  • 定义开发规范(eslint、tsc、prettier)
  • 选择打包工具(rollup)
  • 相关代码可在 git tag v1.0 查看

选择项目结构

Multi-repo

  • 每个服务和项目都有一个单独的存储库
  • 团队可以自主工作; 个人的变更不会影响其他团队或项目的变更
  • 管理员可以将访问控制限制到开发人员需要访问的项目或服务
  • 良好的性能,因为有限的代码和较小的服务单元
  • 开发人员可以很容易地实现 CDCI,因为他们可以独立地构建服务
  • 对库和其他常见代码的任何更改都应该定期同步,以避免以后出现问题

Mono-repo

  • 一个组织的所有项目代码都使用一个中央存储仓库。
  • 团队可以一起协作和工作,可以看到彼此的变化。
  • 每个人都可以访问整个项目结构
  • 如果项目规模不断增长,可能会导致并发大问题。
  • 难以实现持续部署(CD)持续集成(CI)
  • 开发人员可以轻松地共享库、 和其他在中央存储库中更新的公共代码

很多大型项目都是用 Mono-repo 结构管理,比如 Vue,Bable,我们也选择 Mono-repo搭建项目

选择 Mono-repo 工具

安装 yarn

npm install yarn -g

初始化 yarn

yarn init -y

添加 workspace 配置

在根目录的 package.json 中新增 workspaceprivate 属性 如下:

package.json
{
"private": true,
"workspaces": ["packages/*"],
"type": "module",
"scripts": { "test": 'echo "Error: no test specified" && exit 1' },
"author": "",
"license": "MIT",
"packageManager": "yarn@1.22.22",
}

package.json文件定义了工作空间的根目录。也就是说, packages 目录下的文件就是 Mono-repo 的子项目。

配置 .gitignore

新增 .gitignore 文件,忽略以下的文件:

.gitignore
.idea/
.vscode/
node*modules/
build
*.tgz
my-app\_
template/src/**tests**/**snapshots**/
lerna-debug.log
npm-debug.log*
yarn-debug.log*
yarn-error.log\*
/.changelog
.npm/

.Ds_Store

配置 ESLint

使用 eslint 代码规范检查

安装 eslint

yarn  add eslint globals eslint-plugin-import-x  typescript-eslint -D -W

新增 eslint 配置

.eslint.config.js
import { builtinModules } from "node:module";

import globals from "globals";
import importX from "eslint-plugin-import-x";
import tseslint from "typescript-eslint";
import eslint from "@eslint/js";

const DOMGlobals = ["window", "document"];
const NodeGlobals = ["module", "require"];

const banConstEnum = {
selector: "TSEnumDeclaration[const=true]",
message:
"Please use non-const enums. This project automatically inlines enums.",
};

export default tseslint.config(
eslint.configs.recommended,
{
files: ["**/*.js", "**/*.ts", "**/*.tsx"],
extends: [tseslint.configs.base],
plugins: {
"import-x": importX,
},
rules: {
"no-debugger": "error",

"no-console": ["error", { allow: ["warn", "error", "info"] }],
// most of the codebase are expected to be env agnostic
"no-restricted-globals": ["error", ...DOMGlobals, ...NodeGlobals],

"no-restricted-syntax": [
"error",
banConstEnum,
{
selector: "ObjectPattern > RestElement",
message:
"Our output target is ES2016, and object rest spread results in " +
"verbose helpers and should be avoided.",
},
{
selector: "ObjectExpression > SpreadElement",
message:
"esbuild transpiles object spread into very verbose inline helpers.\n" +
"Please use the `extend` helper from @vue/shared instead.",
},
{
selector: "AwaitExpression",
message:
"Our output target is ES2016, so async/await syntax should be avoided.",
},
{
selector: "ChainExpression",
message:
"Our output target is ES2016, and optional chaining results in " +
"verbose helpers and should be avoided.",
},
],
"sort-imports": ["error", { ignoreDeclarationSort: true }],

"import-x/no-nodejs-modules": [
"error",
{ allow: builtinModules.map((mod) => `node:${mod}`) },
],
// This rule enforces the preference for using '@ts-expect-error' comments in TypeScript
// code to indicate intentional type errors, improving code clarity and maintainability.
"@typescript-eslint/prefer-ts-expect-error": "error",
// Enforce the use of 'import type' for importing types
"@typescript-eslint/consistent-type-imports": [
"error",
{
fixStyle: "inline-type-imports",
disallowTypeAnnotations: false,
},
],
// Enforce the use of top-level import type qualifier when an import only has specifiers with inline type qualifiers
"@typescript-eslint/no-import-type-side-effects": "error",

"import-x/order": [
"error",
{
groups: [
"builtin",
"external",
"internal",
"sibling",
"parent",
"index",
"unknown",
],
"newlines-between": "always",
},
],
},
},

// Node scripts
{
files: ["eslint.config.js", "scripts/**", "packages/*/npm/*.js"],
languageOptions: {
globals: { ...globals.node },
},
rules: {
"no-restricted-globals": "off",
"no-restricted-syntax": ["error", banConstEnum],
"no-console": "off",
},
}
);

配置 Prettier

安装 代码风格检查 prettier

安装 prettier

yarn add prettier -D -W

新增 .prettierrc

新建 .prettierrc 配置文件,添加配置:

.prettierrc
{
"printWidth": 100,
"semi": true,
"singleQuote": true,
"trailingComma": "all",
"htmlWhitespaceSensitivity": "strict",
"endOfLine": "auto",
"quoteProps": "as-needed",
"jsxSingleQuote": true,
"arrowParens": "avoid"
}

package.json"scripts" 中增加 lint 对应的执行脚本:

package.json
"lint": "eslint --ext .ts,.jsx,.tsx --fix --quiet ./packages"

配置 typescript

安装 typescript

yarn  add typescript @types/node -D -W

新增 tsconfig.json

tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"rootDir": ".",
"target": "esnext",
"module": "esnext",
"lib": ["dom", "dom.iterable", "esnext"],
"moduleResolution": "node",
"strict": true,
"allowJs": true,
"removeComments": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"types": ["node"],
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"paths": {
"react": ["packages/react"],
"shared": ["packages/shared"],
"react-reconciler": ["packages/react-reconciler"]
}
},
"include": ["packages/**/*.ts", "packages/**/*.d.ts"],
"exclude": ["node_modules"]
}

选择打包工具(rollup)

因为我们要开发的是一个库,而不是业务代码。希望工具尽可能简洁,打包产物可读性高,所以选择 rollup

安装 rollup

yarn add rollup -D -W

新建文件夹 scripts/rollup,用于放所有的打包脚本。