UNPKG

@chinese-fonts/zqfs

Version:
456 lines (441 loc) 16.3 kB
<!doctype html> <html lang="zh-cn"> <head> <meta charset="UTF-8" /> <title>字体分包构建报告</title> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <link rel="stylesheet" href="https://fastly.jsdelivr.net/npm/vant@4.9.15/lib/index.css" /> <link href="https://unpkg.com/vue3-easy-data-table@1.5.47/dist/style.css" rel="stylesheet" /> <link rel="stylesheet" href="./result.css" /> <style> body { overflow-wrap: break-word; font-size: 18px; background-color: #edf0f3; --easy-table-border: 0; } main { padding: 20px; margin-top: var(--van-nav-bar-height); margin-bottom: var(--van-tabbar-height); } .light-blue { --easy-table-body-row-font-color: #427cb7; } .light-red { --easy-table-body-row-font-color: #b74273; } .hint { display: block; text-align: center; color: gray; margin: 1rem; } .scroller { height: 100%; } .user { height: 32%; padding: 0 12px; display: flex; align-items: center; } </style> </head> <body> <div id="app"> <van-nav-bar :title="reporter.state?.css?.family +' 分包报告'" right-text="Github" @click-right="toGithub" style="position: fixed; width: 100%; top: 0" ></van-nav-bar> <div v-if="reporter.isLoading">加载中</div> <div v-if="reporter.isError">加载错误</div> <main :style="style"> <van-cell-group inset title="样式控制"> <van-field v-model="fontSize" label="字体大小" placeholder="请输入字体大小" ></van-field> <van-field v-model="fontWeight" label="字体重量" placeholder="请输入字重" ></van-field> </van-cell-group> <!-- 汇总信息 --> <display-chart v-if="reporter.isOk() && activePage === 0" :reporter="reporter.state" ></display-chart> <!-- 字体信息表格 --> <name-table v-if="reporter.isOk() && activePage === 1" :reporter="reporter.state" ></name-table> <!-- 单包查询 --> <pkg-list v-if="reporter.isOk() && activePage === 2" :reporter="reporter.state" ></pkg-list> <div class="hint"> <a href="https://chinese-font.netlify.app">中文网字计划</a> <span> cn-font-split 生成 </span> </div> </main> <!-- 底部导航栏 --> <van-tabbar v-model="activePage"> <van-tabbar-item icon="home-o">汇总</van-tabbar-item> <van-tabbar-item icon="home-o">字体信息</van-tabbar-item> <van-tabbar-item icon="search">分包</van-tabbar-item> </van-tabbar> </div> </body> <script src="https://unpkg.com/vue@3.4.33"></script> <script src="https://unpkg.com/vant@4/lib/vant.min.js"></script> <script src="https://unpkg.com/vue3-easy-data-table@1.5.47/dist/vue3-easy-data-table.umd.js"></script> <script src="https://unpkg.com/echarts@5.5.1"></script> <script src="https://unpkg.com/vue-echarts@7.0.3"></script> <script src="https://unpkg.com/protobufjs@7.4.0/dist/protobuf.min.js"></script> <script> const { createApp } = Vue; const app = createApp({ data() { return { reporter: PromiseToState(loadReport), activePage: 0, fontWeight: '', fontSize: 16, }; }, methods: { toGithub() { window.open('https://github.com/KonghaYao/cn-font-split'); }, }, async mounted() { const state = await this.reporter.refetch(); this.fontWeight = state.css.weight; }, computed: { style() { const size = this.fontSize < 12 ? 12 : this.fontSize; return ( `font-family: '${this.reporter.state?.css?.family}';` + `font-weight: ${this.fontWeight};` + `--van-cell-font-size: ${size}px;` ); }, }, }); /** 封装Promise为状态对象 **/ function PromiseToState(fn) { return { state: {}, isOk() { return !this.isLoading && !this.isError && this.state; }, isLoading: false, isError: false, async refetch() { this.isLoading = true; this.isError = false; try { this.state = await fn(); } catch (e) { console.error(e); this.isError = true; } this.isLoading = false; return this.state; }, }; } /** 载入构建出来的二进制报告文件 **/ async function loadReport() { return new Promise((resolve, reject) => { protobuf.load('./index.proto', (err, root) => { if (err) return reject(err); fetch('./reporter.bin') .then((res) => res.arrayBuffer()) .then((buf) => { const OutputReport = root.lookup('OutputReport'); const data = OutputReport.decode( new Uint8Array(buf), ); console.log(data); resolve(data); }) .catch(reject); }); }); } globalThis.app = app; app.use(vant); app.component('v-chart', VueECharts); app.component('easy-data-table', window['vue3-easy-data-table']); </script> <!-- 汇总数据 --> <template id="display-chart"> <van-cell-group inset title="构建信息"> <van-cell title="构建工具" value="cn-font-split"></van-cell> <van-cell title="构建版本" :value="reporter.version"></van-cell> <van-cell title="构建平台" :value="reporter.platform"></van-cell> </van-cell-group> <van-cell-group inset title="构建详情"> <div style="height: 300px; width: 400px"> <v-chart :option="pieOptions"></v-chart> </div> <div style="height: 400px; width: 100%"> <v-chart :option="option"></v-chart> </div> </van-cell-group> </template> <script> const tooltip = { trigger: 'axis', axisPointer: { type: 'cross', crossStyle: { color: '#999', }, }, }; app.component('display-chart', { template: '#display-chart', props: { reporter: Object, }, computed: { option() { const data = this.reporter.subsetDetail ?? []; return { title: { text: '构建耗时', x: 'center', }, xAxis: { type: 'category' }, tooltip, yAxis: [ { type: 'value', name: 'time / ms', }, { type: 'value', name: 'bytes / KB', }, ], series: [ { name: 'time', type: 'bar', data: data.map((i) => i.duration), }, { name: 'bytes', type: 'line', data: data.map((i) => (i.bytes / 1024).toFixed(2), ), }, ], }; }, pieOptions() { const message = this.reporter.bundleMessage; if (!message) return {}; return { title: { text: '构建大小对比', x: 'center', }, series: [ { type: 'pie', radius: ['45%', '60%'], label: { formatter(b, c) { return `${b.name}\n${( b.value / (1024 * 1024) ).toFixed(2)}MB`; }, }, data: [ { value: message.bundledBytes, name: 'bundled', }, { value: message.originBytes, name: 'origin', }, ], }, { type: 'pie', radius: [0, '30%'], label: { formatter(b, c) { return `${b.name}\n${b.value}`; }, }, data: [ { value: message.bundledSize, name: 'bundled', }, { value: message.originSize, name: 'origin', }, ], }, ], }; }, }, }); </script> <!-- 字体信息表格 --> <template id="name-table"> <van-cell-group inset title="CSS 信息"> <van-cell title="font-family" :value="reporter.css?.family" ></van-cell> <van-cell title="font-weight" :value="reporter.css?.weight" ></van-cell> <van-cell title="font-style" :value="reporter.css?.style" ></van-cell> <van-cell title="font-display" :value="reporter.css?.display" ></van-cell> </van-cell-group> <van-cell-group inset title="字体信息"> <easy-data-table :headers="columns" :items="reporter.nameTable??[]" :rows-per-page="1000" :body-row-class-name="useColor" ></easy-data-table> </van-cell-group> </template> <script> app.component('name-table', { template: '#name-table', props: { reporter: Object, }, data() { return { color: { Windows: 'light-blue', Macintosh: 'light-red', }, columns: [ { text: '语言', value: 'language', sortable: true, minWidth: '36px', }, { text: '平台', value: 'platform', sortable: true, minWidth: '20px', }, { text: '名称', value: 'name', sortable: true, minWidth: '50px', }, { text: '值', value: 'value', sortable: true, width: '200px', }, ], }; }, methods: { useColor(item) { return this.color[item.platform]; }, }, }); </script> <!-- 每个包的数据 --> <template id="pkg-list"> <van-cell-group inset> <van-field v-model="search" label="搜索" placeholder="请输入关键字" ></van-field> </van-cell-group> <van-cell-group inset title="字体分包详情"> <v-list ref="list" :items="items" :first-render="10" style="height: 80vh" > <template #default="{ item, index }"> <div style="padding: 0 1rem"> <h2 :style="{ width: item.width }"> ITEM: {{ index }} - {{ item.hash }} </h2> <span> {{String.fromCodePoint(...item.chars)}} </span> </div> </template> </v-list> </van-cell-group> </template> <script src="https://unpkg.com/@virtual-list/vue/dist/v3/index.iife.js"></script> <script> app.component('v-list', virtualListVue); app.component('pkg-list', { template: '#pkg-list', props: { reporter: Object, }, data() { return { activeNames: [], search: '', }; }, mounted() {}, computed: { items() { const list = this.reporter.subsetDetail ?? []; if (this.search) { return list.filter((i) => i.hash.includes(this.search)); } return list; }, }, }); </script> <script> app.mount('#app'); </script> </html>