搭建组件库vue(monorepo )

原笔记Eric's Wiki

项目初始化

shell

mkdir toy-element

cd toy-element

git init

code .

用 vscode 打开,既然是 monorepo ,那就先创建一个 pnpm-workspace.yaml 文件。

shell

mkdir packages

echo -e 'packages:\n  - "packages/*"' > pnpm-workspace.yaml

pnpm init

创建 .gitignore

# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
coverage
dist
dist-ssr
*.local

/cyperss/videos/
/cypress/srceenshots/

.vitepress/dist
.vitepress/cache

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

为了目录扁平,我就只创建 packages 这么一个 pnpm 工作区,下面大概介绍一下这个项目计划的分包结构

shell

- components # 组件目录
- core # npm 包入口
- docs # 文档目录
- hooks # 组合式API hooks 目录
- play # 组件开发实验室
- theme # 主题目录
- utils # 工具函数目录

好接下来创建这些子包的目录

shell

ce packages

在 packages 目录下创建 init.shell 内容如下

shell

for i in components core docs hooks theme utils; do
  mkdir $i
  cd $i
  pnpm init
  cd ..
done

执行后删除 init.shell

这波 play 目录先留着,我们用 vite 来创建一个 vue 开发项目

shell

pnpm create vite play --template vue-ts

分别到 各个分包目录中修改 package.json 中的 name

安装基础依赖

shell

pnpm add -Dw typescript@^5.2.2 vite@^5.1.4 vitest@^1.4.0 vue-tsc@^1.8.27 postcss-color-mix@^1.1.0 postcss-each@^1.1.0 postcss-each-variables@^0.3.0 postcss-for@^2.1.1 postcss-nested@^6.0.1 @types/node@^20.11.20 @types/lodash-es@^4.17.12 @vitejs/plugin-vue@^5.0.4 @vitejs/plugin-vue-jsx@^3.1.0 @vue/tsconfig@^0.5.1

pnpm add -w lodash-es@^4.17.21 vue@^3.4.19

在 根目录 package.json 中添加如下内容

json

{
  "dependencies": {
    "toy-element": "workspace:*",
    "@toy-element/hooks": "workspace:*",
    "@toy-element/utils": "workspace:*",
    "@toy-element/theme": "workspace:*"
  }
}

接下来,添加 分包 中的依赖

  • components

  • shell
    pnpm add -D @vue/test-utils@^2.4.5 @vitest/coverage-v8@^1.4.0 jsdom@^24.0.0 --filter @toy-element/components
    pnpm add @popperjs/core@^2.11.8 async-validator@^4.2.5 --filter @toy-element/components
  • core

    在 core/package.json 中添加如下内容

  • json
    {
      "dependencies": {
        "@toy-element/components": "workspace:*"
      }
    }
  • docs

  • shell
    pnpm add -D [email protected] --filter @toy-element/docs
  • play

    将 play/package.json 中冗余部分删除

创建各个分包 入口

首先我们在根目录创建一些必要额配置文件

postcss.config.cjs

js

/* eslint-env node */
module.exports = {
  plugins: [
    require("postcss-nested"),
    require("postcss-each-variables"),
    require("postcss-each")({
      plugins: {
        beforeEach: [require("postcss-for"), require("postcss-color-mix")],
      },
    }),
  ],
};

tsconfig.json

json

{
  "extends": "@vue/tsconfig/tsconfig.dom.json",
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "module": "ESNext",
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "skipLibCheck": true,

    /* Bundler mode */
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "preserve",
    "jsxImportSource": "vue",

    /* Linting */
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true
  },
  "include": ["packages/**/*.ts", "packages/**/*.tsx", "packages/**/*.vue"]
}

tsconfig.node.json

json

{
  "extends": "@tsconfig/node18/tsconfig.json",
  "include": ["packages/**/**.config.ts"],
  "compilerOptions": {
    "composite": true,
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "types": ["node"]
  }
}
  • components

    创建 index.ts 以及第一个开胃菜 Button 组件的目录

    我们先在 Button 目录创建一个最简陋的 vue sfc

vue

并在 Button 目录中创建 入口 index.ts 导出我们的 Button 组件

注: 这里说明一下,我们这次的组件库项目每个组件的目录大致结构如下,简单统一规范一下

  • shell
    - Xxx.test.tsx
    - Xxx.vue
    - types.ts
    - style.css
    - index.ts
    - * constants.ts

    在 components/index.ts 中导出我们的 Button 组件

    改 package.json 中 入口为 index.ts

  • core

    创建 index.tscomponents.ts

typescript

// components.ts

import { ErButton } from "@toy-element/components";
import type { Plugin } from "vue";

export default [ErButton] as Plugin[];

创建 第一个 utils 文件 install.ts 用于 vue plugin 安装的一系列操作

