使用pnpm的workplace搭建Vue3项目实践

·  阅读 1728
使用pnpm的workplace搭建Vue3项目实践

我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第1篇文章,点击查看活动详情

之前有一段时间使用过qiankun微前端,每个子项目都有同样的api请求模块和可复用的组件,想要抽离出来公用,却没有想到比较好的方法。

了解了pnpm的workplace和Lerna,还有monorepo,所以想着又又又搭建一个Vue3项目的monorepo仓库。

旧的做法

在没有使用monorepo的情况下,选择了多代码库(multirepos),其实就是每个子项目单独一个git仓库,而公共api模块和公共组件模块也是一个git仓库,使用npm的file方式引入。

如package.json代码所示,使用npm install ../common/就可以引入。

// package.json
{ 
    "name": "project-name", 
    "version": "0.1.0", 
    "dependencies": { 
        "common": "file:../common" 
    } 
//... 
}
复制代码

但十分难受的是,如果修改了common模块的代码,需要再跑一次npm install,而且可能需要把子项目node_modules下的common文件夹删了再安装才行,或许是需要修改common模块的版本version才行吧。

每次修改common模块的代码都要安装一次,真的太麻烦了。而且因为common模块为独立的git仓库,会存在其他同事代码未提交,导致其他子项目报错的问题。并且每完成一个完整的功能,多个仓库也需要分别提交代码,也是相对麻烦的。

开始搭建

创建根目录项目

Vue3新的官方文档上线之后,才知道可以用npm init vue@3创建项目,基本可以vue-cli一样,都是可选各类配置。

这里选择了vue-routerpiniaeslint,没有选ts,大家可以根据需要自选。

WX20220910-161117.png

项目初始化之后,需要打开终端执行pnpm i,然后按照pnpm官网的说法,新建pnpm-workspace.yaml文件

packages:
  # 子项目模块
  - 'packages/*'
  # 全局组件模块
  - 'components/**'
  # api请求模块
  - 'apis/**'
  # 公共方法模块
  - 'utils/**'
  # exclude packages that are inside test directories
  - '!**/test/**'
复制代码

