前端乱码-前端组件库搭建之pnpm workspace

3,070 阅读4分钟

最近在考虑搭个小的组件库,主要是用来学习TS、Vue3,由于组件库需要文档,测试项目,测试用例等等,如果安装多个项目,安装依赖这活就有点上头。看了些社区的文章,monorepo这种方式可以帮助把依赖放到统一的仓库中进行管理。过去使用lerna + yarn workspace, 现在比较流行的是pnpm workspace。确定使用pnpm后向各方借鉴学习,写了个小的MVP,作为组件库的第一步。

一、搭建workspace

  1. 新建项目并初始化
    mkdir jedi-space
    cd jedi-space
    pnpm init

  2. 新建pnpm-workspace.yaml 文件

packages:
    # packages 目录下的所有次级目录
  - "packages/**" 
    # 测试文件夹
  - "example"
    # 文档目录
  - "docs"
  1. 完善目录文件夹
jedi-space
├─ docs
├─ example
├─ package.json
├─ packages
└─ pnpm-workspace.yaml

4. 在根目录安装依赖
pnpm i vite -w
pnpm i vue@latest -w

  1. packages文件夹 新增components文件夹,进入components路径pnpm init 初始化一下
    {
     "name": "@jedi-space/components",
     "version": "1.0.0",
     "description": "",
     "main": "index.js",
     "scripts": {
       "test": "echo \"Error: no test specified\" && exit 1"
     },
     "keywords": [],
     "author": "",
     "license": "ISC"
    }

name是workspace中其他项目判断的重要依据,根据自己需要重命名

二、搭建测试项目

  1. example文件夹重复操作并且新增html.index文件
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Example</title>
</head>
<body>
  <div id="app"></div>
  <script src="./src/main.ts" type="module"></script>
</body>
</html>

  1. 新增src文件夹,src目录新增main.ts
import {createApp} from 'vue'
import App from './App.vue'

createApp(App).mount('#app')
  1. 新建app.vue
<template>
 <div class=''>
  hello example
 </div>
</template>
<script lang='ts' setup name='App'>

</script>
  1. 安装依赖, -w 表示安装workspace依赖,pnpm-workspace.yaml中涵盖的目录会用到
    pnpm i vite -wD
    pnpm i vue -w
    pnpm i @vitejs/plugin-vue -wD
    pnpm i @vitejs/plugin-vue-jsx -wD
    喜欢SFC就安装@vitejs/plugin-vue, 喜欢jsx就安装@vitejs/plugin-vue-jsx。

  2. 在example文件夹中新增vite.config.ts

import {defineConfig} from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'

export default defineConfig({
  plugins: [
    vue(),
    vueJsx()
  ]
})
  1. example目录下package.json 的script中添加
"scripts": {
    ...
    "dev": "vite"
  },

启动命令pnpm vite

image.png

example 暂且搞定。
另外,根目录添加shims-vue.d.ts文件,处理下图的警告提示

image.png

declare module "*.vue" {
  import { DefineComponent } from "vue";
  const component: DefineComponent<{}, {}, any>;
  export default component;
}

三、组件库编写

  1. packages/components目录下新建sfcButton文件夹,编写简单的sfc版本button组件 sfcButton/src/Button.vue
<template>
 <button>
  <slot>SFC按钮</slot>
 </button>
</template>
<script lang='ts' setup>
  defineOptions({ name: 'SfcButton'})
</script>

sfcButton/index.ts

    import SfcButton from './src/Button.vue'
    export default SfcButton
  1. packages/components目录下新建jsxButton文件夹,编写简单的jsx版本button组件 jsxButton/src/Button.vue
import {defineComponent} from 'vue'

export default defineComponent({
  name:'JsxButton',
  setup(props,context){
    return <button>
      {context.slots.default?.()}
    </button>
  }
})

jsxButton/index.ts

import JsxButton from './src/Button'
export default JsxButton
  1. 处理报错 image.png

根目录新建tsconfig.json

    {
      "compilerOptions": {
        "jsx": "preserve"
      }
    }

