Howdyjs组件库迁移Vue3设计与总结
/ / 总字数855,阅读预计耗时5分钟
目录
将个人组件库 Howdyjs 使用 Vue + Typescript 进行重构,使用 Vite 构建开发站点,Rollup 进行组件打包并分包发布 NPM。
Link
主要变更
- 新版全面采用
Typescript
- Vue 组件部分将使用
Vue3
重构,不向下兼容,有 Vue2.X 需求的请使用旧版 - 因各组件内的关联性不强,新版的组件库将进行分包发布,可便于按需加载
- 旧版多数包都将功能封装成 Vue 指令,并默认导出的是 Vue 指令,现在新版将默认导出原生构造函数,便于跨框架或原生使用,但同时保留了 Vue 指令封装的使用方式
- 使用
lerna
进行分包管理 - 使用
Rollup
进行组件打包 - 展示站点使用
Vite
搭建
架构说明
Vite
综合对比之后,发现采用 Vite 基本可以实现当前展示站点的所有功能,而且在开发环境下热更新速度极快,所以新版项目采用了 Vite 构建开发站点。
由于项目有导入.md 文件的需求,而 Vite 并不能直接使用 Webpack 的 markdown-loader,所以暂时自己写一个简单的 markdown-plugin 在 Vite 中使用
const markdownPlugin = (options: any) => { return { name: "markdown", transform(code: string, id: string) { if (!/\.md/.test(id)) { return; } const result = marked(code, options); return `export default ${JSON.stringify(result)}`; }, };};export default { plugins: [ vue(), markdownPlugin({ highlight: (code: string) => { if (code.includes("template")) { return hljs.highlight("html", code).value; } else if (code.includes('lang="ts"')) { return hljs.highlight("typescript", code).value; } else { return hljs.highlightAuto(code).value; } }, }), ],};
Vite 新版文档地址: https://vitejs.dev/
Lerna
Lerna 是一个项目内包管理工具,虽然当前项目内的组件关联性不强,但也提前先引入了 Lerna 进行分包管理。
- 执行
npm run bootstrap
命令进行项目初始化. - 执行
npm run publish
命令可快速发包
Rollup 打包
组件使用 Rollup 进行打包,执行npm run build:pkg
打包各 Packages,包含 cjs、es 和其 d.ts 文件。
使用 nodejs 执行 rollup 打包,代码位于/scripts 下,build.js 为打包初始模板,一个组件会被打包出 3 种格式:cjs
/esm
/umd
,格式说明参考格式
Vue 路由自动生成
使用 Vite 打包时,Vue 路由懒加载是基于 Rollup 的动态引入插件的,它对我原站点的格式不太适用。而由于展示站点中,各个路由格式是具有一定通用性的,所有采用了一种读取文件目录自动生成路由文件的方式。
// 自动生成路由文件const fs = require("fs");const packagesDirs = fs.readdirSync("./src/pages");const packagesMap = {};packagesDirs.map((package) => { const exampleDirs = fs.readdirSync(`./src/pages/${package}/example`); const exampleNum = exampleDirs.length; packagesMap[package] = exampleNum;});const packages = Object.keys(packagesMap).map((key) => { return { name: key, exampleNum: packagesMap[key], };});const routes = [ { path: "/", name: "home", component: "i(../views/home.vue)", }, ...packages.map((pkg) => { const { name, exampleNum } = pkg; return { path: `/${name}`, name: `${name}`, redirect: `/${name}/readme`, component: `i(../pages/${name}/index.vue)`, children: [ { path: `/${name}/readme`, name: `${name}-readme`, component: "i(../components/PageReadme.vue)", }, ...Array.from({ length: exampleNum }, (_, exampleIndex) => { return { path: `/${name}/example${exampleIndex + 1}`, name: `${name}-example${exampleIndex + 1}`, component: `i(../pages/${name}/example/example${ exampleIndex + 1 }.vue)`, }; }), ], }; }),];
const reg = /"i\((.*?)\)"/g;const routesStr = JSON.stringify(routes, null, 2).replace( reg, (...arg) => `() => import("${arg[1]}")`);
const output = `/* eslint-disable */import { createRouter, createWebHistory } from 'vue-router';const router = createRouter({ history: createWebHistory('/howdy/'), routes: ${routesStr}});
export default router;`;
fs.writeFileSync("./src/router/index.ts", output);
执行命令npm run gen-router
后,会自动读取/packages 下的包文件,然后生成出对应的路由。