configureProject_bin.js 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. #!/usr/bin/env node
  2. const fs = require('fs');
  3. const path = require('path');
  4. const inquirerModule = import('inquirer');
  5. const jsoncParser = require('jsonc-parser');
  6. // 创建目录的函数
  7. function createDirIfNotExist(dirPath) {
  8. if (!fs.existsSync(dirPath)) {
  9. fs.mkdirSync(dirPath, {
  10. recursive: true,
  11. });
  12. }
  13. }
  14. // 复制目录的函数
  15. function copyDir(src, dest) {
  16. createDirIfNotExist(dest);
  17. const entries = fs.readdirSync(src, {
  18. withFileTypes: true,
  19. });
  20. for (const entry of entries) {
  21. const srcPath = path.join(src, entry.name);
  22. const destPath = path.join(dest, entry.name);
  23. if (entry.isDirectory()) {
  24. copyDir(srcPath, destPath);
  25. } else {
  26. fs.copyFileSync(srcPath, destPath);
  27. }
  28. }
  29. }
  30. function appendStylesToFile(filePath, styles) {
  31. const fileContent = fs.readFileSync(filePath, 'utf8');
  32. const newContent = `${fileContent}\n<style>\n${styles}\n</style>`;
  33. fs.writeFileSync(filePath, newContent, 'utf8');
  34. }
  35. class InitProject {
  36. destBase = process.cwd();
  37. sourceBase = __dirname;
  38. answers = {};
  39. srcPath = '';
  40. init(answers) {
  41. const { creationMethod } = answers;
  42. this.answers = answers;
  43. this.srcPath = creationMethod === 'CLI'
  44. ? path.join(this.destBase, './src')
  45. : this.destBase;
  46. }
  47. async run() {
  48. const { setManifestJSON, setPagesJSON } = await this.askForProjectCreationMethod(); // CLI or HBuilderX
  49. this.copyFile();
  50. setManifestJSON && this.setManifest();
  51. setPagesJSON && this.setPages();
  52. this.addStyleToApp();
  53. }
  54. async askForProjectCreationMethod() {
  55. console.log('配置相关说明,请参考:https://cloud.tencent.com/document/product/647/97754#2.2-.E9.A1.B9.E7.9B.AE.E9.85.8D.E7.BD.AE.E6.9B.B4.E6.94.B9');
  56. const questions = [
  57. {
  58. type: 'list',
  59. name: 'creationMethod',
  60. message: '请选择当前项目的创建方式:',
  61. choices: ['HBuilderX', 'CLI'],
  62. default: 'HBuilderX',
  63. },
  64. {
  65. type: 'confirm',
  66. name: 'createViteConfig',
  67. message:
  68. '是否创建vite.config.ts文件(若已存在该配置文件,请根据文档描述手动进行修改)?',
  69. default: true,
  70. },
  71. {
  72. type: 'confirm',
  73. name: 'createTsConfig',
  74. message:
  75. '是否创建tsconfig.json文件(若已存在该配置文件,请根据文档描述手动进行修改)?',
  76. default: true,
  77. },
  78. {
  79. type: 'confirm',
  80. name: 'setManifestJSON',
  81. message:
  82. '是否自动配置mainfest.json文件(若选择否,请根据文档描述手动进行修改)?',
  83. default: true,
  84. },
  85. {
  86. type: 'confirm',
  87. name: 'setPagesJSON',
  88. message:
  89. '是否自动配置pages.json文件(若选择否,请根据文档描述手动进行修改)?',
  90. default: true,
  91. },
  92. ];
  93. // 等待 inquirer 导入完成
  94. const inquirer = await inquirerModule;
  95. const answers = await inquirer.default.prompt(questions);
  96. this.init(answers);
  97. return answers;
  98. }
  99. copyFile() {
  100. const { creationMethod, createViteConfig, createTsConfig } = this.answers;
  101. // Copy roomkit and locales directories
  102. ['roomkit', 'locales', 'router'].forEach((dir) => {
  103. copyDir(
  104. path.join(this.sourceBase, './src', dir),
  105. path.join(this.srcPath, dir),
  106. );
  107. });
  108. // Copy wxmini_dev.sh and wxmini_prod.sh files
  109. ['wxmini_dev.sh', 'wxmini_prod.sh'].forEach((file) => {
  110. fs.copyFileSync(
  111. path.join(this.sourceBase, file),
  112. path.join(this.destBase, file),
  113. );
  114. });
  115. // Copy RTCRoomEngine.wasm.br file
  116. const wasmDest = './static/RTCRoomEngine.wasm.br';
  117. createDirIfNotExist(path.dirname(wasmDest));
  118. fs.copyFileSync(
  119. './node_modules/@tencentcloud/tuiroom-engine-wx/RTCRoomEngine.wasm.br',
  120. path.join(this.srcPath, wasmDest),
  121. );
  122. fs.copyFileSync(
  123. path.join(this.sourceBase, 'src/pages/index.vue'),
  124. path.join(this.srcPath, 'pages/roomkitTest.vue'),
  125. );
  126. if (createViteConfig) {
  127. fs.copyFileSync(
  128. path.join(
  129. this.sourceBase,
  130. creationMethod === 'CLI'
  131. ? './vite.config.ts'
  132. : 'vite.config_HBuliderX.ts',
  133. ),
  134. path.join(this.destBase, 'vite.config.ts'),
  135. );
  136. }
  137. if (createTsConfig) {
  138. fs.copyFileSync(
  139. path.join(
  140. this.sourceBase,
  141. creationMethod === 'CLI' ? 'tsconfig.json' : 'tsconfig_HBuliderX.json',
  142. ),
  143. path.join(this.destBase, 'tsconfig.json'),
  144. );
  145. }
  146. }
  147. // manifest.json 配置修改
  148. setManifest() {
  149. const manifestPath = path.join(this.srcPath, 'manifest.json');
  150. const manifestContent = fs.readFileSync(manifestPath, 'utf8');
  151. // 使用 jsonc-parser 来解析带有注释的 JSON
  152. const manifest = jsoncParser.parse(manifestContent);
  153. const oldConfig = manifest['mp-weixin'];
  154. // 新增的配置
  155. const newConfig = {
  156. setting: {
  157. urlCheck: false,
  158. packNpmManually: true,
  159. packNpmRelationList: [
  160. ...(oldConfig?.setting?.packNpmRelationList || []),
  161. ...(oldConfig?.setting?.packNpmRelationList
  162. && oldConfig?.setting?.packNpmRelationList[
  163. oldConfig?.setting?.packNpmRelationList.length - 1
  164. ]?.packageJsonPath === './roomkit/package.json'
  165. ? []
  166. : [
  167. {
  168. packageJsonPath: './package.json',
  169. miniprogramNpmDistDir: './',
  170. },
  171. {
  172. packageJsonPath: './roomkit/package.json',
  173. miniprogramNpmDistDir: './roomkit',
  174. },
  175. ]),
  176. ],
  177. },
  178. usingComponents: true,
  179. optimization: {
  180. ...(oldConfig?.optimization || {}),
  181. subPackages: true,
  182. },
  183. };
  184. // 合并配置
  185. manifest['mp-weixin'] = Object.assign({}, oldConfig, newConfig);
  186. const edits = jsoncParser.modify(
  187. manifestContent,
  188. ['mp-weixin'],
  189. manifest['mp-weixin'],
  190. { formattingOptions: { insertSpaces: true, tabSize: 2 } },
  191. );
  192. const newContent = jsoncParser.applyEdits(manifestContent, edits);
  193. // 写回manifest.json文件
  194. fs.writeFileSync(manifestPath, newContent, 'utf8');
  195. }
  196. // pages.json 配置修改
  197. setPages() {
  198. const pagesPath = path.join(this.srcPath, 'pages.json');
  199. const pagesContent = fs.readFileSync(pagesPath, 'utf8');
  200. // 使用 jsonc-parser 来解析带有注释的 JSON
  201. const pages = jsoncParser.parse(pagesContent);
  202. // 新增的配置
  203. const newConfig = {
  204. // pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
  205. pages: [
  206. pages?.pages[0]?.path !== 'pages/roomkitTest'
  207. ? {
  208. path: 'pages/roomkitTest',
  209. style: {
  210. navigationBarTitleText: '',
  211. },
  212. }
  213. : null,
  214. ...(pages?.pages || []),
  215. ].filter(Boolean),
  216. subpackages: [
  217. ...((pages?.subpackages && pages.subpackages[0]?.root !== 'roomkit')
  218. || []),
  219. {
  220. root: 'roomkit',
  221. pages: [
  222. {
  223. path: 'pages/home',
  224. style: {
  225. navigationBarTitleText: 'home',
  226. },
  227. },
  228. {
  229. path: 'pages/room',
  230. style: {
  231. navigationBarTitleText: 'room',
  232. },
  233. },
  234. ],
  235. },
  236. ],
  237. globalStyle: {
  238. ...(pages?.globalStyle || {}),
  239. usingComponents: {
  240. ...(pages?.globalStyle?.usingComponents || {}),
  241. 'trtc-pusher': '@tencentcloud/trtc-component-wx/trtc-pusher',
  242. 'trtc-player': '@tencentcloud/trtc-component-wx/trtc-player',
  243. },
  244. },
  245. };
  246. // 合并配置
  247. const newPages = Object.assign({}, pages, newConfig);
  248. const edits = jsoncParser.modify(pagesContent, [], newPages, {
  249. formattingOptions: { insertSpaces: true, tabSize: 2 },
  250. });
  251. const newContent = jsoncParser.applyEdits(pagesContent, edits);
  252. // 写回 pages.json文件
  253. fs.writeFileSync(pagesPath, newContent, 'utf8');
  254. }
  255. addStyleToApp() {
  256. const styles = `
  257. page{
  258. height: 100%;
  259. box-sizing: border-box;
  260. }
  261. view,label{
  262. box-sizing: border-box;
  263. }
  264. `;
  265. appendStylesToFile(path.join(this.srcPath, 'App.vue'), styles);
  266. }
  267. }
  268. const init = () => {
  269. const initProject = new InitProject();
  270. initProject.run();
  271. };
  272. init();