vue3组件库添加脚本的实现示例
作者:程序员长夜
添加脚本
在操作组件库的时候有一些操作比较繁琐,因此添加脚本,通过脚本执行这些繁琐的事情
在项目根目录创建script目录
添加组件
创建组件目录及固定结构
每次新建组件都需要徐建如下操作:
- 在packages文件夹中创建组件目录
- 在docs\demos中创建组件的目录
- 在docs\components中创建组件目录
- ……
通过编写一些脚本帮我自动创建对应的文件夹和文件,在script目录创建add.js和tools.js文件以及创建add文件夹,在add文件夹下创建directoryFile.js文件
:::demo ${componentName}/index ::: `; // 文档目录 const directory = path.join(docPath, componentName); // 判断是否有工具路径 const isExists = fs.existsSync(directory); if (isExists) { exit(`${directory}目录已经存在`); } // 文档路径 const documentPath = path.join(directory, "/base.md"); fs.mkdirSync(directory); // 写入文件 fs.writeFileSync(documentPath, documentTemplate); // 工具 myLog("创建组件文档", documentPath); // ------- 创建组件文档 end ------ // ---------创建组件demo start ----- // demo路径 const demoPath = path.join(__dirname, "../../docs/demos"); // demo目录 const demoDirectory = path.join(demoPath, componentName); // 创建文件夹 fs.mkdirSync(demoDirectory); // 文件路径 const demoFilePath = path.join(demoDirectory, "/index.vue"); // demo 模板 const demoTemplate = `<template> <div> <${capitalizeFirstLetter(componentName)} /> </div> </template> <script> export default { name: "${componentName}-demo", }; </script> <style lang="scss" scoped> </style>`; // 写入文件 fs.writeFileSync(demoFilePath, demoTemplate); // 工具 myLog("创建demo文件", demoFilePath); // ---------创建组件demo end ----- // ---------创建组件 start ----- // 组件路径 const componentPath = path.join(__dirname, "../../packages"); // 组件目录 const componentDirectory = path.join(componentPath, componentName); // 创建文件夹 fs.mkdirSync(componentDirectory); // 组件主目录 const componentMainDirectory = path.join(componentDirectory, "src"); // 创建文件夹 fs.mkdirSync(componentMainDirectory); // 组件主文件 const componentMainFilePath = path.join(componentMainDirectory, "/index.vue"); // 组件内容 const componentTemplate = `<template> <div> <div>${componentName}</div> </div> </template> <script> export default { name: "${componentName}", }; </script> <style lang="scss" scoped> </style>`; fs.writeFileSync(componentMainFilePath, componentTemplate); // 组件安装文件 const componentInstallPath = path.join(componentDirectory, "index.ts"); // 判断导入组件组件组件使用大写还是小写 let subassembly = capitalizeFirstLetter(componentName) === componentName ? lowerFirstLetter(componentName) : capitalizeFirstLetter(componentName); // 组件安装 const componentInstall = `import ${subassembly} from "./src/index.vue"; import { withInstall } from "../withInstall"; const ${capitalizeFirstLetter(componentName)} = withInstall(${subassembly}); export default ${capitalizeFirstLetter(componentName)};`; // 写入文件 fs.writeFileSync(componentInstallPath, componentInstall); myLog("创建组件目录", componentDirectory); // ---------创建组件 end ----- };
组件介绍
:::demo ${componentName}/index ::: `; // 文档目录 const directory = path.join(docPath, componentName); // 判断是否有工具路径 const isExists = fs.existsSync(directory); if (isExists) { exit(`${directory}目录已经存在`); } // 文档路径 const documentPath = path.join(directory, "/base.md"); fs.mkdirSync(directory); // 写入文件 fs.writeFileSync(documentPath, documentTemplate); // 工具 myLog("创建组件文档", documentPath); // ------- 创建组件文档 end ------ // ---------创建组件demo start ----- // demo路径 const demoPath = path.join(__dirname, "../../docs/demos"); // demo目录 const demoDirectory = path.join(demoPath, componentName); // 创建文件夹 fs.mkdirSync(demoDirectory); // 文件路径 const demoFilePath = path.join(demoDirectory, "/index.vue"); // demo 模板 const demoTemplate = `<template> <div> <${capitalizeFirstLetter(componentName)} /> </div> </template> <script> export default { name: "${componentName}-demo", }; </script> <style lang="scss" scoped> </style>`; // 写入文件 fs.writeFileSync(demoFilePath, demoTemplate); // 工具 myLog("创建demo文件", demoFilePath); // ---------创建组件demo end ----- // ---------创建组件 start ----- // 组件路径 const componentPath = path.join(__dirname, "../../packages"); // 组件目录 const componentDirectory = path.join(componentPath, componentName); // 创建文件夹 fs.mkdirSync(componentDirectory); // 组件主目录 const componentMainDirectory = path.join(componentDirectory, "src"); // 创建文件夹 fs.mkdirSync(componentMainDirectory); // 组件主文件 const componentMainFilePath = path.join(componentMainDirectory, "/index.vue"); // 组件内容 const componentTemplate = `<template> <div> <div>${componentName}</div> </div> </template> <script> export default { name: "${componentName}", }; </script> <style lang="scss" scoped> </style>`; fs.writeFileSync(componentMainFilePath, componentTemplate); // 组件安装文件 const componentInstallPath = path.join(componentDirectory, "index.ts"); // 判断导入组件组件组件使用大写还是小写 let subassembly = capitalizeFirstLetter(componentName) === componentName ? lowerFirstLetter(componentName) : capitalizeFirstLetter(componentName); // 组件安装 const componentInstall = `import ${subassembly} from "./src/index.vue"; import { withInstall } from "../withInstall"; const ${capitalizeFirstLetter(componentName)} = withInstall(${subassembly}); export default ${capitalizeFirstLetter(componentName)};`; // 写入文件 fs.writeFileSync(componentInstallPath, componentInstall); myLog("创建组件目录", componentDirectory); // ---------创建组件 end ----- };
在add.js导入
/* eslint-disable no-undef */ import { warn } from "./tools.js"; import { directoryFile } from "./add/directoryFile.js"; // 组件名称 let componentName = process.argv[2]; if (!componentName) { warn("Usage: npm run add <component-name>"); process.exit(1); } // 创建目录 directoryFile();
然后在package.json中添加命令就可以了
"add": "node ./script/add.js"
这样需要创建组件的时候只需要在命令行中输入
npm run add 组件名称
修改components.d.ts
上面的操作创建了组件的目录及基本结构,在创建组件的时候还需要再components.d.ts引入组件设置类型
因此在add文件夹下面创建add-componentDTs.js文件,并在add.js中引入
/* eslint-disable no-undef */ // 添加 packages\components.d.ts 文件中的类型 import fs from "fs-extra"; import { myLog, capitalizeFirstLetter } from "../tools.js"; const componentName = process.argv[2]; // 从命令行参数获取组件名 // 需要处理的文件路径 const filePath = "./packages/components.d.ts"; // 文件路径,请替换为实际路径 // 需要导入的组件路径 const importPath = `./${componentName.toLowerCase()}/src/index.vue`; // 假设组件的导入路径与组件名相关联 // 导入组件 const importStatement = `import ${capitalizeFirstLetter(componentName)} from "${importPath}";\n`; // 组件类型 const componentDeclaration = `\t${capitalizeFirstLetter(componentName)}: typeof ${capitalizeFirstLetter(componentName)};\n`; async function addComponent() { try { let fileContent = await fs.readFile(filePath, "utf8"); // 检查是否已存在该组件的导入和声明,避免重复添加 if (!fileContent.includes(importStatement) && !fileContent.includes(componentDeclaration)) { // 在导入部分添加新组件导入 // eslint-disable-next-line quotes const importSectionEndIndex = fileContent.indexOf('declare module "vue"'); fileContent = fileContent.slice(0, importSectionEndIndex) + importStatement + fileContent.slice(importSectionEndIndex); // 在GlobalComponents接口中添加新组件声明 const globalComponentsStartIndex = fileContent.indexOf("{", importSectionEndIndex); const globalComponentsEndIndex = fileContent.indexOf("}", importSectionEndIndex); // 提取出 导出的类型 const globalComponentsSection = fileContent.slice( globalComponentsStartIndex, globalComponentsEndIndex, ); fileContent = fileContent.replace( globalComponentsSection, `${globalComponentsSection}${componentDeclaration}`, ); await fs.writeFile(filePath, fileContent, "utf8"); // console.log(`Component ${componentName} has been added successfully.`); myLog(`Component ${componentName} has been added successfully.`); } else { // console.log(`Component ${componentName} is already present in the file.`); myLog(`Component ${componentName} is already present in the file.`); } } catch (error) { console.error("An error occurred:", error); } } export default addComponent;
修改index.ts
在add文件夹下面创建add-indexTs.js文件
/* eslint-disable no-undef */ import fs from "fs"; import { myLog, capitalizeFirstLetter } from "../tools.js"; // 指定要修改的文件路径 const filePath = "./packages/index.ts"; // 要添加的组件名称 const componentName = process.argv[process.argv.length - 1]; // 从命令行参数获取,如 'abc' // 确保组件名符合导入语句的格式 const formattedComponentName = componentName.replace(/\.vue$/, "").replace(/^\//, ""); export const addIndexTs = () => { // 读取文件内容 fs.readFile(filePath, "utf8", (err, data) => { if (err) { console.error(`读取文件失败: ${err}`); return; } // 添加导入语句在现有导入语句之后(如果尚未存在) const importRegex = /import\s+.+?from\s+["'].*?["'];/g; let lastImportMatch; while ((lastImportMatch = importRegex.exec(data)) !== null) { // 找到最后一个匹配的导入语句 } const importLine = `\nimport ${capitalizeFirstLetter(formattedComponentName)} from "./${formattedComponentName}";\n`; if (!lastImportMatch || !data.includes(importLine)) { const insertPosition = lastImportMatch ? lastImportMatch.index + lastImportMatch[0].length : data.indexOf("const components:"); data = data.slice(0, insertPosition) + importLine + data.slice(insertPosition); } // 更新组件列表(如果尚未存在) const componentsStart = "const components: { [propName: string]: Component } = {"; const componentsEnd = "};"; const componentsIndexStart = data.indexOf(componentsStart); const componentsIndexEnd = data.indexOf(componentsEnd, componentsIndexStart); if (componentsIndexStart !== -1 && componentsIndexEnd !== -1) { let componentsBlock = data.substring( componentsIndexStart, componentsIndexEnd + componentsEnd.length, ); if (!componentsBlock.includes(`${formattedComponentName}:`)) { componentsBlock = componentsBlock.replace( componentsEnd, ` ${capitalizeFirstLetter(formattedComponentName)},\n${componentsEnd}`, ); data = data.substring(0, componentsIndexStart) + componentsBlock + data.substring(componentsIndexEnd + componentsEnd.length); } } // 更新导出语句 const exportStart = "export {"; const exportEnd = "};"; const exportIndexStart = data.lastIndexOf(exportStart); const exportIndexEnd = data.indexOf(exportEnd, exportIndexStart); if (exportIndexStart !== -1 && exportIndexEnd !== -1) { let exportsBlock = data.substring(exportIndexStart, exportIndexEnd + exportEnd.length); if (!exportsBlock.includes(`${formattedComponentName},`)) { const currentExports = exportsBlock .replace(exportStart, "") .replace(exportEnd, "") .trim() .split(",") .map(s => s.trim()); if (currentExports[currentExports.length - 1] !== "") { currentExports.push(capitalizeFirstLetter(formattedComponentName)); exportsBlock = `${exportStart} ${currentExports.join(", ")} ${exportEnd}`; } else { exportsBlock = exportsBlock.replace( exportEnd, `, ${formattedComponentName}\n${exportEnd}`, ); } data = data.substring(0, exportIndexStart) + exportsBlock + data.substring(exportIndexEnd + exportEnd.length); } } // 写回文件 fs.writeFile(filePath, data, "utf8", err => { if (err) { console.error(`写入文件失败: ${err}`); } else { myLog(`${formattedComponentName} 已成功添加到文件`, "packages/index.ts"); } }); }); };
添加vitePress菜单
经过以上操作添加组件基本完成,还剩余添加说明文档的侧边栏
在add文件夹中创建add-vitePressConfig.js
/* eslint-disable no-undef */ import fs from "fs"; import { myLog } from "../tools.js"; const vitePressConfig = "./docs/.vitepress/config.ts"; const componentName = process.argv[2]; // 从命令行参数获取,如 'abc' const componentNameCn = process.argv[3]; // 从命令行参数获取,如 'abc' const addMenu = `{ text: "${componentNameCn || "组件名称"}", link: "/components/${componentName}/base.md" },`; export const addVitePressConfig = () => { // 读取文件 fs.readFile(vitePressConfig, "utf8", (err, data) => { if (err) { console.error(`读取文件失败: ${err}`); return; } let componentsIndexStart = data.indexOf("items: ["); let componentsEnd = "],"; let componentsIndexEnd = data.indexOf(componentsEnd, componentsIndexStart); let componentsBlock = data.substring(componentsIndexStart, componentsIndexEnd); componentsBlock = ` ${componentsBlock} ${addMenu} `; data = data.substring(0, componentsIndexStart) + componentsBlock + data.substring(componentsIndexEnd); fs.writeFile(vitePressConfig, data, "utf8", err => { if (err) { console.error(`写入文件失败: ${err}`); } else { myLog( `${componentNameCn || "组件"}${componentName} 已成功添加到文档库菜单`, "docs/.vitepress/config.ts", ); } }); }); };
使用
经过以上完成了组件创建脚本,这样就不需要我们自己在修改一些文件了,直接编写组件内容、demo、组件文档就可以了
在命令行中使用
npm run add table 表格
- table 是组件的文件夹名称和组件的name名称
- 表格 用来在说明文档中展示和菜单显示
组件名称首字母无论是大写还是小写字母,在使用的时候都需要使用的时候都需要变成大写字母
提交git
每次需要提交代码的时候都需要执行git add . 、git commit -m "" 、git push
编写一个脚本帮我们自动提交代码
安装依赖
npm i child_process -D
在script文件夹下面创建push.js
/* eslint-disable no-undef */ // 导入Node.js的child_process模块中的exec函数,用于在子进程中执行Shell命令 import { exec } from "child_process"; import { finish, warn } from "./tools.js"; // 这个异步函数接收一个命令字符串作为参数,使用exec执行该命令,并将其包装成一个Promise。如果命令执行成功,它会解析Promise并返回包含stdout和stderr的对象;如果执行失败,则拒绝Promise并返回错误。 const runCommand = command => new Promise((resolve, reject) => { exec(command, (error, stdout, stderr) => { if (error) { console.error(`exec error: ${error}`); reject(error); } else { resolve({ stdout, stderr }); } }); }); // 这是一个异步函数,负责执行一系列Git操作:添加所有改动、根据提供的或默认的提交信息进行提交、然后推送更改。它接受一个可选的commitMessage参数,默认值为"新增组件"。 const main = async (commitMessage = "新增组件") => { try { await runCommand("git add ."); const messageOption = commitMessage ? `-m "${commitMessage}"` : ""; await runCommand(`git commit ${messageOption}`); await runCommand("git push"); finish("代码提交成功"); } catch (error) { warn("Error during Git operations:", error); } }; // 从命令行参数读取提交信息 // 从Node.js进程的命令行参数中读取信息。process.argv是一个数组,包含了启动脚本的Node.js可执行文件的路径、脚本文件的路径,以及之后的所有参数。slice(2)用来去掉前两个元素,只保留实际传入的参数。如果提供了参数,它们会被连接成一个字符串作为提交信息,否则使用默认的"新增组件"。 const args = process.argv.slice(2); const commitMessage = args.length > 0 ? args.join(" ") : "新增组件"; // 调用main函数,并使用.catch处理任何在执行过程中抛出的错误,错误信息会被打印到控制台。 main(commitMessage).catch(console.error);
打包部署
对项目进行打包部署分为如下几步:
- 更改版本号
- 打包npm
- 切换镜像源
- 登录镜像源
- 部署
在script文件夹下卖弄创建npmPush.js和npmPush文件夹
更改版本号
在npmPush文件夹下面创建bumpVersion.js
// 修改版本号 import fs from "fs"; import path from "path"; import { fileURLToPath } from "url"; import { finish, warn } from "../tools.js"; export const bumpVersion = () => { // 当前文件路径 const __filename = fileURLToPath(import.meta.url); // 当前文件的目录 const __dirname = path.dirname(__filename); // 读取package.json文件 const packagePath = path.resolve(__dirname, "../../package.json"); const packageJson = JSON.parse(fs.readFileSync(packagePath, "utf8")); // 原来的版本 const originally = packageJson.version; // 分解版本号为数组,便于操作 const versionParts = packageJson.version.split(".").map(Number); // 示例:递增补丁版本号 versionParts[2]++; // 假设是主版本.次版本.补丁版本的形式 // 重新组合版本号 packageJson.version = versionParts.join("."); // 将修改后的内容写回package.json fs.writeFileSync(packagePath, JSON.stringify(packageJson, null, 2), "utf8"); finish(`版本更新成功: ${originally} --> ${packageJson.version}`, packagePath); };
在script\npmPush.js文件中引入
import { bumpVersion } from "./npmPush/bumpVersion.js"; bumpVersion();
打包组件库
在npmPush文件夹下面创建packNpm.js
/* eslint-disable no-undef */ // 导入Node.js的child_process模块中的exec函数,用于在子进程中执行Shell命令 import { finish, warn, runCommand } from "../tools.js"; export const packNpm = async () => { // 这是一个异步函数,负责执行一系列Git操作:添加所有改动、根据提供的或默认的提交信息进行提交、然后推送更改。它接受一个可选的commitMessage参数,默认值为"新增组件"。 try { await runCommand("npm run lib"); finish("打包成功"); } catch (error) { warn("打包发生错误:", error); } };
在script\npmPush.js文件中引入
import { bumpVersion } from "./npmPush/bumpVersion.js"; import { packNpm } from "./npmPush/packNpm.js"; const npmPush = async () => { await bumpVersion(); await packNpm(); }; npmPush();
提交npm私库
在npmPush文件夹下面创建submitNpm.js
/* eslint-disable no-undef */ import { finish, warn, runCommand } from "../tools.js"; export const submitNpm = async () => { try { await runCommand("npm publish"); finish("推送成功"); await runCommand("npm run push '部署' "); finish("代码提交成功"); } catch (error) { warn("打包发生错误:", error); } };
在script\npmPush.js文件中引入
import { bumpVersion } from "./npmPush/bumpVersion.js"; import { packNpm } from "./npmPush/packNpm.js"; import { submitNpm } from "./npmPush/submitNpm.js"; const npmPush = async () => { await bumpVersion(); await packNpm(); await submitNpm(); }; npmPush();
总结
暂时先添加这三个脚本吧,需要注意的是:在打包部署之前需要登录npm库
在代码中用到的tools.js文件
/* eslint-disable no-undef */ // 导入Node.js的child_process模块中的exec函数,用于在子进程中执行Shell命令 import { exec } from "child_process"; import ora from "ora"; // 首字母大写 export const capitalizeFirstLetter = str => str.charAt(0).toUpperCase() + str.slice(1); // 首字母转小写 export const lowerFirstLetter = str => str.charAt(0).toLowerCase() + str.slice(1); // 打印 // 打印方法 export const myLog = function (text, path) { /* var black="\033[30m black \033[0m"; var red="\033[31m red \033[0m"; var green="\033[32m green \033[0m"; var yellow="\033[33m yellow78979 \033[0m"; var blue="\033[34m blue \033[0m"; var popurse="\033[35m popurse \033[0m"; var indigo="\033[36m indigo \033[0m"; var white="\033[37m white \033[0m"; var mix="\033[37;42m white \033[0m"; console.log(black, red, green, yellow, blue, popurse, white);*/ let popurse = "\x1b[32m 提示 \x1b[0m"; process.stdout.write(popurse); let toolPathhint = "\x1b[34m " + text + " \x1b[0m"; let toolPathPath = "\x1b[32m" + path + " \x1b[0m"; console.log(toolPathhint, toolPathPath); }; export const warn = function (text) { /* var black="\033[30m black \033[0m"; var red="\033[31m red \033[0m"; var green="\033[32m green \033[0m"; var yellow="\033[33m yellow78979 \033[0m"; var blue="\033[34m blue \033[0m"; var popurse="\033[35m popurse \033[0m"; var indigo="\033[36m indigo \033[0m"; var white="\033[37m white \033[0m"; var mix="\033[37;42m white \033[0m"; console.log(black, red, green, yellow, blue, popurse, white);*/ let popurse = "\x1b[31m 警告 \x1b[0m"; process.stdout.write(popurse); let toolPathhint = "\x1b[31m " + text + " \x1b[0m"; console.log(toolPathhint); }; /** * * @param {string} text 输出打印 */ export const finish = function (text) { /* var black="\033[30m black \033[0m"; var red="\033[31m red \033[0m"; var green="\033[32m green \033[0m"; var yellow="\033[33m yellow78979 \033[0m"; var blue="\033[34m blue \033[0m"; var popurse="\033[35m popurse \033[0m"; var indigo="\033[36m indigo \033[0m"; var white="\033[37m white \033[0m"; var mix="\033[37;42m white \033[0m"; console.log(black, red, green, yellow, blue, popurse, white);*/ let popurse = "\x1b[35m 完成 \x1b[0m"; process.stdout.write(popurse); let toolPathhint = "\x1b[36m " + text + " \x1b[0m"; console.log(toolPathhint); }; /** * * @param {String} command 需要执行的命令 * @returns */ export const runCommand = command => { let isGit = command.indexOf("git") === -1; let spinner; if (isGit) { spinner = ora(`开始执行: "${command}"`).start(); } return new Promise((resolve, reject) => { exec(command, (error, stdout, stderr) => { myLog("\n当前命令:", command); if (error) { if (isGit) { spinner.fail(`exec error: ${error}`); } reject("error", error); } else { if (isGit) { // 打印命令的标准输出和标准错误,如果需要的话 if (command === "npm run lib") { // spinner.succeed(`命令 "${command}" 执行成功.`); console.log(`命令输出: ${stdout}`); console.error(`stderr: ${stderr}`); finish("打包完成"); } else if (command === "git push") { finish("代码提交成功"); } else if (command === "npm publish") { finish("npm库推送成功"); } spinner.succeed(`命令 "${command}" 执行成功.`); resolve(true); // 命令成功执行, 解决Promise } else { resolve({ stdout, stderr }); } } }); }); };
到此这篇关于vue3组件库添加脚本的实现示例的文章就介绍到这了,更多相关vue3组件库添加脚本内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!