1、准备

乐高组件库地址
在 haha-cli-dev-template 这个模块下,新建目录 haha-cli-dev-lego-components, 把下载后的代码改为 template 放在这个目录下。
image.png
修改 package.json, 删掉 file 字段(因为有file,会导致只上传dest文件的内容),npm publish

  1. "name": "<%= className %>",
  2. "version": "<%= version %>",
  3. "description": "<%= description %>",

数据库中,添加tag、igore字段。
image.png
后台系统修改model

  1. 'use strict'
  2. module.exports = app => {
  3. const { STRING, INTEGER } = app.Sequelize
  4. const Templates = app.model.define('templates', {
  5. id: { type: INTEGER, primaryKey: true, autoIncrement: true, allowNull: false, comment: '模板id' },
  6. name: { type: STRING(255), allowNull: false, comment: '名称' },
  7. npmName: { type: STRING(255), allowNull: false, comment: '模板名称' },
  8. version: { type: STRING(255), allowNull: false, comment: '模板版本' },
  9. npmType: { type: STRING(255), allowNull: false, comment: '是否是标准模板' },
  10. installCommand: { type: STRING(255), allowNull: false, comment: '安装依赖命令' },
  11. startCommand: { type: STRING(255), allowNull: false, comment: '启动命令' },
  12. tag: { type: STRING(255), allowNull: false, comment: '标签' },
  13. ignore: { type: STRING(255), allowNull: false, comment: '忽略的文件' }
  14. })
  15. return Templates
  16. }

2、项目和组件模板数据隔离+动态配置 ejs 的 ignore

  1. //标准安装
  2. async installNormalTemplate() {
  3. ...
  4. const ignore = ['**/node_modules/**', ...this.template?.ignore.split(',')]
  5. ...
  6. }
  7. //如果模板中存在 png 等类型的文件,导致 ejs 渲染失败,都可以加在 ignore 中(**.png)
  8. createTemplateChoice(type) {
  9. return this.templates
  10. .filter(item => item.tag === type)
  11. ?.map(item => ({
  12. name: item.name,
  13. value: item.npmName
  14. }))
  15. }

3、获取组件信息功能开发

  1. //3、选择创建项目或组件
  2. async getBaseInfo() {
  3. let info = {}
  4. function isNamevalid(val) {
  5. return /^[a-zA-Z]+([-][a-zA-Z0-9]|[_][a-zA-Z0-9]|[a-zA-Z0-9])*$/.test(val)
  6. }
  7. const { type } = await inquirer.prompt({
  8. type: 'list',
  9. message: '请选择初始化类型',
  10. name: 'type',
  11. default: TYPE_PROJECT,
  12. choices: [
  13. {
  14. name: '项目',
  15. value: TYPE_PROJECT
  16. },
  17. {
  18. name: '组件',
  19. value: TYPE_COMPONENT
  20. }
  21. ]
  22. })
  23. const title = TYPE_PROJECT === type ? '项目' : '组件'
  24. const promptArr = [
  25. {
  26. type: 'input',
  27. message: `请输入${title}版本号`,
  28. name: 'version',
  29. default: '1.0.0',
  30. validate: val => !!semver.valid(val) || '请输入合法的版本号',
  31. filter: val => {
  32. if (!!semver.valid(val)) {
  33. return semver.valid(val)
  34. }
  35. return val
  36. }
  37. },
  38. {
  39. type: 'list',
  40. message: `请选择${title}模板`,
  41. name: 'npmName',
  42. choices: this.createTemplateChoice(type)
  43. }
  44. ]
  45. const projectPromt = {
  46. type: 'input',
  47. message: `请输入${title}名称`,
  48. name: 'project',
  49. default: 'HahaDemo',
  50. validate: function (val) {
  51. //检查项目名称和版本号的合法性
  52. const done = this.async()
  53. setTimeout(function () {
  54. //1、必须首字母大写,
  55. //2、尾字符必须为英文或者数字,不能为字符
  56. //3、字符仅允许'-_'
  57. //类型合法有:a a-b a_b a-b-c a_b_c a1_b1_c1 a1 a1-b1-c1
  58. if (!isNamevalid(val)) {
  59. done(`请输入合法的${title}名称(要求英文字母开头,数字或字母结尾,字符只允许使用 - 以及 _)`)
  60. return
  61. }
  62. done(null, true)
  63. }, 0)
  64. }
  65. }
  66. //命令行输入的projectName是否合法,不合法则重新填入项目名称
  67. if (!isNamevalid(this.projectName)) {
  68. promptArr.unshift(projectPromt)
  69. } else {
  70. info.project = this.projectName
  71. }
  72. if (type === TYPE_COMPONENT) {
  73. const descriptPrompt = {
  74. type: 'input',
  75. message: `请输入${title}描述`,
  76. name: 'descript',
  77. validate: val => {
  78. if (!val) {
  79. return '组件描述不可以为空'
  80. }
  81. return true
  82. }
  83. }
  84. promptArr.push(descriptPrompt)
  85. }
  86. const result = await inquirer.prompt(promptArr)
  87. if (result?.project) {
  88. info.project = result?.project
  89. }
  90. //4、获取项目的基本信息
  91. return {
  92. type,
  93. ...result,
  94. ...info,
  95. className: require('kebab-case')(info.project).replace(/^-/, '')
  96. }
  97. }