panel_ex.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. /*
  2. 面板扩展
  3. 功能: 监听 creator项目下 node_modules 目录与加载
  4. */
  5. 'use strict';
  6. const path = require('path');
  7. const fs = require('fs');
  8. const tools = require('../../tools/tools');
  9. const prsPath = Editor.Project && Editor.Project.path ? Editor.Project.path : Editor.remote.projectPath;
  10. const node_modules_path = path.join(prsPath,'node_modules');
  11. const REG_EXP_MULTILAYER = /node_modules/g
  12. const REG_EXP_JSON_CONFIG = /(tsconfig.*\.json|jsconfig.*\.json|package\.json)/;
  13. const REG_EXP_TS_CONFIG = /(tsconfig.*\.json|jsconfig.*\.json)/;
  14. const REG_EXP_PACKAGE = /(package\.json)/
  15. module.exports = {
  16. /** @type import('../../panel/vs-panel/vs-panel-base') */
  17. parent : null,
  18. // 初始化事件
  19. onLoadEvent(parent){
  20. // index.js 对象
  21. this.parent = parent;
  22. this.dependencies = {};
  23. // 创建view缓存model事件
  24. this.parent.monaco.editor.onDidCreateModel((model)=>
  25. {
  26. // 加载 tsconfig 配置文件解析
  27. let url = model.uri.toString();
  28. if(url.match(REG_EXP_TS_CONFIG) && this.isDependencie(url)){
  29. this.parent.tsWr.addProjectReference(url)
  30. setTimeout(()=>this.parent.tsWr.writeOtherFile(url,model.getValue()),1);
  31. }else{
  32. this.updatePackageMainModulePath(model)
  33. }
  34. });
  35. // 删除代码文件 view缓存model
  36. this.parent.monaco.editor.onWillDisposeModel((model)=>{
  37. // 删除 tsconfig 配置文件解析
  38. let url = model.uri.toString();
  39. let isconfig = url.match(REG_EXP_TS_CONFIG);
  40. if(isconfig){ 
  41. this.parent.tsWr.removeProjectReference(url)
  42. }
  43. if(isconfig || url.endsWith('package.json')){
  44. setTimeout(()=>this.parent.tsWr.removeOtherFile(url),1);
  45. }
  46. });
  47. this.initProjectConfig()
  48. },
  49. // 加载creator游戏脚本package.json、tsconfig.json配置
  50. initProjectConfig()
  51. {
  52. // 加载、监听tsconfig项目配置变动
  53. let tsconfigPath = path.join(prsPath,'tsconfig.json');
  54. this.watchFile = this.parent.fileMgr.addWatchPath(tsconfigPath,this.onFileStatChange.bind(this))
  55. // 必须先加载package项目配置
  56. let packagePath = path.join(prsPath,'package.json');
  57. if(tools.isFileExit(packagePath)){
  58. let jsonText = fs.readFileSync(packagePath).toString()
  59. this.updateProjectPackage(jsonText)
  60. }
  61. // 监听package项目配置变动
  62. this.parent.fileMgr.addWatchPath(packagePath,(eventName,files)=>{
  63. if (eventName == "create" || eventName == 'change') {
  64. if(tools.isFileExit(packagePath)){
  65. let jsonText = fs.readFileSync(packagePath).toString()
  66. this.updateProjectPackage(jsonText,true)
  67. }
  68. }
  69. this.onFileStatChange(eventName,files);
  70. })
  71. },
  72. // 设置选项
  73. setOptions(cfg,isInit)
  74. { if(cfg.enabledNpmDir == null) return;
  75. if(cfg.enabledNpmDir){
  76. if(!isInit){
  77. return Editor.log("加载node_modules设置 重启creator后生效")
  78. }
  79. this.initWatch()
  80. }else if(!cfg.enabledNpmDir && this._isInit)
  81. {
  82. this.stop()
  83. }
  84. },
  85. // 初始化 node_modules 文件夹监听
  86. initWatch(){
  87. delete this.check_timeout;
  88. this._isInit = true;
  89. this.watchFile = this.parent.fileMgr.addWatchPath(node_modules_path,this.onFileStatChange.bind(this))
  90. },
  91. // node_modules文件变化监听
  92. onFileStatChange(eventName,files){
  93. if (eventName == "init" || eventName == "create") {
  94. // Finished walking the tree
  95. this.addNodeModuleFiles(files);
  96. }else if (eventName == 'change') {
  97. this.changeNodeModuleFiles(files);
  98. }else if (eventName == 'delete') {
  99. this.unlinkNodeModuleFiles(files);
  100. }
  101. },
  102. // 读取项目package文件信息
  103. updateProjectPackage(text,isLoadDependenciesFiles=false){
  104. let packageContent = tools.parseJson(text);
  105. if(packageContent == null){
  106. return;
  107. }
  108. // 依赖包加载,用于代码提示自动导入路径
  109. this.dependencies = Object.assign(
  110. {},
  111. packageContent.dependencies,
  112. packageContent.devDependencies,
  113. packageContent.peerDependencies,
  114. packageContent.bundledDependencies,
  115. packageContent.optionalDependencies,
  116. );
  117. // 加载依赖模块文件
  118. if(isLoadDependenciesFiles){
  119. for (const key in this.dependencies) {
  120. let packagePath = path.join(node_modules_path,key,'package.json');
  121. packagePath = packagePath.replace(/\\/g,'/')
  122. if(tools.isFileExit(packagePath)){
  123. let packageModel = this.parent.loadVsModel(packagePath,path.extname(packagePath),false);
  124. this.updatePackageMainModulePath(packageModel);
  125. };
  126. }
  127. }
  128. },
  129. // 系统文件保存修改内容
  130. onAssetsChangedEvent(file){
  131. let fspath = file.uuid == 'outside' ? file.url : Editor.remote.assetdb.uuidToFspath(file.uuid);
  132. if(fspath.match(REG_EXP_JSON_CONFIG)){
  133. let vs_model = this.parent.fileMgr.getModelByFsPath(fspath);
  134. if(vs_model && this.isDependencie(vs_model.uri.toString())){
  135. this.parent.tsWr.writeOtherFile(vs_model.uri.toString(),vs_model.getValue());
  136. }
  137. }
  138. },
  139. // 刷新并导入并模块入口文件
  140. updatePackageMainModulePath(model){
  141. let url = model.uri.toString();
  142. if(!url.match(REG_EXP_PACKAGE) || !this.isDependencie(url)){
  143. return;
  144. }
  145. setTimeout(async ()=>{
  146. this.parent.tsWr.writeOtherFile(url,model.getValue()); // 保存package.json文件缓存到ts解析器参与进一步解析工作
  147. let tryModulePaths = await this.parent.tsWr.getPackageMainModulePath(url);
  148. // console.log("modeule包路径:",url,tryModulePaths)
  149. let filePath = await this.parent.fileMgr.loadNeedImportPathsAsync({[url]:tryModulePaths});
  150. if(filePath){
  151. // 性能优化: 忽略模块文件import路径深度解析功能
  152. this.parent.tsWr.setIgnoreTryImportScriptFile(this.parent.fileMgr.fsPathToModelUrl(filePath));
  153. }
  154. },1)
  155. },
  156. // 是否项目依赖的包
  157. isDependencie(url){
  158. let split = url.split('node_modules')
  159. let modulePath = split[1];
  160. if(!modulePath || tools.objectCount(this.dependencies) == 0){
  161. return true;
  162. }
  163. let dir = path.dirname(modulePath);
  164. dir = dir.substr(1);
  165. for (const key in this.dependencies) {
  166. if(key == dir){
  167. return true;
  168. }
  169. }
  170. return false;
  171. },
  172. // 多层 node_modules 目录
  173. isMultilayerNodeModuleDir(filePath){
  174. let reg = filePath.match(REG_EXP_MULTILAYER);
  175. return reg && reg.length>1;
  176. },
  177. isNodeModuleDir(path){
  178. return path && path.indexOf(node_modules_path) != -1;
  179. },
  180. addNodeModuleFiles(files){
  181. let c_files = []
  182. for (let k in files) {
  183. let filePath = files[k]
  184. if(!this.isMultilayerNodeModuleDir(filePath) && !filePath.endsWith('.DS_Store')){
  185. filePath = filePath.replace(/\\/g,'/');
  186. if(!this.parent.file_list_map[filePath]){
  187. c_files.push({
  188. url : filePath,
  189. uuid: 'outside'
  190. })
  191. }
  192. }
  193. }
  194. this.parent.messages['asset-db:assets-created'].bind(this.parent)(0,c_files)
  195. },
  196. // 改变文件
  197. changeNodeModuleFiles(files){
  198. let c_files = []
  199. for (let k in files) {
  200. let filePath = files[k];
  201. if(!this.isMultilayerNodeModuleDir(filePath) && !filePath.endsWith('.DS_Store')){
  202. filePath = filePath.replace(/\\/g,'/');
  203. if(!this.parent.file_list_map[filePath]){
  204. c_files.push({
  205. url : filePath,
  206. uuid: 'outside'
  207. })
  208. }
  209. }
  210. }
  211. for (let i = 0; i < c_files.length; i++) {
  212. const element = c_files[i];
  213. this.parent.messages['asset-db:asset-changed'].bind(this.parent)(0,element)
  214. }
  215. },
  216. // 移除文件
  217. unlinkNodeModuleFiles(files){
  218. let removeFiles = []
  219. for (let k in files) {
  220. let filePath = files[k]
  221. if(!this.isMultilayerNodeModuleDir(filePath) && !filePath.endsWith('.DS_Store')){
  222. filePath = filePath.replace(/\\/g,'/');
  223. if(this.parent.file_list_map[filePath]){
  224. removeFiles.push({
  225. url : filePath,
  226. path : filePath,
  227. uuid: 'outside'
  228. })
  229. }
  230. }
  231. }
  232. // console.log('移除文件夹:',removeFiles)
  233. this.parent.messages['asset-db:assets-deleted'].bind(this.parent)(0,removeFiles)
  234. },
  235. stop(){
  236. if(this.watchFile){
  237. this.watchFile.stop()
  238. this.watchFile = null;
  239. }
  240. if(this.check_timeout){
  241. clearTimeout(this.check_timeout);
  242. delete this.check_timeout;
  243. }
  244. },
  245. // 面板销毁
  246. onDestroy(){
  247. this.stop()
  248. },
  249. /************* 事件 *************/
  250. messages:{
  251. 'scene:saved'(){
  252. }
  253. },
  254. };