使用 monorepo 架构创建项目

pnpm workspace 实践

项目架构采用 pnpm workspace + changelog + husky

github 示例地址1 - Vue+Nest 全栈模版 github 示例地址2 - Vue+TS 前端模版

pnpm

项目初始化,修改车生成的 package.json 文件中的 private:true,防止根目录发布

sh 复制代码
pnpm init

根目录创建 pnpm-workspace.yaml 文件

配置 pnpm 的 monorepo 工作区,比如这里我们配置 blog 是博客主体,play 是测试用的,packages 下面又可以有主题包、组件包、工具包等等

这里注意一下,如果是多项目方式,根目录 package.json 中的 name 为项目名(看自己想定什么就设置一下)

而子项目中的 package.json 文件中的 name 就需要以 @ + 根目录 package.json 中的 name 名 + / + 子项目名

yaml 复制代码
packages:  
  - 'packages/*'
  - 'doc'

指定运行Node、pnpm 版本

json 复制代码
{
    "engines": {
        "node": ">=20",
        "pnpm": ">=8"
    }
}

接下来我们切换到 packages 目录中,创建子项目 比如我这里要创建 vitepress 项目

sh 复制代码
cd doc

pnpm dlx vitepress init

创建 vue 项目就使用

sh 复制代码
pnpm create vite

只允许使用 pnpm

如果不希望其他人使用 yarn、npm 等包管理器,只需要在 package.json 文件添加以下命令

json 复制代码
{
    "scripts": {
        "preinstall": "npx only-allow pnpm"
    }
}

只要有人使用其他包管理器安装依赖就会报错!

添加依赖

  • 全局依赖
sh 复制代码
pnpm add xxx -D -W
# or 
pnpm add xxx -Dw

-W:workspace-root 把依赖安装到全局 node_modules -D:开发依赖

依赖区别: dependencies:生产依赖 devDependencies:开发依赖 peerDependencies:宿主依赖(运行主依赖),指定当前模块包在使用需要安装的依赖

  • 局部依赖
sh 复制代码
# 路径在需要引入依赖的目录
pnpm add xxx -D

# 在根目录 @xxx/xxx 为子项目 name 名
pnpm add xxx -F @xxx/xxx

ESLint && Prettier

引入依赖

sh 复制代码
pnpm add eslint prettier -Dw

# 初始化 eslint 配置
pnpm eslint --init

# 其他依赖
pnpm add -Dw @typescript-eslint/parser eslint-plugin-vue @typescript-eslint/eslint-plugin

# 解决冲突
pnpm add eslint-config-prettier eslint-plugin-prettier -Dw

解决冲突

.eslintrc.cjs

js 复制代码
{
  extends: [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:vue/vue3-essential",
    // 将 prettier 放在最后面,让它的优先级比 eslint 低一点
    "plugin:prettier/recommended",
  ],
}

添加检查命令

json 复制代码
{
    "lint": "eslint . --ext .vue,.js,.ts,.jsx,.tsx",
    "format": "prettier --write ./**/*.{vue,ts,tsx,js,jsx,css,less,scss,json,md}",
}

内部包的引用

husky + lint-staged 代码预检查

引入依赖

sh 复制代码
pnpm add husky lint-staged -Dw

添加脚本命令到 json 中

json 复制代码
{
  "prepare": "husky install"
}

运行一下命令,创建一个 pre-commit 钩子

sh 复制代码
#手动运行
pnpm prepare

#添加 pre-commit 钩子
npx husky add .husky/pre-commit "npx --no-install lint-staged"

pre-commit

sh 复制代码
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

# 这是自己加的
echo "--------- 代码预检查 ---------"

npx --no-install lint-staged

配置 lint-staged,在 package.json 中添加下面的配置信息

json 复制代码
//与 scripts 同一级
{
  "lint-staged": {
    "*.{js,vue,ts,jsx,tsx}": [
      "prettier --write",
      "eslint --fix"
    ],
    "*.{html,css,less,scss,md}": [
      "prettier --write"
    ]
  },
}

提交规范

引入依赖

sh 复制代码
pnpm add @commitlint/cli @commitlint/config-conventional cz-git -Dw

添加命令

json 复制代码
{
    "type":"module",
      "scripts": {
    "cz": "git cz",
  },
      "config": {
    "commitizen": {
      "path": "node_modules/cz-git"
    }
  },
}

我们用它来限制不符合规范的提交信息,根目录创建commitlint.config.js文件-如果后面报错就需要将文件改为 .cjs 同时还需修改一些内容

js 复制代码
// commitlint.config.js

