feat(frontend): tabler-iconsの使用されていないアイコンを削除するように

This commit is contained in:
kakkokari-gtyih 2025-01-25 15:56:23 +09:00
parent 1cd1264ec0
commit 9265182729
16 changed files with 394 additions and 51 deletions

View File

@ -11,6 +11,7 @@
"packages/frontend-shared",
"packages/frontend",
"packages/frontend-embed",
"packages/icons-subsetter",
"packages/backend",
"packages/sw",
"packages/misskey-js",

View File

@ -15,13 +15,13 @@
"@rollup/plugin-json": "6.1.0",
"@rollup/plugin-replace": "5.0.7",
"@rollup/pluginutils": "5.1.3",
"@tabler/icons-webfont": "3.3.0",
"@twemoji/parser": "15.1.1",
"@vitejs/plugin-vue": "5.2.0",
"@vue/compiler-sfc": "3.5.12",
"astring": "1.9.0",
"buraha": "0.0.1",
"estree-walker": "3.0.3",
"icons-subsetter": "workspace:*",
"mfm-js": "0.24.0",
"misskey-js": "workspace:*",
"frontend-shared": "workspace:*",
@ -40,6 +40,7 @@
},
"devDependencies": {
"@misskey-dev/summaly": "5.1.0",
"@tabler/icons-webfont": "3.3.0",
"@testing-library/vue": "8.1.0",
"@types/estree": "1.0.6",
"@types/micromatch": "4.0.9",

View File

@ -6,7 +6,12 @@
// https://vitejs.dev/config/build-options.html#build-modulepreload
import 'vite/modulepreload-polyfill';
import '@tabler/icons-webfont/dist/tabler-icons.scss';
if (import.meta.env.DEV) {
await import('@tabler/icons-webfont/dist/tabler-icons.scss');
} else {
await import('icons-subsetter/built/tabler-icons-classes.css');
await import('icons-subsetter/built/tabler-icons-frontendEmbed.css');
}
import '@/style.scss';
import { createApp, defineAsyncComponent } from 'vue';

View File

@ -25,7 +25,6 @@
"@rollup/plugin-replace": "5.0.7",
"@rollup/pluginutils": "5.1.3",
"@syuilo/aiscript": "0.19.0",
"@tabler/icons-webfont": "3.3.0",
"@twemoji/parser": "15.1.1",
"@vitejs/plugin-vue": "5.2.0",
"@vue/compiler-sfc": "3.5.12",
@ -46,6 +45,7 @@
"estree-walker": "3.0.3",
"eventemitter3": "5.0.1",
"frontend-shared": "workspace:*",
"icons-subsetter": "workspace:*",
"idb-keyval": "6.2.1",
"insert-text-at-cursor": "0.3.0",
"is-file-animated": "1.0.2",
@ -95,6 +95,7 @@
"@storybook/types": "8.4.4",
"@storybook/vue3": "8.4.4",
"@storybook/vue3-vite": "8.4.4",
"@tabler/icons-webfont": "3.3.0",
"@testing-library/vue": "8.1.0",
"@types/canvas-confetti": "^1.6.4",
"@types/estree": "1.0.6",

View File

@ -6,7 +6,12 @@
// https://vitejs.dev/config/build-options.html#build-modulepreload
import 'vite/modulepreload-polyfill';
import '@tabler/icons-webfont/dist/tabler-icons.scss';
if (import.meta.env.DEV) {
await import('@tabler/icons-webfont/dist/tabler-icons.scss');
} else {
await import('icons-subsetter/built/tabler-icons-classes.css');
await import('icons-subsetter/built/tabler-icons-frontend.css');
}
import '@/style.scss';
import { mainBoot } from '@/boot/main-boot.js';

View File

@ -0,0 +1,15 @@
## これは何
フロントエンドの各パッケージで使用されているtabler iconsのclassをスキャンし、使用されているiconのみを抽出するツールです。
なお、サブセット版に無いアイコンが呼び出された場合は本物のtabler icons フォントにフォールバックするようになっています。
このツールは本番ビルド時にのみ使用されます開発モードでも最初の1回だけビルドが走りますが、これは型エラーを抑制するためにファイルを置いておく用の措置です
現時点では `src/generator.ts``filesToScan` にスキャン対象のファイルが書かれています。もしこれに当てはまらないファイルをサブセットのスキャン対象とする場合はこの部分を適宜修正してください。
## 使い方
```bash
pnpm build
```

View File

@ -0,0 +1,18 @@
import tsParser from '@typescript-eslint/parser';
import sharedConfig from '../shared/eslint.config.js';
// eslint-disable-next-line import/no-default-export
export default [
...sharedConfig,
{
files: ['**/*.ts', '**/*.tsx'],
languageOptions: {
parserOptions: {
parser: tsParser,
project: ['./tsconfig.json'],
sourceType: 'module',
tsconfigRootDir: import.meta.dirname,
},
},
},
];

View File

@ -0,0 +1,25 @@
{
"name": "icons-subsetter",
"version": "0.0.0",
"private": true,
"description": "Subset tabler-icons webfont",
"type": "module",
"scripts": {
"build": "tsx src/generator.ts",
"lint": "eslint"
},
"devDependencies": {
"@tabler/icons-webfont": "https://github.com/misskey-dev/tabler-icons/archive/refs/tags/3.29.0-mi.1913+5921534bc.tar.gz",
"@types/node": "22.9.0",
"@typescript-eslint/eslint-plugin": "7.17.0",
"@typescript-eslint/parser": "7.17.0",
"harfbuzzjs": "0.4.4",
"tiny-glob": "^0.2.9",
"tsx": "4.4.0",
"typescript": "5.6.3",
"wasm-ttf2woff": "1.0.0"
},
"files": [
"built"
]
}

View File

@ -0,0 +1,125 @@
import { promises as fsp, existsSync } from 'fs';
import path from 'path';
import glob from 'tiny-glob';
import { generateSubsettedFont } from './subsetter.js';
const filesToScan = {
frontend: 'packages/frontend/src/**/*.{ts,vue}',
//frontendShared: 'packages/frontend-shared/js/**/*.{ts}', // 現時点では該当がないのでスキップ。ここをコメントアウトするときは、各フロントエンドにこのチャンクのCSSのimportを追加すること
frontendEmbed: 'packages/frontend-embed/src/**/*.{ts,vue}',
};
async function main() {
const start = performance.now();
// 1. ビルドディレクトリを削除
if (existsSync('./built')) {
await fsp.rm('./built', { recursive: true });
}
await fsp.mkdir('./built');
// 2. tabler-icons.min.cssから、class名とUnicodeのマッピングを抽出
const css = await fsp.readFile('node_modules/@tabler/icons-webfont/dist/tabler-icons.min.css', 'utf-8');
const cssRegex = /\.(ti-[a-z0-9-]+)::?before\s*{\n?\s*content:\s*["']\\([a-fA-F0-9]+)["'];?\n?\s*}/g;
const rgMap = new Map<string, string>();
let matches: RegExpExecArray | null;
while ((matches = cssRegex.exec(css)) !== null) {
rgMap.set(matches[1], matches[2]);
}
// 3. tabler-icons-classes.cssから、@font-faceを削除して書き出し
const cssWithoutFontFace = css.replace(/@font-face\s*{[^}]*}/g, '');
await fsp.writeFile('./built/tabler-icons-classes.css', cssWithoutFontFace);
// 4. フォールバック用のtabler-icons.woff2をコピー
const fontPath = 'node_modules/@tabler/icons-webfont/dist/fonts/';
await fsp.copyFile(fontPath + 'tabler-icons.woff2', './built/tabler-icons.woff2');
// 5. 各チャンクごとにファイルをスキャンして、使用されているアイコンを抽出
const unicodeRangeValues = new Map<string, number[]>();
for (const [key, dir] of Object.entries(filesToScan)) {
console.log(`Scanning ${key}...`);
const iconsToPack = new Set<string>();
const cwd = path.resolve(process.cwd(), '../../');
const files = await glob(dir, { cwd });
for (const file of files) {
//console.log(`Scanning ${file}`);
const content = await fsp.readFile(path.resolve(cwd, file), 'utf-8');
const classRegex = /ti-[a-z0-9-]+/g;
let matches: RegExpExecArray | null;
while ((matches = classRegex.exec(content)) !== null) {
const icon = matches[0];
if (rgMap.has(icon)) {
iconsToPack.add(icon);
}
}
}
// 6. チャンク内で使用されているアイコンのUnicodeの配列を生成
const unicodeValues = Array.from(iconsToPack).map((icon) => parseInt(rgMap.get(icon)!, 16));
unicodeRangeValues.set(key, unicodeValues);
}
// 7. Tabler Iconフォントをサブセット化
const subsettedFonts = await generateSubsettedFont(fontPath + 'tabler-icons.ttf', unicodeRangeValues);
// 8. サブセット化したフォント・CSSを書き出し
await Promise.allSettled(Array.from(subsettedFonts.entries()).map(async ([key, buffer]) => {
const cssRules = [`@font-face {
font-family: "tabler-icons";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("./tabler-icons.woff2") format("woff2");
}`];
// サブセット化したフォントの中身があるunicodeRangeValuesの配列が殻ではない場合のみ、サブセットしたものに関する情報を追記
if (unicodeRangeValues.get(key)!.length > 0) {
await fsp.writeFile(`./built/tabler-icons-${key}.woff2`, buffer);
const unicodeRangeString = (() => {
const values = unicodeRangeValues.get(key)!.sort((a, b) => a - b);
const ranges = [];
for (let i = 0; i < values.length; i++) {
const start = values[i];
let end = values[i];
while (values[i + 1] === end + 1) {
end = values[i + 1];
i++;
}
if (start === end) {
ranges.push(`U+${start.toString(16)}`);
} else if (start + 1 === end) {
ranges.push(`U+${start.toString(16)}`, `U+${end.toString(16)}`);
} else {
ranges.push(`U+${start.toString(16)}-${end.toString(16)}`);
}
}
return ranges.join(', ');
})();
cssRules.push(`@font-face {
font-family: "tabler-icons";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("./tabler-icons-${key}.woff2") format("woff2");
unicode-range: ${unicodeRangeString};
}`);
}
await fsp.writeFile(`./built/tabler-icons-${key}.css`, cssRules.join('\n\n') + '\n');
}));
const end = performance.now();
console.log(`Done in ${Math.round((end - start) * 100) / 100}ms`);
}
main().catch((err) => {
console.error(err);
process.exit(1);
});

View File

@ -0,0 +1,76 @@
import { promises as fsp } from 'fs';
import { ttf2woff } from 'wasm-ttf2woff';
export async function generateSubsettedFont(ttfPath: string, unicodeRangeValues: Map<string, number[]>) {
const ttf = await fsp.readFile(ttfPath);
const {
instance: { exports: harfbuzzWasm },
}: any = await WebAssembly.instantiate(await fsp.readFile('./node_modules/harfbuzzjs/hb-subset.wasm'));
const heapu8 = new Uint8Array(harfbuzzWasm.memory.buffer);
const subsetFonts = new Map<string, Buffer>();
let i = 0;
for (const [key, unicodeValues] of unicodeRangeValues) {
i++;
console.log(`Generating subset ${i} of ${unicodeRangeValues.size}...`);
// サブセット入力を作成
const input = harfbuzzWasm.hb_subset_input_create_or_fail();
if (input === 0) {
throw new Error('hb_subset_input_create_or_fail (harfbuzz) returned zero');
}
// フォントバッファにフォントデータをセット
const fontBuffer = harfbuzzWasm.malloc(ttf.byteLength);
heapu8.set(new Uint8Array(ttf), fontBuffer);
// フォントフェイスを作成
const blob = harfbuzzWasm.hb_blob_create(fontBuffer, ttf.byteLength, 2, 0, 0);
const face = harfbuzzWasm.hb_face_create(blob, 0);
harfbuzzWasm.hb_blob_destroy(blob);
// Unicodeセットに指定されたUnicodeポイントを追加
const inputUnicodes = harfbuzzWasm.hb_subset_input_unicode_set(input);
for (const unicode of unicodeValues) {
harfbuzzWasm.hb_set_add(inputUnicodes, unicode);
}
// サブセットを作成
let subset;
try {
subset = harfbuzzWasm.hb_subset_or_fail(face, input);
if (subset === 0) {
harfbuzzWasm.hb_face_destroy(face);
harfbuzzWasm.free(fontBuffer);
throw new Error('hb_subset_or_fail (harfbuzz) returned zero');
}
} finally {
harfbuzzWasm.hb_subset_input_destroy(input);
}
// サブセットフォントデータを取得
const result = harfbuzzWasm.hb_face_reference_blob(subset);
const offset = harfbuzzWasm.hb_blob_get_data(result, 0);
const subsetByteLength = harfbuzzWasm.hb_blob_get_length(result);
if (subsetByteLength === 0) {
harfbuzzWasm.hb_face_destroy(face);
harfbuzzWasm.hb_blob_destroy(result);
harfbuzzWasm.free(fontBuffer);
throw new Error('hb_blob_get_length (harfbuzz) returned zero');
}
// サブセットフォントをバッファに格納
subsetFonts.set(key, Buffer.from(await ttf2woff(heapu8.slice(offset, offset + subsetByteLength))));
// メモリを解放
harfbuzzWasm.hb_blob_destroy(result);
harfbuzzWasm.hb_face_destroy(subset);
harfbuzzWasm.hb_face_destroy(face);
harfbuzzWasm.free(fontBuffer);
}
return subsetFonts;
}

View File

@ -0,0 +1,20 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"strictFunctionTypes": true,
"strictNullChecks": true,
"esModuleInterop": true,
"lib": [
"esnext",
"dom"
]
},
"include": [
"src/**/*.ts"
],
"exclude": []
}

