当前位置:Gxlcms > JavaScript > Vue多组件仓库开发与发布详解

Vue多组件仓库开发与发布详解

时间:2021-07-01 10:21:17 帮助过:7人阅读

在开发组件时,我们可能会期望一类组件放在同一个代码仓库下,就像element那样,我们可以使用element提供的脚手架,也可以使用vue cli 3创建一个更‘新'的项目。

项目创建

通过vue cli 3创建项目,创建文件夹packages用于存放组件。

单个组件目录

在packages下就是每一个组件,每个组件和单独项目一样,会有package.json、README.md、src、dist等文件及目录。

如何演示/调试组件

在组件开发过称中,我们需要对组件进行展示,所以创建了examples文件夹,用于存放每个组件示例。

通过一个列表展示出所有的组件,点击选择当前开发的组件,进入对应的example。

路由的根就是一个导航列表,然后每个组件对应一个路由,通过一个配置文件的components.js来生成这个路由。

  1. // 路由
  2. import Navigation from "./Navigation";
  3. import components from "./components";
  4. let routes = components.map(component => ({
  5. path: `/${component.name}`,
  6. component: () => import(`../examples/${component.name}`)
  7. }));
  8. routes.unshift({
  9. path: "",
  10. component: Navigation
  11. });
  12. export default routes;

自动化脚本

创建/编译/发布

创建新的组件,需要修改components.js配置文件,在examples和packages下创建对应目录。

编译/发布组件,因为仓库下会有多个组件,如果一次发布多个,就需要进入每个文件夹下执行命令。

上面过程实现自动化,有很多种方式,比如可以通过npm run <script>,可以直接通过node命令等。这里我参考element,采用了Makefile。

创建script文件夹,其中包括创建脚本new.js和构建脚本build.js。

创建脚本

创建脚本主要就是目录的创建与文件的写入,其中可能需要注意的可能就是格式问题。

一种方式是在``之间,按照规范格式去完成写入内容,这样做比较麻烦,而且可能面临格式化要求修改问题。

另一种方式是在脚本中引入eslint,脚本中的eslint.CLIEngine可以根据配置文件(比如.eslintrc.js)格式化文件。需要注意的是需要比命令行中配置需要多添加fix: true配置, 如下

  1. const CLIEngine = eslint.CLIEngine;
  2. const cli = new CLIEngine({ ...require("../.eslintrc.js"), fix: true });

eslint在脚本中的使用方法,更具体的可以参考eslint文档中Node.js API部分。

  1. // scripts/new.js部分
  2. ...
  3. components.push({
  4. label: newName,
  5. name: newName
  6. })
  7. const updateConfig = function(path, components) {
  8. writeFile(path, `module.exports = ${JSON.stringify(components)}`).then(() => {
  9. console.log("完成components.js")
  10. // 格式化
  11. CLIEngine.outputFixes(cli.executeOnFiles([configPath]))
  12. })
  13. }
  14. const createPackages = function(componentName) {
  15. try {
  16. const dir = path.resolve(__dirname, `../packages/${componentName}/`)
  17. // 创建文件夹
  18. if (!fs.existsSync(dir)) {
  19. fs.mkdirSync(dir)
  20. console.log(`完成创建packages/${componentName}文件夹`)
  21. }
  22. // 写入README
  23. if (!fs.existsSync(`${dir}/README.md`)) {
  24. writeFile(
  25. `${dir}/README.md`,
  26. `## ${componentName}
  27. ### 使用说明
  28. `
  29. ).then(() => {
  30. console.log("完成创建README")
  31. })
  32. }
  33. // 写入package.json
  34. if (!fs.existsSync(`${dir}/package.json`)) {
  35. writeFile(
  36. `${dir}/package.json`,
  37. `{
  38. "name": "@hy/${componentName}",
  39. "version": "1.0.0",
  40. "description": "${componentName}",
  41. "main": "./dist/hy-${componentName}.umd.min.js",
  42. "keywords": [
  43. "${componentName}",
  44. "vue"
  45. ],
  46. "author": "",
  47. "license": "ISC"
  48. }
  49. `
  50. ).then(() => {
  51. console.log("完成创建package.json")
  52. })
  53. }
  54. // 创建index.js
  55. if (!fs.existsSync(`${dir}/index.js`)) {
  56. writeFile(`${dir}/index.js`, `export {}`).then(() => {
  57. console.log("完成创建index.js")
  58. CLIEngine.outputFixes(cli.executeOnFiles([`${dir}/index.js`]))
  59. })
  60. }
  61. } catch (err) {
  62. console.error(err)
  63. }
  64. }
  65. const createExample = function(componentName) {
  66. try {
  67. const dir = path.resolve(__dirname, `../examples/${componentName}/`)
  68. // 创建文件夹
  69. if (!fs.existsSync(dir)) {
  70. fs.mkdirSync(dir)
  71. console.log(`完成创建examples/${componentName}文件夹`)
  72. }
  73. // 写入index.vue
  74. if (!fs.existsSync(`${dir}/index.vue`)) {
  75. writeFile(
  76. `${dir}/index.vue`,
  77. `<template>
  78. </template>
  79. <script>
  80. import { } from '../../packages/${componentName}/index'
  81. export default {
  82. components: {}
  83. }
  84. </script>
  85. `
  86. ).then(() => {
  87. console.log(`完成创建examples/${componentName}/index.vue文件`)
  88. // 格式化index.vue
  89. CLIEngine.outputFixes(cli.executeOnFiles([`${dir}/index.vue`]))
  90. })
  91. }
  92. } catch (err) {
  93. console.error(err)
  94. }
  95. }
  96. ...

构建脚本

  1. // build.js
  2. ...
  3. async function build() {
  4. for (let i = 0, len = components.length; i < len; i++) {
  5. const name = components[i].name
  6. await buildService.run(
  7. "build",
  8. {
  9. _: ["build", `${root}/packages/${name}/src/index.js`],
  10. target: "lib",
  11. name: `hy-${name}`,
  12. dest: `${root}/packages/${name}/dist`,
  13. // 生成格式: umd格式会同时成功demo.html commonjs,umd,umd-min
  14. formats: "commonjs,umd-min"
  15. // clean: false
  16. },
  17. ["--target=all", `./packages/${name}/src/index.js`]
  18. )
  19. }
  20. }
  21. ...

Lerna

lerna是一个多包仓库管理的工具,可以帮助创建、管理、发布多包仓库中的包。

关于lerna我也没有太深入得使用,只是用到了发布。首先在项目下执行init初始化了项目,在每次commit之后,可以执行publish。lerna会对应代码库打tag,并发布到npm仓库。

项目版本问题

0.0.1为不规范版本号,最小应该从1.0.0开始。npm publish无法发布,但是lerna publish可以发布。

导致结果安装为固定版本号,而不是以^开头的版本号范围。outdate可以检测到有更新,无法通过update升级。

组件开发

组件开发主要是在packages/<component name>/src目录下进行,在example/<component name>/目录下可以引入该组件src下的源文件,用一些数据来进行开发测试。组件开发和项目中的组件开发基本相同。

作为组件库中的组件,需要更多的考虑其通用性和易用性。不能为了通用而加入很多的属性,而使其失去易用性;同样也不能为了易用,而使其过于简单,使用范围过于局限。

对于每一个属性、每个抛出去的方法,都需要认真考虑其必要性。

唯一不同的地方可能需要注意的是导出的方式。

一种是直接导出组件,这种形式在使用时需要引入,并且在components中声明,也就是局部注册。

另一种是添加install方法后导出。这种形式需要调用vue.use方法,相当于全局注册。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

人气教程排行