From af011562bd157a393f2d3d484facac68bcbade18 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Wed, 13 Aug 2025 00:38:48 +0900 Subject: [PATCH 1/3] feat: bootloader in frontend package (frontend) --- packages/backend/src/config.ts | 4 +++- packages/backend/src/server/web/views/base.pug | 4 ++-- packages/frontend/@types/global.d.ts | 1 + .../server/web/boot.js => frontend/src/_bootloader.ts} | 10 ++++++++-- packages/frontend/src/utility/virtual.d.ts | 5 +++++ packages/frontend/vite.config.ts | 2 ++ scripts/build-assets.mjs | 2 +- 7 files changed, 22 insertions(+), 6 deletions(-) rename packages/{backend/src/server/web/boot.js => frontend/src/_bootloader.ts} (97%) diff --git a/packages/backend/src/config.ts b/packages/backend/src/config.ts index f71f1d7e34..bab238c0c6 100644 --- a/packages/backend/src/config.ts +++ b/packages/backend/src/config.ts @@ -185,6 +185,7 @@ export type Config = { driveUrl: string; userAgent: string; frontendEntry: { file: string | null }; + frontendBootLoader: { file: string }; frontendManifestExists: boolean; frontendEmbedEntry: { file: string | null }; frontendEmbedManifestExists: boolean; @@ -235,7 +236,7 @@ export function loadConfig(): Config { const frontendEmbedManifestExists = fs.existsSync(_dirname + '/../../../built/_frontend_embed_vite_/manifest.json'); const frontendManifest = frontendManifestExists ? JSON.parse(fs.readFileSync(`${_dirname}/../../../built/_frontend_vite_/manifest.json`, 'utf-8')) - : { 'src/_boot_.ts': { file: null } }; + : { 'src/_boot_.ts': { file: null }, 'src/_bootloader.ts': { file: 'src/_bootloader.ts' } }; const frontendEmbedManifest = frontendEmbedManifestExists ? JSON.parse(fs.readFileSync(`${_dirname}/../../../built/_frontend_embed_vite_/manifest.json`, 'utf-8')) : { 'src/boot.ts': { file: null } }; @@ -312,6 +313,7 @@ export function loadConfig(): Config { : null, userAgent: `Misskey/${version} (${config.url})`, frontendEntry: frontendManifest['src/_boot_.ts'], + frontendBootLoader: frontendManifest['src/_bootloader.ts'], frontendManifestExists: frontendManifestExists, frontendEmbedEntry: frontendEmbedManifest['src/boot.ts'], frontendEmbedManifestExists: frontendEmbedManifestExists, diff --git a/packages/backend/src/server/web/views/base.pug b/packages/backend/src/server/web/views/base.pug index a76c75fe5c..3ab420ea4b 100644 --- a/packages/backend/src/server/web/views/base.pug +++ b/packages/backend/src/server/web/views/base.pug @@ -2,6 +2,7 @@ block vars block loadClientEntry - const entry = config.frontendEntry; + - const bootLoader = config.frontendBootLoader; - const baseUrl = config.url; doctype html @@ -76,8 +77,7 @@ html script(type='application/json' id='misskey_clientCtx' data-generated-at=now) != clientCtx - script - include ../boot.js + script(type='module', src=`/vite/${bootLoader.file}`) body noscript: p diff --git a/packages/frontend/@types/global.d.ts b/packages/frontend/@types/global.d.ts index 8a067a78ec..d8bb566760 100644 --- a/packages/frontend/@types/global.d.ts +++ b/packages/frontend/@types/global.d.ts @@ -6,6 +6,7 @@ type FIXME = any; declare const _LANGS_: string[][]; +declare const _LANG_IDS_: string[]; declare const _VERSION_: string; declare const _ENV_: string; declare const _DEV_: boolean; diff --git a/packages/backend/src/server/web/boot.js b/packages/frontend/src/_bootloader.ts similarity index 97% rename from packages/backend/src/server/web/boot.js rename to packages/frontend/src/_bootloader.ts index 0c0b46f82b..75d53e0bdd 100644 --- a/packages/backend/src/server/web/boot.js +++ b/packages/frontend/src/_bootloader.ts @@ -5,8 +5,14 @@ 'use strict'; +interface Window { + CLIENT_ENTRY: string | undefined; +} + // ブロックの中に入れないと、定義した変数がブラウザのグローバルスコープに登録されてしまい邪魔なので (async () => { + const CLIENT_ENTRY = window.CLIENT_ENTRY; + window.onerror = (e) => { console.error(e); renderError('SOMETHING_HAPPENED', e); @@ -23,7 +29,7 @@ } //#region Detect language - const supportedLangs = LANGS; + const supportedLangs = _LANG_IDS_; /** @type { string } */ let lang = localStorage.getItem('lang'); if (lang == null || !supportedLangs.includes(lang)) { @@ -46,7 +52,7 @@ //#region Script async function importAppScript() { - await import(CLIENT_ENTRY ? `/vite/${CLIENT_ENTRY.replace('scripts', lang)}` : '/vite/src/_boot_.ts') + await import(`/vite/${(CLIENT_ENTRY ?? 'src/_boot_.ts').replace('scripts', lang)}`) .catch(async e => { console.error(e); renderError('APP_IMPORT', e); diff --git a/packages/frontend/src/utility/virtual.d.ts b/packages/frontend/src/utility/virtual.d.ts index 00f01992aa..a50e5ec1fb 100644 --- a/packages/frontend/src/utility/virtual.d.ts +++ b/packages/frontend/src/utility/virtual.d.ts @@ -25,3 +25,8 @@ declare module 'search-index:settings' { declare module 'search-index:admin' { export const searchIndexes: XGeneratedSearchIndexItem[]; } + +declare module 'virtual:supported-langs' { + const value: string[]; + export default value; +} diff --git a/packages/frontend/vite.config.ts b/packages/frontend/vite.config.ts index 9b54014b54..fe2a7d470a 100644 --- a/packages/frontend/vite.config.ts +++ b/packages/frontend/vite.config.ts @@ -160,6 +160,7 @@ export function getConfig(): UserConfig { define: { _VERSION_: JSON.stringify(meta.version), _LANGS_: JSON.stringify(Object.entries(locales).map(([k, v]) => [k, v._lang_])), + _LANG_IDS_: JSON.stringify(Object.keys(locales)), _ENV_: JSON.stringify(process.env.NODE_ENV), _DEV_: process.env.NODE_ENV !== 'production', _PERF_PREFIX_: JSON.stringify('Misskey:'), @@ -178,6 +179,7 @@ export function getConfig(): UserConfig { input: { i18n: './src/i18n.ts', entry: './src/_boot_.ts', + bootloader: './src/_bootloader.ts', }, external: externalPackages.map(p => p.match), preserveEntrySignatures: 'allow-extension', diff --git a/scripts/build-assets.mjs b/scripts/build-assets.mjs index e610a72380..07c2c24dbe 100644 --- a/scripts/build-assets.mjs +++ b/scripts/build-assets.mjs @@ -53,7 +53,7 @@ async function buildBackendScript() { await fs.mkdir('./packages/backend/built/server/web', { recursive: true }); for (const file of [ - './packages/backend/src/server/web/boot.js', + //'./packages/backend/src/server/web/boot.js', './packages/backend/src/server/web/boot.embed.js', './packages/backend/src/server/web/bios.js', './packages/backend/src/server/web/cli.js', From 0ec4f87ef8b0f1eae9560ce6d9491fe1807e67e2 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Wed, 13 Aug 2025 00:51:44 +0900 Subject: [PATCH 2/3] feat: bootloader in frontend package (embed) --- packages/backend/src/config.ts | 4 +++- packages/backend/src/server/web/views/base-embed.pug | 4 ++-- packages/frontend-embed/@types/global.d.ts | 1 + .../boot.embed.js => frontend-embed/src/_bootloader.ts} | 8 ++++++-- packages/frontend-embed/vite.config.ts | 2 ++ scripts/build-assets.mjs | 2 +- 6 files changed, 15 insertions(+), 6 deletions(-) rename packages/{backend/src/server/web/boot.embed.js => frontend-embed/src/_bootloader.ts} (96%) diff --git a/packages/backend/src/config.ts b/packages/backend/src/config.ts index bab238c0c6..1e8bed97d4 100644 --- a/packages/backend/src/config.ts +++ b/packages/backend/src/config.ts @@ -188,6 +188,7 @@ export type Config = { frontendBootLoader: { file: string }; frontendManifestExists: boolean; frontendEmbedEntry: { file: string | null }; + frontendEmbedBootLoader: { file: string }; frontendEmbedManifestExists: boolean; mediaProxy: string; externalMediaProxyEnabled: boolean; @@ -239,7 +240,7 @@ export function loadConfig(): Config { : { 'src/_boot_.ts': { file: null }, 'src/_bootloader.ts': { file: 'src/_bootloader.ts' } }; const frontendEmbedManifest = frontendEmbedManifestExists ? JSON.parse(fs.readFileSync(`${_dirname}/../../../built/_frontend_embed_vite_/manifest.json`, 'utf-8')) - : { 'src/boot.ts': { file: null } }; + : { 'src/boot.ts': { file: null }, 'src/_bootloader.ts': { file: 'src/_bootloader.ts' } }; const config = yaml.load(fs.readFileSync(path, 'utf-8')) as Source; @@ -316,6 +317,7 @@ export function loadConfig(): Config { frontendBootLoader: frontendManifest['src/_bootloader.ts'], frontendManifestExists: frontendManifestExists, frontendEmbedEntry: frontendEmbedManifest['src/boot.ts'], + frontendEmbedBootLoader: frontendEmbedManifest['src/_bootloader.ts'], frontendEmbedManifestExists: frontendEmbedManifestExists, perChannelMaxNoteCacheCount: config.perChannelMaxNoteCacheCount ?? 1000, perUserNotificationsMaxCount: config.perUserNotificationsMaxCount ?? 500, diff --git a/packages/backend/src/server/web/views/base-embed.pug b/packages/backend/src/server/web/views/base-embed.pug index 29de86b8b6..e4e70acb22 100644 --- a/packages/backend/src/server/web/views/base-embed.pug +++ b/packages/backend/src/server/web/views/base-embed.pug @@ -2,6 +2,7 @@ block vars block loadClientEntry - const entry = config.frontendEmbedEntry; + - const bootLoader = config.frontendEmbedBootLoader; doctype html @@ -47,8 +48,7 @@ html(class='embed') script(type='application/json' id='misskey_embedCtx' data-generated-at=now) != embedCtx - script - include ../boot.embed.js + script(type='module', src=`/embed_vite/${bootLoader.file}`) body noscript: p diff --git a/packages/frontend-embed/@types/global.d.ts b/packages/frontend-embed/@types/global.d.ts index 8a067a78ec..d8bb566760 100644 --- a/packages/frontend-embed/@types/global.d.ts +++ b/packages/frontend-embed/@types/global.d.ts @@ -6,6 +6,7 @@ type FIXME = any; declare const _LANGS_: string[][]; +declare const _LANG_IDS_: string[]; declare const _VERSION_: string; declare const _ENV_: string; declare const _DEV_: boolean; diff --git a/packages/backend/src/server/web/boot.embed.js b/packages/frontend-embed/src/_bootloader.ts similarity index 96% rename from packages/backend/src/server/web/boot.embed.js rename to packages/frontend-embed/src/_bootloader.ts index 022ff064ad..420ce43685 100644 --- a/packages/backend/src/server/web/boot.embed.js +++ b/packages/frontend-embed/src/_bootloader.ts @@ -5,6 +5,10 @@ 'use strict'; +interface Window { + CLIENT_ENTRY: string | undefined; +} + // ブロックの中に入れないと、定義した変数がブラウザのグローバルスコープに登録されてしまい邪魔なので (async () => { window.onerror = (e) => { @@ -32,7 +36,7 @@ } //#region Detect language & fetch translations - const supportedLangs = LANGS; + const supportedLangs = _LANG_IDS_; /** @type { string } */ let lang = localStorage.getItem('lang'); if (lang == null || !supportedLangs.includes(lang)) { @@ -55,7 +59,7 @@ //#region Script async function importAppScript() { - await import(CLIENT_ENTRY ? `/embed_vite/${CLIENT_ENTRY.replace('scripts', lang)}` : '/embed_vite/src/_boot_.ts') + await import(`/embed_vite/${(window.CLIENT_ENTRY ?? 'src/boot.ts').replace('scripts', lang)}`) .catch(async e => { console.error(e); renderError('APP_IMPORT'); diff --git a/packages/frontend-embed/vite.config.ts b/packages/frontend-embed/vite.config.ts index 3ddee9b8a9..eae02c4909 100644 --- a/packages/frontend-embed/vite.config.ts +++ b/packages/frontend-embed/vite.config.ts @@ -121,6 +121,7 @@ export function getConfig(): UserConfig { define: { _VERSION_: JSON.stringify(meta.version), _LANGS_: JSON.stringify(Object.entries(locales).map(([k, v]) => [k, v._lang_])), + _LANG_IDS_: JSON.stringify(Object.keys(locales)), _ENV_: JSON.stringify(process.env.NODE_ENV), _DEV_: process.env.NODE_ENV !== 'production', _PERF_PREFIX_: JSON.stringify('Misskey:'), @@ -139,6 +140,7 @@ export function getConfig(): UserConfig { input: { i18n: './src/i18n.ts', entry: './src/boot.ts', + bootloader: './src/_bootloader.ts', }, external: externalPackages.map(p => p.match), preserveEntrySignatures: 'allow-extension', diff --git a/scripts/build-assets.mjs b/scripts/build-assets.mjs index 07c2c24dbe..0f260360e7 100644 --- a/scripts/build-assets.mjs +++ b/scripts/build-assets.mjs @@ -54,7 +54,7 @@ async function buildBackendScript() { for (const file of [ //'./packages/backend/src/server/web/boot.js', - './packages/backend/src/server/web/boot.embed.js', + //'./packages/backend/src/server/web/boot.embed.js', './packages/backend/src/server/web/bios.js', './packages/backend/src/server/web/cli.js', './packages/backend/src/server/web/error.js', From d97547da0502315091fb27ca924bede458b528b5 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Wed, 13 Aug 2025 01:21:03 +0900 Subject: [PATCH 3/3] =?UTF-8?q?chore:=20=E5=85=B1=E9=80=9A=E3=81=97?= =?UTF-8?q?=E3=81=A6=E3=82=8B=E3=83=AD=E3=82=B8=E3=83=83=E3=82=AF=E3=82=92?= =?UTF-8?q?=E3=81=84=E3=81=8F=E3=81=A4=E3=81=8B=E7=A7=BB=E5=8B=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/frontend-embed/src/_bootloader.ts | 71 ++++-------------- packages/frontend-shared/@types/global.d.ts | 1 + packages/frontend-shared/js/bootloader.ts | 74 ++++++++++++++++++ packages/frontend/src/_bootloader.ts | 83 ++++----------------- 4 files changed, 104 insertions(+), 125 deletions(-) create mode 100644 packages/frontend-shared/js/bootloader.ts diff --git a/packages/frontend-embed/src/_bootloader.ts b/packages/frontend-embed/src/_bootloader.ts index 420ce43685..e7b3c2299b 100644 --- a/packages/frontend-embed/src/_bootloader.ts +++ b/packages/frontend-embed/src/_bootloader.ts @@ -5,22 +5,24 @@ 'use strict'; +import { addStyle, bootloaderLocales, detectLanguage } from '@@/js/bootloader'; + interface Window { CLIENT_ENTRY: string | undefined; } // ブロックの中に入れないと、定義した変数がブラウザのグローバルスコープに登録されてしまい邪魔なので (async () => { - window.onerror = (e) => { - console.error(e); + window.onerror = (error) => { + console.error(error); renderError('SOMETHING_HAPPENED'); }; - window.onunhandledrejection = (e) => { - console.error(e); + window.onunhandledrejection = (error) => { + console.error(error); renderError('SOMETHING_HAPPENED_IN_PROMISE'); }; - let forceError = localStorage.getItem('forceError'); + const forceError = localStorage.getItem('forceError'); if (forceError != null) { renderError('FORCED_ERROR', 'This error is forced by having forceError in local storage.'); return; @@ -35,33 +37,13 @@ interface Window { document.documentElement.classList.add('noborder'); } - //#region Detect language & fetch translations - const supportedLangs = _LANG_IDS_; - /** @type { string } */ - let lang = localStorage.getItem('lang'); - if (lang == null || !supportedLangs.includes(lang)) { - if (supportedLangs.includes(navigator.language)) { - lang = navigator.language; - } else { - lang = supportedLangs.find(x => x.split('-')[0] === navigator.language); - - // Fallback - if (lang == null) lang = 'en-US'; - } - } - - // for https://github.com/misskey-dev/misskey/issues/10202 - if (lang == null || lang.toString == null || lang.toString() === 'null') { - console.error('invalid lang value detected!!!', typeof lang, lang); - lang = 'en-US'; - } - //#endregion + const lang = detectLanguage(); //#region Script async function importAppScript() { await import(`/embed_vite/${(window.CLIENT_ENTRY ?? 'src/boot.ts').replace('scripts', lang)}`) - .catch(async e => { - console.error(e); + .catch(async error => { + console.error(error); renderError('APP_IMPORT'); }); } @@ -76,44 +58,19 @@ interface Window { } //#endregion - async function addStyle(styleText) { - let css = document.createElement('style'); - css.appendChild(document.createTextNode(styleText)); - document.head.appendChild(css); - } - - async function renderError(code) { + async function renderError(code: string, _details?) { // Cannot set property 'innerHTML' of null を回避 if (document.readyState === 'loading') { await new Promise(resolve => window.addEventListener('DOMContentLoaded', resolve)); } - let messages = null; - const bootloaderLocales = localStorage.getItem('bootloaderLocales'); - if (bootloaderLocales) { - messages = JSON.parse(bootloaderLocales); - } - if (!messages) { - // older version of misskey does not store bootloaderLocales, stores locale as a whole - const legacyLocale = localStorage.getItem('locale'); - if (legacyLocale) { - const parsed = JSON.parse(legacyLocale); - messages = { - ...(parsed._bootErrors ?? {}), - reload: parsed.reload, - }; - } - } - if (!messages) messages = {}; - - const title = messages?.title || 'Failed to initialize Misskey'; - const reload = messages?.reload || 'Reload'; + const messages = bootloaderLocales(); document.body.innerHTML = ` -
${title}
+
${messages.title}
Error Code: ${code}
`; addStyle(` #misskey_app, diff --git a/packages/frontend-shared/@types/global.d.ts b/packages/frontend-shared/@types/global.d.ts index 52081d07b3..83011e7557 100644 --- a/packages/frontend-shared/@types/global.d.ts +++ b/packages/frontend-shared/@types/global.d.ts @@ -7,6 +7,7 @@ type FIXME = any; declare const _LANGS_: string[][]; +declare const _LANG_IDS_: string[]; declare const _VERSION_: string; declare const _ENV_: string; declare const _DEV_: boolean; diff --git a/packages/frontend-shared/js/bootloader.ts b/packages/frontend-shared/js/bootloader.ts new file mode 100644 index 0000000000..792023f03f --- /dev/null +++ b/packages/frontend-shared/js/bootloader.ts @@ -0,0 +1,74 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +// common portion of bootloader for frontend and frontend-embed + +import type { Locale } from '../../../locales/index.js'; + +export function detectLanguage(): string { + const supportedLangs = _LANG_IDS_; + let lang: string | null | undefined = localStorage.getItem('lang'); + if (lang == null || !supportedLangs.includes(lang)) { + if (supportedLangs.includes(navigator.language)) { + lang = navigator.language; + } else { + lang = supportedLangs.find(x => x.split('-')[0] === navigator.language); + + // Fallback + lang ??= 'en-US'; + } + } + + // for https://github.com/misskey-dev/misskey/issues/10202 + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (lang == null || lang.toString == null || lang.toString() === 'null') { + console.error('invalid lang value detected!!!', typeof lang, lang); + lang = 'en-US'; + } + + return lang; +} + +type BootLoaderLocales = Locale['_bootErrors'] & Pick; + +export function bootloaderLocales(): BootLoaderLocales { + let messages: Partial | null = null; + const bootloaderLocalesJson = localStorage.getItem('bootloaderLocales'); + if (bootloaderLocalesJson) { + messages = JSON.parse(bootloaderLocalesJson); + } + if (!messages) { + // older version of misskey does not store bootloaderLocales, stores locale as a whole + const legacyLocale = localStorage.getItem('locale'); + if (legacyLocale) { + const parsed = JSON.parse(legacyLocale); + messages = { + ...(parsed._bootErrors ?? {}), + reload: parsed.reload, + }; + } + } + + return Object.assign({ + title: 'Failed to initialize Misskey', + solution: 'The following actions may solve the problem.', + solution1: 'Update your os and browser', + solution2: 'Disable an adblocker', + solution3: 'Clear the browser cache', + solution4: '(Tor Browser) Set dom.webaudio.enabled to true', + otherOption: 'Other options', + otherOption1: 'Clear preferences and cache', + otherOption2: 'Start the simple client', + otherOption3: 'Start the repair tool', + otherOption4: 'Start Misskey in safe mode', + reload: 'Reload', + }, messages) as BootLoaderLocales; +} + +export function addStyle(styleText: string) { + const styleElement = document.createElement('style'); + styleElement.appendChild(document.createTextNode(styleText)); + document.head.appendChild(styleElement); +} diff --git a/packages/frontend/src/_bootloader.ts b/packages/frontend/src/_bootloader.ts index 75d53e0bdd..839e3b22bf 100644 --- a/packages/frontend/src/_bootloader.ts +++ b/packages/frontend/src/_bootloader.ts @@ -3,8 +3,12 @@ * SPDX-License-Identifier: AGPL-3.0-only */ +/* eslint no-restricted-globals: off */ + 'use strict'; +import { addStyle, bootloaderLocales, detectLanguage } from '@@/js/bootloader'; + interface Window { CLIENT_ENTRY: string | undefined; } @@ -13,42 +17,22 @@ interface Window { (async () => { const CLIENT_ENTRY = window.CLIENT_ENTRY; - window.onerror = (e) => { - console.error(e); - renderError('SOMETHING_HAPPENED', e); + window.onerror = (error) => { + console.error(error); + renderError('SOMETHING_HAPPENED', error); }; - window.onunhandledrejection = (e) => { - console.error(e); - renderError('SOMETHING_HAPPENED_IN_PROMISE', e); + window.onunhandledrejection = (error) => { + console.error(error); + renderError('SOMETHING_HAPPENED_IN_PROMISE', error); }; - let forceError = localStorage.getItem('forceError'); + const forceError = localStorage.getItem('forceError'); if (forceError != null) { renderError('FORCED_ERROR', 'This error is forced by having forceError in local storage.'); return; } - //#region Detect language - const supportedLangs = _LANG_IDS_; - /** @type { string } */ - let lang = localStorage.getItem('lang'); - if (lang == null || !supportedLangs.includes(lang)) { - if (supportedLangs.includes(navigator.language)) { - lang = navigator.language; - } else { - lang = supportedLangs.find(x => x.split('-')[0] === navigator.language); - - // Fallback - if (lang == null) lang = 'en-US'; - } - } - - // for https://github.com/misskey-dev/misskey/issues/10202 - if (lang == null || lang.toString == null || lang.toString() === 'null') { - console.error('invalid lang value detected!!!', typeof lang, lang); - lang = 'en-US'; - } - //#endregion + const lang = detectLanguage(); //#region Script async function importAppScript() { @@ -84,7 +68,7 @@ interface Window { if (!isSafeMode) { const theme = localStorage.getItem('theme'); if (theme) { - for (const [k, v] of Object.entries(JSON.parse(theme))) { + for (const [k, v] of Object.entries(JSON.parse(theme) as Record)) { document.documentElement.style.setProperty(`--MI_THEME-${k}`, v.toString()); // HTMLの theme-color 適用 @@ -125,50 +109,13 @@ interface Window { } } - async function addStyle(styleText) { - let css = document.createElement('style'); - css.appendChild(document.createTextNode(styleText)); - document.head.appendChild(css); - } - async function renderError(code, details) { // Cannot set property 'innerHTML' of null を回避 if (document.readyState === 'loading') { await new Promise(resolve => window.addEventListener('DOMContentLoaded', resolve)); } - let messages = null; - const bootloaderLocales = localStorage.getItem('bootloaderLocales'); - if (bootloaderLocales) { - messages = JSON.parse(bootloaderLocales); - } - if (!messages) { - // older version of misskey does not store bootloaderLocales, stores locale as a whole - const legacyLocale = localStorage.getItem('locale'); - if (legacyLocale) { - const parsed = JSON.parse(legacyLocale); - messages = { - ...(parsed._bootErrors ?? {}), - reload: parsed.reload, - }; - } - } - if (!messages) messages = {}; - - messages = Object.assign({ - title: 'Failed to initialize Misskey', - solution: 'The following actions may solve the problem.', - solution1: 'Update your os and browser', - solution2: 'Disable an adblocker', - solution3: 'Clear the browser cache', - solution4: '(Tor Browser) Set dom.webaudio.enabled to true', - otherOption: 'Other options', - otherOption1: 'Clear preferences and cache', - otherOption2: 'Start the simple client', - otherOption3: 'Start the repair tool', - otherOption4: 'Start Misskey in safe mode', - reload: 'Reload', - }, messages); + const messages = bootloaderLocales(); const safeModeUrl = new URL(window.location.href); safeModeUrl.searchParams.set('safemode', 'true'); @@ -220,7 +167,7 @@ interface Window {
`; - errorsElement = document.getElementById('errors'); + errorsElement = document.getElementById('errors')!; } const detailsElement = document.createElement('details'); detailsElement.id = 'errorInfo';