View File

@ -142,7 +142,7 @@ importers:
version: 10.4.7(@nestjs/common@10.4.7(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.7)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1)
'@nestjs/testing':
specifier: 10.4.7
version: 10.4.7(@nestjs/common@10.4.7(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.7(@nestjs/common@10.4.7(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.7)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.7(@nestjs/common@10.4.7(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.7))
version: 10.4.7(@nestjs/common@10.4.7(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.7)(@nestjs/platform-express@10.4.7)
'@peertube/http-signature':
specifier: 1.7.0
version: 1.7.0
@ -709,9 +709,6 @@ importers:
'@syuilo/aiscript':
specifier: 0.19.0
version: 0.19.0
'@tabler/icons-webfont':
specifier: 3.3.0
version: 3.3.0
'@twemoji/parser':
specifier: 15.1.1
version: 15.1.1
@ -772,6 +769,9 @@ importers:
frontend-shared:
specifier: workspace:*
version: link:../frontend-shared
icons-subsetter:
specifier: workspace:*
version: link:../icons-subsetter
idb-keyval:
specifier: 6.2.1
version: 6.2.1
@ -914,6 +914,9 @@ importers:
'@storybook/vue3-vite':
specifier: 8.4.4
version: 8.4.4(storybook@8.4.4(bufferutil@4.0.8)(prettier@3.3.3)(utf-8-validate@6.0.4))(vite@5.4.11(@types/node@22.9.0)(sass@1.79.3)(terser@5.36.0))(vue@3.5.12(typescript@5.6.3))
'@tabler/icons-webfont':
specifier: 3.3.0
version: 3.3.0
'@testing-library/vue':
specifier: 8.1.0
version: 8.1.0(@vue/compiler-sfc@3.5.12)(@vue/server-renderer@3.5.12(vue@3.5.12(typescript@5.6.3)))(vue@3.5.12(typescript@5.6.3))
@ -1055,9 +1058,6 @@ importers:
'@rollup/pluginutils':
specifier: 5.1.3
version: 5.1.3(rollup@4.26.0)
'@tabler/icons-webfont':
specifier: 3.3.0
version: 3.3.0
'@twemoji/parser':
specifier: 15.1.1
version: 15.1.1
@ -1079,6 +1079,9 @@ importers:
frontend-shared:
specifier: workspace:*
version: link:../frontend-shared
icons-subsetter:
specifier: workspace:*
version: link:../icons-subsetter
json5:
specifier: 2.2.3
version: 2.2.3
@ -1125,6 +1128,9 @@ importers:
'@misskey-dev/summaly':
specifier: 5.1.0
version: 5.1.0
'@tabler/icons-webfont':
specifier: 3.3.0
version: 3.3.0
'@testing-library/vue':
specifier: 8.1.0
version: 8.1.0(@vue/compiler-sfc@3.5.12)(@vue/server-renderer@3.5.12(vue@3.5.12(typescript@5.6.3)))(vue@3.5.12(typescript@5.6.3))
@ -1157,7 +1163,7 @@ importers:
version: 7.17.0(eslint@9.14.0)(typescript@5.6.3)
'@vitest/coverage-v8':
specifier: 1.6.0
version: 1.6.0(vitest@1.6.0(@types/node@22.9.0)(happy-dom@10.0.3)(jsdom@24.1.1)(sass@1.79.4)(terser@5.36.0))
version: 1.6.0(vitest@1.6.0(@types/node@22.9.0)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.79.4)(terser@5.36.0))
'@vue/runtime-core':
specifier: 3.5.12
version: 3.5.12
@ -1244,6 +1250,36 @@ importers:
specifier: 9.4.3
version: 9.4.3(eslint@9.14.0)
packages/icons-subsetter:
devDependencies:
'@tabler/icons-webfont':
specifier: https://github.com/misskey-dev/tabler-icons/archive/refs/tags/3.29.0-mi.1913+5921534bc.tar.gz
version: https://github.com/misskey-dev/tabler-icons/archive/refs/tags/3.29.0-mi.1913+5921534bc.tar.gz
'@types/node':
specifier: 22.9.0
version: 22.9.0
'@typescript-eslint/eslint-plugin':
specifier: 7.17.0
version: 7.17.0(@typescript-eslint/parser@7.17.0(eslint@9.14.0)(typescript@5.6.3))(eslint@9.14.0)(typescript@5.6.3)
'@typescript-eslint/parser':
specifier: 7.17.0
version: 7.17.0(eslint@9.14.0)(typescript@5.6.3)
harfbuzzjs:
specifier: 0.4.4
version: 0.4.4
tiny-glob:
specifier: ^0.2.9
version: 0.2.9
tsx:
specifier: 4.4.0
version: 4.4.0
typescript:
specifier: 5.6.3
version: 5.6.3
wasm-ttf2woff:
specifier: 1.0.0
version: 1.0.0
packages/misskey-bubble-game:
dependencies:
eventemitter3:
@ -4179,6 +4215,13 @@ packages:
'@tabler/icons-webfont@3.3.0':
resolution: {integrity: sha512-vMsxtwTXdC4QH4uDajZjBYThILEI0dP+Mn1s4XZkVtnJ793IF31i3596nYetWhAJnrED0UJ0HQWSbmqVxVQbxA==}
'@tabler/icons-webfont@https://github.com/misskey-dev/tabler-icons/archive/refs/tags/3.29.0-mi.1913+5921534bc.tar.gz':
resolution: {tarball: https://github.com/misskey-dev/tabler-icons/archive/refs/tags/3.29.0-mi.1913+5921534bc.tar.gz}
version: 3.29.0-mi.1913
'@tabler/icons@3.29.0':
resolution: {integrity: sha512-VWNINymdmhay3MDvWVREmRwuWLSrX3YiInKvs5L4AHRF4bAfJabLlEReE0BW/XFsBt22ff8/C8Eam/LXlF97mA==}
'@tabler/icons@3.3.0':
resolution: {integrity: sha512-PLVe9d7b59sKytbx00KgeGhQG3N176Ezv8YMmsnSz4s0ifDzMWlp/h2wEfQZ0ZNe8e377GY2OW6kovUe3Rnd0g==}
@ -6882,10 +6925,16 @@ packages:
resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==}
engines: {node: '>= 0.4'}
globalyzer@0.1.0:
resolution: {integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==}
globby@11.1.0:
resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
engines: {node: '>=10'}
globrex@0.1.2:
resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==}
google-protobuf@3.21.2:
resolution: {integrity: sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==}
@ -6932,6 +6981,9 @@ packages:
resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==}
engines: {node: '>=6'}
harfbuzzjs@0.4.4:
resolution: {integrity: sha512-8rRncykQxQsHJaPchDRNLYJqkt9YbQ/dZ/LkF64W3Qxx5tgHYAsjYq+TOH2PVRwrM405AWbLChWk8BKECmTgkA==}
has-bigints@1.0.2:
resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==}
@ -10246,6 +10298,9 @@ packages:
through@2.3.8:
resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
tiny-glob@0.2.9:
resolution: {integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==}
tiny-invariant@1.3.3:
resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
@ -10897,6 +10952,9 @@ packages:
walker@1.0.8:
resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==}
wasm-ttf2woff@1.0.0:
resolution: {integrity: sha512-JS4Xk/3TswEXBORjSEaXXTyw+YqCfpg3Ri6Gj/tDimrCeRirealWTckpf010k7mQyOo4ucYBDXLKcSXfVPh/VA==}
web-push@3.6.7:
resolution: {integrity: sha512-OpiIUe8cuGjrj3mMBFWY+e4MMIkW3SVT+7vEIjvD9kejGUypv8GPDf84JdPWskK8zMRIJ6xYGm+Kxr8YkPyA0A==}
engines: {node: '>= 16'}
@ -13074,7 +13132,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@nestjs/testing@10.4.7(@nestjs/common@10.4.7(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.7(@nestjs/common@10.4.7(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.7)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.7(@nestjs/common@10.4.7(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.7))':
'@nestjs/testing@10.4.7(@nestjs/common@10.4.7(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.7)(@nestjs/platform-express@10.4.7)':
dependencies:
'@nestjs/common': 10.4.7(reflect-metadata@0.2.2)(rxjs@7.8.1)
'@nestjs/core': 10.4.7(@nestjs/common@10.4.7(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.7)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1)
@ -14571,6 +14629,12 @@ snapshots:
dependencies:
'@tabler/icons': 3.3.0
'@tabler/icons-webfont@https://github.com/misskey-dev/tabler-icons/archive/refs/tags/3.29.0-mi.1913+5921534bc.tar.gz':
dependencies:
'@tabler/icons': 3.29.0
'@tabler/icons@3.29.0': {}
'@tabler/icons@3.3.0': {}
'@tensorflow/tfjs-backend-cpu@4.4.0(@tensorflow/tfjs-core@4.4.0(encoding@0.1.13))':
@ -15264,7 +15328,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@vitest/coverage-v8@1.6.0(vitest@1.6.0(@types/node@22.9.0)(happy-dom@10.0.3)(jsdom@24.1.1)(sass@1.79.4)(terser@5.36.0))':
'@vitest/coverage-v8@1.6.0(vitest@1.6.0(@types/node@22.9.0)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.79.4)(terser@5.36.0))':
dependencies:
'@ampproject/remapping': 2.2.1
'@bcoe/v8-coverage': 0.2.3
@ -15279,7 +15343,7 @@ snapshots:
std-env: 3.7.0
strip-literal: 2.1.0
test-exclude: 6.0.0
vitest: 1.6.0(@types/node@22.9.0)(happy-dom@10.0.3)(jsdom@24.1.1)(sass@1.79.4)(terser@5.36.0)
vitest: 1.6.0(@types/node@22.9.0)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.79.4)(terser@5.36.0)
transitivePeerDependencies:
- supports-color
@ -18036,6 +18100,8 @@ snapshots:
dependencies:
define-properties: 1.2.0
globalyzer@0.1.0: {}
globby@11.1.0:
dependencies:
array-union: 2.1.0
@ -18045,6 +18111,8 @@ snapshots:
merge2: 1.4.1
slash: 3.0.0
globrex@0.1.2: {}
google-protobuf@3.21.2:
optional: true
@ -18121,6 +18189,8 @@ snapshots:
hard-rejection@2.1.0: {}
harfbuzzjs@0.4.4: {}
has-bigints@1.0.2: {}
has-flag@3.0.0: {}
@ -19046,35 +19116,6 @@ snapshots:
jsdoc-type-pratt-parser@4.1.0: {}
jsdom@24.1.1:
dependencies:
cssstyle: 4.0.1
data-urls: 5.0.0
decimal.js: 10.4.3
form-data: 4.0.1
html-encoding-sniffer: 4.0.0
http-proxy-agent: 7.0.2
https-proxy-agent: 7.0.5
is-potential-custom-element-name: 1.0.1
nwsapi: 2.2.12
parse5: 7.2.1
rrweb-cssom: 0.7.1
saxes: 6.0.0
symbol-tree: 3.2.4
tough-cookie: 4.1.4
w3c-xmlserializer: 5.0.0
webidl-conversions: 7.0.0
whatwg-encoding: 3.1.1
whatwg-mimetype: 4.0.0
whatwg-url: 14.0.0
ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)
xml-name-validator: 5.0.0
transitivePeerDependencies:
- bufferutil
- supports-color
- utf-8-validate
optional: true
jsdom@24.1.1(bufferutil@4.0.7)(utf-8-validate@6.0.3):
dependencies:
cssstyle: 4.0.1
@ -21990,6 +22031,11 @@ snapshots:
through@2.3.8: {}
tiny-glob@0.2.9:
dependencies:
globalyzer: 0.1.0
globrex: 0.1.2
tiny-invariant@1.3.3: {}
tinybench@2.6.0: {}
@ -22532,7 +22578,7 @@ snapshots:
- supports-color
- terser
vitest@1.6.0(@types/node@22.9.0)(happy-dom@10.0.3)(jsdom@24.1.1)(sass@1.79.4)(terser@5.36.0):
vitest@1.6.0(@types/node@22.9.0)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.79.4)(terser@5.36.0):
dependencies:
'@vitest/expect': 1.6.0
'@vitest/runner': 1.6.0
@ -22557,7 +22603,7 @@ snapshots:
optionalDependencies:
'@types/node': 22.9.0
happy-dom: 10.0.3
jsdom: 24.1.1
jsdom: 24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4)
transitivePeerDependencies:
- less
- lightningcss
@ -22691,6 +22737,8 @@ snapshots:
dependencies:
makeerror: 1.0.12
wasm-ttf2woff@1.0.0: {}
web-push@3.6.7:
dependencies:
asn1.js: 5.4.1