typescript

import type { App, Plugin } from "vue";
import { each } from "lodash-es";

type SFCWithInstall = T & Plugin;

export function makeInstaller(components: Plugin[]) {
  const install = (app: App) =>
    each(components, (c) => {
      app.use(c);
    });

  return install;
}

export const withInstall = (component: T) => {
  (component as SFCWithInstall).install = (app: App) => {
    const name = (component as any)?.name || "UnnamedComponent";
    app.component(name, component as SFCWithInstall);
  };
  return component as SFCWithInstall;
};

在 core/index.ts 中导出我们的 components

  • typescript
    import { makeInstaller } from "@toy-element/utils";
    import components from "./components";
    
    const installer = makeInstaller(components);
    
    export * from "@toy-element/components";
    export default installer;

    改 package.json 中 入口为 index.ts

  • theme 创建 index.cssreset.css 在 theme/index.css 中导入 reset.css

css

/** reset.css */
body {
  font-family: var(--er-font-family);
  font-weight: 400;
  font-size: var(--er-font-size-base);
  line-height: calc(var(--er-font-size-base) * 1.2);
  color: var(--er-text-color-primary);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  -webkit-tap-highlight-color: transparent;
}

a {
  color: var(--er-color-primary);
  text-decoration: none;

  &:hover,
  &:focus {
    color: var(--er-color-primary-light-3);
  }

  &:active {
    color: var(--er-color-primary-dark-2);
  }
}

h1,
h2,
h3,
h4,
h5,
h6 {
  color: var(--er-text-color-regular);
  font-weight: inherit;

  &:first-child {
    margin-top: 0;
  }

  &:last-child {
    margin-bottom: 0;
  }
}

h1 {
  font-size: calc(var(--er-font-size-base) + 6px);
}

h2 {
  font-size: calc(var(--er-font-size-base) + 4px);
}

h3 {
  font-size: calc(var(--er-font-size-base) + 2px);
}

h4,
h5,
h6,
p {
  font-size: inherit;
}

p {
  line-height: 1.8;

  &:first-child {
    margin-top: 0;
  }

  &:last-child {
    margin-bottom: 0;
  }
}

sup,
sub {
  font-size: calc(var(--er-font-size-base) - 1px);
}

small {
  font-size: calc(var(--er-font-size-base) - 2px);
}

hr {
  margin-top: 20px;
  margin-bottom: 20px;
  border: 0;
  border-top: 1px solid var(--er-border-color-lighter);
}
  • css
    /** index.css */
    @import "./reset.css";

    改 package.json 中 入口为 index.css 在 core/index.ts 中导出我们的 theme

    好,我们去 play 目录中看看效果

创建VitePress文档

直接参考官方文档 快速开始 | VitePress

npx vitepress init

npm script 以及 gihub actions

首先我们创建一些 必要的 npm script

在 根目录 package.json 中添加

json

{
  "scripts": {
    "dev": "pnpm --filter @toy-element/play dev",
    "docs:dev": "pnpm --filter @toy-element/docs dev",
    "docs:build": "pnpm --filter @toy-element/docs build",
    "test": "echo \"todo\""
  }
}

跑一跑试一下

接下来去 github 创建一个仓库,复制仓库地址

shell

git remote add origin https://github.com/your-name/your-repo.git

创建一个 .github/workflows/test-and-deploy.yml 文件,内容如下

yaml

name: Test and deploy

on:
  push:
    branches:
      - master

jobs:
  test:
    name: Run Lint and Test
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repo
        uses: actions/checkout@v3

      - name: Setup Node
        uses: actions/setup-node@v3

      - name: Install pnpm 
        run: npm install -g pnpm

      - name: Install dependencies
        run: pnpm install --frozen-lockfile

      - name: Run tests
        run: npm run test

  build:
    name: Build docs
    runs-on: ubuntu-latest
    needs: test

    steps:
      - name: Checkout repo
        uses: actions/checkout@v3

      - name: Setup Node
        uses: actions/setup-node@v3

      - name: Install pnpm
        run: npm install -g pnpm

      - name: Install dependencies
        run: pnpm install --frozen-lockfile

      - name: Build docs
        run: npm run docs:build

      - name: Upload docs
        uses: actions/upload-artifact@v3
        with:
          name: docs
          path: ./packages/docs/.vitepress/dist

  deploy:
    name: Deploy to GitHub Pages
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: Download docs
        uses: actions/download-artifact@v3
        with:
          name: docs

      - name: Deploy to GitHub Pages
        uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${
  
  { secrets.GH_TOKEN }}
          publish_dir: .

去 github 仓库的 setting 中设置 secrets

好了,我们可以提交我们的 “first commit” 了

你可能感兴趣的:(组件库,vue.js,前端,javascript)