/** @type {import('cz-git').UserConfig} */
export default {
  extends: ["@commitlint/config-conventional"],
  rules: {
    "type-enum": [
      2,
      "always",
      [
        "feat",
        "fix",
        "docs",
        "style",
        "refactor",
        "test",
        "build",
        "chore",
        "perf",
        "ci",
        "revert",
      ],
    ],
    "type-case": [2, "always", "lower-case"],
    "type-empty": [2, "never"],
    "subject-full-stop": [2, "never", "."],
    "header-max-length": [2, "always", 100],
    "subject-case": [
      2,
      "never",
      ["sentence-case", "start-case", "pascal-case", "upper-case"],
    ],
  },
  prompt: {
    useEmoji: true,
    allowCustomIssuePrefix: true,
    allowEmptyIssuePrefix: true,
    confirmColorize: true,
    messages: {
      type: "选择你要提交的类型 :",
      scope: "选择一个提交范围(可选):",
      customScope: "请输入自定义的提交范围 :",
      subject: "填写简短精炼的变更描述 :\n",
      body: "填写更加详细的变更描述(可选)。使用 '|' 换行 :\n",
      breaking: "列举非兼容性重大的变更(可选)。使用 '|' 换行 :\n",
      footerPrefixesSelect: "选择关联issue前缀(可选):",
      customFooterPrefix: "输入自定义issue前缀 :",
      footer: "列举关联issue (可选) 例如: #31, #I3244 :\n",
      confirmCommit: "是否提交或修改commit ?",
    },
    types: [
      {
        value: "feat",
        emoji: "✨",
        name: "feat:     新增功能 | A new feature",
      },
      { value: "fix", name: "fix:      修复缺陷 | A bug fix" },
      {
        value: "docs",
        emoji: "📚",
        name: "docs:     文档更新 | Documentation only changes",
      },
      {
        value: "style",
        emoji: "💎",
        name: "style:    代码格式 | Changes that do not affect the meaning of the code",
      },
      {
        value: "refactor",
        emoji: "📦",
        name: "refactor: 代码重构 | A code change that neither fixes a bug nor adds a feature",
      },
      {
        value: "perf",
        emoji: "🚀",
        name: "perf:     性能提升 | A code change that improves performance",
      },
      {
        value: "test",
        emoji: "🚨",
        name: "test:     测试相关 | Adding missing tests or correcting existing tests",
      },
      {
        value: "build",
        emoji: "🛠",
        name: "build:    构建相关 | Changes that affect the build system or external dependencies",
      },
      {
        value: "ci",
        emoji: "⚙️",
        name: "ci:       持续集成 | Changes to our CI configuration files and scripts",
      },
      {
        value: "revert",
        emoji: "🗑",
        name: "revert:   回退代码 | Revert to a commit",
      },
      {
        value: "chore",
        emoji: "♻️",
        name: "chore:    其他修改 | Other changes that do not modify src or test files",
      },
    ],
  },
};

使用 husky 生成 commit-msg 文件,验证提交信息

sh 复制代码
npx husky add .husky/commit-msg "npx --no-install commitlint --edit $1"

commit-msg

sh 复制代码
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

# 自己加的
echo "--------- 执行commit-msg校验 ---------"

npx --no-install commitlint --edit $1

changeset

引入依赖并初始化

sh 复制代码
# -D 开发依赖
# -w 公共依赖
pnpm add -Dw @changesets/cli

# 初始化
pnpm changeset init

初始化后会在根目录下生成 .changeset 文件夹

其中 config.json 作为默认 changeset 配置文件

  • changelog: changelog 生成方式
  • commit: 不要让 changeset 在 publish 的时候帮我们做 git add
  • linked: 配置哪些包要共享版本
  • access: 公私有安全设定,内网建议 restricted ,开源使用 public
  • baseBranch: 项目主分支
  • updateInternalDependencies: 确保某包依赖的包发生 upgrade,该包也要发生 version upgrade 的衡量单位(量级)
  • ignore: 不需要变动 version 的包
  • ___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH: 在每次 version 变动时一定无理由 patch 抬升依赖他的那些包的版本,防止陷入 major 优先的未更新问题

changeset 常用命令及说明

sh 复制代码
# 使用 changeset 进行记录版本修改
npx changeset add

# 使用 changeset version 提交版本修改
npx changeset version

# 使用 changeset publish 进行发包
npx changeset publish

版本号一般有三个部分,以.隔开,就像 X.Y.Z,其中

  • X:主版本号,不兼容的大改动,major
  • Y:次版本号,功能性的改动,minor
  • Z:修订版本号,问题修复,patch

changeset version 提交版本修改

.npmrc

pnpm 常用

.npmrc 复制代码
strict-peer-dependencies=false
shell-emulator=true
auto-install-peers=false
相关推荐
MediaTea8 小时前
Python:模块 __dict__ 详解
开发语言·前端·数据库·python
aigcapi9 小时前
[深度观察] RAG 架构重塑流量分发:2025 年 GEO 优化技术路径与头部服务商选型指南
大数据·人工智能·架构
字节跳动开源9 小时前
Midscene v1.0 发布 - 视觉驱动,UI 自动化体验跃迁
前端·人工智能·客户端
Gavin在路上9 小时前
智能体之深入解析 LLM 多智能体 (Multi-Agent) 四大主流架构(6)
架构
光影少年9 小时前
三维前端需要会哪些东西
前端·webgl
王林不想说话10 小时前
React自定义Hooks
前端·react.js·typescript
heyCHEEMS10 小时前
Uni-app 性能天坑:为什么 v-if 删不掉 DOM 节点
前端
马致良10 小时前
三年前写的一个代码工具,至今已被 AI Coding 完全取代。
前端·ai编程
橙某人10 小时前
LogicFlow 交互新体验:让锚点"活"起来,鼠标跟随动效实战!🧲
前端·javascript·vue.js
借个火er10 小时前
依赖注入系统
前端