UNPKG

rigjs

Version:

A multi-repos dev tool based on yarn and git.Rigjs is intended to be the simplest way to develop,share and deliver codes between different developers or different projects.

317 lines (303 loc) 9.96 kB
import CICD, { DeployTarget } from '@/classes/cicd/CICD'; import CICDCmd from '@/classes/cicd/CICDCmd'; import CDN from '@/classes/cicd/Deploy/CDN'; import ESA from '@/classes/cicd/Deploy/ESA'; const delay = async (ms: number) => { await new Promise((resolve) => { setTimeout(resolve, ms); }); }; const setRewriteUri = async ( domain: string, original: string | string[], deployDir: string | string[], cdn: CDN ) => { const rwriteResult = await cdn.setRewriteUri( domain, Array.isArray(original) ? original : [original], Array.isArray(deployDir) ? deployDir : [deployDir], ['enhance_break'] ); const configId = rwriteResult?.DomainConfigList.DomainConfigModel[0].ConfigId; for (let i = 0; i <= 100; i++) { const configInfo = await cdn.describeCdnDomainConfigs(domain, configId); const domainConfigs = configInfo.DomainConfigs.DomainConfig; let successCount = 0; for (const domainConfig of domainConfigs) { if (domainConfig.Status === 'success') { successCount++; } else if (domainConfig.Status === 'failed') { throw new Error('cdn rewrite fail'); } } if (successCount === domainConfigs.length) { break; } if (i === 100) { throw new Error('cdn rewrite timeout 10min'); } await delay(3000); } }; const refreshCache = async (urls: string[], cdn: CDN) => { const refreshResult = await cdn.refreshCache(urls.join('\n')); console.log('Please Wait For RefreshCache...'); for (let i = 0; i <= 100; i++) { const desResult = await cdn.describeRefreshTaskById( refreshResult.RefreshTaskId ); let successCount = 0; for (const item of desResult.Tasks) { if (item.Status === 'Complete') { successCount++; } else if (item.Status === 'Failed') { throw new Error('RefreshCache Failed'); } } if (successCount === desResult.Tasks.length) { break; } if (i === 100) { throw new Error('refresh cache timeout 10min'); } await delay(3000); } console.log('RefreshCache Done'); }; /** * ESA publish path (edge_provider === 'esa'). Sets back-to-origin URI rewrite * rules per domain, then purges the entry URLs. * * Mapping vs CDN: hash mode only needs the entry page rewritten to * `/<deployDir>/index.html` (publicPath already carries deployDir so static * files resolve at the OSS origin directly). history/mpa additionally prepend * deployDir for static files and fall back to the entry for extension-less * routes — those dynamic-rewrite expressions need validation on a live ESA site. */ const publishViaEsa = async ( cicd: CICD, cicdCmd: CICDCmd, target: DeployTarget ) => { const esa = new ESA(target); if (!cicdCmd.endpoints || cicdCmd.endpoints.length === 0) { throw new Error('Endpoints.length Can Not Be 0!'); } const purgeByDomain: { [domain: string]: string[] } = {}; for (const endpoint of cicdCmd.endpoints) { const deployDir = endpoint.deployDir.replace(/\\/g, '/'); const webEntryPath = endpoint.web_entry_path || target.web_entry_path || '/'; const ruleBase = `rig-${deployDir.replace(/[^\w]+/g, '-')}`.replace( /-+/g, '-' ); for (const domain of endpoint.domains) { if (cicd.web_type === 'hash') { await esa.setRewriteRule( domain, `${ruleBase}-entry`, `(http.request.uri.path eq "${webEntryPath}")`, 'static', `/${deployDir}/index.html`, 1 ); } else { await esa.setRewriteRule( domain, `${ruleBase}-file`, `(http.request.uri.path.extension ne "")`, 'dynamic', `concat("/${deployDir}", http.request.uri.path)`, 1 ); await esa.setRewriteRule( domain, `${ruleBase}-entry`, 'true', cicd.web_type === 'mpa' ? 'dynamic' : 'static', cicd.web_type === 'mpa' ? `concat("/${deployDir}", http.request.uri.path, ".html")` : `/${deployDir}/index.html`, 2 ); } if (!purgeByDomain[domain]) { purgeByDomain[domain] = []; } purgeByDomain[domain].push(`https://${domain}${webEntryPath}`); } } for (const domain of Object.keys(purgeByDomain)) { console.log(`ESA purge ${domain}:`, purgeByDomain[domain]); await esa.purgeCache(domain, purgeByDomain[domain]); } console.log('ESA rewrite rules + purge done'); }; export default async (cmd: any) => { try { const rewriteConfigs: { [domain: string]: { original: string[]; deployDir: string[] }; } = {}; const setRewriteConfig = ( domain: string, originalItem: string, deployDirItem: string ) => { if (rewriteConfigs[domain]) { rewriteConfigs[domain].original.push(originalItem); rewriteConfigs[domain].deployDir.push(deployDirItem); } else { rewriteConfigs[domain] = { original: [originalItem], deployDir: [deployDirItem], }; } }; //create cicd object const cicd = CICD.createByDefault(cmd); //construct cmd object const cicdCmd = new CICDCmd(cmd, cicd); console.log('Start Publish-----'); const target = Array.isArray(cicdCmd.cicd.target) ? cicdCmd.cicd.target[0] : cicdCmd.cicd.target; if (target.edge_provider === 'esa') { await publishViaEsa(cicd, cicdCmd, target); console.log('Publish Done-----'); return; } const cdn = new CDN(target); const urls: string[] = []; if (!cicdCmd.endpoints || cicdCmd.endpoints.length === 0) { throw new Error('Endpoints.length Can Not Be 0!'); } for (const endpoint of cicdCmd.endpoints) { if ( !endpoint.uri_rewrite && (!target.uri_rewrite || !target.uri_rewrite.original || !target.uri_rewrite.original_regexp) ) { let webEntryPath: string; if (cicd.web_type === 'mpa') { webEntryPath = '/'; } else if (cicd.web_type === 'history') { webEntryPath = '/'; } else { webEntryPath = endpoint.web_entry_path ? endpoint.web_entry_path : target.web_entry_path || '/'; } for (const domain of endpoint.domains) { if (cicd.web_type === 'mpa') { //mpa匹配非首页 setRewriteConfig( domain, '^\\/([\\w-/]*\\w+)(?![^?]*\\.\\w+)', `/${endpoint.deployDir.replace(/\\/g, '/')}/$1.html` ); //mpa匹配文件 setRewriteConfig( domain, `^\\/([^?]*\\.[a-zA-Z0-9]+)($|\\?)`, `/${endpoint.deployDir.replace(/\\/g, '/')}/$1` ); } else if (cicd.web_type === 'history') { //spa/history匹配非首页 setRewriteConfig( domain, '^\\/([\\w-/]*\\w+)(?![^?]*\\.\\w+)', `/${endpoint.deployDir.replace(/\\/g, '/')}/index.html` ); //spa-history匹配文件 setRewriteConfig( domain, `^\\/([^?]*\\.[a-zA-Z0-9]+)($|\\?)`, `/${endpoint.deployDir.replace(/\\/g, '/')}/$1` ); } else { //spa-hash匹配文件 //hash模式支持一个域名支持多个网页应用的入口路径,如/,/app1,/app2,都是不同的网页应用 //需要替换webpack中的publicPath为实际OSS的目录 setRewriteConfig( domain, `^\\/([^?]*\\.[a-zA-Z0-9]+)($|\\?)`, `/$1` ); } //首页匹配正则,hash,history,mpa三个模式通用 setRewriteConfig( domain, `^(${webEntryPath})($|\\?|#|\\/\\?|\\/$)`, `/${endpoint.deployDir.replace(/\\/g, '/')}/index.html` ); urls.push(`https://${domain}${webEntryPath}`); } } else { const uriRewrite = endpoint.uri_rewrite ? endpoint.uri_rewrite : target.uri_rewrite; if (!uriRewrite) { continue; } for (const domain of endpoint.domains) { if (cicd.web_type !== 'hash') { setRewriteConfig( domain, '^\\/([^?]*\\.[a-zA-Z0-9]+)($|\\?)', `/${endpoint.deployDir.replace(/\\/g, '/')}/$1` ); } else { setRewriteConfig( domain, '^\\/([^?]*\\.[a-zA-Z0-9]+)($|\\?)', `/$1` ); } setRewriteConfig( domain, `${ uriRewrite.original_regexp ? uriRewrite.original_regexp : uriRewrite.original }`, `/${endpoint.deployDir.replace(/\\/g, '/')}/index.html` ); urls.push(`https://${domain}${uriRewrite.original}`); } } } // 回源URI改写 console.log('Please Wait For Set RWrite URI...'); const setRewriteUriPromises: Promise<any>[] = []; console.log('rewriteConfigs: ', rewriteConfigs); Object.keys(rewriteConfigs).forEach((domain) => { const rewriteConfig = rewriteConfigs[domain]; setRewriteUriPromises.push( setRewriteUri( domain, rewriteConfig.original, rewriteConfig.deployDir, cdn ) ); }); if (setRewriteUriPromises.length > 0) { await Promise.all(setRewriteUriPromises); } else { console.log('Not Have To Set RWrite URI'); } console.log('Set RWrite URI Done'); //刷新cdn if (urls.length > 0) { await refreshCache(urls, cdn); } else { console.log('Not Have To RefreshCache'); } console.log('Publish Done-----'); } catch (e: any) { console.error(e.message); process.exit(1); } };