configureProject.js 8.5 KB

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