将个人组件库 Howdyjs 使用 Vue + Typescript 进行重构,使用 Vite 构建开发站点,Rollup 进行组件打包并分包发布 NPM。
Typescript
Vue3
重构,不向下兼容,有 Vue2.X 需求的请使用旧版lerna
进行分包管理Rollup
进行组件打包Vite
搭建综合对比之后,发现采用 Vite 基本可以实现当前展示站点的所有功能,而且在开发环境下热更新速度极快,所以新版项目采用了 Vite 构建开发站点。
由于项目有导入.md 文件的需求,而 Vite 并不能直接使用 Webpack 的 markdown-loader,所以暂时自己写一个简单的 markdown-plugin 在 Vite 中使用
// vite.config.ts
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 进行分包管理。
npm run bootstrap
命令进行项目初始化.npm run publish
命令可快速发包组件使用 Rollup 进行打包,执行npm run build:pkg
打包各 Packages,包含 cjs、es 和其 d.ts 文件。
使用 nodejs 执行 rollup 打包,代码位于/scripts 下,build.js 为打包初始模板,一个组件会被打包出 3 种格式:cjs
/esm
/umd
,格式说明参考格式
使用 Vite 打包时,Vue 路由懒加载是基于 Rollup 的动态引入插件的,它对我原站点的格式不太适用。而由于展示站点中,各个路由格式是具有一定通用性的,所有采用了一种读取文件目录自动生成路由文件的方式。
// scripts/gen-route.js
// 自动生成路由文件
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 下的包文件,然后生成出对应的路由。