在项目根目录新建packages文件夹,packages/*是子项目模块的文件夹,里面放子项目的代码,后续依旧是使用npm init vue@3初始化。

'components/**''apis/**''utils/**'这三个模块可以使用vite初始化

使用vite初始化模块

可以使用vite创建单纯的js项目,相对简约一些。

api请求模块

打开终端,使用pnpm create vite创建apis模块,项目名称是apis,接着选择VanillaJavaScript

Project name: … apis
✔ Select a framework: › VanillaSelect a variant: › JavaScript
复制代码

然后对项目进行删减,把不需要的文件删除,然后新建index.jsrequest.js文件和modules文件夹。

image.png

在apis文件夹打开终端安装axiospnpm i axios -S

二次封装axios的文章太多了,这里就简单地做请求拦截和响应拦截就完了,大家可以在掘金找到合适的封装方式,或者了解开源项目的封装方式,实现自己的需求。

request.js代码如下

import axios from "axios";

const http = axios.create({
  baseURL: "",
  timeout: 1000 * 60,
  withCredentials: true
});

// 请求拦截
http.interceptors.request.use((config) => {
    // 防止缓存,GET请求默认带_t参数
    if (config.method === "get") {
      config.params = {
        ...config.params,
        ...{ _t: new Date().getTime() },
      };
    }
    return config;
  },
  (error) => {
    return Promise.reject(error);
  }
);

// 响应拦截
http.interceptors.response.use((response) => {
    if (response.data.code === 401 || response.data.code === 10001) {
      return Promise.reject(response.data.msg);
    }
    return response;
  },
  (error) => {
    return Promise.reject(error);
  }
);

export default http;
复制代码

在modules文件夹下创建用户模块的请求,新建users.js文件,代码如下

import http from '../request'

export const findAll = (params) => {
  return http({
    url: '/api/users/findAll',
    method: 'get',
    params
  })
}
复制代码

最后在index.js文件中引入并导出users模块,代码如下

import * as users from './modules/users'

export default {
  users
}
复制代码

在项目中引入使用

可以使用pnpm add apis的方式引入,但尝试后发现会安装到npm社区的包,所以建议修改apis中package.json文件的name。

比如修改为@project/apis,再引入pnpm add @project/apis就可以了.

可以看到根目录的package.json中多了"@project/apis": "workspace:^0.0.1",,附带了apis模块的版本号,也可以修改为"@project/apis": "workspace:*",

这时候可以新建vue文件,在onMounted的时候调用请求,在控制台有请求发出,那就已经成功了。

可以配合我之前的NestJS文章,搭建简单的后端测试效果

image.png

全局组件模块

和上面一样,依旧是vite创建项目,选择vue的模板

npm create vite
Need to install the following packages:
  create-vite
Ok to proceed? (y) 
✔ Project name: … components
✔ Select a framework: › VueSelect a variant: › JavaScript
复制代码

这里选择使用element-plus,根目录项目和用到组件模块的项目都建议安装。接着删减不需要的文件和目录,并在src目录下新建vue组件。

image.png

依旧是需要在index.js文件中进行导出,可以看到这里加了一个name属性,是作为全组注册组件的名称使用,也可以使用文件名称,export出去的模块有个__name属性可以作为组件名称使用。

import TestBtn from "./src/testBtn/index.vue";
TestBtn.name = "testBtn";

export default { TestBtn };
export {
  TestBtn
}
复制代码

自动注册全局组件

Vue项目中的实用技巧记录 - 掘金 (juejin.cn),这篇文章中有webpackvite,如何在vue项目中自动注册全局组件的案例,并且使用到ts。

使用之前需要安装组件模块,和上面的api模块一样,需要修改package.json文件的name,然后pnpm add @project/components,如果是按需引入,在vue组件中import { TestBtn } from '@project/components'即可。

下面是全局注册的做法,在项目根目录中新建autoRegistCompontents.js,引入所有组件并全局注册,代码如下。

import gobalComponents from '@project/components'
import { defineComponent } from "vue";

const autoRegist = {
  install(app) {
    for (const key in gobalComponents) {
      const component = gobalComponents[key]
      const name = component.name
      app.component(name, defineComponent(component));
    }
  }
}

export default autoRegist
复制代码

最后在mian.js中调用autoRegist的注册方法。

import autoRegist from "./autoRegistCompontents";

app.use(autoRegist)
复制代码

在项目中使用

直接调用即可

<test-btn></test-btn>
复制代码

image.png

utils模块

和api模块类似,这里就不赘述了,可以直接看git的代码

子项目搭建

子项目需要在packages文件夹下初始化,作为独立项目开发使用,需要把上面的模块通通引入。

pnpm add @project/components
pnpm add @project/apis
pnpm add @project/utils
复制代码

复制autoRegistCompontents.js到项目中,并在main.js中使用。

子项目代码如下

packages/system · Elvis/monorepo-workplace - 码云 - 开源中国 (gitee.com)

总结

monorepo解决了微前端或多个前端项目可以在一个git仓库管理的问题,提取各项目的公用部分成为单独模块,减少了多个项目组件模块,api请求模块代码大量重复问题。不仅适用于微前端,若是有多个项目有大量公用代码重复,且又是独立的git仓库管理,可考虑改用monorepo的git管理方式。

完整代码如下

monorepo-workplace: pnpm的workplace项目 (gitee.com)

文章推荐

Nestjs入门,使用nest-cli创建项目并新建接口 - 掘金 (juejin.cn)

逃离土味团队和鲨鱼辣椒领导|2022年中总结 - 掘金 (juejin.cn)

Vue3如何更好地使用qrcodejs生成二维码并添加文字描述 - 掘金 (juejin.cn)

分类:
前端
收藏成功!
已添加到「」, 点击更改