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';