Sharkey/packages/frontend/vite.config.ts
CenTdemeern1 25fe3ceca1 Use esm.sh instead of unpkg as Ruffle CDN
This way admins don't have to change their content security policy
2024-12-08 19:15:41 +01:00

205 lines
6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import path from 'path';
import pluginReplace from '@rollup/plugin-replace';
import pluginVue from '@vitejs/plugin-vue';
import { type UserConfig, defineConfig } from 'vite';
import { localesVersion } from '../../locales/version.js';
import locales from '../../locales/index.js';
import meta from '../../package.json';
import packageInfo from './package.json' with { type: 'json' };
import pluginUnwindCssModuleClassName from './lib/rollup-plugin-unwind-css-module-class-name.js';
import pluginJson5 from './vite.json5.js';
import { pluginReplaceIcons } from './vite.replaceIcons.js';
const extensions = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.json', '.json5', '.svg', '.sass', '.scss', '.css', '.vue', '.wasm'];
/**
* Misskeyのフロントエンドにバンドルせず、CDNなどから別途読み込むリソースを記述する。
* CDNを使わずにバンドルしたい場合、以下の配列から該当要素を削除orコメントアウトすればOK
*/
const externalPackages = [
// shikiコードブロックのシンタックスハイライトで使用中はテーマ・言語の定義の容量が大きいため、それらはCDNから読み込む
{
name: 'shiki',
match: /^shiki\/(?<subPkg>(langs|themes))$/,
path(id: string, pattern: RegExp): string {
const match = pattern.exec(id)?.groups;
return match
? `https://esm.sh/shiki@${packageInfo.dependencies.shiki}/${match['subPkg']}`
: id;
},
},
// sharkey: Used for SkFlashPlayer, has large wasm files so it's loaded via Ruffle's preferred CDN
{
name: 'ruffle',
match: /^@ruffle-rs\/ruffle\/?(?<file>.*)$/,
path(id: string, pattern: RegExp): string {
const match = pattern.exec(id)?.groups;
return match
? `https://esm.sh/@ruffle-rs/ruffle@${packageInfo.dependencies['@ruffle-rs/ruffle']}/${match['file']}`
: id;
},
},
];
const hash = (str: string, seed = 0): number => {
let h1 = 0xdeadbeef ^ seed,
h2 = 0x41c6ce57 ^ seed;
for (let i = 0, ch; i < str.length; i++) {
ch = str.charCodeAt(i);
h1 = Math.imul(h1 ^ ch, 2654435761);
h2 = Math.imul(h2 ^ ch, 1597334677);
}
h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);
return 4294967296 * (2097151 & h2) + (h1 >>> 0);
};
const BASE62_DIGITS = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
function toBase62(n: number): string {
if (n === 0) {
return '0';
}
let result = '';
while (n > 0) {
result = BASE62_DIGITS[n % BASE62_DIGITS.length] + result;
n = Math.floor(n / BASE62_DIGITS.length);
}
return result;
}
export function getConfig(): UserConfig {
return {
base: '/vite/',
server: {
port: 5173,
headers: { // なんか効かない
'X-Frame-Options': 'DENY',
},
},
plugins: [
pluginVue(),
pluginUnwindCssModuleClassName(),
pluginJson5(),
...pluginReplaceIcons(),
...process.env.NODE_ENV === 'production'
? [
pluginReplace({
preventAssignment: true,
values: {
'isChromatic()': JSON.stringify(false),
},
}),
]
: [],
],
resolve: {
extensions,
alias: {
'@/': __dirname + '/src/',
'@@/': __dirname + '/../frontend-shared/',
'/client-assets/': __dirname + '/assets/',
'/static-assets/': __dirname + '/../backend/assets/',
'/fluent-emojis/': __dirname + '/../../fluent-emojis/dist/',
'/tossface/': __dirname + '/../../tossface-emojis/dist/',
'/fluent-emoji/': __dirname + '/../../fluent-emojis/dist/',
},
},
css: {
modules: {
generateScopedName(name, filename, _css): string {
const id = (path.relative(__dirname, filename.split('?')[0]) + '-' + name).replace(/[\\\/\.\?&=]/g, '-').replace(/(src-|vue-)/g, '');
const shortId = id.replace(/^(components(-global)?|widgets|ui(-_common_)?)-/, '');
return shortId + '-' + toBase62(hash(id)).substring(0, 4);
},
},
},
define: {
_VERSION_: JSON.stringify(meta.version),
_LANGS_: JSON.stringify(Object.entries(locales).map(([k, v]) => [k, v._lang_])),
_LANGS_VERSION_: JSON.stringify(localesVersion),
_ENV_: JSON.stringify(process.env.NODE_ENV),
_DEV_: process.env.NODE_ENV !== 'production',
_PERF_PREFIX_: JSON.stringify('Misskey:'),
_DATA_TRANSFER_DRIVE_FILE_: JSON.stringify('mk_drive_file'),
_DATA_TRANSFER_DRIVE_FOLDER_: JSON.stringify('mk_drive_folder'),
_DATA_TRANSFER_DECK_COLUMN_: JSON.stringify('mk_deck_column'),
__VUE_OPTIONS_API__: true,
__VUE_PROD_DEVTOOLS__: false,
},
build: {
target: [
'chrome116',
'firefox116',
'safari16',
],
manifest: 'manifest.json',
rollupOptions: {
input: {
app: './src/_boot_.ts',
},
external: externalPackages.map(p => p.match),
output: {
manualChunks: {
vue: ['vue'],
photoswipe: ['photoswipe', 'photoswipe/lightbox', 'photoswipe/style.css'],
},
chunkFileNames: process.env.NODE_ENV === 'production' ? '[hash:8].js' : '[name]-[hash:8].js',
assetFileNames: process.env.NODE_ENV === 'production' ? '[hash:8][extname]' : '[name]-[hash:8][extname]',
paths(id) {
for (const p of externalPackages) {
if (p.match.test(id)) {
return p.path(id, p.match);
}
}
return id;
},
},
},
cssCodeSplit: true,
outDir: __dirname + '/../../built/_frontend_vite_',
assetsDir: '.',
emptyOutDir: false,
sourcemap: process.env.NODE_ENV === 'development',
reportCompressedSize: false,
// https://vitejs.dev/guide/dep-pre-bundling.html#monorepos-and-linked-dependencies
commonjsOptions: {
include: [/misskey-js/, /misskey-reversi/, /misskey-bubble-game/, /node_modules/],
},
},
worker: {
format: 'es',
},
test: {
environment: 'happy-dom',
deps: {
optimizer: {
web: {
include: [
// XXX: misskey-dev/browser-image-resizer has no "type": "module"
'browser-image-resizer',
],
},
},
},
includeSource: ['src/**/*.ts'],
},
};
}
const config = defineConfig(({ command, mode }) => getConfig());
export default config;