组件库
基于element UI创建组件库
优化组件库
创建vue3组件库
vue3组件库添加脚本
本文档使用 MrDoc 发布
-
+
首页
vue3组件库添加脚本
# 添加脚本 在操作组件库的时候有一些操作比较繁琐,因此添加脚本,通过脚本执行这些繁琐的事情 在项目根目录创建`script`目录 ### 添加组件 #### 创建组件目录及固定结构 每次新建组件都需要徐建如下操作: 1. 在packages文件夹中创建组件目录 2. 在docs\\demos中创建组件的目录 3. 在docs\\components中创建组件目录 4. …… 通过编写一些脚本帮我自动创建对应的文件夹和文件,在`script`目录创建`add.js`和`tools.js`文件以及创建`add`文件夹,在`add`文件夹下创建`directoryFile.js`文件 ```js /* eslint-disable no-undef */ import fs from "fs"; import path from "path"; import { fileURLToPath } from "url"; import { capitalizeFirstLetter, myLog, warn, lowerFirstLetter } from "../tools.js"; // 当前文件路径 const __filename = fileURLToPath(import.meta.url); // 当前文件的目录 const __dirname = path.dirname(__filename); // 组件名称 let componentName = process.argv[2]; let componentNameCn = process.argv[3]; // 终止 const exit = function (log) { console.error(log); process.exit(1); }; export const directoryFile = () => { // ------- 创建组件文档 start ------ // 文档路径 const docPath = path.join(__dirname, "../../docs/components/"); // 文档模板 const documentTemplate = `# ${componentName} ${componentNameCn || ""} 组件介绍 :::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`导入 ```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`中添加命令就可以了 ```json "add": "node ./script/add.js" ``` 这样需要创建组件的时候只需要在命令行中输入 ```bash npm run add 组件名称 ``` #### 修改components.d.ts 上面的操作创建了组件的目录及基本结构,在创建组件的时候还需要再`components.d.ts`引入组件设置类型 因此在`add`文件夹下面创建`add-componentDTs.js`文件,并在`add.js`中引入 ```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`文件 ```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` ```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、组件文档就可以了 在命令行中使用 ```bash npm run add table 表格 ``` * table 是组件的文件夹名称和组件的name名称 * 表格 用来在说明文档中展示和菜单显示 > 组件名称首字母无论是大写还是小写字母,在使用的时候都需要使用的时候都需要变成大写字母 ### 提交git 每次需要提交代码的时候都需要执行`git add .` 、`git commit -m ""` 、`git push` 编写一个脚本帮我们自动提交代码 安装依赖 ```bash npm i child_process -D ``` 在`script`文件夹下面创建`push.js` ```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); ``` ### 打包部署 对项目进行打包部署分为如下几步: 1. 更改版本号 2. 打包npm 3. 切换镜像源 4. 登录镜像源 5. 部署 在`script`文件夹下卖弄创建`npmPush.js`和`npmPush`文件夹 #### 更改版本号 在`npmPush`文件夹下面创建`bumpVersion.js` ```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`文件中引入 ```js import { bumpVersion } from "./npmPush/bumpVersion.js"; bumpVersion(); ``` #### 打包组件库 在`npmPush`文件夹下面创建`packNpm.js` ```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`文件中引入 ```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` ```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`文件中引入 ```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`文件 ```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 }); } } }); }); }; ```
admin
2024年7月2日 11:54
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
分享
链接
类型
密码
更新密码