View File

@ -3,6 +3,7 @@ packages:
- 'packages/frontend-shared'
- 'packages/frontend'
- 'packages/frontend-embed'
- 'packages/icons-subsetter'
- 'packages/sw'
- 'packages/misskey-js'
- 'packages/misskey-js/generator'

View File

@ -33,10 +33,6 @@ async function copyFrontendFonts() {
await fs.cp('./packages/frontend/node_modules/three/examples/fonts', './built/_frontend_dist_/fonts', { dereference: true, recursive: true });
}
async function copyFrontendTablerIcons() {
await fs.cp('./packages/frontend/node_modules/@tabler/icons-webfont/dist', './built/_frontend_dist_/tabler-icons', { dereference: true, recursive: true });
}
async function copyFrontendLocales() {
generateDTS();
@ -88,7 +84,6 @@ async function buildBackendStyle() {
async function build() {
await Promise.all([
copyFrontendFonts(),
copyFrontendTablerIcons(),
copyFrontendLocales(),
copyBackendViews(),
buildBackendScript(),

View File

@ -10,6 +10,7 @@ const fs = require('fs');
fs.rmSync(__dirname + '/../packages/frontend-shared/built', { recursive: true, force: true });
fs.rmSync(__dirname + '/../packages/frontend/built', { recursive: true, force: true });
fs.rmSync(__dirname + '/../packages/frontend-embed/built', { recursive: true, force: true });
fs.rmSync(__dirname + '/../packages/icons-subsetter/built', { recursive: true, force: true });
fs.rmSync(__dirname + '/../packages/sw/built', { recursive: true, force: true });
fs.rmSync(__dirname + '/../packages/misskey-js/built', { recursive: true, force: true });
fs.rmSync(__dirname + '/../packages/misskey-reversi/built', { recursive: true, force: true });

View File

@ -32,6 +32,12 @@ await Promise.all([
stdout: process.stdout,
stderr: process.stderr,
}),
// icons-subsetterは開発段階では使用されないが、型エラーを抑制するためにはじめの一度だけビルドする
execa('pnpm', ['--filter', 'icons-subsetter', 'build'], {
cwd: _dirname + '/../',
stdout: process.stdout,
stderr: process.stderr,
}),
]);
await Promise.all([