Vue3移动端组件库Varlet源码主题阅读之一:本地启动服务时都做了什么
本文为
Varlet组件库源码主题阅读系列第一篇
Vue开源的组件库有很多,基本各个大厂都会做一个,所以作为个人再重复造轮子其实意义也不是很大,但是笔者对于如何设计一个Vue组件库还是挺感兴趣的。
不同的组件库架构肯定有所不同,不过大体思路应该都差不多,笔者在众多组件库中挑选了Varlet 来进行剖析,Varlet是一个基于 Vue3 开发的 Material 风格的移动端组件库,本系列的文章会全面解析这个项目,需要说明的是,不会具体的看某个组件是怎么实现的,而是了解组件库整体的设计,以及按需引入、主题定制、屏幕适配、组件打包、VsCode属性高亮等比较有意思的话题,话不多说,开始吧。
Varlet 版本为:1.27.20
项目结构
先克隆Varlet的项目:
git clone https://github.com/varletjs/varlet.git
初始结构如下:


packages目录下存在很多单独的包,我们后面都会进行介绍。
本地开发
根据官方文档的描述,我们可以使用下面的命令进行本地开发:

Varlet使用的包管理器是pnpm,pnpm是一个速度快、节省磁盘空间的软件包管理器,如果没安装的话需要先安装一下:
npm install -g pnpm
bootstrap命令如下:
pnpm install && node scripts/bootstrap.mjs
先安装依赖,然后执行bootstrap.mjs文件:
// bootstrap.mjs
import { buildCli, buildIcons, buildShared, buildUI, runTask } from './build.mjs'
;(async () => {
await runTask('shared', buildShared)
await Promise.all([runTask('cli', buildCli), runTask('icons', buildIcons)])
await runTask('ui', buildUI)
})()
运行了一波任务,挨个来看,先看runTask方法:
// build.mjs
import ora from 'ora'
export async function runTask(taskName, task) {
const s = ora().start(`Building ${taskName}`)
try {
await task()
s.succeed(`Build ${taskName} completed!`)
} catch (e) {
s.fail(`Build ${taskName} failed!`)
console.error(e.toString())
}
}
ora是一个命令行的loading工具,可以在终端显示好看的loading效果,然后就是执行传入的任务函数。
shared任务:
// build.mjs
import execa from 'execa'
import { resolve } from 'path'
const CWD = process.cwd()// 获取nodejs进程的当前工作目录,也就是项目的根目录
const PKG_SHARED = resolve(CWD, './packages/varlet-shared')// varlet-shared包的绝对路径
export const buildShared = () => execa('pnpm', ['build'], { cwd: PKG_SHARED })
execa是nodejs的child_process的改进版本,返回的是一个Promise,pnpm运行命令可以省略run,直接pnpm build即可,所以上述这个任务就是在varlet-shared包的目录下执行build命令:
tsc && tsc -p tsconfig.cjs.json
使用两个配置文件执行了两次tsc,也就是将src目录下的ts文件分别编译成了es模块和commonjs模块:

cli任务:
// build.mjs
const PKG_CLI = resolve(CWD, './packages/varlet-cli')
export const buildCli = () => execa('pnpm', ['build'], { cwd: PKG_CLI })
到varlet-cli目录下执行build命令:
tsc
同样也是编译ts,这个包的入口为./lib/index.js,未编译前lib目录下只有这一个文件,显然其他文件都是缺失的:

需要先编译才能使用这个包,编译后结果如下:

icons任务:
// build.mjs
const PKG_ICONS = resolve(CWD, './packages/varlet-icons')
export const buildIcons = () => execa('pnpm', ['build'], { cwd: PKG_ICONS })
进入varlet-icons目录下运行build命令:
varlet-icons build
varlet-icons命令的执行文件为同目录下的varlet-icons/lib/index.js,详细逻辑我们后面再说,先看一下运行结果:

其实就是将svg文件编译成字体图标。
ui任务:
// build.mjs
const PKG_UI = resolve(CWD, './packages/varlet-ui')
export const buildUI = (noUmd) => execa('pnpm', ['compile', noUmd ? '--noUmd' : ''], { cwd: PKG_UI })
进入varlet-ui目录下执行compile命令,和前面几个任务不同,这个任务会接收一个参数,顾名思义,是否不要生成umd,但是我搜索了一下并没有找到有传true的情况:

compile命令如下:
varlet-cli compile

该命令的作用是打包varlet的组件,具体实现逻辑后面再看,先看一下运行结果:

主要是编译组件,有三种产物:es模块、commonjs模块、umd模块。
启动前的任务都运行完了,接下来就可以进入varlet-ui目录启动服务了,启动命令pnpm dev:
varlet-cli dev
这个命令做的事情比较多,我们后面再详解,大体上呢会把varlet-cli目录下的site目录复制到varket-ui目录下,并且动态生成两个路由文件:mobile.routes.ts、pc.routes.ts:

访问启动的页面:

报错了,原因很简单,笔者是Windows电脑,路径的分隔符是反斜杠,所以生成的部分路径\没有转换成/,而\和.varlet组合起来会被认为是转义字符:

查看源码发现虽然已经使用了slash来转换Windows平台下的路径问题,但是不知道为啥没有生效:


没办法,只能手动修复一下,我们使用下面这种方法来转换:
import path from 'path'
xxx.split(path.sep).join('/')
修改完以后文档页面示例显示出来了:


右边手机模拟器里的组件导入的是varlet-ui/src/xxx目录下的,也就是开发目录下的组件,所以我们直接修改就可以在页面上查看效果了。
项目的本地启动部分就到这里,我们下篇再见~

浙公网安备 33010602011771号