需求:

  1. npm run gen Hello

指令生成Hello.vue、hello.scss,并在相应文件中添加

场景:

  • 组件库的开发

参考:

1. elementUI (nodejs脚本)

https://github.com/ElemeFE/element/blob/dev/build/bin/new.js
插件 file-save (封装fs模块, 链式调用代替回调)

2. element-plus (shell脚本)

https://github.com/element-plus/element-plus/blob/dev/scripts/gc.sh

  1. "gen": "bash ./scripts/gc.sh"

分析:

新文件, 创建
image.png
旧文件, 读取-修改-重写入
image.png

实现

  1. console.log();
  2. process.on('exit', () => {
  3. console.log();
  4. });
  5. if (!process.argv[2]) {
  6. console.error('[组件名]必填 - Please enter new component name');
  7. process.exit(1);
  8. }
  9. const path = require('path');
  10. const fs = require('fs');
  11. const fileSave = require('file-save');
  12. const uppercamelcase = require('uppercamelcase');
  13. const componentname = process.argv[2];
  14. const chineseName = process.argv[3] || componentname;
  15. const ComponentName = uppercamelcase(componentname);
  16. const PackagePath = path.resolve(__dirname, '../../packages', componentname);
  17. const Files = [
  18. {
  19. filename: 'index.js',
  20. content: `import ${ComponentName} from './src/main';
  21. /* istanbul ignore next */
  22. ${ComponentName}.install = function(Vue) {
  23. Vue.component(${ComponentName}.name, ${ComponentName});
  24. };
  25. export default ${ComponentName};`
  26. },
  27. {
  28. filename: 'src/main.vue',
  29. content: `<template>
  30. <div class="el-${componentname}"></div>
  31. </template>
  32. <script>
  33. export default {
  34. name: 'El${ComponentName}'
  35. };
  36. </script>`
  37. },
  38. {
  39. filename: path.join('../../examples/docs/zh-CN', `${componentname}.md`),
  40. content: `## ${ComponentName} ${chineseName}`
  41. },
  42. {
  43. filename: path.join('../../examples/docs/en-US', `${componentname}.md`),
  44. content: `## ${ComponentName}`
  45. },
  46. {
  47. filename: path.join('../../examples/docs/es', `${componentname}.md`),
  48. content: `## ${ComponentName}`
  49. },
  50. {
  51. filename: path.join('../../examples/docs/fr-FR', `${componentname}.md`),
  52. content: `## ${ComponentName}`
  53. },
  54. {
  55. filename: path.join('../../test/unit/specs', `${componentname}.spec.js`),
  56. content: `import { createTest, destroyVM } from '../util';
  57. import ${ComponentName} from 'packages/${componentname}';
  58. describe('${ComponentName}', () => {
  59. let vm;
  60. afterEach(() => {
  61. destroyVM(vm);
  62. });
  63. it('create', () => {
  64. vm = createTest(${ComponentName}, true);
  65. expect(vm.$el).to.exist;
  66. });
  67. });
  68. `
  69. },
  70. {
  71. filename: path.join('../../packages/theme-chalk/src', `${componentname}.scss`),
  72. content: `@import "mixins/mixins";
  73. @import "common/var";
  74. @include b(${componentname}) {
  75. }`
  76. },
  77. {
  78. filename: path.join('../../types', `${componentname}.d.ts`),
  79. content: `import { ElementUIComponent } from './component'
  80. /** ${ComponentName} Component */
  81. export declare class El${ComponentName} extends ElementUIComponent {
  82. }`
  83. }
  84. ];
  85. // 添加到 components.json
  86. const componentsFile = require('../../components.json');
  87. if (componentsFile[componentname]) {
  88. console.error(`${componentname} 已存在.`);
  89. process.exit(1);
  90. }
  91. componentsFile[componentname] = `./packages/${componentname}/index.js`;
  92. fileSave(path.join(__dirname, '../../components.json'))
  93. .write(JSON.stringify(componentsFile, null, ' '), 'utf8')
  94. .end('\n');
  95. // 添加到 index.scss
  96. const sassPath = path.join(__dirname, '../../packages/theme-chalk/src/index.scss');
  97. const sassImportText = `${fs.readFileSync(sassPath)}@import "./${componentname}.scss";`;
  98. fileSave(sassPath)
  99. .write(sassImportText, 'utf8')
  100. .end('\n');
  101. // 添加到 element-ui.d.ts
  102. const elementTsPath = path.join(__dirname, '../../types/element-ui.d.ts');
  103. let elementTsText = `${fs.readFileSync(elementTsPath)}
  104. /** ${ComponentName} Component */
  105. export class ${ComponentName} extends El${ComponentName} {}`;
  106. const index = elementTsText.indexOf('export') - 1;
  107. const importString = `import { El${ComponentName} } from './${componentname}'`;
  108. elementTsText = elementTsText.slice(0, index) + importString + '\n' + elementTsText.slice(index);
  109. fileSave(elementTsPath)
  110. .write(elementTsText, 'utf8')
  111. .end('\n');
  112. // 创建 package
  113. Files.forEach(file => {
  114. fileSave(path.join(PackagePath, file.filename))
  115. .write(file.content, 'utf8')
  116. .end('\n');
  117. });
  118. // 添加到 nav.config.json
  119. const navConfigFile = require('../../examples/nav.config.json');
  120. Object.keys(navConfigFile).forEach(lang => {
  121. let groups = navConfigFile[lang][4].groups;
  122. groups[groups.length - 1].list.push({
  123. path: `/${componentname}`,
  124. title: lang === 'zh-CN' && componentname !== chineseName
  125. ? `${ComponentName} ${chineseName}`
  126. : ComponentName
  127. });
  128. });
  129. fileSave(path.join(__dirname, '../../examples/nav.config.json'))
  130. .write(JSON.stringify(navConfigFile, null, ' '), 'utf8')
  131. .end('\n');
  132. console.log('DONE!');