4. 好了,此时在packages/components目录新建index.ts文件用于导出文件

import {App} from 'vue'
import JsxButton from './jsxButton'
import SfcButton from './sfcButton'

export{JsxButton,SfcButton}
export default{
  install(app:App){
    app.component(JsxButton.name, JsxButton)
    app.component(SfcButton.name, SfcButton)
  }
}
  1. 然后在example项目中安装组件,名称如图

image.png

pnpm i @jedi-space/components

安装成功后如图

image.png

  1. 更新example/src目录的main.ts
import {createApp} from 'vue'
import App from './App.vue'
import JediUI from '@jedi-space/components'

const app = createApp(App)
app.use(JediUI)
app.mount('#app')

app.vue文件使用组件

<template>
 <div class=''>
  hello example
  <br>
  <SfcButton>JediButton🍊</SfcButton>
  <br>
  <JsxButton>jsxButton🍓</JsxButton>
 </div>
</template>
<script lang='ts' setup>
 defineOptions({name:'App'})
</script>

It works!

image.png

四、下面处理文档项目

  1. 老样子先pnpm init初始化项目 docs路径安装依赖
    pnpm i vitepress@0.22.4 -D
    pnpm i @jedi-space/components

docs目录新建index.md文件
docs项目终端输入echo '# Hello deji-space'>index.md

package.json中加入启动脚本

"scripts": {
    ...
    "docs:dev": "vitepress dev",
    "docs:build": "vitepress build",
    "docs:serve": "vitepress serve"
  },

在docs目录运行pnpm docs:dev可以看到项目可以跑起来了

image.png

  1. 下面就是展示button组件了
    新建.vitepress文件夹
    添加config.js文件
const sidebar = {
  '/': [
    { text: '快速开始', link: '/' },
    {
      text: '按钮',
      children: [
        { text: 'Button 按钮', link: '/components/button/' },
      ]
    },
  ]
}
const config = {
  themeConfig: {
    sidebar,
  }
}
export default config

docs/components/button目录新增index.md文件

# JediButton

<SfcButton>Jedi-SFC-Button🍊</SfcButton>
<JsxButton>Jedi-JSX-Button🍓</JsxButton>
  1. .vitepress/theme目录新建index.ts,用以获取vue实例并注册组件
import Theme from 'vitepress/theme'
import JediUI from '@jedi-space/components'

export default {
    ...Theme,
    enhanceApp: async ({ app}) => {
        app.use(JediUI)
    },
}
  1. 然后还需要解决jsx文件的引入问题docs目录新增vite.config.ts文件
import { defineConfig } from "vite"
import vueJsx from "@vitejs/plugin-vue-jsx"
export default defineConfig({
  plugins: [
    vueJsx(),
  ]
})

完成后pnpm docs:dev 启动项目

image.png

  1. 可以通过安装vitepress-theme-demoblock优化演示效果
    pnpm i vitepress-theme-demoblock@1.4.2 -D
    .vitepress/theme/index.ts 路径文件添加配置
...
import Demo from 'vitepress-theme-demoblock/components/Demo.vue'
import DemoBlock from 'vitepress-theme-demoblock/components/DemoBlock.vue'

export default {
 ...Theme,
  enhanceApp: async ({ app}) => {
    ...
    app.component('Demo', Demo)
    app.component('DemoBlock', DemoBlock)
  },
}

.vitepress/config.ts目录文件添加配置

import {demoBlockPlugin} from 'vitepress-theme-demoblock'
...
const config = {
  ...
  markdown: {
    config: (md) => {
      // 添加DemoBlock插槽
      md.use(demoBlockPlugin)
    }
  }
}
export default config
  1. components/button/index.md文件修改
    # JediButton

    :::demo

    ```vue
    <template>
      <SfcButton>Jedi-SFC-Button🍊</SfcButton>
      <JsxButton>Jedi-JSX-Button🍓</JsxButton>
    </template>
    ```
    :::

pnpm docs:dev重启项目, 搞定!

image.png

[仓库地址](youknowHRT/jedi-space-demo: pnpm workspace MVP (github.com))