UNPKG

youzanyun-devtool-worker

Version:

- web - ws - proxy

458 lines (457 loc) 21.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const path_1 = tslib_1.__importDefault(require("path")); const fs_extra_1 = tslib_1.__importDefault(require("fs-extra")); const download_1 = tslib_1.__importDefault(require("download")); const fast_glob_1 = tslib_1.__importDefault(require("fast-glob")); const merge_1 = tslib_1.__importDefault(require("lodash/merge")); const spring4js_nodejs_1 = require("spring4js-nodejs"); const PageHandler_1 = tslib_1.__importDefault(require("./PageHandler")); let H5ExtensionService = class H5ExtensionService { constructor() { this.previewCompsMap = {}; this._broadcastPreviewComps = new spring4js_nodejs_1.Emitter(); this.onBroadcastPreviewComps = this._broadcastPreviewComps.registerEvent; this.remoteTemplateVersion = {}; this.pageHandlerCache = {}; this.versionFileName = 'ecloud-tpl-version.json'; } async start() { this.workDir = this.configService.getWorkerDir(); const h5DemoDir = this.configService.getH5DemoDir(); await fs_extra_1.default.ensureDir(h5DemoDir); this.h5CompDemoDir = path_1.default.resolve(h5DemoDir, 'h5-extension'); this.h5ReplaceDemoDir = path_1.default.resolve(h5DemoDir, 'h5-script-replace'); const remoteToolConfig = await this.customApiService.getRemoteToolConfig(); if (remoteToolConfig.templateVersion) { this.remoteTemplateVersion = JSON.parse(remoteToolConfig.templateVersion); } } async getMenu(workbenchId, projectId) { let menuData = [{ key: 'home', title: '首页', param: { contentType: 'webview', url: `/html/h5-extension/?projectId=${projectId}&workbenchId=${workbenchId}#/home`, docKey: 'h5-home', } }]; const nodeData = await this.customApiService.getH5NodeList(); if (nodeData && nodeData.length > 0) { const nodeList = nodeData.filter((item) => { const { bizNodeCode, bizNodeElement } = item; return (bizNodeElement.indexOf(1) > -1) && bizNodeCode; }).map((item) => { let { bizNodeName, bizNodeCode, bizNodeId } = item; let url = `/html/h5-extension?projectId=${projectId}&workbenchId=${workbenchId}&selectedKey=${bizNodeId}` + `&nodeName=${bizNodeName}&nodeCode=${bizNodeCode}#/list`; return { key: item.bizNodeId, title: item.bizNodeName, param: { contentType: 'webview', url, docKey: 'h5-custom', } }; }); nodeList.push({ key: 0, title: '全局页面定制', param: { contentType: 'webview', url: `/html/h5-extension?projectId=${projectId}&workbenchId=${workbenchId}&selectedKey=0` + `&nodeName=全局页面定制&nodeCode=_global#/list`, docKey: 'h5-custom', } }); menuData.push({ key: 'pageCustom', title: '页面配置', children: nodeList, }); } menuData.push({ key: 'upload', title: '打包上传', param: { contentType: 'webview', url: `/html/h5-extension/?projectId=${projectId}&workbenchId=${workbenchId}#/upload`, docKey: 'h5-deploy', } }); return menuData; } async initPageDemo(projectId) { const project = await this.projectService.getProjectById(projectId); let versionInfo = {}; const customTypes = ['h5-extension', 'h5-script-replace']; for (let i = 0; i < customTypes.length; i++) { const customType = customTypes[i]; const demoDir = customType === 'h5-script-replace' ? this.h5ReplaceDemoDir : this.h5CompDemoDir; let remoteConfig = {}; remoteConfig.version = customType === 'h5-script-replace' ? this.remoteTemplateVersion.h5ReplaceFrameworkVersion : this.remoteTemplateVersion.h5CompFrameworkVersion; remoteConfig.demoUrl = customType === 'h5-script-replace' ? this.remoteTemplateVersion.h5ReplaceUrl : this.remoteTemplateVersion.h5CompUrl; if (remoteConfig.demoUrl) { await this.checkAndDownloadTpl(remoteConfig, demoDir); const workDir = path_1.default.resolve(project.proPath, `${project.proName}-ui/${customType}`); const versionPath = path_1.default.resolve(workDir, this.versionFileName); let isVersionExist = await fs_extra_1.default.pathExists(versionPath); if (!isVersionExist) { versionInfo[customType] = { latestVersion: remoteConfig.version, currentVersion: null, }; } else { const currentVersionInfo = await fs_extra_1.default.readJSON(versionPath); versionInfo[customType] = { latestVersion: remoteConfig.version, currentVersion: currentVersionInfo.frameworkVersion }; } } } return versionInfo; } async updateH5Project(projectId) { const project = await this.projectService.getProjectById(projectId); const h5CompDir = path_1.default.resolve(project.proPath, `${project.proName}-ui/h5-extension`); await fs_extra_1.default.ensureDir(path_1.default.resolve(h5CompDir, 'src')); await fs_extra_1.default.remove(path_1.default.resolve(h5CompDir, 'ecloud-tpl-version.json')); await fs_extra_1.default.copy(path_1.default.resolve(this.h5CompDemoDir, 'ecloud-tpl-version.json'), path_1.default.resolve(h5CompDir, 'ecloud-tpl-version.json')); await fs_extra_1.default.remove(path_1.default.resolve(h5CompDir, 'webpack')); await fs_extra_1.default.copy(path_1.default.resolve(this.h5CompDemoDir, 'webpack'), path_1.default.resolve(h5CompDir, 'webpack')); await fs_extra_1.default.remove(path_1.default.resolve(h5CompDir, 'package-lock.json')); await fs_extra_1.default.remove(path_1.default.resolve(h5CompDir, 'yarn.lock')); const compPckExist = await fs_extra_1.default.pathExists(path_1.default.resolve(h5CompDir, 'package.json')); if (compPckExist) { const currentCompPackage = await fs_extra_1.default.readJSON(path_1.default.resolve(h5CompDir, 'package.json')); const demoCompPackage = await fs_extra_1.default.readJSON(path_1.default.resolve(this.h5CompDemoDir, 'package.json')); await fs_extra_1.default.writeJSON(path_1.default.resolve(h5CompDir, 'package.json'), merge_1.default({}, currentCompPackage, demoCompPackage), { spaces: 2 }); } else { await fs_extra_1.default.copy(path_1.default.resolve(this.h5CompDemoDir, 'package.json'), path_1.default.resolve(h5CompDir, 'package.json')); } await fs_extra_1.default.remove(path_1.default.resolve(h5CompDir, 'README.md')); await fs_extra_1.default.copy(path_1.default.resolve(this.h5CompDemoDir, 'README.md'), path_1.default.resolve(h5CompDir, 'README.md')); const h5ReplaceDir = path_1.default.resolve(project.proPath, `${project.proName}-ui/h5-script-replace`); await fs_extra_1.default.ensureDir(path_1.default.resolve(h5ReplaceDir, 'src')); await fs_extra_1.default.remove(path_1.default.resolve(h5ReplaceDir, 'ecloud-tpl-version.json')); await fs_extra_1.default.copy(path_1.default.resolve(this.h5ReplaceDemoDir, 'ecloud-tpl-version.json'), path_1.default.resolve(h5ReplaceDir, 'ecloud-tpl-version.json')); await fs_extra_1.default.remove(path_1.default.resolve(h5ReplaceDir, 'webpack')); await fs_extra_1.default.copy(path_1.default.resolve(this.h5ReplaceDemoDir, 'webpack'), path_1.default.resolve(h5ReplaceDir, 'webpack')); await fs_extra_1.default.remove(path_1.default.resolve(h5ReplaceDir, 'package-lock.json')); await fs_extra_1.default.remove(path_1.default.resolve(h5ReplaceDir, 'yarn.lock')); const replacePckExist = await fs_extra_1.default.pathExists(path_1.default.resolve(h5ReplaceDir, 'package.json')); if (replacePckExist) { const currentReplacePackage = await fs_extra_1.default.readJSON(path_1.default.resolve(h5ReplaceDir, 'package.json')); const demoReplacePackage = await fs_extra_1.default.readJSON(path_1.default.resolve(this.h5ReplaceDemoDir, 'package.json')); await fs_extra_1.default.writeJSON(path_1.default.resolve(h5ReplaceDir, 'package.json'), merge_1.default({}, currentReplacePackage, demoReplacePackage), { spaces: 2 }); } else { await fs_extra_1.default.copy(path_1.default.resolve(this.h5ReplaceDemoDir, 'package.json'), path_1.default.resolve(h5ReplaceDir, 'package.json')); } } async getPageCustomList(params) { const { projectId } = params; const result = []; const nodeData = await this.customApiService.getH5NodeList(); if (!nodeData && nodeData.length === 0) { return result; } const feNodeData = nodeData.filter((item) => { const { bizNodeCode, bizNodeElement } = item; return (bizNodeElement.indexOf(1) > -1) && bizNodeCode; }); feNodeData.push({ bizNodeCode: "_global", bizNodeId: 0, bizNodeName: "全局页面定制", id: 0, }); for (let i = 0; i < feNodeData.length; i++) { const { bizNodeCode, bizNodeId } = feNodeData[i]; const pageInfo = await this.getPageCustomListByNodeId({ projectId, nodeCode: bizNodeCode, pageIndex: 0, pageSize: 1000, relType: 2, status: 1, bizNodeElementId: 1, bizNodeId, }); const customInfo = pageInfo.filter((item) => item.isCustomed); if (customInfo.length > 0) { result.push(Object.assign(Object.assign({}, feNodeData[i]), { children: customInfo })); } } return result; } async getPageCustomListByNodeId(params) { const { projectId, nodeCode } = params, yzyParams = tslib_1.__rest(params, ["projectId", "nodeCode"]); let result = []; if (nodeCode === '_global') { result = [{ description: "[特殊] 全局组件定制", id: 0, implType: "components", name: "_global", pageId: 0, pageType: 0, status: 1, }]; } else { const res = await this.customApiService.getH5TemplatesByNodeId(yzyParams); result = res.items || []; result.push({ description: "[特殊] 节点组件定制", id: 0, implType: "components", name: "_common", pageId: 0, pageType: 0, status: 1, }); } if (result && result.length > 0) { const project = await this.projectService.getProjectById(projectId); for (let i = 0; i < result.length; i++) { const { isCustomed, expandedList } = await this.checkCustomed(project, nodeCode, result[i]); result[i].isCustomed = isCustomed; result[i].expandedList = expandedList; } } return result; } async checkCustomed(project, nodeCode, item) { if (!project.proPath) { return { isCustomed: false, expandedList: [] }; } const { name, implType } = item; const customType = implType === 'scriptReplace' ? 'h5-script-replace' : 'h5-extension'; const pageHandler = await this.getPageHandler({ customType, projectId: project.id, nodeCode, pageName: name }); if (implType === 'scriptReplace') { const customInfo = await pageHandler.isPageReplaceCustom(); return customInfo; } else { const isExist = await pageHandler.isPageCompCustom(); let comps = []; if (isExist) { comps = await pageHandler.getComponents(); } return { isCustomed: isExist, expandedList: comps }; } } async getPageHandler({ customType, projectId, nodeCode, pageName }) { let cacheKey = `${projectId}-${customType}-${nodeCode}-${pageName}`; let pageHandler = this.pageHandlerCache[cacheKey]; if (pageHandler) { return pageHandler; } const project = await this.projectService.getProjectById(projectId); pageHandler = new PageHandler_1.default({ h5CompDemoDir: this.h5CompDemoDir, h5ReplaceDemoDir: this.h5ReplaceDemoDir, workDir: this.workDir, customType: customType, projectRootDir: project.proPath, projectName: project.proName, nodeCode, pageName, }); await pageHandler.start(); this.pageHandlerCache[cacheKey] = pageHandler; return pageHandler; } async checkAndDownloadTpl(remoteConfig, demoDir) { let needDownload = false; let cacheVersionInfo = {}; try { cacheVersionInfo = await fs_extra_1.default.readJson(path_1.default.resolve(demoDir, this.versionFileName)); if (remoteConfig.version != cacheVersionInfo.frameworkVersion) { needDownload = true; } } catch (e) { needDownload = true; } if (needDownload) { await fs_extra_1.default.remove(demoDir); await download_1.default(remoteConfig.demoUrl, demoDir, { extract: true, strip: 1, }); } } async getTouchJsPath() { const touchJsPath = path_1.default.resolve(this.configService.getWorkerDir(), 'assets/utils/touch-emulator.js'); return touchJsPath; } async broadcastPreviewComps(projectId, workbenchId, previewComps) { this._broadcastPreviewComps.fire(previewComps); } async updatePreviewComps(projectId, url, previewComps) { const key = projectId + '_' + url; this.previewCompsMap[key] = previewComps; return true; } async getPreviewComps(projectId, url) { const key = projectId + '_' + url; return this.previewCompsMap[key] || []; } async uploadInfo(params) { const { projectId } = params; const project = await this.projectService.getProjectById(projectId); const isClean = await this.projectService.checkProjectStatus(project.proPath); if (!isClean) { throw new Error('请先提交本地代码'); } const userInfo = await this.userService.getUserInfo(); await this.uploadH5CompsInfo(project, userInfo); await this.uploadH5ReplaceInfo(project, userInfo); return true; } async uploadH5CompsInfo(project, userInfo) { const prodBuildDir = path_1.default.resolve(project.proPath, `${project.proName}-ui/h5-extension/dist`); const builds = await fs_extra_1.default.readdir(prodBuildDir); const buildFileNameList = builds.filter(item => { return item !== 'info.json' && !item.endsWith('.map'); }); const fileList = buildFileNameList.map(fileShorr => { return path_1.default.resolve(prodBuildDir, fileShorr); }); const pageNames = buildFileNameList.map(fileShorr => { return fileShorr.split('.')[0]; }); const uploadCompFileList = await this.cdnService.uploadFileToCdn({ projectName: project.proName, pageName: 'h5-comps', fileList, addHash: false, }); const uploadUrls = uploadCompFileList.map(item => item.url); const infoPath = path_1.default.resolve(project.proPath, `${project.proName}-ui/h5-extension/dist/info.json`); const pages = await this.getInfo(uploadUrls, infoPath, pageNames); const customInfo = { type: 'h5', appName: project.proName, commitUser: userInfo.userName || userInfo.mobile || 'youzanyun-developer-tool', commitHash: 'unknown', pages, }; const saveRes = await this.customApiService.saveCustomContent(customInfo); return saveRes; } async uploadH5ReplaceInfo(project, userInfo) { const workDir = path_1.default.resolve(project.proPath, `${project.proName}-ui/h5-script-replace/src`); const distDir = path_1.default.resolve(project.proPath, `${project.proName}-ui/h5-script-replace/dist`); const temp = await fast_glob_1.default('**/main.js', { cwd: workDir }); const result = []; for (let i = 0, len = temp.length; i < len; i++) { const item = temp[i]; const relative = path_1.default.dirname(item); const pageDir = path_1.default.resolve(workDir, relative); const config = await fs_extra_1.default.readJson(pageDir + "/config.json"); if (config.pageName && config.planName) { let pageInfo = { pageName: config.pageName, planName: config.planName, js: [], css: [], }; const distPageDir = path_1.default.resolve(distDir, relative); const buildFileNameList = await fs_extra_1.default.readdir(distPageDir); const jsArr = []; const cssArr = []; for (let j = 0; j < buildFileNameList.length; j++) { const pageFile = path_1.default.join(distPageDir, buildFileNameList[j]); const info = fs_extra_1.default.statSync(pageFile); if (!info.isDirectory()) { if (path_1.default.extname(pageFile) === '.css') { cssArr.push(pageFile); } else if (path_1.default.extname(pageFile) === '.js') { jsArr.push(pageFile); } } } const uploadJs = await this.cdnService.uploadFileToCdn({ projectName: project.proName, pageName: config.pageName, fileList: jsArr, addHash: false, }); pageInfo.js = uploadJs.map(item => item.url); const uploadCss = await this.cdnService.uploadFileToCdn({ projectName: project.proName, pageName: config.pageName, fileList: cssArr, addHash: false, }); pageInfo.css = uploadCss.map(item => item.url); result.push(pageInfo); } } if (result.length === 0) { return; } const customInfo = { type: 'scriptReplace', appName: project.proName, commitUser: userInfo.userName || userInfo.mobile || 'youzanyun-developer-tool', commitHash: 'unknown', pages: result, }; const saveRes = await this.customApiService.saveCustomContent(customInfo); return saveRes; } async getInfo(urls, infoPath, fileNameList) { const pagesInfo = await fs_extra_1.default.readJSON(infoPath); const result = []; fileNameList.map((pageName, i) => { result.push(Object.assign({ pageName, url: urls[i], methods: [], components: [] }, pagesInfo[pageName])); }); return result; } ; }; tslib_1.__decorate([ spring4js_nodejs_1.Resource() ], H5ExtensionService.prototype, "projectService", void 0); tslib_1.__decorate([ spring4js_nodejs_1.Resource() ], H5ExtensionService.prototype, "configService", void 0); tslib_1.__decorate([ spring4js_nodejs_1.Resource() ], H5ExtensionService.prototype, "customApiService", void 0); tslib_1.__decorate([ spring4js_nodejs_1.Resource() ], H5ExtensionService.prototype, "cdnService", void 0); tslib_1.__decorate([ spring4js_nodejs_1.Resource() ], H5ExtensionService.prototype, "userService", void 0); H5ExtensionService = tslib_1.__decorate([ spring4js_nodejs_1.Service() ], H5ExtensionService); exports.default = H5ExtensionService; ;