// @ts-nocheck /** * 在构建出的 js 中增加代码片段,用作记录构建产物的 git 信息 * 上报构建产物资源体积信息等 */ const fs = require('fs'); const path = require('path'); const os = require('os'); const gzipSize = require('gzip-size'); const axios = require('axios'); const AES = require('@ali/aes-tracker/index-node'); const AESPluginEvent = require('@ali/aes-tracker-plugin-event/index-node'); const gitRemoteOriginUrl = require('git-remote-origin-url'); class AssetsInfoPlugin { constructor(options = {}) { this.options = options; } apply(compiler) { compiler.hooks.afterEmit.tap('AssetsInfoPlugin', async () => { const { BUILD_GIT_GROUP, BUILD_GIT_PROJECT, BUILD_GIT_COMMITID, BUILD_GIT_BRANCH, BUILD_ENV, BUILD_USER } = process.env; const { assetsPath = '' } = this.options; let repoInfo; let repo; if (BUILD_ENV === 'cloud') { repoInfo = { branch: BUILD_GIT_BRANCH, commitId: BUILD_GIT_COMMITID, }; repo = `${BUILD_GIT_GROUP}/${BUILD_GIT_PROJECT}`; } else { const gitDir = path.join(process.cwd(), '.git'); if (!fs.existsSync(gitDir)) { return; } const url = await gitRemoteOriginUrl() || ''; if (url) { if (url.startsWith('git@')) { const repoArray = url.split(':'); if (repoArray && repoArray[1]) { repo = repoArray[1].replace('.git', ''); } } else if (url.startsWith('http') || url.startsWith('https')) { const repoArray = url.split('/'); const len = repoArray.length; if (repoArray && len > 1) { repo = repoArray.slice(len - 2, len).join('/').replace('.git', ''); } } } if (!repo) { return; } const HEAD = fs.readFileSync(path.join(gitDir, 'HEAD'), { encoding: 'utf-8' }); const currentBranch = HEAD.replace('ref: refs/heads/', '').replace('\n', '').replace('\r', ''); const commitId = fs.readFileSync(path.join(gitDir, HEAD.replace('ref: ', '').replace('\r', '').replace('\n', '')), { encoding: 'utf-8' }).replace('\r', '').replace('\n', ''); repoInfo = { branch: currentBranch, commitId, }; } const snippet = `${os.EOL}if(!window.__assets_info__){window.__assets_info__={};}window.__assets_info__['${repo}']=${JSON.stringify(repoInfo)};`; const sendEvent = new AES( { pid: 'teamix-cli', user_type: '14', } ).use(AESPluginEvent); const sizeStat = []; const handleFile = dir => { const files = fs.readdirSync(dir); files.forEach(file => { const filePath = path.join(dir, file); const stat = fs.statSync(filePath); if (stat.isDirectory()) { handleFile(filePath); } else if (stat.isFile()) { let size = 0; try { size = gzipSize.fileSync(filePath, { level: 6, // 和 Chrome 保持一致 }); } catch (_err) { // } sizeStat.push({ file: filePath.replace('/cloud/source_code', ''), size: Math.ceil(size / 1024), // 转成 KB }) sendEvent('asset-size-event', { et: 'EXP', c1: repo, // 仓库名 c2: repoInfo.branch, // 分支信息 c3: filePath, c4: Math.ceil(size / 1024), // 转成 KB }); if (file.endsWith('.js')) { fs.appendFileSync(filePath, snippet); } } }); }; handleFile(assetsPath); if (BUILD_ENV === 'cloud') { try { const sizeThreshold = 500; const needWarn = sizeStat.filter(stat => { return stat.size > sizeThreshold; }); const markdown = `## ${repo} 构建成功!\n${needWarn.length ? `以下文件 gzip 后体积超过 **${sizeThreshold} KB**,请关注并做好优化:\n${needWarn.map(item => `+ ${item.file} : ${item.size}KB\n`)}` : ''}`; const res = await axios({ url: 'https://pre-teamix.alibaba-inc.com/openapi/v1/ding/msg', method: 'post', data: { key: 'assets_info', // 这里传入你刚注册好的key specifiedUserList: [BUILD_USER], userMsg: { // 这里配置消息通知的内容和样式,具体参考下面的文档 msgtype: 'markdown', markdown: { title: 'Teamix 构建通知', text: markdown, }, }, }, }) } catch (_err) { // } } }); } } module.exports = AssetsInfoPlugin;