From 78653a90092723ec12ddacb10d65f6d0b1380b96 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Thu, 31 Mar 2022 19:56:43 +0800 Subject: [PATCH 01/20] wip --- package.json | 1 + packages/mask/.webpack/manifest.ts | 5 - .../tasks/Cancellable/PopupSSR/index.mv3.ts | 9 ++ .../tasks/Cancellable/PopupSSR/index.ts | 38 ++++++ .../tasks/Cancellable/PopupSSR/loader.js | 5 + .../tasks/Cancellable/PopupSSR/worker.tsx | 39 ++++++ .../tasks/Cancellable/PopupSSR/worker_init.ts | 7 + .../Cancellable/PopupSSR/worker_patch.js | 5 + packages/mask/background/tasks/setup.hmr.ts | 3 + packages/mask/public/popups-ssr.html | 15 +++ packages/mask/public/popups-ssr.js | 7 + .../options-page/DashboardDialogs/Base.tsx | 7 +- packages/mask/src/extension/popups/UI.tsx | 5 +- .../components/DisconnectDialog/index.tsx | 2 +- packages/mask/src/manifest.json | 2 +- packages/mask/src/setup.popup.ssr.tsx | 42 ++++++ packages/mask/src/utils/MaskTheme.ts | 97 ++++++++++++++ packages/mask/src/utils/theme.ts | 126 +----------------- .../src/utils/useClassicMaskFullPageTheme.ts | 20 +++ pnpm-lock.yaml | 2 + 20 files changed, 307 insertions(+), 130 deletions(-) create mode 100644 packages/mask/background/tasks/Cancellable/PopupSSR/index.mv3.ts create mode 100644 packages/mask/background/tasks/Cancellable/PopupSSR/index.ts create mode 100644 packages/mask/background/tasks/Cancellable/PopupSSR/loader.js create mode 100644 packages/mask/background/tasks/Cancellable/PopupSSR/worker.tsx create mode 100644 packages/mask/background/tasks/Cancellable/PopupSSR/worker_init.ts create mode 100644 packages/mask/background/tasks/Cancellable/PopupSSR/worker_patch.js create mode 100644 packages/mask/public/popups-ssr.html create mode 100644 packages/mask/public/popups-ssr.js create mode 100644 packages/mask/src/setup.popup.ssr.tsx create mode 100644 packages/mask/src/utils/MaskTheme.ts create mode 100644 packages/mask/src/utils/useClassicMaskFullPageTheme.ts diff --git a/package.json b/package.json index 22912c4d45f0..ff29c47c64d2 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "@emotion/cache": "^11.7.1", "@emotion/react": "^11.8.2", "@emotion/serialize": "^1.0.2", + "@emotion/server": "^11.4.0", "@emotion/styled": "^11.8.1", "@emotion/utils": "^1.1.0", "@mui/icons-material": "5.5.1", diff --git a/packages/mask/.webpack/manifest.ts b/packages/mask/.webpack/manifest.ts index 6e023d2394e6..dc03597ad110 100644 --- a/packages/mask/.webpack/manifest.ts +++ b/packages/mask/.webpack/manifest.ts @@ -41,11 +41,6 @@ function modify(manifest: Manifest, flags: NormalizedFlags) { stableDevelopmentExtensionID(manifest) } - // Mask 2.0 - if (flags.mode === 'development' || flags.channel === 'beta' || flags.channel === 'insider') { - manifest.browser_action = { default_popup: 'popups.html' } - } - if (flags.hmr) { manifest.web_accessible_resources.push('*.json', '*.js') } diff --git a/packages/mask/background/tasks/Cancellable/PopupSSR/index.mv3.ts b/packages/mask/background/tasks/Cancellable/PopupSSR/index.mv3.ts new file mode 100644 index 000000000000..2b819dd1bd7a --- /dev/null +++ b/packages/mask/background/tasks/Cancellable/PopupSSR/index.mv3.ts @@ -0,0 +1,9 @@ +export default async function PopupSSR(signal: AbortSignal) { + browser.runtime.onMessage.addListener(f) + signal.addEventListener('abort', () => browser.runtime.onMessage.removeListener(f), { once: true }) +} + +function f(message: any) { + if (!(message.type === 'popups-ssr')) return + return import('./worker').then((x) => x.main()) +} diff --git a/packages/mask/background/tasks/Cancellable/PopupSSR/index.ts b/packages/mask/background/tasks/Cancellable/PopupSSR/index.ts new file mode 100644 index 000000000000..664ef6bdeaef --- /dev/null +++ b/packages/mask/background/tasks/Cancellable/PopupSSR/index.ts @@ -0,0 +1,38 @@ +import { OnDemandWorker } from '../../../../utils-pure/OnDemandWorker' + +let worker = new OnDemandWorker(new URL('./worker_init.ts', import.meta.url), { name: 'PopupSSR' }) +export default async function PopupSSR(signal: AbortSignal) { + browser.runtime.onMessage.addListener(f) + + if (import.meta.webpackHot) { + // To receive the HMR + const _f = () => import('./worker_init') + import.meta.webpackHot.accept('./worker_init.ts', () => { + if (signal.aborted) return + worker.terminate() + worker = new OnDemandWorker(new URL('./worker_init.ts', import.meta.url), { name: 'PopupSSR' }) + }) + } + signal.addEventListener( + 'abort', + () => { + browser.runtime.onMessage.removeListener(f) + worker.terminate() + }, + { once: true }, + ) +} + +function f(message: any) { + if (!(message.type === 'popups-ssr')) return + return new Promise((resolve) => { + worker.postMessage('ping') + worker.addEventListener( + 'message', + (data) => { + resolve(data.data) + }, + { once: true }, + ) + }) +} diff --git a/packages/mask/background/tasks/Cancellable/PopupSSR/loader.js b/packages/mask/background/tasks/Cancellable/PopupSSR/loader.js new file mode 100644 index 000000000000..f62408758122 --- /dev/null +++ b/packages/mask/background/tasks/Cancellable/PopupSSR/loader.js @@ -0,0 +1,5 @@ +// This is a JS file to make TypeScript happy. +import { PopupSSR as _ } from '../../../../src/setup.popup.ssr.tsx' + +export let PopupSSR = _ +import.meta.webpackHot && import.meta.webpackHot.accept('../../../../src/setup.popup.ssr.tsx', () => (PopupSSR = _)) diff --git a/packages/mask/background/tasks/Cancellable/PopupSSR/worker.tsx b/packages/mask/background/tasks/Cancellable/PopupSSR/worker.tsx new file mode 100644 index 000000000000..4ba3c7f1ea4f --- /dev/null +++ b/packages/mask/background/tasks/Cancellable/PopupSSR/worker.tsx @@ -0,0 +1,39 @@ +// I'm a WebWorker! + +import './worker_patch' +// @ts-ignore +import { PopupSSR } from './loader' +import { renderToString } from 'react-dom/server' +// @ts-ignore +import createCache from '@emotion/cache/dist/emotion-cache.cjs.prod.js' +import { CacheProvider } from '@emotion/react' +import createEmotionServer from '@emotion/server/create-instance' +// TODO: +import { TssCacheProvider } from '../../../../../theme/node_modules/tss-react' + +export async function main(): Promise<{ html: string; css: string }> { + return render() +} + +function serverCache(key: string) { + const cache = createCache({ key }) + return cache +} +function render() { + debugger + const muiCache = serverCache('mui') + const tssCache = serverCache('tss') + const tssServer = createEmotionServer(tssCache) + const muiServer = createEmotionServer(muiCache) + + const html = renderToString( + + + + + , + ) + const muiCSS = muiServer.constructStyleTagsFromChunks(muiServer.extractCriticalToChunks(html)) + const tssCSS = tssServer.constructStyleTagsFromChunks(tssServer.extractCriticalToChunks(html)) + return { html, css: muiCSS + tssCSS } +} diff --git a/packages/mask/background/tasks/Cancellable/PopupSSR/worker_init.ts b/packages/mask/background/tasks/Cancellable/PopupSSR/worker_init.ts new file mode 100644 index 000000000000..fe32745524e8 --- /dev/null +++ b/packages/mask/background/tasks/Cancellable/PopupSSR/worker_init.ts @@ -0,0 +1,7 @@ +import { main } from './worker' + +globalThis.addEventListener('message', async () => { + const result = await main() + globalThis.postMessage(result) +}) +globalThis.postMessage('alive') diff --git a/packages/mask/background/tasks/Cancellable/PopupSSR/worker_patch.js b/packages/mask/background/tasks/Cancellable/PopupSSR/worker_patch.js new file mode 100644 index 000000000000..4465fd91acb9 --- /dev/null +++ b/packages/mask/background/tasks/Cancellable/PopupSSR/worker_patch.js @@ -0,0 +1,5 @@ +globalThis.document = { + querySelectorAll() { + return [] + }, +} diff --git a/packages/mask/background/tasks/setup.hmr.ts b/packages/mask/background/tasks/setup.hmr.ts index fb221264c44e..8e856f9778e0 100644 --- a/packages/mask/background/tasks/setup.hmr.ts +++ b/packages/mask/background/tasks/setup.hmr.ts @@ -4,11 +4,14 @@ import * as InjectContentScriptMV3 from './Cancellable/InjectContentScripts-mv3' import * as IsolatedDashboardBridge from './Cancellable/IsolatedDashboardBridge' import * as CleanupProfileDatabase from './Cancellable/CleanProfileAndAvatar' import * as NotificationsToMobile from './Cancellable/NotificationsToMobile' +import * as PopupSSR from './Cancellable/PopupSSR' +import * as PopupSSR_MV3 from './Cancellable/PopupSSR/index.mv3' type CancelableJob = { default: (signal: AbortSignal) => void } const CancelableJobs: CancelableJob[] = [ NewInstalled, process.env.manifest === '2' ? InjectContentScript : InjectContentScriptMV3, + process.env.manifest === '2' ? PopupSSR : PopupSSR_MV3, IsolatedDashboardBridge, process.env.architecture === 'app' ? null! : CleanupProfileDatabase, NotificationsToMobile, diff --git a/packages/mask/public/popups-ssr.html b/packages/mask/public/popups-ssr.html new file mode 100644 index 000000000000..407b4fcd652d --- /dev/null +++ b/packages/mask/public/popups-ssr.html @@ -0,0 +1,15 @@ + + + + Mask Network + + + + + + + + + + + diff --git a/packages/mask/public/popups-ssr.js b/packages/mask/public/popups-ssr.js new file mode 100644 index 000000000000..e7db493a910c --- /dev/null +++ b/packages/mask/public/popups-ssr.js @@ -0,0 +1,7 @@ +browser.runtime.sendMessage({ type: 'popups-ssr' }).then(({ html, css }) => { + document.head.insertAdjacentHTML('beforeend', css) + document.body.innerHTML = '
' + html + '
' +}) + +// As the return value of the executeScript +undefined diff --git a/packages/mask/src/extension/options-page/DashboardDialogs/Base.tsx b/packages/mask/src/extension/options-page/DashboardDialogs/Base.tsx index 94633995c73a..3f71f35d957a 100644 --- a/packages/mask/src/extension/options-page/DashboardDialogs/Base.tsx +++ b/packages/mask/src/extension/options-page/DashboardDialogs/Base.tsx @@ -12,7 +12,10 @@ import { import { makeStyles } from '@masknet/theme' import { ThemeProvider } from '@mui/material/styles' import CloseIcon from '@mui/icons-material/Close' -import { extendsTheme, useClassicMaskFullPageTheme, useMatchXS } from '../../../utils' +import { extendsTheme, useMatchXS, useThemeLanguage } from '../../../utils' +import { useValueRef } from '@masknet/shared-base-ui' +import { appearanceSettings } from '../../../settings/settings' +import { useClassicMaskFullPageTheme } from '../../../utils/useClassicMaskFullPageTheme' const useStyles = makeStyles()((theme) => ({ root: { @@ -101,7 +104,7 @@ export function useModal diff --git a/packages/mask/src/extension/popups/UI.tsx b/packages/mask/src/extension/popups/UI.tsx index c50ed7a8e8ef..f3e2a9b294cb 100644 --- a/packages/mask/src/extension/popups/UI.tsx +++ b/packages/mask/src/extension/popups/UI.tsx @@ -2,16 +2,17 @@ import { lazy } from 'react' import { Navigate, Route, Routes, HashRouter } from 'react-router-dom' import { createInjectHooksRenderer, useActivatedPluginsDashboard } from '@masknet/plugin-infra' import { PopupRoutes } from '@masknet/shared-base' -import { useClassicMaskFullPageTheme } from '../../utils' +import { useClassicMaskFullPageTheme } from '../../utils/useClassicMaskFullPageTheme' import '../../social-network-adaptor/browser-action' import { Web3Provider } from '@masknet/web3-shared-evm' import { PopupWeb3Context } from '../../web3/context' import { PopupFrame } from './components/PopupFrame' import { Appearance } from '@masknet/theme' import { MaskUIRoot } from '../../UIRoot' +import { useThemeLanguage } from '../../utils' function useAlwaysLightTheme() { - return useClassicMaskFullPageTheme({ forcePalette: Appearance.light }) + return useClassicMaskFullPageTheme(Appearance.light, useThemeLanguage()) } const Wallet = lazy(() => import('./pages/Wallet')) const Personas = lazy(() => import('./pages/Personas')) diff --git a/packages/mask/src/extension/popups/pages/Personas/components/DisconnectDialog/index.tsx b/packages/mask/src/extension/popups/pages/Personas/components/DisconnectDialog/index.tsx index 55a1efcb25c1..4b59bc01606e 100644 --- a/packages/mask/src/extension/popups/pages/Personas/components/DisconnectDialog/index.tsx +++ b/packages/mask/src/extension/popups/pages/Personas/components/DisconnectDialog/index.tsx @@ -5,7 +5,7 @@ import { Button, Dialog, DialogActions, DialogContent, Typography, DialogProps } import { makeStyles } from '@masknet/theme' import { formatPersonaFingerprint, PersonaInformation, type ProfileIdentifier } from '@masknet/shared-base' import { LoadingButton } from '@mui/lab' -import { useI18N } from '../../../../../../utils' +import { useI18N } from '../../../../../../utils/i18n-next-ui' const useStyles = makeStyles()(() => ({ title: { diff --git a/packages/mask/src/manifest.json b/packages/mask/src/manifest.json index f436056eeecf..2dde7cd12dc9 100644 --- a/packages/mask/src/manifest.json +++ b/packages/mask/src/manifest.json @@ -7,7 +7,7 @@ "background": { "page": "background.html" }, "options_ui": { "page": "dashboard.html", "open_in_tab": true }, "icons": { "16": "16x16.png", "48": "48x48.png", "128": "128x128.png", "256": "256x256.png" }, - "browser_action": { "default_popup": "popups.html" }, + "browser_action": { "default_popup": "popups-ssr.html" }, "homepage_url": "https://mask.io", "description": "The portal to the new & open Internet. Send encrypted message and decentralized Apps right on top of social networks.", "web_accessible_resources": ["js/*", "*.png", "*.css"], diff --git a/packages/mask/src/setup.popup.ssr.tsx b/packages/mask/src/setup.popup.ssr.tsx new file mode 100644 index 000000000000..7ac09aaa6b34 --- /dev/null +++ b/packages/mask/src/setup.popup.ssr.tsx @@ -0,0 +1,42 @@ +import { ThemeProvider } from '@emotion/react' +import { ECKeyIdentifier, PersonaInformation, ProfileIdentifier } from '@masknet/shared-base' +import { Appearance } from '@masknet/theme' +import { enUS } from '@mui/material/locale' +import { noop } from 'lodash-unified' +import { PersonaHomeUI } from './extension/popups/pages/Personas/Home/UI' +import { useClassicMaskFullPageTheme } from './utils/useClassicMaskFullPageTheme' + +function useAlwaysLightTheme() { + return useClassicMaskFullPageTheme(Appearance.light, [enUS, false]) +} +export function PopupSSR() { + const i: PersonaInformation = { + identifier: new ECKeyIdentifier('secp256k1', 'hihihi'), + linkedProfiles: [ + { + identifier: new ProfileIdentifier('secp256k1', 'hihihi'), + nickname: 'jack', + }, + ], + } + return ( + + + + ) +} diff --git a/packages/mask/src/utils/MaskTheme.ts b/packages/mask/src/utils/MaskTheme.ts new file mode 100644 index 000000000000..3950635b5688 --- /dev/null +++ b/packages/mask/src/utils/MaskTheme.ts @@ -0,0 +1,97 @@ +import { ValueRef } from '@dimensiondev/holoflows-kit' +import { SubscriptionFromValueRef } from '@masknet/shared-base' +import { PaletteMode, unstable_createMuiStrictModeTheme, type ThemeOptions } from '@mui/material' +import { grey, orange } from '@mui/material/colors' +import { cloneDeep, merge } from 'lodash-unified' +import type { Subscription } from 'use-subscription' + +function getFontFamily(monospace?: boolean) { + // We want to look native. + // Windows has no CJK sans monospace. Accommodate that. + // We only use it for fingerprints anyway so CJK coverage ain't a problem... yet. + const monofont = navigator.platform.startsWith('Win') ? 'Consolas, monospace' : 'monospace' + // https://caniuse.com/font-family-system-ui + // Firefox does NOT support yet it in any form on Windows, but tests indicate that it agrees with Edge in using the UI font for sans-serif: + // Microsoft YaHei on zh-Hans-CN. + return !monospace ? '-apple-system, system-ui, sans-serif' : monofont +} +const base: ThemeOptions = { + palette: { + primary: { main: '#1c68f3' }, + secondary: orange, + text: { hint: 'rgba(0, 0, 0, 0.38)' }, + }, + typography: { + fontFamily: getFontFamily(), + }, + breakpoints: { + values: { + xs: 0, + sm: 600, + md: 1112, + lg: 1280, + xl: 1920, + }, + }, + components: { + MuiLink: { defaultProps: { underline: 'hover' } }, + MuiButton: { + styleOverrides: { + root: { + textTransform: 'unset', + minWidth: '100px', + }, + }, + defaultProps: { + size: 'small', + disableElevation: true, + }, + }, + MuiTab: { + styleOverrides: { + root: { + textTransform: 'unset', + padding: '0', + // up-sm + '@media screen and (min-width: 600px)': { + minWidth: 160, + }, + }, + }, + }, + MuiDialog: { + styleOverrides: { + paper: { + borderRadius: '12px', + }, + }, + }, + }, +} +const lightThemePatch: Partial = { + palette: { + mode: 'light', + }, +} +const darkThemePatch: Partial = { + palette: { + mode: 'dark', + background: { + paper: grey[900], + }, + }, + components: { + MuiPaper: { + // https://github.com/mui-org/material-ui/pull/25522 + styleOverrides: { root: { backgroundImage: 'unset' } }, + }, + }, +} +const baseTheme = (theme: 'dark' | 'light') => { + if (theme === 'light') return merge(cloneDeep(base), lightThemePatch) + return merge(cloneDeep(base), darkThemePatch) +} +// Theme +export const MaskLightTheme = unstable_createMuiStrictModeTheme(baseTheme('light')) +export const MaskDarkTheme = unstable_createMuiStrictModeTheme(baseTheme('dark')) +export const staticSubscription: Subscription = SubscriptionFromValueRef(new ValueRef('light')) diff --git a/packages/mask/src/utils/theme.ts b/packages/mask/src/utils/theme.ts index 3baa14bdc2ab..59946443e7eb 100644 --- a/packages/mask/src/utils/theme.ts +++ b/packages/mask/src/utils/theme.ts @@ -1,117 +1,20 @@ -import { ValueRef } from '@dimensiondev/holoflows-kit' import { useValueRef } from '@masknet/shared-base-ui' -import { SubscriptionFromValueRef } from '@masknet/shared-base' -import { Appearance, or, makeStyles, parseColor } from '@masknet/theme' +import { Appearance, makeStyles, parseColor } from '@masknet/theme' import { LanguageOptions, SupportedLanguages } from '@masknet/public-api' -import { PaletteMode, unstable_createMuiStrictModeTheme } from '@mui/material' -import { blue, green, grey, orange, red } from '@mui/material/colors' +import { unstable_createMuiStrictModeTheme } from '@mui/material' +import { blue, green, red } from '@mui/material/colors' import { jaJP, koKR, zhTW, zhCN, enUS, Localization } from '@mui/material/locale/index' import type { Theme, ThemeOptions } from '@mui/material/styles/createTheme' import { cloneDeep, merge } from 'lodash-unified' import { useRef } from 'react' -import { appearanceSettings, languageSettings } from '../settings/settings' +import { languageSettings } from '../settings/settings' import { activatedSocialNetworkUI } from '../social-network' import './theme-global.d' -import { Subscription, useSubscription } from 'use-subscription' +import { useSubscription } from 'use-subscription' import produce, { setAutoFreeze } from 'immer' import twitterColorSchema from '../social-network-adaptor/twitter.com/customization/twitter-color-schema.json' +import { staticSubscription, MaskDarkTheme, MaskLightTheme } from './MaskTheme' -function getFontFamily(monospace?: boolean) { - // We want to look native. - - // Windows has no CJK sans monospace. Accommodate that. - // We only use it for fingerprints anyway so CJK coverage ain't a problem... yet. - const monofont = navigator.platform.startsWith('Win') ? 'Consolas, monospace' : 'monospace' - // https://caniuse.com/font-family-system-ui - // Firefox does NOT support yet it in any form on Windows, but tests indicate that it agrees with Edge in using the UI font for sans-serif: - // Microsoft YaHei on zh-Hans-CN. - return !monospace ? '-apple-system, system-ui, sans-serif' : monofont -} - -const base: ThemeOptions = { - palette: { - primary: { main: '#1c68f3' }, // blue, - secondary: orange, - text: { hint: 'rgba(0, 0, 0, 0.38)' }, - }, - typography: { - fontFamily: getFontFamily(), - }, - breakpoints: { - values: { - xs: 0, - sm: 600, - md: 1112, - lg: 1280, - xl: 1920, - }, - }, - components: { - MuiLink: { defaultProps: { underline: 'hover' } }, - MuiButton: { - styleOverrides: { - root: { - textTransform: 'unset', - minWidth: '100px', - }, - }, - defaultProps: { - size: 'small', - disableElevation: true, - }, - }, - MuiTab: { - styleOverrides: { - root: { - textTransform: 'unset', - padding: '0', - // up-sm - '@media screen and (min-width: 600px)': { - minWidth: 160, - }, - }, - }, - }, - MuiDialog: { - styleOverrides: { - paper: { - borderRadius: '12px', - }, - }, - }, - }, -} - -const lightThemePatch: Partial = { - palette: { - mode: 'light', - }, -} - -const darkThemePatch: Partial = { - palette: { - mode: 'dark', - background: { - paper: grey[900], - }, - }, - components: { - MuiPaper: { - // https://github.com/mui-org/material-ui/pull/25522 - styleOverrides: { root: { backgroundImage: 'unset' } }, - }, - }, -} - -const baseTheme = (theme: 'dark' | 'light') => { - if (theme === 'light') return merge(cloneDeep(base), lightThemePatch) - return merge(cloneDeep(base), darkThemePatch) -} - -// Theme -const MaskLightTheme = unstable_createMuiStrictModeTheme(baseTheme('light')) -const MaskDarkTheme = unstable_createMuiStrictModeTheme(baseTheme('dark')) -const staticSubscription: Subscription = SubscriptionFromValueRef(new ValueRef('light')) export function useClassicMaskSNSTheme() { const { current: provider } = useRef( activatedSocialNetworkUI.customization.paletteMode?.current || staticSubscription, @@ -125,21 +28,6 @@ export function useClassicMaskSNSTheme() { const theme = unstable_createMuiStrictModeTheme(baseTheme, localization) return usePostTheme(theme) } -/** - * @deprecated - * - Popups: migrate to \@masknet/theme package - */ -export function useClassicMaskFullPageTheme(overwrite?: ClassicMaskFullPageThemeOptions) { - const userPreference = or(overwrite?.forcePalette, useValueRef(appearanceSettings)) - const systemPreference: PaletteMode = matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' - const finalPalette: PaletteMode = userPreference === Appearance.default ? systemPreference : userPreference - - const baseTheme = finalPalette === 'dark' ? MaskDarkTheme : MaskLightTheme - const [localization, isRTL] = useThemeLanguage() - // TODO: support RTL - return unstable_createMuiStrictModeTheme(baseTheme, localization) -} - /** * Only used in swap pages under popups, will replace it in the future */ @@ -349,7 +237,7 @@ export function usePopupsMaskFullPageTheme() { return unstable_createMuiStrictModeTheme(PopupTheme) } -function useThemeLanguage(): [loc: Localization, RTL: boolean] { +export function useThemeLanguage(): [loc: Localization, RTL: boolean] { let language = useValueRef(languageSettings) // TODO: support auto language if (language === LanguageOptions.__auto__) language = LanguageOptions.enUS diff --git a/packages/mask/src/utils/useClassicMaskFullPageTheme.ts b/packages/mask/src/utils/useClassicMaskFullPageTheme.ts new file mode 100644 index 000000000000..615bd2261c81 --- /dev/null +++ b/packages/mask/src/utils/useClassicMaskFullPageTheme.ts @@ -0,0 +1,20 @@ +import { Appearance } from '@masknet/theme' +import { PaletteMode, unstable_createMuiStrictModeTheme } from '@mui/material' +import type { Localization } from '@mui/material/locale' +import { MaskDarkTheme, MaskLightTheme } from './MaskTheme' + +/** + * @deprecated + * - Popups: migrate to \@masknet/theme package + */ +export function useClassicMaskFullPageTheme( + userPreference: Appearance, + [localization]: [loc: Localization, RTL: boolean], +) { + const systemPreference: PaletteMode = + 'matchMedia' in globalThis ? (matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : 'light' + const finalPalette: PaletteMode = userPreference === Appearance.default ? systemPreference : userPreference + + const baseTheme = finalPalette === 'dark' ? MaskDarkTheme : MaskLightTheme + return unstable_createMuiStrictModeTheme(baseTheme, localization) +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8ce135339edc..243e38e07303 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,6 +17,7 @@ importers: '@emotion/cache': ^11.7.1 '@emotion/react': ^11.8.2 '@emotion/serialize': ^1.0.2 + '@emotion/server': ^11.4.0 '@emotion/styled': ^11.8.1 '@emotion/utils': ^1.1.0 '@jest/globals': ^28.0.0-alpha.3 @@ -64,6 +65,7 @@ importers: '@emotion/cache': 11.7.1 '@emotion/react': 11.8.2_00a11a054056e3746b551a83b9229751 '@emotion/serialize': 1.0.2 + '@emotion/server': 11.4.0 '@emotion/styled': 11.8.1_99e6c630d8f9e4aaf14c79d0138a2fa8 '@emotion/utils': 1.1.0 '@mui/icons-material': 5.5.1_25c2be9db5642b081e6658d3ddfb5f23 From de16372cc438de74b2d92a140f2200073b5048b0 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Thu, 31 Mar 2022 20:06:40 +0800 Subject: [PATCH 02/20] patch pkg --- package.json | 12 +++++----- patches/@emotion+cache+11.7.1.patch | 23 ++++++++++++++++++ patches/@emotion+react+11.8.2.patch | 23 ++++++++++++++++++ patches/@emotion+serialize+1.0.2.patch | 23 ++++++++++++++++++ patches/@emotion+server+11.4.0.patch | 22 +++++++++++++++++ patches/@emotion+styled+11.8.1.patch | 23 ++++++++++++++++++ patches/@emotion+utils+1.1.0.patch | 23 ++++++++++++++++++ pnpm-lock.yaml | 33 +++++++++++--------------- 8 files changed, 157 insertions(+), 25 deletions(-) create mode 100644 patches/@emotion+cache+11.7.1.patch create mode 100644 patches/@emotion+react+11.8.2.patch create mode 100644 patches/@emotion+serialize+1.0.2.patch create mode 100644 patches/@emotion+server+11.4.0.patch create mode 100644 patches/@emotion+styled+11.8.1.patch create mode 100644 patches/@emotion+utils+1.1.0.patch diff --git a/package.json b/package.json index ff29c47c64d2..f55fe022b617 100644 --- a/package.json +++ b/package.json @@ -28,12 +28,12 @@ }, "dependencies": { "@dimensiondev/kit": "0.0.0-20220228054820-f2378be", - "@emotion/cache": "^11.7.1", - "@emotion/react": "^11.8.2", - "@emotion/serialize": "^1.0.2", - "@emotion/server": "^11.4.0", - "@emotion/styled": "^11.8.1", - "@emotion/utils": "^1.1.0", + "@emotion/cache": "11.7.1", + "@emotion/react": "11.8.2", + "@emotion/serialize": "1.0.2", + "@emotion/server": "11.4.0", + "@emotion/styled": "11.8.1", + "@emotion/utils": "1.1.0", "@mui/icons-material": "5.5.1", "@mui/lab": "5.0.0-alpha.75", "@mui/material": "5.5.3", diff --git a/patches/@emotion+cache+11.7.1.patch b/patches/@emotion+cache+11.7.1.patch new file mode 100644 index 000000000000..cf1d0874d8b7 --- /dev/null +++ b/patches/@emotion+cache+11.7.1.patch @@ -0,0 +1,23 @@ +# generated by patch-package 6.5.0 on 2022-03-31 20:04:11 +# +# command: +# npx patch-package @emotion/cache --exclude nothing +# +# declared package: +# @emotion/cache: 11.7.1 +# +diff --git a/node_modules/@emotion/cache/package.json b/node_modules/@emotion/cache/package.json +index 437f0bf..c74881a 100644 +--- a/node_modules/@emotion/cache/package.json ++++ b/node_modules/@emotion/cache/package.json +@@ -4,10 +4,6 @@ + "description": "emotion's cache", + "main": "dist/emotion-cache.cjs.js", + "module": "dist/emotion-cache.esm.js", +- "browser": { +- "./dist/emotion-cache.cjs.js": "./dist/emotion-cache.browser.cjs.js", +- "./dist/emotion-cache.esm.js": "./dist/emotion-cache.browser.esm.js" +- }, + "types": "types/index.d.ts", + "license": "MIT", + "repository": "https://github.com/emotion-js/emotion/tree/main/packages/cache", diff --git a/patches/@emotion+react+11.8.2.patch b/patches/@emotion+react+11.8.2.patch new file mode 100644 index 000000000000..15bbdbd43a85 --- /dev/null +++ b/patches/@emotion+react+11.8.2.patch @@ -0,0 +1,23 @@ +# generated by patch-package 6.5.0 on 2022-03-31 20:04:21 +# +# command: +# npx patch-package @emotion/react --exclude nothing +# +# declared package: +# @emotion/react: 11.8.2 +# +diff --git a/node_modules/@emotion/react/package.json b/node_modules/@emotion/react/package.json +index 22fba2d..fafe561 100644 +--- a/node_modules/@emotion/react/package.json ++++ b/node_modules/@emotion/react/package.json +@@ -3,10 +3,6 @@ + "version": "11.8.2", + "main": "dist/emotion-react.cjs.js", + "module": "dist/emotion-react.esm.js", +- "browser": { +- "./dist/emotion-react.cjs.js": "./dist/emotion-react.browser.cjs.js", +- "./dist/emotion-react.esm.js": "./dist/emotion-react.browser.esm.js" +- }, + "types": "types/index.d.ts", + "files": [ + "src", diff --git a/patches/@emotion+serialize+1.0.2.patch b/patches/@emotion+serialize+1.0.2.patch new file mode 100644 index 000000000000..593b0577dd1c --- /dev/null +++ b/patches/@emotion+serialize+1.0.2.patch @@ -0,0 +1,23 @@ +# generated by patch-package 6.5.0 on 2022-03-31 20:04:26 +# +# command: +# npx patch-package @emotion/serialize --exclude nothing +# +# declared package: +# @emotion/serialize: 1.0.2 +# +diff --git a/node_modules/@emotion/serialize/package.json b/node_modules/@emotion/serialize/package.json +index ef39314..15044d3 100644 +--- a/node_modules/@emotion/serialize/package.json ++++ b/node_modules/@emotion/serialize/package.json +@@ -27,9 +27,5 @@ + "src", + "dist", + "types/*.d.ts" +- ], +- "browser": { +- "./dist/emotion-serialize.cjs.js": "./dist/emotion-serialize.browser.cjs.js", +- "./dist/emotion-serialize.esm.js": "./dist/emotion-serialize.browser.esm.js" +- } ++ ] + } diff --git a/patches/@emotion+server+11.4.0.patch b/patches/@emotion+server+11.4.0.patch new file mode 100644 index 000000000000..c6165591f537 --- /dev/null +++ b/patches/@emotion+server+11.4.0.patch @@ -0,0 +1,22 @@ +# generated by patch-package 6.5.0 on 2022-03-31 20:04:34 +# +# command: +# npx patch-package @emotion/server --exclude nothing +# +# declared package: +# @emotion/server: 11.4.0 +# +diff --git a/node_modules/@emotion/server/package.json b/node_modules/@emotion/server/package.json +index fdb6ec6..26c61fd 100644 +--- a/node_modules/@emotion/server/package.json ++++ b/node_modules/@emotion/server/package.json +@@ -50,9 +50,6 @@ + "bugs": { + "url": "https://github.com/emotion-js/emotion/issues" + }, +- "browser": { +- "./dist/emotion-server.cjs.js": "./dist/emotion-server.browser.cjs.js" +- }, + "preconstruct": { + "entrypoints": [ + "./index.js", diff --git a/patches/@emotion+styled+11.8.1.patch b/patches/@emotion+styled+11.8.1.patch new file mode 100644 index 000000000000..205c0c061b34 --- /dev/null +++ b/patches/@emotion+styled+11.8.1.patch @@ -0,0 +1,23 @@ +# generated by patch-package 6.5.0 on 2022-03-31 20:04:40 +# +# command: +# npx patch-package @emotion/styled --exclude nothing +# +# declared package: +# @emotion/styled: 11.8.1 +# +diff --git a/node_modules/@emotion/styled/package.json b/node_modules/@emotion/styled/package.json +index fec82fb..a18ff0e 100644 +--- a/node_modules/@emotion/styled/package.json ++++ b/node_modules/@emotion/styled/package.json +@@ -49,10 +49,6 @@ + "macro.js.flow" + ], + "umd:main": "dist/emotion-styled.umd.min.js", +- "browser": { +- "./dist/emotion-styled.cjs.js": "./dist/emotion-styled.browser.cjs.js", +- "./dist/emotion-styled.esm.js": "./dist/emotion-styled.browser.esm.js" +- }, + "preconstruct": { + "umdName": "emotionStyled", + "entrypoints": [ diff --git a/patches/@emotion+utils+1.1.0.patch b/patches/@emotion+utils+1.1.0.patch new file mode 100644 index 000000000000..aa458cbe8864 --- /dev/null +++ b/patches/@emotion+utils+1.1.0.patch @@ -0,0 +1,23 @@ +# generated by patch-package 6.5.0 on 2022-03-31 20:04:44 +# +# command: +# npx patch-package @emotion/utils --exclude nothing +# +# declared package: +# @emotion/utils: 1.1.0 +# +diff --git a/node_modules/@emotion/utils/package.json b/node_modules/@emotion/utils/package.json +index d661529..e5738e8 100644 +--- a/node_modules/@emotion/utils/package.json ++++ b/node_modules/@emotion/utils/package.json +@@ -4,10 +4,6 @@ + "description": "internal utils for emotion", + "main": "dist/emotion-utils.cjs.js", + "module": "dist/emotion-utils.esm.js", +- "browser": { +- "./dist/emotion-utils.cjs.js": "./dist/emotion-utils.browser.cjs.js", +- "./dist/emotion-utils.esm.js": "./dist/emotion-utils.browser.esm.js" +- }, + "types": "types/index.d.ts", + "license": "MIT", + "scripts": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 243e38e07303..1108efc7dc44 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,12 +14,12 @@ importers: '@dimensiondev/eslint-plugin': ^0.0.1-20220117062517-fd3cb01 '@dimensiondev/kit': 0.0.0-20220228054820-f2378be '@dimensiondev/patch-package': ^6.5.0 - '@emotion/cache': ^11.7.1 - '@emotion/react': ^11.8.2 - '@emotion/serialize': ^1.0.2 - '@emotion/server': ^11.4.0 - '@emotion/styled': ^11.8.1 - '@emotion/utils': ^1.1.0 + '@emotion/cache': 11.7.1 + '@emotion/react': 11.8.2 + '@emotion/serialize': 1.0.2 + '@emotion/server': 11.4.0 + '@emotion/styled': 11.8.1 + '@emotion/utils': 1.1.0 '@jest/globals': ^28.0.0-alpha.3 '@magic-works/i18n-codegen': ^0.1.0 '@masknet/cli': workspace:* @@ -5272,7 +5272,7 @@ packages: dependencies: '@babel/helper-module-imports': 7.16.7 '@babel/plugin-syntax-jsx': 7.16.7 - '@babel/runtime': 7.17.2 + '@babel/runtime': 7.17.8 '@emotion/hash': 0.8.0 '@emotion/memoize': 0.7.5 '@emotion/serialize': 1.0.2 @@ -5360,7 +5360,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.17.2 + '@babel/runtime': 7.17.8 '@emotion/babel-plugin': 11.7.2 '@emotion/cache': 11.7.1 '@emotion/serialize': 1.0.2 @@ -5399,7 +5399,7 @@ packages: '@emotion/css': optional: true dependencies: - '@emotion/utils': 1.0.0 + '@emotion/utils': 1.1.0 html-tokenize: 2.0.1 multipipe: 1.0.2 through: 2.3.8 @@ -5452,7 +5452,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.17.2 + '@babel/runtime': 7.17.8 '@emotion/babel-plugin': 11.7.2 '@emotion/is-prop-valid': 1.1.2 '@emotion/react': 11.8.2_00a11a054056e3746b551a83b9229751 @@ -5473,10 +5473,6 @@ packages: resolution: {integrity: sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==} dev: true - /@emotion/utils/1.0.0: - resolution: {integrity: sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA==} - dev: false - /@emotion/utils/1.1.0: resolution: {integrity: sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ==} dev: false @@ -11762,7 +11758,7 @@ packages: /babel-plugin-macros/2.8.0: resolution: {integrity: sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==} dependencies: - '@babel/runtime': 7.17.2 + '@babel/runtime': 7.17.8 cosmiconfig: 6.0.0 resolve: 1.22.0 @@ -17815,7 +17811,7 @@ packages: dependencies: buffer-from: 0.1.2 inherits: 2.0.4 - minimist: 1.2.5 + minimist: 1.2.6 readable-stream: 1.0.34 through2: 0.4.2 dev: false @@ -19791,7 +19787,7 @@ packages: resolution: {integrity: sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==} hasBin: true dependencies: - minimist: 1.2.5 + minimist: 1.2.6 /json5/2.2.0: resolution: {integrity: sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==} @@ -20814,7 +20810,6 @@ packages: /minimist/1.2.6: resolution: {integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==} - dev: false /minipass-collect/1.0.2: resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==} @@ -25646,7 +25641,7 @@ packages: dependencies: '@types/json5': 0.0.29 json5: 1.0.1 - minimist: 1.2.5 + minimist: 1.2.6 strip-bom: 3.0.0 dev: true From 3ea8c97910629d635db43dfecca614ece97f809f Mon Sep 17 00:00:00 2001 From: Jack Works Date: Thu, 31 Mar 2022 20:38:21 +0800 Subject: [PATCH 03/20] wip --- .../tasks/Cancellable/PopupSSR/worker.tsx | 4 +--- .../tasks/Cancellable/PopupSSR/worker_patch.js | 6 +----- packages/mask/src/setup.popup.ssr.tsx | 13 +++++++++---- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/packages/mask/background/tasks/Cancellable/PopupSSR/worker.tsx b/packages/mask/background/tasks/Cancellable/PopupSSR/worker.tsx index 4ba3c7f1ea4f..1f5c8503dd72 100644 --- a/packages/mask/background/tasks/Cancellable/PopupSSR/worker.tsx +++ b/packages/mask/background/tasks/Cancellable/PopupSSR/worker.tsx @@ -4,8 +4,7 @@ import './worker_patch' // @ts-ignore import { PopupSSR } from './loader' import { renderToString } from 'react-dom/server' -// @ts-ignore -import createCache from '@emotion/cache/dist/emotion-cache.cjs.prod.js' +import createCache from '@emotion/cache' import { CacheProvider } from '@emotion/react' import createEmotionServer from '@emotion/server/create-instance' // TODO: @@ -20,7 +19,6 @@ function serverCache(key: string) { return cache } function render() { - debugger const muiCache = serverCache('mui') const tssCache = serverCache('tss') const tssServer = createEmotionServer(tssCache) diff --git a/packages/mask/background/tasks/Cancellable/PopupSSR/worker_patch.js b/packages/mask/background/tasks/Cancellable/PopupSSR/worker_patch.js index 4465fd91acb9..8337712ea57f 100644 --- a/packages/mask/background/tasks/Cancellable/PopupSSR/worker_patch.js +++ b/packages/mask/background/tasks/Cancellable/PopupSSR/worker_patch.js @@ -1,5 +1 @@ -globalThis.document = { - querySelectorAll() { - return [] - }, -} +// diff --git a/packages/mask/src/setup.popup.ssr.tsx b/packages/mask/src/setup.popup.ssr.tsx index 7ac09aaa6b34..4fe8e9d162eb 100644 --- a/packages/mask/src/setup.popup.ssr.tsx +++ b/packages/mask/src/setup.popup.ssr.tsx @@ -1,21 +1,26 @@ import { ThemeProvider } from '@emotion/react' -import { ECKeyIdentifier, PersonaInformation, ProfileIdentifier } from '@masknet/shared-base' +import { ECKeyIdentifier, PersonaInformation, ProfileIdentifier, i18NextInstance } from '@masknet/shared-base' import { Appearance } from '@masknet/theme' import { enUS } from '@mui/material/locale' import { noop } from 'lodash-unified' import { PersonaHomeUI } from './extension/popups/pages/Personas/Home/UI' import { useClassicMaskFullPageTheme } from './utils/useClassicMaskFullPageTheme' +import { initReactI18next } from 'react-i18next' +import { addMaskI18N } from '../shared-ui/locales/languages' + +initReactI18next.init(i18NextInstance) +addMaskI18N(i18NextInstance) function useAlwaysLightTheme() { return useClassicMaskFullPageTheme(Appearance.light, [enUS, false]) } export function PopupSSR() { const i: PersonaInformation = { - identifier: new ECKeyIdentifier('secp256k1', 'hihihi'), + identifier: new ECKeyIdentifier('secp256k1', Math.random().toString()), linkedProfiles: [ { - identifier: new ProfileIdentifier('secp256k1', 'hihihi'), - nickname: 'jack', + identifier: new ProfileIdentifier('secp256k1', Math.random().toString()), + nickname: Math.random().toString(), }, ], } From 3255c6451845a8fbf44c45181186347b1942d16d Mon Sep 17 00:00:00 2001 From: Jack Works Date: Fri, 1 Apr 2022 16:29:48 +0800 Subject: [PATCH 04/20] feat: support ssr --- packages/mask/.webpack/flags.ts | 2 +- packages/mask/src/extension/popups/UI.tsx | 10 ++- .../components/InitialPlaceholder/index.tsx | 4 +- .../popups/components/PopupFrame/index.tsx | 12 +-- .../popups/pages/Personas/Home/UI.tsx | 6 +- .../popups/pages/Personas/Home/index.tsx | 1 - .../Personas/components/ProfileList/index.tsx | 3 +- packages/mask/src/setup.popup.ssr.tsx | 85 ++++++++++++++----- packages/shared/src/constants.tsx | 4 +- patches/@emotion+styled+11.8.1.patch | 17 +++- 10 files changed, 102 insertions(+), 42 deletions(-) diff --git a/packages/mask/.webpack/flags.ts b/packages/mask/.webpack/flags.ts index fe708b3b4793..cd56673992ad 100644 --- a/packages/mask/.webpack/flags.ts +++ b/packages/mask/.webpack/flags.ts @@ -47,7 +47,7 @@ export function computedBuildFlags(flags: ReturnType sourceMapKind = 'inline-cheap-source-map' supportWebAssembly = false } else if (mode === 'development') { - sourceMapKind = 'eval-cheap-source-map' + sourceMapKind = false } else { sourceMapKind = false } diff --git a/packages/mask/src/extension/popups/UI.tsx b/packages/mask/src/extension/popups/UI.tsx index f3e2a9b294cb..aeb0b48db96d 100644 --- a/packages/mask/src/extension/popups/UI.tsx +++ b/packages/mask/src/extension/popups/UI.tsx @@ -10,6 +10,7 @@ import { PopupFrame } from './components/PopupFrame' import { Appearance } from '@masknet/theme' import { MaskUIRoot } from '../../UIRoot' import { useThemeLanguage } from '../../utils' +import { useMyPersonas } from '../../components/DataSource/useMyPersonas' function useAlwaysLightTheme() { return useClassicMaskFullPageTheme(Appearance.light, useThemeLanguage()) @@ -24,13 +25,14 @@ const ThirdPartyRequestPermission = lazy(() => import('./ThirdPartyRequestPermis const PluginRender = createInjectHooksRenderer(useActivatedPluginsDashboard, (x) => x.GlobalInjection) export default function Popups() { + const personaLength = useMyPersonas().length return ( - )} /> - )} /> + )} /> + )} /> } /> } /> } /> @@ -48,6 +50,6 @@ export default function Popups() { ) } -function frame(x: React.ReactNode) { - return +function frame(personaLength: number, x: React.ReactNode) { + return } diff --git a/packages/mask/src/extension/popups/components/InitialPlaceholder/index.tsx b/packages/mask/src/extension/popups/components/InitialPlaceholder/index.tsx index 487429ed5222..af60e271d6ac 100644 --- a/packages/mask/src/extension/popups/components/InitialPlaceholder/index.tsx +++ b/packages/mask/src/extension/popups/components/InitialPlaceholder/index.tsx @@ -1,3 +1,5 @@ +// ! This file is used during SSR. DO NOT import new files that does not work in SSR + import { memo } from 'react' import { Box, Button, Typography } from '@mui/material' import { makeStyles } from '@masknet/theme' @@ -5,7 +7,7 @@ import { useEnterDashboard } from '../../hook/useEnterDashboard' import { useMatch } from 'react-router-dom' import { PopupRoutes } from '@masknet/shared-base' import { MasksIcon, MaskWalletIcon } from '@masknet/icons' -import { useI18N } from '../../../../utils' +import { useI18N } from '../../../../utils/i18n-next-ui' const useStyles = makeStyles()({ container: { diff --git a/packages/mask/src/extension/popups/components/PopupFrame/index.tsx b/packages/mask/src/extension/popups/components/PopupFrame/index.tsx index 21881ee4d917..82f307209b42 100644 --- a/packages/mask/src/extension/popups/components/PopupFrame/index.tsx +++ b/packages/mask/src/extension/popups/components/PopupFrame/index.tsx @@ -1,12 +1,13 @@ +// ! This file is used during SSR. DO NOT import new files that does not work in SSR + import { memo } from 'react' import { NavLink, useNavigate, useLocation, useMatch } from 'react-router-dom' import { Box, GlobalStyles, Paper } from '@mui/material' import { makeStyles } from '@masknet/theme' import { ArrowBackIcon, MiniMaskIcon } from '@masknet/icons' import { PopupRoutes } from '@masknet/shared-base' -import { useMyPersonas } from '../../../../components/DataSource/useMyPersonas' import { InitialPlaceholder } from '../InitialPlaceholder' -import { useI18N } from '../../../../utils' +import { useI18N } from '../../../../utils/i18n-next-ui' function GlobalCss() { return ( @@ -68,14 +69,15 @@ const useStyles = makeStyles()((theme) => ({ }, })) -export interface PopupFrameProps extends React.PropsWithChildren<{}> {} +export interface PopupFrameProps extends React.PropsWithChildren<{}> { + personaLength: number +} export const PopupFrame = memo((props) => { const { t } = useI18N() const navigate = useNavigate() const { classes, cx } = useStyles() const location = useLocation() - const personas = useMyPersonas() const excludePath = [ useMatch(PopupRoutes.Wallet), @@ -129,7 +131,7 @@ export const PopupFrame = memo((props) => { - {personas.length === 0 && !matchRecovery ? : props.children} + {props.personaLength === 0 && !matchRecovery ? : props.children} diff --git a/packages/mask/src/extension/popups/pages/Personas/Home/UI.tsx b/packages/mask/src/extension/popups/pages/Personas/Home/UI.tsx index ff6008a700fe..07d0d8b80f5b 100644 --- a/packages/mask/src/extension/popups/pages/Personas/Home/UI.tsx +++ b/packages/mask/src/extension/popups/pages/Personas/Home/UI.tsx @@ -17,7 +17,7 @@ import { EnterDashboard } from '../../../components/EnterDashboard' import { PersonaListUI } from '../components/PersonaList' import { useI18N } from '../../../../../utils/i18n-next-ui' import urlcat from 'urlcat' -import type { NavigateFunction } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' const useStyles = makeStyles()({ content: { @@ -96,14 +96,14 @@ const useStyles = makeStyles()({ }) export interface PersonaHomeUIProps extends ProfileListProps { - navigate: NavigateFunction currentPersona: PersonaInformation | undefined personas: PersonaInformation[] | undefined onChangeCurrentPersona: (identifier: ECKeyIdentifier) => void onDeletePersona: (persona: PersonaInformation | undefined) => void } export const PersonaHomeUI = memo((props: PersonaHomeUIProps) => { - const { navigate, currentPersona, personas, onDeletePersona, onChangeCurrentPersona } = props + const navigate = useNavigate() + const { currentPersona, personas, onDeletePersona, onChangeCurrentPersona } = props const { t } = useI18N() const { classes, cx } = useStyles() diff --git a/packages/mask/src/extension/popups/pages/Personas/Home/index.tsx b/packages/mask/src/extension/popups/pages/Personas/Home/index.tsx index ab1a295cca27..d370b51a0ce7 100644 --- a/packages/mask/src/extension/popups/pages/Personas/Home/index.tsx +++ b/packages/mask/src/extension/popups/pages/Personas/Home/index.tsx @@ -126,7 +126,6 @@ const PersonaHome = memo(() => { SOCIAL_MEDIA_ICON_MAPPING={SOCIAL_MEDIA_ICON_MAPPING} definedSocialNetworks={definedSocialNetworks} currentPersona={currentPersona} - navigate={navigate} personas={personas} onDeletePersona={setDeletingPersona} onChangeCurrentPersona={onChangeCurrentPersona} diff --git a/packages/mask/src/extension/popups/pages/Personas/components/ProfileList/index.tsx b/packages/mask/src/extension/popups/pages/Personas/components/ProfileList/index.tsx index dd93dbe5de73..c337a3dac01d 100644 --- a/packages/mask/src/extension/popups/pages/Personas/components/ProfileList/index.tsx +++ b/packages/mask/src/extension/popups/pages/Personas/components/ProfileList/index.tsx @@ -11,7 +11,6 @@ import { DisconnectDialog } from '../DisconnectDialog' const useStyles = makeStyles()({ list: { padding: '0 0 70px 0', - height: 487, overflow: 'auto', }, item: { @@ -136,7 +135,7 @@ export const ProfileList = memo((props: ProfileListProps) => { ) }) -interface MergedProfileInformation extends ProfileInformation { +export interface MergedProfileInformation extends ProfileInformation { is_valid?: boolean identity?: string platform?: NextIDPlatform diff --git a/packages/mask/src/setup.popup.ssr.tsx b/packages/mask/src/setup.popup.ssr.tsx index 4fe8e9d162eb..b645cf948036 100644 --- a/packages/mask/src/setup.popup.ssr.tsx +++ b/packages/mask/src/setup.popup.ssr.tsx @@ -1,5 +1,12 @@ import { ThemeProvider } from '@emotion/react' -import { ECKeyIdentifier, PersonaInformation, ProfileIdentifier, i18NextInstance } from '@masknet/shared-base' +import { + ECKeyIdentifier, + PersonaInformation, + ProfileIdentifier, + i18NextInstance, + EnhanceableSite, + PopupRoutes, +} from '@masknet/shared-base' import { Appearance } from '@masknet/theme' import { enUS } from '@mui/material/locale' import { noop } from 'lodash-unified' @@ -7,6 +14,16 @@ import { PersonaHomeUI } from './extension/popups/pages/Personas/Home/UI' import { useClassicMaskFullPageTheme } from './utils/useClassicMaskFullPageTheme' import { initReactI18next } from 'react-i18next' import { addMaskI18N } from '../shared-ui/locales/languages' +import { + FacebookColoredIcon, + InstagramColoredIcon, + MindsIcon, + TwitterColoredIcon, + OpenSeaColoredIcon, +} from '@masknet/icons' +import type { MergedProfileInformation } from './extension/popups/pages/Personas/components/ProfileList' +import { PopupFrame } from './extension/popups/components/PopupFrame' +import { StaticRouter } from 'react-router-dom/server' initReactI18next.init(i18NextInstance) addMaskI18N(i18NextInstance) @@ -14,34 +31,58 @@ addMaskI18N(i18NextInstance) function useAlwaysLightTheme() { return useClassicMaskFullPageTheme(Appearance.light, [enUS, false]) } + +const SOCIAL_MEDIA_ICON_MAPPING: Record = { + [EnhanceableSite.Twitter]: , + [EnhanceableSite.Facebook]: , + [EnhanceableSite.Minds]: , + [EnhanceableSite.Instagram]: , + [EnhanceableSite.OpenSea]: , +} +const DEFINED_SITES = [ + EnhanceableSite.Twitter, + EnhanceableSite.Facebook, + EnhanceableSite.Minds, + EnhanceableSite.Instagram, + EnhanceableSite.OpenSea, +] export function PopupSSR() { const i: PersonaInformation = { - identifier: new ECKeyIdentifier('secp256k1', Math.random().toString()), + identifier: new ECKeyIdentifier('secp256k1', 'abc'), linkedProfiles: [ { - identifier: new ProfileIdentifier('secp256k1', Math.random().toString()), - nickname: Math.random().toString(), + identifier: new ProfileIdentifier('secp256k1', 'abc'), + nickname: 'Jack', }, ], } + const b: MergedProfileInformation[] = [ + { + identifier: new ProfileIdentifier('twitter.com', 'jack'), + nickname: 'Jack', + }, + ] return ( - - - + + + + + + + ) } diff --git a/packages/shared/src/constants.tsx b/packages/shared/src/constants.tsx index 03e0e05d3d99..99930ff4457e 100644 --- a/packages/shared/src/constants.tsx +++ b/packages/shared/src/constants.tsx @@ -1,4 +1,3 @@ -import type { ReactNode } from 'react' import { FacebookColoredIcon, InstagramColoredIcon, @@ -13,7 +12,8 @@ export const TWITTER_ID = 'twitter.com' export const INSTAGRAM_ID = 'instagram.com' export const OPENSEA_ID = 'opensea.io' -export const SOCIAL_MEDIA_ICON_MAPPING: Record = { +// When you add a new icon, don't forget to add it in packages/mask/src/setup.popup.ssr.tsx +export const SOCIAL_MEDIA_ICON_MAPPING: Record = { [TWITTER_ID]: , [FACEBOOK_ID]: , [MINDS_ID]: , diff --git a/patches/@emotion+styled+11.8.1.patch b/patches/@emotion+styled+11.8.1.patch index 205c0c061b34..ccbd4e348950 100644 --- a/patches/@emotion+styled+11.8.1.patch +++ b/patches/@emotion+styled+11.8.1.patch @@ -1,4 +1,4 @@ -# generated by patch-package 6.5.0 on 2022-03-31 20:04:40 +# generated by patch-package 6.5.0 on 2022-04-01 16:22:25 # # command: # npx patch-package @emotion/styled --exclude nothing @@ -6,6 +6,21 @@ # declared package: # @emotion/styled: 11.8.1 # +diff --git a/node_modules/@emotion/styled/base/package.json b/node_modules/@emotion/styled/base/package.json +index 96f433f..bd1ec82 100644 +--- a/node_modules/@emotion/styled/base/package.json ++++ b/node_modules/@emotion/styled/base/package.json +@@ -2,10 +2,6 @@ + "main": "dist/emotion-styled-base.cjs.js", + "module": "dist/emotion-styled-base.esm.js", + "umd:main": "dist/emotion-styled-base.umd.min.js", +- "browser": { +- "./dist/emotion-styled-base.cjs.js": "./dist/emotion-styled-base.browser.cjs.js", +- "./dist/emotion-styled-base.esm.js": "./dist/emotion-styled-base.browser.esm.js" +- }, + "types": "../types/base", + "preconstruct": { + "umdName": "emotionStyledBase" diff --git a/node_modules/@emotion/styled/package.json b/node_modules/@emotion/styled/package.json index fec82fb..a18ff0e 100644 --- a/node_modules/@emotion/styled/package.json From 5c20fded0f2a943aaaa268339d84777ddb172846 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Fri, 1 Apr 2022 16:56:46 +0800 Subject: [PATCH 05/20] refactor: support ssrt --- .../tasks/Cancellable/PopupSSR/index.mv3.ts | 7 +- .../tasks/Cancellable/PopupSSR/index.ts | 17 ++-- .../tasks/Cancellable/PopupSSR/loader.js | 6 +- .../Cancellable/PopupSSR/prepare-data.ts | 9 ++ .../tasks/Cancellable/PopupSSR/type.ts | 13 +++ .../tasks/Cancellable/PopupSSR/worker.tsx | 37 ++------- .../tasks/Cancellable/PopupSSR/worker_init.ts | 6 +- .../Cancellable/PopupSSR/worker_patch.js | 1 - packages/mask/src/setup.popup.ssr.tsx | 83 ++++++++++--------- packages/theme/src/index.ts | 1 + 10 files changed, 89 insertions(+), 91 deletions(-) create mode 100644 packages/mask/background/tasks/Cancellable/PopupSSR/prepare-data.ts create mode 100644 packages/mask/background/tasks/Cancellable/PopupSSR/type.ts delete mode 100644 packages/mask/background/tasks/Cancellable/PopupSSR/worker_patch.js diff --git a/packages/mask/background/tasks/Cancellable/PopupSSR/index.mv3.ts b/packages/mask/background/tasks/Cancellable/PopupSSR/index.mv3.ts index 2b819dd1bd7a..d660935a864c 100644 --- a/packages/mask/background/tasks/Cancellable/PopupSSR/index.mv3.ts +++ b/packages/mask/background/tasks/Cancellable/PopupSSR/index.mv3.ts @@ -5,5 +5,10 @@ export default async function PopupSSR(signal: AbortSignal) { function f(message: any) { if (!(message.type === 'popups-ssr')) return - return import('./worker').then((x) => x.main()) + return (async () => { + const x = import('./worker') + const y = import('./prepare-data').then((f) => f.prepareSSR()) + const [{ main }, data] = await Promise.all([x, y]) + return main(data) + })() } diff --git a/packages/mask/background/tasks/Cancellable/PopupSSR/index.ts b/packages/mask/background/tasks/Cancellable/PopupSSR/index.ts index 664ef6bdeaef..c77a390c0f8b 100644 --- a/packages/mask/background/tasks/Cancellable/PopupSSR/index.ts +++ b/packages/mask/background/tasks/Cancellable/PopupSSR/index.ts @@ -1,18 +1,11 @@ +import { serializer } from '@masknet/shared-base' import { OnDemandWorker } from '../../../../utils-pure/OnDemandWorker' +import { prepareSSR } from './prepare-data' -let worker = new OnDemandWorker(new URL('./worker_init.ts', import.meta.url), { name: 'PopupSSR' }) +const worker = new OnDemandWorker(new URL('./worker_init.ts', import.meta.url), { name: 'PopupSSR' }) export default async function PopupSSR(signal: AbortSignal) { browser.runtime.onMessage.addListener(f) - if (import.meta.webpackHot) { - // To receive the HMR - const _f = () => import('./worker_init') - import.meta.webpackHot.accept('./worker_init.ts', () => { - if (signal.aborted) return - worker.terminate() - worker = new OnDemandWorker(new URL('./worker_init.ts', import.meta.url), { name: 'PopupSSR' }) - }) - } signal.addEventListener( 'abort', () => { @@ -26,7 +19,9 @@ export default async function PopupSSR(signal: AbortSignal) { function f(message: any) { if (!(message.type === 'popups-ssr')) return return new Promise((resolve) => { - worker.postMessage('ping') + prepareSSR() + .then(serializer.serialization) + .then((data) => worker.postMessage(data)) worker.addEventListener( 'message', (data) => { diff --git a/packages/mask/background/tasks/Cancellable/PopupSSR/loader.js b/packages/mask/background/tasks/Cancellable/PopupSSR/loader.js index f62408758122..c4aaaef1ab08 100644 --- a/packages/mask/background/tasks/Cancellable/PopupSSR/loader.js +++ b/packages/mask/background/tasks/Cancellable/PopupSSR/loader.js @@ -1,5 +1,5 @@ // This is a JS file to make TypeScript happy. -import { PopupSSR as _ } from '../../../../src/setup.popup.ssr.tsx' +import { render as _ } from '../../../../src/setup.popup.ssr.tsx' -export let PopupSSR = _ -import.meta.webpackHot && import.meta.webpackHot.accept('../../../../src/setup.popup.ssr.tsx', () => (PopupSSR = _)) +export let render = _ +import.meta.webpackHot && import.meta.webpackHot.accept('../../../../src/setup.popup.ssr.tsx', () => (render = _)) diff --git a/packages/mask/background/tasks/Cancellable/PopupSSR/prepare-data.ts b/packages/mask/background/tasks/Cancellable/PopupSSR/prepare-data.ts new file mode 100644 index 000000000000..ca71ceeb1d65 --- /dev/null +++ b/packages/mask/background/tasks/Cancellable/PopupSSR/prepare-data.ts @@ -0,0 +1,9 @@ +import type { PopupSSR_Props } from './type' + +export async function prepareSSR(): Promise { + return { + currentPersonaIndex: 0, + mergedProfiles: [], + personas: [], + } +} diff --git a/packages/mask/background/tasks/Cancellable/PopupSSR/type.ts b/packages/mask/background/tasks/Cancellable/PopupSSR/type.ts new file mode 100644 index 000000000000..eff986fa84f7 --- /dev/null +++ b/packages/mask/background/tasks/Cancellable/PopupSSR/type.ts @@ -0,0 +1,13 @@ +import type { NextIDPlatform, PersonaInformation, ProfileInformation } from '@masknet/shared-base' + +export interface PopupSSR_Props { + personas: PersonaInformation[] | undefined + currentPersonaIndex: number | undefined + mergedProfiles: MergedProfileInformation[] +} + +export interface MergedProfileInformation extends ProfileInformation { + is_valid?: boolean + identity?: string + platform?: NextIDPlatform +} diff --git a/packages/mask/background/tasks/Cancellable/PopupSSR/worker.tsx b/packages/mask/background/tasks/Cancellable/PopupSSR/worker.tsx index 1f5c8503dd72..685a9e8089b2 100644 --- a/packages/mask/background/tasks/Cancellable/PopupSSR/worker.tsx +++ b/packages/mask/background/tasks/Cancellable/PopupSSR/worker.tsx @@ -1,37 +1,10 @@ // I'm a WebWorker! -import './worker_patch' // @ts-ignore -import { PopupSSR } from './loader' -import { renderToString } from 'react-dom/server' -import createCache from '@emotion/cache' -import { CacheProvider } from '@emotion/react' -import createEmotionServer from '@emotion/server/create-instance' -// TODO: -import { TssCacheProvider } from '../../../../../theme/node_modules/tss-react' +import { render } from './loader' +import type { PopupSSR_Props } from './type' -export async function main(): Promise<{ html: string; css: string }> { - return render() -} - -function serverCache(key: string) { - const cache = createCache({ key }) - return cache -} -function render() { - const muiCache = serverCache('mui') - const tssCache = serverCache('tss') - const tssServer = createEmotionServer(tssCache) - const muiServer = createEmotionServer(muiCache) - - const html = renderToString( - - - - - , - ) - const muiCSS = muiServer.constructStyleTagsFromChunks(muiServer.extractCriticalToChunks(html)) - const tssCSS = tssServer.constructStyleTagsFromChunks(tssServer.extractCriticalToChunks(html)) - return { html, css: muiCSS + tssCSS } +const Render: (props: PopupSSR_Props) => { html: string; css: string } = render +export async function main(props: PopupSSR_Props): Promise<{ html: string; css: string }> { + return Render(props) } diff --git a/packages/mask/background/tasks/Cancellable/PopupSSR/worker_init.ts b/packages/mask/background/tasks/Cancellable/PopupSSR/worker_init.ts index fe32745524e8..76e62e7b30eb 100644 --- a/packages/mask/background/tasks/Cancellable/PopupSSR/worker_init.ts +++ b/packages/mask/background/tasks/Cancellable/PopupSSR/worker_init.ts @@ -1,7 +1,9 @@ import { main } from './worker' +import { serializer } from '@masknet/shared-base' -globalThis.addEventListener('message', async () => { - const result = await main() +globalThis.addEventListener('message', async (event) => { + const data = serializer.deserialization(event.data) as any + const result = await main(data) globalThis.postMessage(result) }) globalThis.postMessage('alive') diff --git a/packages/mask/background/tasks/Cancellable/PopupSSR/worker_patch.js b/packages/mask/background/tasks/Cancellable/PopupSSR/worker_patch.js deleted file mode 100644 index 8337712ea57f..000000000000 --- a/packages/mask/background/tasks/Cancellable/PopupSSR/worker_patch.js +++ /dev/null @@ -1 +0,0 @@ -// diff --git a/packages/mask/src/setup.popup.ssr.tsx b/packages/mask/src/setup.popup.ssr.tsx index b645cf948036..c0996603aaec 100644 --- a/packages/mask/src/setup.popup.ssr.tsx +++ b/packages/mask/src/setup.popup.ssr.tsx @@ -1,19 +1,17 @@ -import { ThemeProvider } from '@emotion/react' -import { - ECKeyIdentifier, - PersonaInformation, - ProfileIdentifier, - i18NextInstance, - EnhanceableSite, - PopupRoutes, -} from '@masknet/shared-base' -import { Appearance } from '@masknet/theme' -import { enUS } from '@mui/material/locale' +import { i18NextInstance, EnhanceableSite, PopupRoutes } from '@masknet/shared-base' import { noop } from 'lodash-unified' -import { PersonaHomeUI } from './extension/popups/pages/Personas/Home/UI' -import { useClassicMaskFullPageTheme } from './utils/useClassicMaskFullPageTheme' +import { Appearance, TssCacheProvider } from '@masknet/theme' +import { ThemeProvider, CacheProvider } from '@emotion/react' +import { enUS } from '@mui/material/locale' +import { renderToString } from 'react-dom/server' +import createCache from '@emotion/cache' +import createEmotionServer from '@emotion/server/create-instance' +import { StaticRouter } from 'react-router-dom/server' import { initReactI18next } from 'react-i18next' import { addMaskI18N } from '../shared-ui/locales/languages' +import { PopupFrame } from './extension/popups/components/PopupFrame' +import { PersonaHomeUI } from './extension/popups/pages/Personas/Home/UI' +import { useClassicMaskFullPageTheme } from './utils/useClassicMaskFullPageTheme' import { FacebookColoredIcon, InstagramColoredIcon, @@ -21,17 +19,29 @@ import { TwitterColoredIcon, OpenSeaColoredIcon, } from '@masknet/icons' -import type { MergedProfileInformation } from './extension/popups/pages/Personas/components/ProfileList' -import { PopupFrame } from './extension/popups/components/PopupFrame' -import { StaticRouter } from 'react-router-dom/server' +import type { PopupSSR_Props } from '../background/tasks/Cancellable/PopupSSR/type' -initReactI18next.init(i18NextInstance) -addMaskI18N(i18NextInstance) +export function render(props: PopupSSR_Props) { + const muiCache = createCache({ key: 'mui' }) + const tssCache = createCache({ key: 'tss' }) + const tssServer = createEmotionServer(tssCache) + const muiServer = createEmotionServer(muiCache) -function useAlwaysLightTheme() { - return useClassicMaskFullPageTheme(Appearance.light, [enUS, false]) + const html = renderToString( + + + + + , + ) + const muiCSS = muiServer.constructStyleTagsFromChunks(muiServer.extractCriticalToChunks(html)) + const tssCSS = tssServer.constructStyleTagsFromChunks(tssServer.extractCriticalToChunks(html)) + return { html, css: muiCSS + tssCSS } } +initReactI18next.init(i18NextInstance) +addMaskI18N(i18NextInstance) + const SOCIAL_MEDIA_ICON_MAPPING: Record = { [EnhanceableSite.Twitter]: , [EnhanceableSite.Facebook]: , @@ -46,40 +56,31 @@ const DEFINED_SITES = [ EnhanceableSite.Instagram, EnhanceableSite.OpenSea, ] -export function PopupSSR() { - const i: PersonaInformation = { - identifier: new ECKeyIdentifier('secp256k1', 'abc'), - linkedProfiles: [ - { - identifier: new ProfileIdentifier('secp256k1', 'abc'), - nickname: 'Jack', - }, - ], - } - const b: MergedProfileInformation[] = [ - { - identifier: new ProfileIdentifier('twitter.com', 'jack'), - nickname: 'Jack', - }, - ] + +function useAlwaysLightTheme() { + return useClassicMaskFullPageTheme(Appearance.light, [enUS, false]) +} +function PopupSSR(props: PopupSSR_Props) { + const currentPersona = + props.personas && props.currentPersonaIndex ? props.personas[props.currentPersonaIndex] : void 0 return ( diff --git a/packages/theme/src/index.ts b/packages/theme/src/index.ts index 3af80710f206..2764905d6304 100644 --- a/packages/theme/src/index.ts +++ b/packages/theme/src/index.ts @@ -47,6 +47,7 @@ export * from './UIHelper/custom-ui-helper' export * from './CSSVariableInjector' export { getMaskColor, useMaskColor, MaskColorVar, applyMaskColorVars } from './constants' export type { MaskCSSVariableColor } from './constants' +export { TssCacheProvider } from 'tss-react' const query = '(prefers-color-scheme: dark)' export function useSystemPreferencePalette(): PaletteMode { From 50035e0c16a941a25649510f3f005708052bfcb5 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Fri, 1 Apr 2022 17:44:47 +0800 Subject: [PATCH 06/20] feat: ssr with data --- .../background/services/identity/index.ts | 6 ++ .../services/identity/persona/query.ts | 59 +++++++++++++++++++ .../services/identity/profile/query.ts | 42 +++++++++++++ .../Cancellable/PopupSSR/prepare-data.ts | 12 ++-- .../tasks/Cancellable/PopupSSR/type.ts | 13 ++-- packages/mask/background/tsconfig.json | 3 +- .../background-script/IdentityService.ts | 21 ------- .../popups/pages/Personas/Home/UI.tsx | 2 +- .../popups/pages/Personas/Home/index.tsx | 27 ++------- .../Personas/components/ProfileList/index.tsx | 7 ++- .../pages/Personas/hooks/usePersonaContext.ts | 2 +- packages/mask/src/setup.popup.ssr.tsx | 8 +-- 12 files changed, 135 insertions(+), 67 deletions(-) create mode 100644 packages/mask/background/services/identity/persona/query.ts create mode 100644 packages/mask/background/services/identity/profile/query.ts diff --git a/packages/mask/background/services/identity/index.ts b/packages/mask/background/services/identity/index.ts index 0196cfdcbe81..ce73908fb79c 100644 --- a/packages/mask/background/services/identity/index.ts +++ b/packages/mask/background/services/identity/index.ts @@ -1,3 +1,9 @@ export { createPersonaByPrivateKey } from './persona/create' export { signWithPersona, type SignRequest, type SignRequestResult, generateSignResult } from './persona/sign' export { exportPersonaMnemonicWords, exportPersonaPrivateKey } from './persona/backup' +export { queryOwnedPersonaInformation, queryCurrentPersona, queryCurrentPersona_internal } from './persona/query' +export { + type ProfileInformationWithNextID, + queryOwnedProfileInformationWithNextID, + queryOwnedProfileInformationWithNextID_internal, +} from './profile/query' diff --git a/packages/mask/background/services/identity/persona/query.ts b/packages/mask/background/services/identity/persona/query.ts new file mode 100644 index 000000000000..0bbf0b839f7b --- /dev/null +++ b/packages/mask/background/services/identity/persona/query.ts @@ -0,0 +1,59 @@ +import { ECKeyIdentifier, PersonaInformation, ProfileInformation } from '@masknet/shared-base' +import { queryAvatarDataURL } from '../../../database/avatar-cache/avatar' +import { queryPersonasDB, queryProfileDB } from '../../../database/persona/db' + +export async function queryOwnedPersonaInformation(): Promise { + const personas = await queryPersonasDB({ hasPrivateKey: true }) + const result: PersonaInformation[] = [] + for (const persona of personas.sort((a, b) => (a.updatedAt > b.updatedAt ? 1 : -1))) { + const map: ProfileInformation[] = [] + result.push({ + nickname: persona.nickname, + identifier: persona.identifier, + linkedProfiles: map, + publicHexKey: persona.publicHexKey, + }) + for (const [profile] of persona.linkedProfiles) { + const linkedProfile = await queryProfileDB(profile) + + map.push({ + identifier: profile, + nickname: linkedProfile?.nickname, + avatar: linkedProfile + ? await queryAvatarDataURL(linkedProfile.identifier).catch(() => undefined) + : undefined, + }) + } + } + return result +} + +export async function queryCurrentPersona(): Promise { + const id = await queryCurrentPersonaIdentifierUnchecked() + const owned = await queryOwnedPersonaInformation() + + if (!owned.length) return + if (!id) return owned[0].identifier + + if (owned.some((x) => x.identifier.equals(id))) return id + return owned[0].identifier +} + +/** @internal */ +export async function queryCurrentPersona_internal(owned: PersonaInformation[]) { + const id = await queryCurrentPersonaIdentifierUnchecked() + + if (!owned.length) return + if (!id) return owned[0].identifier + + if (owned.some((x) => x.identifier.equals(id))) return id + return owned[0].identifier +} + +async function queryCurrentPersonaIdentifierUnchecked(): Promise { + // TODO: This is a hack. We cannot access "settings" API in this TS project. This should be an temporally workaround. + const raw = 'settings+currentPersonaIdentifier' + const currentIdentifier = await browser.storage.local.get(raw) + if (!currentIdentifier[raw]) return + return ECKeyIdentifier.fromString(String(currentIdentifier[raw]), ECKeyIdentifier).unwrapOr(undefined) +} diff --git a/packages/mask/background/services/identity/profile/query.ts b/packages/mask/background/services/identity/profile/query.ts new file mode 100644 index 000000000000..fdadb81edf83 --- /dev/null +++ b/packages/mask/background/services/identity/profile/query.ts @@ -0,0 +1,42 @@ +import type { PersonaInformation, ProfileInformation, NextIDPlatform, PersonaIdentifier } from '@masknet/shared-base' +import { NextIDProof } from '@masknet/web3-providers' +import { queryCurrentPersona_internal, queryOwnedPersonaInformation } from '../persona/query' + +export interface ProfileInformationWithNextID extends ProfileInformation { + is_valid?: boolean + identity?: string + platform?: NextIDPlatform +} +export async function queryOwnedProfileInformationWithNextID() { + const list = await queryOwnedPersonaInformation() + const id = await queryCurrentPersona_internal(list) + return queryOwnedProfileInformationWithNextID_internal(list, id) +} +/** @internal */ +export async function queryOwnedProfileInformationWithNextID_internal( + ownedPersonas: PersonaInformation[], + currentPersonaID: PersonaIdentifier | undefined, +): Promise { + const currentPersona = ownedPersonas.find((x) => x.identifier.equals(currentPersonaID)) + + if (!currentPersona) return [] + if (!currentPersona.publicHexKey) return currentPersona.linkedProfiles + + const response = await NextIDProof.queryExistedBindingByPersona(currentPersona.publicHexKey) + if (!response) return currentPersona.linkedProfiles + + return currentPersona.linkedProfiles.map((profile) => { + const target = response.proofs.find( + (x) => + profile.identifier.userId.toLowerCase() === x.identity.toLowerCase() && + profile.identifier.network.replace('.com', '') === x.platform, + ) + + return { + ...profile, + platform: target?.platform, + identity: target?.identity, + is_valid: target?.is_valid, + } + }) +} diff --git a/packages/mask/background/tasks/Cancellable/PopupSSR/prepare-data.ts b/packages/mask/background/tasks/Cancellable/PopupSSR/prepare-data.ts index ca71ceeb1d65..49f9c95bc615 100644 --- a/packages/mask/background/tasks/Cancellable/PopupSSR/prepare-data.ts +++ b/packages/mask/background/tasks/Cancellable/PopupSSR/prepare-data.ts @@ -1,9 +1,11 @@ +import { queryOwnedPersonaInformation, queryCurrentPersona_internal } from '../../../services/identity' +import { queryOwnedProfileInformationWithNextID_internal } from '../../../services/identity/profile/query' import type { PopupSSR_Props } from './type' export async function prepareSSR(): Promise { - return { - currentPersonaIndex: 0, - mergedProfiles: [], - personas: [], - } + const personas = await queryOwnedPersonaInformation() + const currentPersona = await queryCurrentPersona_internal(personas) + const profilesWithNextID = await queryOwnedProfileInformationWithNextID_internal(personas, currentPersona) + + return { profilesWithNextID, currentPersona, personas } } diff --git a/packages/mask/background/tasks/Cancellable/PopupSSR/type.ts b/packages/mask/background/tasks/Cancellable/PopupSSR/type.ts index eff986fa84f7..248635bdcd52 100644 --- a/packages/mask/background/tasks/Cancellable/PopupSSR/type.ts +++ b/packages/mask/background/tasks/Cancellable/PopupSSR/type.ts @@ -1,13 +1,8 @@ -import type { NextIDPlatform, PersonaInformation, ProfileInformation } from '@masknet/shared-base' +import type { PersonaIdentifier, PersonaInformation } from '@masknet/shared-base' +import type { ProfileInformationWithNextID } from '../../../services/identity/profile/query' export interface PopupSSR_Props { personas: PersonaInformation[] | undefined - currentPersonaIndex: number | undefined - mergedProfiles: MergedProfileInformation[] -} - -export interface MergedProfileInformation extends ProfileInformation { - is_valid?: boolean - identity?: string - platform?: NextIDPlatform + currentPersona: PersonaIdentifier | undefined + profilesWithNextID: ProfileInformationWithNextID[] } diff --git a/packages/mask/background/tsconfig.json b/packages/mask/background/tsconfig.json index b97bc2510f7c..6abcef6274e0 100644 --- a/packages/mask/background/tsconfig.json +++ b/packages/mask/background/tsconfig.json @@ -14,6 +14,7 @@ { "path": "../shared" }, { "path": "../utils-pure" }, { "path": "../../encryption" }, - { "path": "../../gun-utils" } + { "path": "../../gun-utils" }, + { "path": "../../web3-providers" } ] } diff --git a/packages/mask/src/extension/background-script/IdentityService.ts b/packages/mask/src/extension/background-script/IdentityService.ts index ba1095534d49..3235fba1b8e1 100644 --- a/packages/mask/src/extension/background-script/IdentityService.ts +++ b/packages/mask/src/extension/background-script/IdentityService.ts @@ -19,8 +19,6 @@ import { ProfileIdentifier, ECKeyIdentifierFromJsonWebKey, EC_JsonWebKey, - PersonaInformation, - ProfileInformation, PostIVIdentifier, RelationFavor, NextIDAction, @@ -160,25 +158,6 @@ export async function queryLastPersonaCreated() { return first(orderBy(all, (x) => x.createdAt, 'desc')) } -export async function queryOwnedPersonaInformation(): Promise { - const personas = await queryPersonas(undefined, true) - const result: PersonaInformation[] = [] - for (const persona of personas.sort((a, b) => (a.updatedAt > b.updatedAt ? 1 : -1))) { - const map: ProfileInformation[] = [] - result.push({ - nickname: persona.nickname, - identifier: persona.identifier, - linkedProfiles: map, - publicHexKey: persona.publicHexKey, - }) - for (const [profile] of persona.linkedProfiles) { - const linkedProfile = await queryProfile(profile) - - map.push({ identifier: profile, nickname: linkedProfile.nickname, avatar: linkedProfile.avatar }) - } - } - return result -} export async function restoreFromObject(object: null | BackupJSONFileLatest): Promise { if (!object) return null await restoreBackup(object) diff --git a/packages/mask/src/extension/popups/pages/Personas/Home/UI.tsx b/packages/mask/src/extension/popups/pages/Personas/Home/UI.tsx index 07d0d8b80f5b..2da2c91e0728 100644 --- a/packages/mask/src/extension/popups/pages/Personas/Home/UI.tsx +++ b/packages/mask/src/extension/popups/pages/Personas/Home/UI.tsx @@ -157,7 +157,7 @@ export const PersonaHomeUI = memo((props: PersonaHomeUIProps) => { onConfirmDisconnect={props.onConfirmDisconnect} onDisconnectProfile={props.onDisconnectProfile} openProfilePage={props.openProfilePage} - mergedProfiles={props.mergedProfiles} + profilesWithNextID={props.profilesWithNextID} definedSocialNetworks={props.definedSocialNetworks} SOCIAL_MEDIA_ICON_MAPPING={props.SOCIAL_MEDIA_ICON_MAPPING} /> diff --git a/packages/mask/src/extension/popups/pages/Personas/Home/index.tsx b/packages/mask/src/extension/popups/pages/Personas/Home/index.tsx index d370b51a0ce7..5d81bcb85464 100644 --- a/packages/mask/src/extension/popups/pages/Personas/Home/index.tsx +++ b/packages/mask/src/extension/popups/pages/Personas/Home/index.tsx @@ -57,27 +57,10 @@ const PersonaHome = memo(() => { [currentPersona], ) - const { value: mergedProfiles, retry: refreshProfileList } = useAsyncRetry(async () => { - if (!currentPersona) return [] - if (!currentPersona.publicHexKey) return currentPersona.linkedProfiles - const response = await NextIDProof.queryExistedBindingByPersona(currentPersona.publicHexKey) - if (!response) return currentPersona.linkedProfiles - - return currentPersona.linkedProfiles.map((profile) => { - const target = response.proofs.find( - (x) => - profile.identifier.userId.toLowerCase() === x.identity.toLowerCase() && - profile.identifier.network.replace('.com', '') === x.platform, - ) - - return { - ...profile, - platform: target?.platform, - identity: target?.identity, - is_valid: target?.is_valid, - } - }) - }, [currentPersona]) + const { value: profilesWithNextID, retry: refreshProfileList } = useAsyncRetry( + Services.Identity.queryOwnedProfileInformationWithNextID, + [currentPersona], + ) const [{ loading: confirmLoading }, onConfirmDisconnect] = useAsyncFn( async (unbind: UnbindStatus) => { @@ -121,7 +104,7 @@ const PersonaHome = memo(() => { onConnectNextID={onConnectNextID} onConnectProfile={onConnectProfile} onDisconnectProfile={Services.Identity.detachProfile} - mergedProfiles={mergedProfiles ?? EMPTY_LIST} + profilesWithNextID={profilesWithNextID ?? EMPTY_LIST} openProfilePage={Services.SocialNetwork.openProfilePage} SOCIAL_MEDIA_ICON_MAPPING={SOCIAL_MEDIA_ICON_MAPPING} definedSocialNetworks={definedSocialNetworks} diff --git a/packages/mask/src/extension/popups/pages/Personas/components/ProfileList/index.tsx b/packages/mask/src/extension/popups/pages/Personas/components/ProfileList/index.tsx index c337a3dac01d..b30e0f0327bc 100644 --- a/packages/mask/src/extension/popups/pages/Personas/components/ProfileList/index.tsx +++ b/packages/mask/src/extension/popups/pages/Personas/components/ProfileList/index.tsx @@ -7,6 +7,7 @@ import { makeStyles } from '@masknet/theme' import { useI18N } from '../../../../../../utils/i18n-next-ui' import { GrayMasks } from '@masknet/icons' import { DisconnectDialog } from '../DisconnectDialog' +import type { ProfileInformationWithNextID } from '../../../../../background-script/IdentityService' const useStyles = makeStyles()({ list: { @@ -112,7 +113,7 @@ export const ProfileList = memo((props: ProfileListProps) => { <> } @@ -154,7 +155,7 @@ interface ProfileListUIProps { const ProfileListUI = memo((props: ProfileListUIProps) => { const { definedSocialNetworks, - mergedProfiles: profiles, + profilesWithNextID: profiles, onConnectProfile, onConnectNextID, onDisconnect, diff --git a/packages/mask/src/extension/popups/pages/Personas/hooks/usePersonaContext.ts b/packages/mask/src/extension/popups/pages/Personas/hooks/usePersonaContext.ts index bb3ffe6c81f5..011ebaf41413 100644 --- a/packages/mask/src/extension/popups/pages/Personas/hooks/usePersonaContext.ts +++ b/packages/mask/src/extension/popups/pages/Personas/hooks/usePersonaContext.ts @@ -12,7 +12,7 @@ function usePersonaContext() { const [deletingPersona, setDeletingPersona] = useState() const currentIdentifier = useValueRef(currentPersonaIdentifier) - const { value: personas, retry } = useAsyncRetry(async () => Services.Identity.queryOwnedPersonaInformation()) + const { value: personas, retry } = useAsyncRetry(Services.Identity.queryOwnedPersonaInformation) useEffect(() => { return MaskMessages.events.ownPersonaChanged.on(retry) }, [retry]) diff --git a/packages/mask/src/setup.popup.ssr.tsx b/packages/mask/src/setup.popup.ssr.tsx index c0996603aaec..c917399f5957 100644 --- a/packages/mask/src/setup.popup.ssr.tsx +++ b/packages/mask/src/setup.popup.ssr.tsx @@ -22,6 +22,7 @@ import { import type { PopupSSR_Props } from '../background/tasks/Cancellable/PopupSSR/type' export function render(props: PopupSSR_Props) { + console.log('render with props', props) const muiCache = createCache({ key: 'mui' }) const tssCache = createCache({ key: 'tss' }) const tssServer = createEmotionServer(tssCache) @@ -61,15 +62,14 @@ function useAlwaysLightTheme() { return useClassicMaskFullPageTheme(Appearance.light, [enUS, false]) } function PopupSSR(props: PopupSSR_Props) { - const currentPersona = - props.personas && props.currentPersonaIndex ? props.personas[props.currentPersonaIndex] : void 0 + const currentPersona = props.personas?.find((x) => x.identifier.equals(props.currentPersona)) return ( - + Date: Fri, 1 Apr 2022 18:28:24 +0800 Subject: [PATCH 07/20] fix: first render fails --- .../tasks/Cancellable/PopupSSR/worker.tsx | 2 +- packages/mask/src/setup.popup.ssr.tsx | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/packages/mask/background/tasks/Cancellable/PopupSSR/worker.tsx b/packages/mask/background/tasks/Cancellable/PopupSSR/worker.tsx index 685a9e8089b2..24febb6aa52b 100644 --- a/packages/mask/background/tasks/Cancellable/PopupSSR/worker.tsx +++ b/packages/mask/background/tasks/Cancellable/PopupSSR/worker.tsx @@ -4,7 +4,7 @@ import { render } from './loader' import type { PopupSSR_Props } from './type' -const Render: (props: PopupSSR_Props) => { html: string; css: string } = render +const Render: (props: PopupSSR_Props) => Promise<{ html: string; css: string }> = render export async function main(props: PopupSSR_Props): Promise<{ html: string; css: string }> { return Render(props) } diff --git a/packages/mask/src/setup.popup.ssr.tsx b/packages/mask/src/setup.popup.ssr.tsx index c917399f5957..2483b710d725 100644 --- a/packages/mask/src/setup.popup.ssr.tsx +++ b/packages/mask/src/setup.popup.ssr.tsx @@ -1,5 +1,5 @@ import { i18NextInstance, EnhanceableSite, PopupRoutes } from '@masknet/shared-base' -import { noop } from 'lodash-unified' +import { noop, once } from 'lodash-unified' import { Appearance, TssCacheProvider } from '@masknet/theme' import { ThemeProvider, CacheProvider } from '@emotion/react' import { enUS } from '@mui/material/locale' @@ -21,8 +21,14 @@ import { } from '@masknet/icons' import type { PopupSSR_Props } from '../background/tasks/Cancellable/PopupSSR/type' -export function render(props: PopupSSR_Props) { - console.log('render with props', props) +const init = once(() => + i18NextInstance.init().then(() => { + addMaskI18N(i18NextInstance) + initReactI18next.init(i18NextInstance) + }), +) +export async function render(props: PopupSSR_Props) { + await init() const muiCache = createCache({ key: 'mui' }) const tssCache = createCache({ key: 'tss' }) const tssServer = createEmotionServer(tssCache) @@ -40,9 +46,6 @@ export function render(props: PopupSSR_Props) { return { html, css: muiCSS + tssCSS } } -initReactI18next.init(i18NextInstance) -addMaskI18N(i18NextInstance) - const SOCIAL_MEDIA_ICON_MAPPING: Record = { [EnhanceableSite.Twitter]: , [EnhanceableSite.Facebook]: , From d3fee5e1f1145cbbf0862153c53e6a6abf02c180 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Fri, 1 Apr 2022 21:05:43 +0800 Subject: [PATCH 08/20] feat: full ssr --- packages/mask/public/popups-ssr.js | 26 +++++-- packages/mask/src/PopupSSR_Root.tsx | 69 ++++++++++++++++++ packages/mask/src/UIRoot.tsx | 9 ++- packages/mask/src/extension/popups/UI.tsx | 7 +- .../popups/components/PopupFrame/index.tsx | 2 +- .../popups/pages/Personas/Home/index.tsx | 4 +- .../pages/Personas/hooks/usePersonaContext.ts | 12 +++- packages/mask/src/extension/popups/render.tsx | 31 +++++++- .../plugins/ITO/SNSAdaptor/ClaimAllDialog.tsx | 2 +- packages/mask/src/setup.popup.ssr.tsx | 70 ++----------------- .../mask/src/utils/createNormalReactRoot.tsx | 34 ++++++--- 11 files changed, 174 insertions(+), 92 deletions(-) create mode 100644 packages/mask/src/PopupSSR_Root.tsx diff --git a/packages/mask/public/popups-ssr.js b/packages/mask/public/popups-ssr.js index e7db493a910c..f67b6f46677b 100644 --- a/packages/mask/public/popups-ssr.js +++ b/packages/mask/public/popups-ssr.js @@ -1,7 +1,25 @@ -browser.runtime.sendMessage({ type: 'popups-ssr' }).then(({ html, css }) => { - document.head.insertAdjacentHTML('beforeend', css) - document.body.innerHTML = '
' + html + '
' -}) +if (location.hash === '') location.hash = '#/personas' +if (location.hash === '#/personas') { + console.time('[SSR] Request') + browser.runtime.sendMessage({ type: 'popups-ssr' }).then(({ html, css }) => { + // Hmm, React goes first + if (document.querySelector('#root')) return + console.timeEnd('[SSR] Request') + console.time('[SSR] Hydrate') + document.head.insertAdjacentHTML('beforeend', css) + document.body.innerHTML = '
' + html + '
' + }) +} + +load() +async function load() { + const html = await fetch('/popups.html').then((x) => x.text()) + const parser = new DOMParser() + const doc = parser.parseFromString(html, 'text/html') + for (const script of doc.body.querySelectorAll('script')) { + import(new URL(script.src, location.href).toString()) + } +} // As the return value of the executeScript undefined diff --git a/packages/mask/src/PopupSSR_Root.tsx b/packages/mask/src/PopupSSR_Root.tsx new file mode 100644 index 000000000000..6ab2a8608f10 --- /dev/null +++ b/packages/mask/src/PopupSSR_Root.tsx @@ -0,0 +1,69 @@ +import { EnhanceableSite, PopupRoutes } from '@masknet/shared-base' +import { noop } from 'lodash-unified' +import { Appearance, MaskThemeProvider } from '@masknet/theme' +import { enUS } from '@mui/material/locale' +import { StaticRouter } from 'react-router-dom/server' +import { PopupFrame } from './extension/popups/components/PopupFrame' +import { PersonaHomeUI } from './extension/popups/pages/Personas/Home/UI' +import { useClassicMaskFullPageTheme } from './utils/useClassicMaskFullPageTheme' +import { + FacebookColoredIcon, + InstagramColoredIcon, + MindsIcon, + TwitterColoredIcon, + OpenSeaColoredIcon, +} from '@masknet/icons' +import type { PopupSSR_Props } from '../background/tasks/Cancellable/PopupSSR/type' +import { Suspense } from 'react' + +const SOCIAL_MEDIA_ICON_MAPPING: Record = { + [EnhanceableSite.Facebook]: , + [EnhanceableSite.Twitter]: , + [EnhanceableSite.Instagram]: , + [EnhanceableSite.Minds]: , + [EnhanceableSite.OpenSea]: , +} +const DEFINED_SITES = [ + EnhanceableSite.Facebook, + EnhanceableSite.Twitter, + EnhanceableSite.Instagram, + EnhanceableSite.Minds, + EnhanceableSite.OpenSea, +] +function useAlwaysLightTheme() { + return useClassicMaskFullPageTheme(Appearance.light, [enUS, false]) +} +export function PopupSSR(props: PopupSSR_Props) { + const currentPersona = props.personas?.find((x) => x.identifier.equals(props.currentPersona)) + return ( + + 'light'}> + + + + + + + + + + ) +} diff --git a/packages/mask/src/UIRoot.tsx b/packages/mask/src/UIRoot.tsx index aa9a5f12c085..9a9dc2b98630 100644 --- a/packages/mask/src/UIRoot.tsx +++ b/packages/mask/src/UIRoot.tsx @@ -1,6 +1,6 @@ import { Suspense } from 'react' import { Web3Provider } from '@masknet/web3-shared-evm' -import { CssBaseline, StyledEngineProvider, Theme } from '@mui/material' +import { StyledEngineProvider, Theme } from '@mui/material' import { NetworkPluginID, PluginsWeb3ContextProvider, useAllPluginsWeb3State } from '@masknet/plugin-infra' import { I18NextProviderHMR, SharedContextProvider } from '@masknet/shared' import { ErrorBoundary, ErrorBoundaryBuildInfoContext, useValueRef } from '@masknet/shared-base-ui' @@ -57,10 +57,9 @@ export function MaskUIRoot({ children, kind, useTheme }: MaskUIRootProps) { useMaskIconPalette={useMaskIconPalette} CustomSnackbarOffsetY={isFacebook(activatedSocialNetworkUI) ? 80 : undefined} useTheme={useTheme} - baseline={kind === 'page'}> - - {jsx} - + baseline={kind === 'page'} + children={jsx} + /> ), (jsx) => {jsx}, ) diff --git a/packages/mask/src/extension/popups/UI.tsx b/packages/mask/src/extension/popups/UI.tsx index aeb0b48db96d..b996e16c42f3 100644 --- a/packages/mask/src/extension/popups/UI.tsx +++ b/packages/mask/src/extension/popups/UI.tsx @@ -1,4 +1,4 @@ -import { lazy } from 'react' +import { lazy, useEffect, useState } from 'react' import { Navigate, Route, Routes, HashRouter } from 'react-router-dom' import { createInjectHooksRenderer, useActivatedPluginsDashboard } from '@masknet/plugin-infra' import { PopupRoutes } from '@masknet/shared-base' @@ -26,6 +26,9 @@ const PluginRender = createInjectHooksRenderer(useActivatedPluginsDashboard, (x) export default function Popups() { const personaLength = useMyPersonas().length + const [client, setClient] = useState(false) + useEffect(() => setClient(true), []) + return ( @@ -43,7 +46,7 @@ export default function Popups() { } />
{/* TODO: Should only load plugins when the page is plugin-aware. */} - + {client ? : null}
diff --git a/packages/mask/src/extension/popups/components/PopupFrame/index.tsx b/packages/mask/src/extension/popups/components/PopupFrame/index.tsx index 82f307209b42..063cf0f52a4e 100644 --- a/packages/mask/src/extension/popups/components/PopupFrame/index.tsx +++ b/packages/mask/src/extension/popups/components/PopupFrame/index.tsx @@ -18,7 +18,7 @@ function GlobalCss() { overflowX: 'hidden', margin: '0 auto !important', maxWidth: '100%', - '-webkit-font-smoothing': 'subpixel-antialiased', + WebkitFontSmoothing: 'subpixel-antialiased', '&::-webkit-scrollbar': { display: 'none', }, diff --git a/packages/mask/src/extension/popups/pages/Personas/Home/index.tsx b/packages/mask/src/extension/popups/pages/Personas/Home/index.tsx index 5d81bcb85464..599b1e99f82a 100644 --- a/packages/mask/src/extension/popups/pages/Personas/Home/index.tsx +++ b/packages/mask/src/extension/popups/pages/Personas/Home/index.tsx @@ -1,5 +1,5 @@ import { memo, useCallback } from 'react' -import { PersonaContext } from '../hooks/usePersonaContext' +import { initData, PersonaContext } from '../hooks/usePersonaContext' import { useNavigate } from 'react-router-dom' import { PersonaHomeUI } from './UI' import { @@ -57,7 +57,7 @@ const PersonaHome = memo(() => { [currentPersona], ) - const { value: profilesWithNextID, retry: refreshProfileList } = useAsyncRetry( + const { value: profilesWithNextID = initData.profiles, retry: refreshProfileList } = useAsyncRetry( Services.Identity.queryOwnedProfileInformationWithNextID, [currentPersona], ) diff --git a/packages/mask/src/extension/popups/pages/Personas/hooks/usePersonaContext.ts b/packages/mask/src/extension/popups/pages/Personas/hooks/usePersonaContext.ts index 011ebaf41413..5f40f5d421a7 100644 --- a/packages/mask/src/extension/popups/pages/Personas/hooks/usePersonaContext.ts +++ b/packages/mask/src/extension/popups/pages/Personas/hooks/usePersonaContext.ts @@ -7,12 +7,20 @@ import Services from '../../../../service' import { head } from 'lodash-unified' import { useEffect, useState } from 'react' import { MaskMessages } from '../../../../../utils' +import type { ProfileInformationWithNextID } from '../../../../background-script/IdentityService' +export const initData: { + currentIdentifier?: string + personas?: PersonaInformation[] + profiles?: ProfileInformationWithNextID[] +} = {} function usePersonaContext() { const [deletingPersona, setDeletingPersona] = useState() - const currentIdentifier = useValueRef(currentPersonaIdentifier) - const { value: personas, retry } = useAsyncRetry(Services.Identity.queryOwnedPersonaInformation) + let currentIdentifier = useValueRef(currentPersonaIdentifier) + if (!currentPersonaIdentifier.ready && initData.currentIdentifier) currentIdentifier = initData.currentIdentifier + + const { value: personas = initData.personas, retry } = useAsyncRetry(Services.Identity.queryOwnedPersonaInformation) useEffect(() => { return MaskMessages.events.ownPersonaChanged.on(retry) }, [retry]) diff --git a/packages/mask/src/extension/popups/render.tsx b/packages/mask/src/extension/popups/render.tsx index 496c8f5138ba..3dc09c90ca7c 100644 --- a/packages/mask/src/extension/popups/render.tsx +++ b/packages/mask/src/extension/popups/render.tsx @@ -1,12 +1,39 @@ import { startPluginDashboard } from '@masknet/plugin-infra' -import { createNormalReactRoot } from '../../utils' +import { createNormalReactRoot, hydrateNormalReactRoot } from '../../utils' import { createPluginHost } from '../../plugin-infra/host' import { Services } from '../service' import { status } from '../../setup.ui' import Popups from './UI' import { InMemoryStorages, PersistentStorages } from '../../../shared/kv-storage' +import createCache from '@emotion/cache' +import { CacheProvider } from '@emotion/react' +import { TssCacheProvider } from '@masknet/theme' +import { initData } from './pages/Personas/hooks/usePersonaContext' -status.then(() => createNormalReactRoot()) +if (location.hash === '' || location.hash === '#/personas') { + async function hydrate() { + await Promise.all([ + Services.Identity.queryCurrentPersona().then((x) => (initData.currentIdentifier = x?.toText())), + Services.Identity.queryOwnedPersonaInformation().then((x) => (initData.personas = x)), + Services.Identity.queryOwnedProfileInformationWithNextID().then((x) => (initData.profiles = x)), + status, + ]) + + const muiCache = createCache({ key: 'css' }) + const tssCache = createCache({ key: 'tss' }) + hydrateNormalReactRoot( + + + + + , + ) + console.timeEnd('[SSR] Hydrate') + } + hydrate() +} else { + status.then(() => createNormalReactRoot()) +} // TODO: Should only load plugins when the page is plugin-aware. startPluginDashboard( diff --git a/packages/mask/src/plugins/ITO/SNSAdaptor/ClaimAllDialog.tsx b/packages/mask/src/plugins/ITO/SNSAdaptor/ClaimAllDialog.tsx index d58a66ae9710..6beab8740f0e 100644 --- a/packages/mask/src/plugins/ITO/SNSAdaptor/ClaimAllDialog.tsx +++ b/packages/mask/src/plugins/ITO/SNSAdaptor/ClaimAllDialog.tsx @@ -95,7 +95,7 @@ const useStyles = makeStyles()((theme, props) => { width: '100%', alignItems: 'center', justifyContent: 'space-between', - '-webkit-font-smoothing': 'antialiased', + WebkitFontSmoothing: 'antialiased', fontSize: 14, }, cardHeaderLocked: { diff --git a/packages/mask/src/setup.popup.ssr.tsx b/packages/mask/src/setup.popup.ssr.tsx index 2483b710d725..4d109b2b49c1 100644 --- a/packages/mask/src/setup.popup.ssr.tsx +++ b/packages/mask/src/setup.popup.ssr.tsx @@ -1,25 +1,14 @@ -import { i18NextInstance, EnhanceableSite, PopupRoutes } from '@masknet/shared-base' -import { noop, once } from 'lodash-unified' -import { Appearance, TssCacheProvider } from '@masknet/theme' -import { ThemeProvider, CacheProvider } from '@emotion/react' -import { enUS } from '@mui/material/locale' +import { i18NextInstance } from '@masknet/shared-base' +import { once } from 'lodash-unified' +import { TssCacheProvider } from '@masknet/theme' +import { CacheProvider } from '@emotion/react' import { renderToString } from 'react-dom/server' import createCache from '@emotion/cache' import createEmotionServer from '@emotion/server/create-instance' -import { StaticRouter } from 'react-router-dom/server' import { initReactI18next } from 'react-i18next' import { addMaskI18N } from '../shared-ui/locales/languages' -import { PopupFrame } from './extension/popups/components/PopupFrame' -import { PersonaHomeUI } from './extension/popups/pages/Personas/Home/UI' -import { useClassicMaskFullPageTheme } from './utils/useClassicMaskFullPageTheme' -import { - FacebookColoredIcon, - InstagramColoredIcon, - MindsIcon, - TwitterColoredIcon, - OpenSeaColoredIcon, -} from '@masknet/icons' import type { PopupSSR_Props } from '../background/tasks/Cancellable/PopupSSR/type' +import { PopupSSR } from './PopupSSR_Root' const init = once(() => i18NextInstance.init().then(() => { @@ -29,7 +18,7 @@ const init = once(() => ) export async function render(props: PopupSSR_Props) { await init() - const muiCache = createCache({ key: 'mui' }) + const muiCache = createCache({ key: 'css' }) const tssCache = createCache({ key: 'tss' }) const tssServer = createEmotionServer(tssCache) const muiServer = createEmotionServer(muiCache) @@ -40,53 +29,8 @@ export async function render(props: PopupSSR_Props) { , - ) + ).replaceAll('href="/', 'href="#/') const muiCSS = muiServer.constructStyleTagsFromChunks(muiServer.extractCriticalToChunks(html)) const tssCSS = tssServer.constructStyleTagsFromChunks(tssServer.extractCriticalToChunks(html)) return { html, css: muiCSS + tssCSS } } - -const SOCIAL_MEDIA_ICON_MAPPING: Record = { - [EnhanceableSite.Twitter]: , - [EnhanceableSite.Facebook]: , - [EnhanceableSite.Minds]: , - [EnhanceableSite.Instagram]: , - [EnhanceableSite.OpenSea]: , -} -const DEFINED_SITES = [ - EnhanceableSite.Twitter, - EnhanceableSite.Facebook, - EnhanceableSite.Minds, - EnhanceableSite.Instagram, - EnhanceableSite.OpenSea, -] - -function useAlwaysLightTheme() { - return useClassicMaskFullPageTheme(Appearance.light, [enUS, false]) -} -function PopupSSR(props: PopupSSR_Props) { - const currentPersona = props.personas?.find((x) => x.identifier.equals(props.currentPersona)) - return ( - - - - - - - - ) -} diff --git a/packages/mask/src/utils/createNormalReactRoot.tsx b/packages/mask/src/utils/createNormalReactRoot.tsx index da1deea5d468..ba9e2b113d33 100644 --- a/packages/mask/src/utils/createNormalReactRoot.tsx +++ b/packages/mask/src/utils/createNormalReactRoot.tsx @@ -1,25 +1,39 @@ import { StrictMode } from 'react' -import { createRoot } from 'react-dom/client' +import { createRoot, hydrateRoot } from 'react-dom/client' import { ErrorBoundary } from '@masknet/shared-base-ui' import { DisableShadowRootContext } from '@masknet/theme' -export function createNormalReactRoot(jsx: JSX.Element, container?: HTMLElement) { +function cleanup() { + if (process.env.NODE_ENV === 'development') { + // Make the document cleaner + setTimeout(() => [...document.querySelectorAll('script')].forEach((x) => x.remove()), 200) + } +} +function getContainer(container?: HTMLElement) { if (!container) container = document.getElementById('root') ?? void 0 if (!container) { container = document.createElement('div') document.body.appendChild(container) } - - if (process.env.NODE_ENV === 'development') { - // Make the document cleaner - setTimeout(() => [...document.querySelectorAll('script')].forEach((x) => x.remove()), 200) - } - - return createRoot(container).render( + return container +} +function Root(jsx: JSX.Element) { + return ( {jsx} - , + ) } +export function createNormalReactRoot(jsx: JSX.Element, dom?: HTMLElement) { + cleanup() + const container = getContainer(dom) + return createRoot(container).render(Root(jsx)) +} + +export function hydrateNormalReactRoot(jsx: JSX.Element, dom?: HTMLElement) { + cleanup() + const container = getContainer(dom) + return hydrateRoot(container, Root(jsx)) +} From db4865f82655c37cd2e7d5656b42f09f0b8d0bd6 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Sat, 2 Apr 2022 13:53:13 +0800 Subject: [PATCH 09/20] feat: support langs --- .../services/identity/persona/query.ts | 8 ++--- .../background/services/settings/index.ts | 9 ++++++ .../background/services/settings/utils.ts | 31 +++++++++++++++++++ .../tasks/Cancellable/PopupSSR/index.mv3.ts | 5 ++- .../Cancellable/PopupSSR/prepare-data.ts | 9 +++++- .../tasks/Cancellable/PopupSSR/type.ts | 2 ++ packages/mask/src/PopupSSR_Root.tsx | 14 +++++++-- packages/mask/src/setup.popup.ssr.tsx | 7 +++-- 8 files changed, 70 insertions(+), 15 deletions(-) create mode 100644 packages/mask/background/services/settings/index.ts create mode 100644 packages/mask/background/services/settings/utils.ts diff --git a/packages/mask/background/services/identity/persona/query.ts b/packages/mask/background/services/identity/persona/query.ts index 0bbf0b839f7b..faeadc5f2d9e 100644 --- a/packages/mask/background/services/identity/persona/query.ts +++ b/packages/mask/background/services/identity/persona/query.ts @@ -1,6 +1,7 @@ import { ECKeyIdentifier, PersonaInformation, ProfileInformation } from '@masknet/shared-base' import { queryAvatarDataURL } from '../../../database/avatar-cache/avatar' import { queryPersonasDB, queryProfileDB } from '../../../database/persona/db' +import { getBrowserStorageUnchecked, InternalStorageKeys } from '../../settings/utils' export async function queryOwnedPersonaInformation(): Promise { const personas = await queryPersonasDB({ hasPrivateKey: true }) @@ -51,9 +52,6 @@ export async function queryCurrentPersona_internal(owned: PersonaInformation[]) } async function queryCurrentPersonaIdentifierUnchecked(): Promise { - // TODO: This is a hack. We cannot access "settings" API in this TS project. This should be an temporally workaround. - const raw = 'settings+currentPersonaIdentifier' - const currentIdentifier = await browser.storage.local.get(raw) - if (!currentIdentifier[raw]) return - return ECKeyIdentifier.fromString(String(currentIdentifier[raw]), ECKeyIdentifier).unwrapOr(undefined) + const raw = String(await getBrowserStorageUnchecked(InternalStorageKeys.currentPersona)) + return ECKeyIdentifier.fromString(raw, ECKeyIdentifier).unwrapOr(undefined) } diff --git a/packages/mask/background/services/settings/index.ts b/packages/mask/background/services/settings/index.ts new file mode 100644 index 000000000000..35ee438398fd --- /dev/null +++ b/packages/mask/background/services/settings/index.ts @@ -0,0 +1,9 @@ +import { LanguageOptions } from '@masknet/public-api' +import { getBrowserStorageUnchecked, InternalStorageKeys } from './utils' + +export async function getLanguagePreference(): Promise { + const raw = String(await getBrowserStorageUnchecked(InternalStorageKeys.language)) + + if (Object.values(LanguageOptions).some((x) => x === raw)) return raw as LanguageOptions + return LanguageOptions.__auto__ +} diff --git a/packages/mask/background/services/settings/utils.ts b/packages/mask/background/services/settings/utils.ts new file mode 100644 index 000000000000..06fd8e1b71de --- /dev/null +++ b/packages/mask/background/services/settings/utils.ts @@ -0,0 +1,31 @@ +// TODO: This is a hack. We cannot access "settings" API in this TS project. This should be an temporally workaround. +/** + * @internal + * @deprecated + */ +export enum InternalStorageKeys { + currentPersona = 'settings+currentPersonaIdentifier', + language = 'settings+language', +} +/** + * @internal + * @deprecated + */ +export async function getBrowserStorageUnchecked( + arg: InternalStorageKeys, +): Promise +export async function getBrowserStorageUnchecked( + ...args: T[] +): Promise> +export async function getBrowserStorageUnchecked( + ...args: T[] +): Promise> { + const raw_result = await browser.storage.local.get(args) + const result: Record = {} as any + + if (args.length === 1) return Reflect.get(raw_result, args[0]) + for (const [key, value] of Object.entries(raw_result)) { + Reflect.set(result, Reflect.get(InternalStorageKeys, key), value) + } + return result +} diff --git a/packages/mask/background/tasks/Cancellable/PopupSSR/index.mv3.ts b/packages/mask/background/tasks/Cancellable/PopupSSR/index.mv3.ts index d660935a864c..694f1b853676 100644 --- a/packages/mask/background/tasks/Cancellable/PopupSSR/index.mv3.ts +++ b/packages/mask/background/tasks/Cancellable/PopupSSR/index.mv3.ts @@ -1,3 +1,4 @@ +import { prepareSSR } from './prepare-data' export default async function PopupSSR(signal: AbortSignal) { browser.runtime.onMessage.addListener(f) signal.addEventListener('abort', () => browser.runtime.onMessage.removeListener(f), { once: true }) @@ -6,9 +7,7 @@ export default async function PopupSSR(signal: AbortSignal) { function f(message: any) { if (!(message.type === 'popups-ssr')) return return (async () => { - const x = import('./worker') - const y = import('./prepare-data').then((f) => f.prepareSSR()) - const [{ main }, data] = await Promise.all([x, y]) + const [{ main }, data] = await Promise.all([import('./worker'), prepareSSR()]) return main(data) })() } diff --git a/packages/mask/background/tasks/Cancellable/PopupSSR/prepare-data.ts b/packages/mask/background/tasks/Cancellable/PopupSSR/prepare-data.ts index 49f9c95bc615..621fac8a8456 100644 --- a/packages/mask/background/tasks/Cancellable/PopupSSR/prepare-data.ts +++ b/packages/mask/background/tasks/Cancellable/PopupSSR/prepare-data.ts @@ -1,11 +1,18 @@ import { queryOwnedPersonaInformation, queryCurrentPersona_internal } from '../../../services/identity' import { queryOwnedProfileInformationWithNextID_internal } from '../../../services/identity/profile/query' +import { getLanguagePreference } from '../../../services/settings' import type { PopupSSR_Props } from './type' export async function prepareSSR(): Promise { + const language = getLanguagePreference() const personas = await queryOwnedPersonaInformation() const currentPersona = await queryCurrentPersona_internal(personas) const profilesWithNextID = await queryOwnedProfileInformationWithNextID_internal(personas, currentPersona) - return { profilesWithNextID, currentPersona, personas } + return { + profilesWithNextID, + currentPersona, + personas, + language: await language, + } } diff --git a/packages/mask/background/tasks/Cancellable/PopupSSR/type.ts b/packages/mask/background/tasks/Cancellable/PopupSSR/type.ts index 248635bdcd52..0666db52cb4d 100644 --- a/packages/mask/background/tasks/Cancellable/PopupSSR/type.ts +++ b/packages/mask/background/tasks/Cancellable/PopupSSR/type.ts @@ -1,3 +1,4 @@ +import type { LanguageOptions } from '@masknet/public-api' import type { PersonaIdentifier, PersonaInformation } from '@masknet/shared-base' import type { ProfileInformationWithNextID } from '../../../services/identity/profile/query' @@ -5,4 +6,5 @@ export interface PopupSSR_Props { personas: PersonaInformation[] | undefined currentPersona: PersonaIdentifier | undefined profilesWithNextID: ProfileInformationWithNextID[] + language: LanguageOptions } diff --git a/packages/mask/src/PopupSSR_Root.tsx b/packages/mask/src/PopupSSR_Root.tsx index 6ab2a8608f10..b237094a9b84 100644 --- a/packages/mask/src/PopupSSR_Root.tsx +++ b/packages/mask/src/PopupSSR_Root.tsx @@ -1,7 +1,7 @@ -import { EnhanceableSite, PopupRoutes } from '@masknet/shared-base' +import { EnhanceableSite, i18NextInstance, PopupRoutes } from '@masknet/shared-base' import { noop } from 'lodash-unified' import { Appearance, MaskThemeProvider } from '@masknet/theme' -import { enUS } from '@mui/material/locale' +import { enUS, jaJP, koKR, Localization, zhTW, zhCN } from '@mui/material/locale' import { StaticRouter } from 'react-router-dom/server' import { PopupFrame } from './extension/popups/components/PopupFrame' import { PersonaHomeUI } from './extension/popups/pages/Personas/Home/UI' @@ -15,6 +15,7 @@ import { } from '@masknet/icons' import type { PopupSSR_Props } from '../background/tasks/Cancellable/PopupSSR/type' import { Suspense } from 'react' +import { SupportedLanguages } from '@masknet/public-api' const SOCIAL_MEDIA_ICON_MAPPING: Record = { [EnhanceableSite.Facebook]: , @@ -30,8 +31,15 @@ const DEFINED_SITES = [ EnhanceableSite.Minds, EnhanceableSite.OpenSea, ] +const LANGS: Record = { + [SupportedLanguages.enUS]: enUS, + [SupportedLanguages.jaJP]: jaJP, + [SupportedLanguages.koKR]: koKR, + [SupportedLanguages.zhCN]: zhCN, + [SupportedLanguages.zhTW]: zhTW, +} function useAlwaysLightTheme() { - return useClassicMaskFullPageTheme(Appearance.light, [enUS, false]) + return useClassicMaskFullPageTheme(Appearance.light, [Reflect.get(LANGS, i18NextInstance.language) || enUS, false]) } export function PopupSSR(props: PopupSSR_Props) { const currentPersona = props.personas?.find((x) => x.identifier.equals(props.currentPersona)) diff --git a/packages/mask/src/setup.popup.ssr.tsx b/packages/mask/src/setup.popup.ssr.tsx index 4d109b2b49c1..21b55e57bfad 100644 --- a/packages/mask/src/setup.popup.ssr.tsx +++ b/packages/mask/src/setup.popup.ssr.tsx @@ -1,4 +1,4 @@ -import { i18NextInstance } from '@masknet/shared-base' +import { i18NextInstance, updateLanguage } from '@masknet/shared-base' import { once } from 'lodash-unified' import { TssCacheProvider } from '@masknet/theme' import { CacheProvider } from '@emotion/react' @@ -10,14 +10,15 @@ import { addMaskI18N } from '../shared-ui/locales/languages' import type { PopupSSR_Props } from '../background/tasks/Cancellable/PopupSSR/type' import { PopupSSR } from './PopupSSR_Root' -const init = once(() => +const init = once((props: PopupSSR_Props) => i18NextInstance.init().then(() => { + updateLanguage(props.language) addMaskI18N(i18NextInstance) initReactI18next.init(i18NextInstance) }), ) export async function render(props: PopupSSR_Props) { - await init() + await init(props) const muiCache = createCache({ key: 'css' }) const tssCache = createCache({ key: 'tss' }) const tssServer = createEmotionServer(tssCache) From 1123df7ffee3cfc003a469801dfdb74dd796801c Mon Sep 17 00:00:00 2001 From: Jack Works Date: Sat, 2 Apr 2022 14:25:09 +0800 Subject: [PATCH 10/20] fix: ssr langs --- .../tasks/Cancellable/PopupSSR/cache.ts | 26 +++++++++++++++++++ .../tasks/Cancellable/PopupSSR/index.mv3.ts | 12 +++++---- .../tasks/Cancellable/PopupSSR/index.ts | 20 +++++++------- packages/mask/src/extension/popups/render.tsx | 3 +++ packages/mask/src/setup.popup.ssr.tsx | 2 +- 5 files changed, 46 insertions(+), 17 deletions(-) create mode 100644 packages/mask/background/tasks/Cancellable/PopupSSR/cache.ts diff --git a/packages/mask/background/tasks/Cancellable/PopupSSR/cache.ts b/packages/mask/background/tasks/Cancellable/PopupSSR/cache.ts new file mode 100644 index 000000000000..adbd479f9936 --- /dev/null +++ b/packages/mask/background/tasks/Cancellable/PopupSSR/cache.ts @@ -0,0 +1,26 @@ +import { MaskMessages } from '../../../../shared/messages' +import { InternalStorageKeys } from '../../../services/settings/utils' +import { prepareSSR } from './prepare-data' +import type { PopupSSR_Props } from './type' + +export let cache: { html: string; css: string } = { html: '', css: '' } +export function startListen( + render: (props: PopupSSR_Props) => Promise<{ html: string; css: string }>, + signal: AbortSignal, +) { + async function task() { + cache = await prepareSSR().then(render) + console.trace('popup ssr ready.') + } + + MaskMessages.events.createInternalSettingsChanged.on(console.log, { signal }) + MaskMessages.events.createInternalSettingsUpdated.on(console.log, { signal }) + MaskMessages.events.createInternalSettingsUpdated.on( + (event) => { + if (event.initial) return + if (event.key === InternalStorageKeys.currentPersona || event.key === InternalStorageKeys.language) task() + }, + { signal }, + ) + task() +} diff --git a/packages/mask/background/tasks/Cancellable/PopupSSR/index.mv3.ts b/packages/mask/background/tasks/Cancellable/PopupSSR/index.mv3.ts index 694f1b853676..7c9afadbe345 100644 --- a/packages/mask/background/tasks/Cancellable/PopupSSR/index.mv3.ts +++ b/packages/mask/background/tasks/Cancellable/PopupSSR/index.mv3.ts @@ -1,13 +1,15 @@ -import { prepareSSR } from './prepare-data' +import { cache, startListen } from './cache' export default async function PopupSSR(signal: AbortSignal) { browser.runtime.onMessage.addListener(f) signal.addEventListener('abort', () => browser.runtime.onMessage.removeListener(f), { once: true }) + + startListen(async (props) => { + const { main } = await import('./worker') + return main(props) + }, signal) } function f(message: any) { if (!(message.type === 'popups-ssr')) return - return (async () => { - const [{ main }, data] = await Promise.all([import('./worker'), prepareSSR()]) - return main(data) - })() + return Promise.resolve(cache) } diff --git a/packages/mask/background/tasks/Cancellable/PopupSSR/index.ts b/packages/mask/background/tasks/Cancellable/PopupSSR/index.ts index c77a390c0f8b..52c411802602 100644 --- a/packages/mask/background/tasks/Cancellable/PopupSSR/index.ts +++ b/packages/mask/background/tasks/Cancellable/PopupSSR/index.ts @@ -1,6 +1,6 @@ import { serializer } from '@masknet/shared-base' import { OnDemandWorker } from '../../../../utils-pure/OnDemandWorker' -import { prepareSSR } from './prepare-data' +import { cache, startListen } from './cache' const worker = new OnDemandWorker(new URL('./worker_init.ts', import.meta.url), { name: 'PopupSSR' }) export default async function PopupSSR(signal: AbortSignal) { @@ -14,20 +14,18 @@ export default async function PopupSSR(signal: AbortSignal) { }, { once: true }, ) + + startListen((props) => { + return new Promise((resolve) => { + Promise.resolve(serializer.serialization(props)).then((data) => worker.postMessage(data)) + worker.addEventListener('message', (data) => resolve(data.data), { once: true }) + }) + }, signal) } function f(message: any) { if (!(message.type === 'popups-ssr')) return return new Promise((resolve) => { - prepareSSR() - .then(serializer.serialization) - .then((data) => worker.postMessage(data)) - worker.addEventListener( - 'message', - (data) => { - resolve(data.data) - }, - { once: true }, - ) + resolve(cache) }) } diff --git a/packages/mask/src/extension/popups/render.tsx b/packages/mask/src/extension/popups/render.tsx index 3dc09c90ca7c..45ab8a62e79b 100644 --- a/packages/mask/src/extension/popups/render.tsx +++ b/packages/mask/src/extension/popups/render.tsx @@ -12,6 +12,8 @@ import { initData } from './pages/Personas/hooks/usePersonaContext' if (location.hash === '' || location.hash === '#/personas') { async function hydrate() { + import('./pages/Personas') + import('./pages/Personas/Home') await Promise.all([ Services.Identity.queryCurrentPersona().then((x) => (initData.currentIdentifier = x?.toText())), Services.Identity.queryOwnedPersonaInformation().then((x) => (initData.personas = x)), @@ -28,6 +30,7 @@ if (location.hash === '' || location.hash === '#/personas') { , ) + import('./pages/Wallet') console.timeEnd('[SSR] Hydrate') } hydrate() diff --git a/packages/mask/src/setup.popup.ssr.tsx b/packages/mask/src/setup.popup.ssr.tsx index 21b55e57bfad..8d31d7fd8333 100644 --- a/packages/mask/src/setup.popup.ssr.tsx +++ b/packages/mask/src/setup.popup.ssr.tsx @@ -12,12 +12,12 @@ import { PopupSSR } from './PopupSSR_Root' const init = once((props: PopupSSR_Props) => i18NextInstance.init().then(() => { - updateLanguage(props.language) addMaskI18N(i18NextInstance) initReactI18next.init(i18NextInstance) }), ) export async function render(props: PopupSSR_Props) { + updateLanguage(props.language) await init(props) const muiCache = createCache({ key: 'css' }) const tssCache = createCache({ key: 'tss' }) From b72dc4f7160914439ce974c125f6bd4ec12f6d0b Mon Sep 17 00:00:00 2001 From: Jack Works Date: Sat, 2 Apr 2022 14:47:20 +0800 Subject: [PATCH 11/20] fix: ssr cache --- .../tasks/Cancellable/PopupSSR/cache.ts | 17 +++++----- .../pages/Personas/hooks/usePersonaContext.ts | 31 ++++++++++++------- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/packages/mask/background/tasks/Cancellable/PopupSSR/cache.ts b/packages/mask/background/tasks/Cancellable/PopupSSR/cache.ts index adbd479f9936..45253e2b2ade 100644 --- a/packages/mask/background/tasks/Cancellable/PopupSSR/cache.ts +++ b/packages/mask/background/tasks/Cancellable/PopupSSR/cache.ts @@ -1,3 +1,4 @@ +import { throttle } from 'lodash-unified' import { MaskMessages } from '../../../../shared/messages' import { InternalStorageKeys } from '../../../services/settings/utils' import { prepareSSR } from './prepare-data' @@ -8,13 +9,16 @@ export function startListen( render: (props: PopupSSR_Props) => Promise<{ html: string; css: string }>, signal: AbortSignal, ) { - async function task() { - cache = await prepareSSR().then(render) - console.trace('popup ssr ready.') - } + const task = throttle( + async function task() { + cache = await prepareSSR().then(render) + }, + 2000, + { leading: true }, + ) - MaskMessages.events.createInternalSettingsChanged.on(console.log, { signal }) - MaskMessages.events.createInternalSettingsUpdated.on(console.log, { signal }) + task()?.then(() => console.log('[Popup SSR] Page ready.')) + MaskMessages.events.ownPersonaChanged.on(task, { signal }) MaskMessages.events.createInternalSettingsUpdated.on( (event) => { if (event.initial) return @@ -22,5 +26,4 @@ export function startListen( }, { signal }, ) - task() } diff --git a/packages/mask/src/extension/popups/pages/Personas/hooks/usePersonaContext.ts b/packages/mask/src/extension/popups/pages/Personas/hooks/usePersonaContext.ts index 5f40f5d421a7..fb140af383b4 100644 --- a/packages/mask/src/extension/popups/pages/Personas/hooks/usePersonaContext.ts +++ b/packages/mask/src/extension/popups/pages/Personas/hooks/usePersonaContext.ts @@ -2,10 +2,9 @@ import { createContainer } from 'unstated-next' import { useValueRef } from '@masknet/shared-base-ui' import { ECKeyIdentifier, Identifier, PersonaInformation } from '@masknet/shared-base' import { currentPersonaIdentifier } from '../../../../../settings/settings' -import { useAsyncRetry } from 'react-use' import Services from '../../../../service' import { head } from 'lodash-unified' -import { useEffect, useState } from 'react' +import { useEffect, useMemo, useState } from 'react' import { MaskMessages } from '../../../../../utils' import type { ProfileInformationWithNextID } from '../../../../background-script/IdentityService' @@ -20,10 +19,12 @@ function usePersonaContext() { let currentIdentifier = useValueRef(currentPersonaIdentifier) if (!currentPersonaIdentifier.ready && initData.currentIdentifier) currentIdentifier = initData.currentIdentifier - const { value: personas = initData.personas, retry } = useAsyncRetry(Services.Identity.queryOwnedPersonaInformation) + const [personas, setPersonas] = useState(initData.personas) useEffect(() => { - return MaskMessages.events.ownPersonaChanged.on(retry) - }, [retry]) + const f = Services.Identity.queryOwnedPersonaInformation + if (!initData.personas) f().then(setPersonas) + return MaskMessages.events.ownPersonaChanged.on(() => f().then(setPersonas)) + }, [initData.personas]) const currentPersona = personas?.find((x) => x.identifier.equals( @@ -31,14 +32,20 @@ function usePersonaContext() { ), ) - const otherPersonas = personas?.filter((x) => !x.identifier.equals(currentPersona?.identifier)) + const otherPersonas = useMemo( + () => personas?.filter((x) => !x.identifier.equals(currentPersona?.identifier)), + [personas, currentPersona?.identifier], + ) - return { - deletingPersona, - setDeletingPersona, - personas: otherPersonas, - currentPersona, - } + return useMemo( + () => ({ + deletingPersona, + setDeletingPersona, + personas: otherPersonas, + currentPersona, + }), + [deletingPersona, otherPersonas, currentPersona], + ) } export const PersonaContext = createContainer(usePersonaContext) From 3fabb3ff0dd07c5d2414113f4487c78fb717ec0e Mon Sep 17 00:00:00 2001 From: Jack Works Date: Sat, 2 Apr 2022 15:07:25 +0800 Subject: [PATCH 12/20] refactor: move theme --- packages/mask/.webpack/flags.ts | 2 +- packages/mask/src/PopupSSR_Root.tsx | 2 +- .../options-page/DashboardDialogs/Base.tsx | 10 +- packages/mask/src/extension/popups/UI.tsx | 4 +- .../src/extension/popups/pages/Swap/index.tsx | 5 +- .../plugins/VCent/SNSAdaptor/TweetDialog.tsx | 2 +- .../facebook.com/customization/custom.ts | 2 +- .../minds.com/customization/custom.ts | 2 +- .../twitter.com/customization/custom.ts | 2 +- packages/mask/src/utils/index.ts | 1 - .../mask/src/utils/{ => theme}/MaskTheme.ts | 9 +- .../{theme-tools.ts => theme/color-tools.ts} | 8 +- packages/mask/src/utils/theme/index.ts | 9 ++ .../src/utils/{ => theme}/theme-global.d.ts | 0 .../useClassicMaskFullPageTheme.ts | 3 +- .../src/utils/theme/useClassicMaskSNSTheme.ts | 25 +++++ .../mask/src/utils/theme/useColorStyles.ts | 18 ++++ .../mask/src/utils/theme/useErrorStyles.ts | 21 +++++ .../usePopupsMaskFullPageTheme.ts} | 91 +------------------ .../mask/src/utils/theme/useThemeLanguage.ts | 21 +++++ 20 files changed, 123 insertions(+), 114 deletions(-) rename packages/mask/src/utils/{ => theme}/MaskTheme.ts (87%) rename packages/mask/src/utils/{theme-tools.ts => theme/color-tools.ts} (94%) create mode 100644 packages/mask/src/utils/theme/index.ts rename packages/mask/src/utils/{ => theme}/theme-global.d.ts (100%) rename packages/mask/src/utils/{ => theme}/useClassicMaskFullPageTheme.ts (92%) create mode 100644 packages/mask/src/utils/theme/useClassicMaskSNSTheme.ts create mode 100644 packages/mask/src/utils/theme/useColorStyles.ts create mode 100644 packages/mask/src/utils/theme/useErrorStyles.ts rename packages/mask/src/utils/{theme.ts => theme/usePopupsMaskFullPageTheme.ts} (69%) create mode 100644 packages/mask/src/utils/theme/useThemeLanguage.ts diff --git a/packages/mask/.webpack/flags.ts b/packages/mask/.webpack/flags.ts index cd56673992ad..fe708b3b4793 100644 --- a/packages/mask/.webpack/flags.ts +++ b/packages/mask/.webpack/flags.ts @@ -47,7 +47,7 @@ export function computedBuildFlags(flags: ReturnType sourceMapKind = 'inline-cheap-source-map' supportWebAssembly = false } else if (mode === 'development') { - sourceMapKind = false + sourceMapKind = 'eval-cheap-source-map' } else { sourceMapKind = false } diff --git a/packages/mask/src/PopupSSR_Root.tsx b/packages/mask/src/PopupSSR_Root.tsx index b237094a9b84..5cec7e0a78dd 100644 --- a/packages/mask/src/PopupSSR_Root.tsx +++ b/packages/mask/src/PopupSSR_Root.tsx @@ -5,7 +5,7 @@ import { enUS, jaJP, koKR, Localization, zhTW, zhCN } from '@mui/material/locale import { StaticRouter } from 'react-router-dom/server' import { PopupFrame } from './extension/popups/components/PopupFrame' import { PersonaHomeUI } from './extension/popups/pages/Personas/Home/UI' -import { useClassicMaskFullPageTheme } from './utils/useClassicMaskFullPageTheme' +import { useClassicMaskFullPageTheme } from './utils/theme/useClassicMaskFullPageTheme' import { FacebookColoredIcon, InstagramColoredIcon, diff --git a/packages/mask/src/extension/options-page/DashboardDialogs/Base.tsx b/packages/mask/src/extension/options-page/DashboardDialogs/Base.tsx index 3f71f35d957a..350d2b5a915e 100644 --- a/packages/mask/src/extension/options-page/DashboardDialogs/Base.tsx +++ b/packages/mask/src/extension/options-page/DashboardDialogs/Base.tsx @@ -10,12 +10,13 @@ import { IconButtonProps, } from '@mui/material' import { makeStyles } from '@masknet/theme' -import { ThemeProvider } from '@mui/material/styles' +import { Theme, ThemeOptions, ThemeProvider } from '@mui/material/styles' import CloseIcon from '@mui/icons-material/Close' -import { extendsTheme, useMatchXS, useThemeLanguage } from '../../../utils' +import { useMatchXS, useThemeLanguage } from '../../../utils' import { useValueRef } from '@masknet/shared-base-ui' import { appearanceSettings } from '../../../settings/settings' -import { useClassicMaskFullPageTheme } from '../../../utils/useClassicMaskFullPageTheme' +import { cloneDeep, merge } from 'lodash-unified' +import { useClassicMaskFullPageTheme } from '../../../utils/theme/useClassicMaskFullPageTheme' const useStyles = makeStyles()((theme) => ({ root: { @@ -163,6 +164,9 @@ const useDashboardDialogWrapperStyles = makeStyles( }, })) +function extendsTheme(extend: (theme: Theme) => ThemeOptions) { + return (theme: Theme) => merge(cloneDeep(theme), extend(theme)) +} const dialogTheme = extendsTheme((theme) => ({ components: { MuiOutlinedInput: { diff --git a/packages/mask/src/extension/popups/UI.tsx b/packages/mask/src/extension/popups/UI.tsx index b996e16c42f3..83993f4ca4fe 100644 --- a/packages/mask/src/extension/popups/UI.tsx +++ b/packages/mask/src/extension/popups/UI.tsx @@ -2,14 +2,14 @@ import { lazy, useEffect, useState } from 'react' import { Navigate, Route, Routes, HashRouter } from 'react-router-dom' import { createInjectHooksRenderer, useActivatedPluginsDashboard } from '@masknet/plugin-infra' import { PopupRoutes } from '@masknet/shared-base' -import { useClassicMaskFullPageTheme } from '../../utils/useClassicMaskFullPageTheme' import '../../social-network-adaptor/browser-action' import { Web3Provider } from '@masknet/web3-shared-evm' import { PopupWeb3Context } from '../../web3/context' import { PopupFrame } from './components/PopupFrame' import { Appearance } from '@masknet/theme' import { MaskUIRoot } from '../../UIRoot' -import { useThemeLanguage } from '../../utils' +import { useThemeLanguage } from '../../utils/theme' +import { useClassicMaskFullPageTheme } from '../../utils/theme/useClassicMaskFullPageTheme' import { useMyPersonas } from '../../components/DataSource/useMyPersonas' function useAlwaysLightTheme() { diff --git a/packages/mask/src/extension/popups/pages/Swap/index.tsx b/packages/mask/src/extension/popups/pages/Swap/index.tsx index 4adb25540b66..8bd2cb7bcaec 100644 --- a/packages/mask/src/extension/popups/pages/Swap/index.tsx +++ b/packages/mask/src/extension/popups/pages/Swap/index.tsx @@ -9,10 +9,11 @@ import { WalletStateBarUI } from '../../components/WalletStateBar' import { SwapBox } from './SwapBox' import { SwapWeb3Context } from '../../../../web3/context' import { PopupRoutes } from '@masknet/shared-base' -import { useI18N, usePopupsMaskFullPageTheme } from '../../../../utils' +import { useI18N } from '../../../../utils' import { NetworkPluginID, useReverseAddress } from '@masknet/plugin-infra' import { TargetChainIdContext } from '../../../../plugins/Trader/trader/useTargetChainIdContext' import { AllProviderTradeContext } from '../../../../plugins/Trader/trader/useAllProviderTradeContext' +import { useSwapPageTheme } from '../../../../utils/theme/usePopupsMaskFullPageTheme' const useStyles = makeStyles()((theme) => { return { @@ -68,7 +69,7 @@ export default function SwapPage() { const { t } = useI18N() const { classes } = useStyles() const chainId = useChainId() - const theme = usePopupsMaskFullPageTheme() + const theme = useSwapPageTheme() const { value: pendingTransactions = [] } = useRecentTransactions({ status: TransactionStatusType.NOT_DEPEND, }) diff --git a/packages/mask/src/plugins/VCent/SNSAdaptor/TweetDialog.tsx b/packages/mask/src/plugins/VCent/SNSAdaptor/TweetDialog.tsx index e67ab12d39da..e5d41cb662e7 100644 --- a/packages/mask/src/plugins/VCent/SNSAdaptor/TweetDialog.tsx +++ b/packages/mask/src/plugins/VCent/SNSAdaptor/TweetDialog.tsx @@ -1,7 +1,7 @@ import { first } from 'lodash-unified' import { Button } from '@mui/material' import { makeStyles } from '@masknet/theme' -import { isDarkTheme } from '../../../utils/theme-tools' +import { isDarkTheme } from '../../../utils/theme' import { ETHIcon } from '../icons/ETH' import { VCentIconLight, VCentIconDark } from '../icons/VCent' import { VALUABLES_VCENT_URL } from '../constants' diff --git a/packages/mask/src/social-network-adaptor/facebook.com/customization/custom.ts b/packages/mask/src/social-network-adaptor/facebook.com/customization/custom.ts index 2d163de13460..2042d879c223 100644 --- a/packages/mask/src/social-network-adaptor/facebook.com/customization/custom.ts +++ b/packages/mask/src/social-network-adaptor/facebook.com/customization/custom.ts @@ -5,7 +5,7 @@ import { useMemo } from 'react' import { useValueRef } from '@masknet/shared-base-ui' import { SubscriptionFromValueRef } from '@masknet/shared-base' import type { SocialNetworkUI } from '../../../social-network' -import { fromRGB, isDark, shade, toRGB } from '../../../utils/theme-tools' +import { fromRGB, isDark, shade, toRGB } from '../../../utils/theme' const primaryColorRef = new ValueRef(toRGB([29, 161, 242])) const primaryColorContrastColorRef = new ValueRef(toRGB([255, 255, 255])) diff --git a/packages/mask/src/social-network-adaptor/minds.com/customization/custom.ts b/packages/mask/src/social-network-adaptor/minds.com/customization/custom.ts index 71f388a0f0d7..18b2086f0e34 100644 --- a/packages/mask/src/social-network-adaptor/minds.com/customization/custom.ts +++ b/packages/mask/src/social-network-adaptor/minds.com/customization/custom.ts @@ -5,7 +5,7 @@ import { useMemo } from 'react' import { useValueRef } from '@masknet/shared-base-ui' import { SubscriptionFromValueRef } from '@masknet/shared-base' import type { SocialNetworkUI } from '../../../social-network' -import { fromRGB, getBackgroundColor, getForegroundColor, shade, toRGB } from '../../../utils/theme-tools' +import { fromRGB, getBackgroundColor, getForegroundColor, shade, toRGB } from '../../../utils/theme' import { themeListItemSelector } from '../utils/selector' // TODO: get this from DOM. But currently Minds has a single primary color diff --git a/packages/mask/src/social-network-adaptor/twitter.com/customization/custom.ts b/packages/mask/src/social-network-adaptor/twitter.com/customization/custom.ts index 9377d76923ad..e6cff6cc609a 100644 --- a/packages/mask/src/social-network-adaptor/twitter.com/customization/custom.ts +++ b/packages/mask/src/social-network-adaptor/twitter.com/customization/custom.ts @@ -5,7 +5,7 @@ import { PaletteMode, Theme, unstable_createMuiStrictModeTheme } from '@mui/mate import produce, { setAutoFreeze } from 'immer' import { useMemo } from 'react' import type { SocialNetworkUI } from '../../../social-network' -import { fromRGB, getBackgroundColor, getForegroundColor, isDark, shade, toRGB } from '../../../utils/theme-tools' +import { fromRGB, getBackgroundColor, getForegroundColor, isDark, shade, toRGB } from '../../../utils/theme' import { isMobileTwitter } from '../utils/isMobile' import { composeAnchorSelector, composeAnchorTextSelector, headingTextSelector } from '../utils/selector' import twitterColorSchema from './twitter-color-schema.json' diff --git a/packages/mask/src/utils/index.ts b/packages/mask/src/utils/index.ts index c6a009552f39..eba2a666feb7 100644 --- a/packages/mask/src/utils/index.ts +++ b/packages/mask/src/utils/index.ts @@ -11,7 +11,6 @@ export * from './i18n-next-ui' export * from './messages' export * from './permissions' export * from './createNormalReactRoot' -export * from './theme-tools' export * from './theme' export * from './utils' export * from './watcher' diff --git a/packages/mask/src/utils/MaskTheme.ts b/packages/mask/src/utils/theme/MaskTheme.ts similarity index 87% rename from packages/mask/src/utils/MaskTheme.ts rename to packages/mask/src/utils/theme/MaskTheme.ts index 3950635b5688..e7a93479ba3d 100644 --- a/packages/mask/src/utils/MaskTheme.ts +++ b/packages/mask/src/utils/theme/MaskTheme.ts @@ -1,9 +1,6 @@ -import { ValueRef } from '@dimensiondev/holoflows-kit' -import { SubscriptionFromValueRef } from '@masknet/shared-base' -import { PaletteMode, unstable_createMuiStrictModeTheme, type ThemeOptions } from '@mui/material' +import { unstable_createMuiStrictModeTheme, type ThemeOptions } from '@mui/material' import { grey, orange } from '@mui/material/colors' import { cloneDeep, merge } from 'lodash-unified' -import type { Subscription } from 'use-subscription' function getFontFamily(monospace?: boolean) { // We want to look native. @@ -91,7 +88,7 @@ const baseTheme = (theme: 'dark' | 'light') => { if (theme === 'light') return merge(cloneDeep(base), lightThemePatch) return merge(cloneDeep(base), darkThemePatch) } -// Theme +/** @deprecated Only use it from useClassicMaskSNSTheme */ export const MaskLightTheme = unstable_createMuiStrictModeTheme(baseTheme('light')) +/** @deprecated Only use it from useClassicMaskSNSTheme */ export const MaskDarkTheme = unstable_createMuiStrictModeTheme(baseTheme('dark')) -export const staticSubscription: Subscription = SubscriptionFromValueRef(new ValueRef('light')) diff --git a/packages/mask/src/utils/theme-tools.ts b/packages/mask/src/utils/theme/color-tools.ts similarity index 94% rename from packages/mask/src/utils/theme-tools.ts rename to packages/mask/src/utils/theme/color-tools.ts index 197f11140ba4..68c7c239196c 100644 --- a/packages/mask/src/utils/theme-tools.ts +++ b/packages/mask/src/utils/theme/color-tools.ts @@ -1,3 +1,5 @@ +import { clamp } from 'lodash-unified' + type RGB = [number, number, number] type RGBA = [number, number, number, number] @@ -19,12 +21,6 @@ export function fromRGB(rgb: string): RGB | undefined { return } -export function clamp(num: number, min: number, max: number) { - if (num < min) return min - if (num > max) return max - return num -} - export function shade(channels: RGB, percentage: number): RGB { return channels.map((c) => clamp(Math.floor((c * (100 + percentage)) / 100), 0, 255)) as RGB } diff --git a/packages/mask/src/utils/theme/index.ts b/packages/mask/src/utils/theme/index.ts new file mode 100644 index 000000000000..76a6527c393c --- /dev/null +++ b/packages/mask/src/utils/theme/index.ts @@ -0,0 +1,9 @@ +import './theme-global.d' + +// Do not export more files. Those files are deprecated. +export * from './color-tools' +export * from './MaskTheme' +export * from './useColorStyles' +export * from './useErrorStyles' +export * from './useThemeLanguage' +export * from './useClassicMaskSNSTheme' diff --git a/packages/mask/src/utils/theme-global.d.ts b/packages/mask/src/utils/theme/theme-global.d.ts similarity index 100% rename from packages/mask/src/utils/theme-global.d.ts rename to packages/mask/src/utils/theme/theme-global.d.ts diff --git a/packages/mask/src/utils/useClassicMaskFullPageTheme.ts b/packages/mask/src/utils/theme/useClassicMaskFullPageTheme.ts similarity index 92% rename from packages/mask/src/utils/useClassicMaskFullPageTheme.ts rename to packages/mask/src/utils/theme/useClassicMaskFullPageTheme.ts index 615bd2261c81..8c8fce367297 100644 --- a/packages/mask/src/utils/useClassicMaskFullPageTheme.ts +++ b/packages/mask/src/utils/theme/useClassicMaskFullPageTheme.ts @@ -4,8 +4,7 @@ import type { Localization } from '@mui/material/locale' import { MaskDarkTheme, MaskLightTheme } from './MaskTheme' /** - * @deprecated - * - Popups: migrate to \@masknet/theme package + * @deprecated Should migrate to \@masknet/theme */ export function useClassicMaskFullPageTheme( userPreference: Appearance, diff --git a/packages/mask/src/utils/theme/useClassicMaskSNSTheme.ts b/packages/mask/src/utils/theme/useClassicMaskSNSTheme.ts new file mode 100644 index 000000000000..28c49addb961 --- /dev/null +++ b/packages/mask/src/utils/theme/useClassicMaskSNSTheme.ts @@ -0,0 +1,25 @@ +import { unstable_createMuiStrictModeTheme } from '@mui/material' +import type { Theme } from '@mui/material/styles/createTheme' +import { useRef } from 'react' +import { activatedSocialNetworkUI } from '../../social-network' +import { useSubscription } from 'use-subscription' +import { MaskDarkTheme, MaskLightTheme } from './MaskTheme' +import { useThemeLanguage } from './useThemeLanguage' +import { SubscriptionFromValueRef } from '@masknet/shared-base' +import { ValueRef } from '@dimensiondev/holoflows-kit' + +const staticRef = SubscriptionFromValueRef(new ValueRef('light')) +/** + * @deprecated Should migrate to \@masknet/theme + */ +export function useClassicMaskSNSTheme() { + const { current: provider } = useRef(activatedSocialNetworkUI.customization.paletteMode?.current || staticRef) + const { current: usePostTheme = (t: Theme) => t } = useRef(activatedSocialNetworkUI.customization.useTheme) + const palette = useSubscription(provider) + const baseTheme = palette === 'dark' ? MaskDarkTheme : MaskLightTheme + + // TODO: support RTL? + const [localization, isRTL] = useThemeLanguage() + const theme = unstable_createMuiStrictModeTheme(baseTheme, localization) + return usePostTheme(theme) +} diff --git a/packages/mask/src/utils/theme/useColorStyles.ts b/packages/mask/src/utils/theme/useColorStyles.ts new file mode 100644 index 000000000000..1d0d1e1ea458 --- /dev/null +++ b/packages/mask/src/utils/theme/useColorStyles.ts @@ -0,0 +1,18 @@ +import { makeStyles } from '@masknet/theme' +import { blue, green, red } from '@mui/material/colors' +import type { MaskDarkTheme } from './MaskTheme' + +export const useColorStyles = makeStyles()((theme: typeof MaskDarkTheme) => { + const dark = theme.palette.mode === 'dark' + return { + error: { + color: dark ? red[500] : red[900], + }, + success: { + color: dark ? green[500] : green[800], + }, + info: { + color: dark ? blue[500] : blue[800], + }, + } +}) diff --git a/packages/mask/src/utils/theme/useErrorStyles.ts b/packages/mask/src/utils/theme/useErrorStyles.ts new file mode 100644 index 000000000000..23734f2110af --- /dev/null +++ b/packages/mask/src/utils/theme/useErrorStyles.ts @@ -0,0 +1,21 @@ +import { makeStyles } from '@masknet/theme' +import { red } from '@mui/material/colors' + +export const useErrorStyles = makeStyles()((theme) => { + const dark = theme.palette.mode === 'dark' + return { + containedPrimary: { + backgroundColor: dark ? red[500] : red[900], + '&:hover': { + backgroundColor: dark ? red[900] : red[700], + }, + }, + outlinedPrimary: { + borderColor: dark ? red[500] : red[900], + color: dark ? red[500] : red[900], + '&:hover': { + borderColor: dark ? red[900] : red[700], + }, + }, + } +}) diff --git a/packages/mask/src/utils/theme.ts b/packages/mask/src/utils/theme/usePopupsMaskFullPageTheme.ts similarity index 69% rename from packages/mask/src/utils/theme.ts rename to packages/mask/src/utils/theme/usePopupsMaskFullPageTheme.ts index 59946443e7eb..f03e10a0f54a 100644 --- a/packages/mask/src/utils/theme.ts +++ b/packages/mask/src/utils/theme/usePopupsMaskFullPageTheme.ts @@ -1,37 +1,13 @@ -import { useValueRef } from '@masknet/shared-base-ui' -import { Appearance, makeStyles, parseColor } from '@masknet/theme' -import { LanguageOptions, SupportedLanguages } from '@masknet/public-api' +import { parseColor } from '@masknet/theme' import { unstable_createMuiStrictModeTheme } from '@mui/material' -import { blue, green, red } from '@mui/material/colors' -import { jaJP, koKR, zhTW, zhCN, enUS, Localization } from '@mui/material/locale/index' -import type { Theme, ThemeOptions } from '@mui/material/styles/createTheme' -import { cloneDeep, merge } from 'lodash-unified' -import { useRef } from 'react' -import { languageSettings } from '../settings/settings' -import { activatedSocialNetworkUI } from '../social-network' -import './theme-global.d' -import { useSubscription } from 'use-subscription' import produce, { setAutoFreeze } from 'immer' -import twitterColorSchema from '../social-network-adaptor/twitter.com/customization/twitter-color-schema.json' -import { staticSubscription, MaskDarkTheme, MaskLightTheme } from './MaskTheme' +import twitterColorSchema from '../../social-network-adaptor/twitter.com/customization/twitter-color-schema.json' +import { MaskLightTheme } from './MaskTheme' -export function useClassicMaskSNSTheme() { - const { current: provider } = useRef( - activatedSocialNetworkUI.customization.paletteMode?.current || staticSubscription, - ) - const { current: usePostTheme = (t: Theme) => t } = useRef(activatedSocialNetworkUI.customization.useTheme) - const palette = useSubscription(provider) - const baseTheme = palette === 'dark' ? MaskDarkTheme : MaskLightTheme - - // TODO: support RTL? - const [localization, isRTL] = useThemeLanguage() - const theme = unstable_createMuiStrictModeTheme(baseTheme, localization) - return usePostTheme(theme) -} /** - * Only used in swap pages under popups, will replace it in the future + * @deprecated Should migrate to \@masknet/theme */ -export function usePopupsMaskFullPageTheme() { +export function useSwapPageTheme() { const baseTheme = MaskLightTheme setAutoFreeze(false) @@ -236,60 +212,3 @@ export function usePopupsMaskFullPageTheme() { }) return unstable_createMuiStrictModeTheme(PopupTheme) } - -export function useThemeLanguage(): [loc: Localization, RTL: boolean] { - let language = useValueRef(languageSettings) - // TODO: support auto language - if (language === LanguageOptions.__auto__) language = LanguageOptions.enUS - - const displayLanguage = language as any as SupportedLanguages - - const langs: Record = { - [SupportedLanguages.enUS]: enUS, - [SupportedLanguages.jaJP]: jaJP, - [SupportedLanguages.koKR]: koKR, - [SupportedLanguages.zhTW]: zhTW, - [SupportedLanguages.zhCN]: zhCN, - } - return [langs[displayLanguage] || enUS, false] -} - -export interface ClassicMaskFullPageThemeOptions { - forcePalette?: Appearance -} - -export const useColorStyles = makeStyles()((theme: typeof MaskDarkTheme) => { - const dark = theme.palette.mode === 'dark' - return { - error: { - color: dark ? red[500] : red[900], - }, - success: { - color: dark ? green[500] : green[800], - }, - info: { - color: dark ? blue[500] : blue[800], - }, - } -}) -export const useErrorStyles = makeStyles()((theme) => { - const dark = theme.palette.mode === 'dark' - return { - containedPrimary: { - backgroundColor: dark ? red[500] : red[900], - '&:hover': { - backgroundColor: dark ? red[900] : red[700], - }, - }, - outlinedPrimary: { - borderColor: dark ? red[500] : red[900], - color: dark ? red[500] : red[900], - '&:hover': { - borderColor: dark ? red[900] : red[700], - }, - }, - } -}) -export function extendsTheme(extend: (theme: Theme) => ThemeOptions) { - return (theme: Theme) => merge(cloneDeep(theme), extend(theme)) -} diff --git a/packages/mask/src/utils/theme/useThemeLanguage.ts b/packages/mask/src/utils/theme/useThemeLanguage.ts new file mode 100644 index 000000000000..55151ea76cf6 --- /dev/null +++ b/packages/mask/src/utils/theme/useThemeLanguage.ts @@ -0,0 +1,21 @@ +import { useValueRef } from '@masknet/shared-base-ui' +import { LanguageOptions, SupportedLanguages } from '@masknet/public-api' +import { jaJP, koKR, zhTW, zhCN, enUS, Localization } from '@mui/material/locale/index' +import { languageSettings } from '../../settings/settings' + +export function useThemeLanguage(): [loc: Localization, RTL: boolean] { + let language = useValueRef(languageSettings) + // TODO: support auto language + if (language === LanguageOptions.__auto__) language = LanguageOptions.enUS + + const displayLanguage = language as any as SupportedLanguages + + const langs: Record = { + [SupportedLanguages.enUS]: enUS, + [SupportedLanguages.jaJP]: jaJP, + [SupportedLanguages.koKR]: koKR, + [SupportedLanguages.zhTW]: zhTW, + [SupportedLanguages.zhCN]: zhCN, + } + return [langs[displayLanguage] || enUS, false] +} From bacab8bb2601ffe88aa930a70415b1e7044ff4d7 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Sat, 2 Apr 2022 15:14:04 +0800 Subject: [PATCH 13/20] refactor: move theme --- .../tasks/Cancellable/PopupSSR/cache.ts | 20 ++++- .../Cancellable/PopupSSR/prepare-data.ts | 18 ----- packages/mask/src/PopupSSR_Root.tsx | 77 ------------------- packages/mask/src/setup.popup.ssr.tsx | 72 +++++++++++++++-- .../theme/useClassicMaskFullPageTheme.ts | 8 ++ .../mask/src/utils/theme/useThemeLanguage.ts | 25 +++--- 6 files changed, 107 insertions(+), 113 deletions(-) delete mode 100644 packages/mask/background/tasks/Cancellable/PopupSSR/prepare-data.ts delete mode 100644 packages/mask/src/PopupSSR_Root.tsx diff --git a/packages/mask/background/tasks/Cancellable/PopupSSR/cache.ts b/packages/mask/background/tasks/Cancellable/PopupSSR/cache.ts index 45253e2b2ade..fe0ce3543dda 100644 --- a/packages/mask/background/tasks/Cancellable/PopupSSR/cache.ts +++ b/packages/mask/background/tasks/Cancellable/PopupSSR/cache.ts @@ -1,8 +1,10 @@ import { throttle } from 'lodash-unified' import { MaskMessages } from '../../../../shared/messages' import { InternalStorageKeys } from '../../../services/settings/utils' -import { prepareSSR } from './prepare-data' import type { PopupSSR_Props } from './type' +import { queryOwnedPersonaInformation, queryCurrentPersona_internal } from '../../../services/identity' +import { queryOwnedProfileInformationWithNextID_internal } from '../../../services/identity/profile/query' +import { getLanguagePreference } from '../../../services/settings' export let cache: { html: string; css: string } = { html: '', css: '' } export function startListen( @@ -11,7 +13,7 @@ export function startListen( ) { const task = throttle( async function task() { - cache = await prepareSSR().then(render) + cache = await prepareData().then(render) }, 2000, { leading: true }, @@ -27,3 +29,17 @@ export function startListen( { signal }, ) } + +async function prepareData(): Promise { + const language = getLanguagePreference() + const personas = await queryOwnedPersonaInformation() + const currentPersona = await queryCurrentPersona_internal(personas) + const profilesWithNextID = await queryOwnedProfileInformationWithNextID_internal(personas, currentPersona) + + return { + profilesWithNextID, + currentPersona, + personas, + language: await language, + } +} diff --git a/packages/mask/background/tasks/Cancellable/PopupSSR/prepare-data.ts b/packages/mask/background/tasks/Cancellable/PopupSSR/prepare-data.ts deleted file mode 100644 index 621fac8a8456..000000000000 --- a/packages/mask/background/tasks/Cancellable/PopupSSR/prepare-data.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { queryOwnedPersonaInformation, queryCurrentPersona_internal } from '../../../services/identity' -import { queryOwnedProfileInformationWithNextID_internal } from '../../../services/identity/profile/query' -import { getLanguagePreference } from '../../../services/settings' -import type { PopupSSR_Props } from './type' - -export async function prepareSSR(): Promise { - const language = getLanguagePreference() - const personas = await queryOwnedPersonaInformation() - const currentPersona = await queryCurrentPersona_internal(personas) - const profilesWithNextID = await queryOwnedProfileInformationWithNextID_internal(personas, currentPersona) - - return { - profilesWithNextID, - currentPersona, - personas, - language: await language, - } -} diff --git a/packages/mask/src/PopupSSR_Root.tsx b/packages/mask/src/PopupSSR_Root.tsx deleted file mode 100644 index 5cec7e0a78dd..000000000000 --- a/packages/mask/src/PopupSSR_Root.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import { EnhanceableSite, i18NextInstance, PopupRoutes } from '@masknet/shared-base' -import { noop } from 'lodash-unified' -import { Appearance, MaskThemeProvider } from '@masknet/theme' -import { enUS, jaJP, koKR, Localization, zhTW, zhCN } from '@mui/material/locale' -import { StaticRouter } from 'react-router-dom/server' -import { PopupFrame } from './extension/popups/components/PopupFrame' -import { PersonaHomeUI } from './extension/popups/pages/Personas/Home/UI' -import { useClassicMaskFullPageTheme } from './utils/theme/useClassicMaskFullPageTheme' -import { - FacebookColoredIcon, - InstagramColoredIcon, - MindsIcon, - TwitterColoredIcon, - OpenSeaColoredIcon, -} from '@masknet/icons' -import type { PopupSSR_Props } from '../background/tasks/Cancellable/PopupSSR/type' -import { Suspense } from 'react' -import { SupportedLanguages } from '@masknet/public-api' - -const SOCIAL_MEDIA_ICON_MAPPING: Record = { - [EnhanceableSite.Facebook]: , - [EnhanceableSite.Twitter]: , - [EnhanceableSite.Instagram]: , - [EnhanceableSite.Minds]: , - [EnhanceableSite.OpenSea]: , -} -const DEFINED_SITES = [ - EnhanceableSite.Facebook, - EnhanceableSite.Twitter, - EnhanceableSite.Instagram, - EnhanceableSite.Minds, - EnhanceableSite.OpenSea, -] -const LANGS: Record = { - [SupportedLanguages.enUS]: enUS, - [SupportedLanguages.jaJP]: jaJP, - [SupportedLanguages.koKR]: koKR, - [SupportedLanguages.zhCN]: zhCN, - [SupportedLanguages.zhTW]: zhTW, -} -function useAlwaysLightTheme() { - return useClassicMaskFullPageTheme(Appearance.light, [Reflect.get(LANGS, i18NextInstance.language) || enUS, false]) -} -export function PopupSSR(props: PopupSSR_Props) { - const currentPersona = props.personas?.find((x) => x.identifier.equals(props.currentPersona)) - return ( - - 'light'}> - - - - - - - - - - ) -} diff --git a/packages/mask/src/setup.popup.ssr.tsx b/packages/mask/src/setup.popup.ssr.tsx index 8d31d7fd8333..b8242ed2c5cc 100644 --- a/packages/mask/src/setup.popup.ssr.tsx +++ b/packages/mask/src/setup.popup.ssr.tsx @@ -1,6 +1,6 @@ -import { i18NextInstance, updateLanguage } from '@masknet/shared-base' -import { once } from 'lodash-unified' -import { TssCacheProvider } from '@masknet/theme' +import { i18NextInstance, updateLanguage, EnhanceableSite, PopupRoutes } from '@masknet/shared-base' +import { once, noop } from 'lodash-unified' +import { TssCacheProvider, MaskThemeProvider } from '@masknet/theme' import { CacheProvider } from '@emotion/react' import { renderToString } from 'react-dom/server' import createCache from '@emotion/cache' @@ -8,17 +8,28 @@ import createEmotionServer from '@emotion/server/create-instance' import { initReactI18next } from 'react-i18next' import { addMaskI18N } from '../shared-ui/locales/languages' import type { PopupSSR_Props } from '../background/tasks/Cancellable/PopupSSR/type' -import { PopupSSR } from './PopupSSR_Root' +import { StaticRouter } from 'react-router-dom/server' +import { PopupFrame } from './extension/popups/components/PopupFrame' +import { PersonaHomeUI } from './extension/popups/pages/Personas/Home/UI' +import { usePopupFullPageTheme } from './utils/theme/useClassicMaskFullPageTheme' +import { + FacebookColoredIcon, + InstagramColoredIcon, + MindsIcon, + TwitterColoredIcon, + OpenSeaColoredIcon, +} from '@masknet/icons' +import { Suspense } from 'react' -const init = once((props: PopupSSR_Props) => +const init = once(() => i18NextInstance.init().then(() => { addMaskI18N(i18NextInstance) initReactI18next.init(i18NextInstance) }), ) export async function render(props: PopupSSR_Props) { + await init() updateLanguage(props.language) - await init(props) const muiCache = createCache({ key: 'css' }) const tssCache = createCache({ key: 'tss' }) const tssServer = createEmotionServer(tssCache) @@ -35,3 +46,52 @@ export async function render(props: PopupSSR_Props) { const tssCSS = tssServer.constructStyleTagsFromChunks(tssServer.extractCriticalToChunks(html)) return { html, css: muiCSS + tssCSS } } + +const SOCIAL_MEDIA_ICON_MAPPING: Record = { + [EnhanceableSite.Facebook]: , + [EnhanceableSite.Twitter]: , + [EnhanceableSite.Instagram]: , + [EnhanceableSite.Minds]: , + [EnhanceableSite.OpenSea]: , +} +const DEFINED_SITES = [ + EnhanceableSite.Facebook, + EnhanceableSite.Twitter, + EnhanceableSite.Instagram, + EnhanceableSite.Minds, + EnhanceableSite.OpenSea, +] +function PopupSSR(props: PopupSSR_Props) { + const currentPersona = props.personas?.find((x) => x.identifier.equals(props.currentPersona)) + return ( + + 'light'}> + + + + + + + + + + ) +} diff --git a/packages/mask/src/utils/theme/useClassicMaskFullPageTheme.ts b/packages/mask/src/utils/theme/useClassicMaskFullPageTheme.ts index 8c8fce367297..40fe44cbacae 100644 --- a/packages/mask/src/utils/theme/useClassicMaskFullPageTheme.ts +++ b/packages/mask/src/utils/theme/useClassicMaskFullPageTheme.ts @@ -2,6 +2,7 @@ import { Appearance } from '@masknet/theme' import { PaletteMode, unstable_createMuiStrictModeTheme } from '@mui/material' import type { Localization } from '@mui/material/locale' import { MaskDarkTheme, MaskLightTheme } from './MaskTheme' +import { useThemeLanguage } from './useThemeLanguage' /** * @deprecated Should migrate to \@masknet/theme @@ -17,3 +18,10 @@ export function useClassicMaskFullPageTheme( const baseTheme = finalPalette === 'dark' ? MaskDarkTheme : MaskLightTheme return unstable_createMuiStrictModeTheme(baseTheme, localization) } + +/** + * @deprecated Should migrate to \@masknet/theme + */ +export function usePopupFullPageTheme() { + return useClassicMaskFullPageTheme(Appearance.light, useThemeLanguage()) +} diff --git a/packages/mask/src/utils/theme/useThemeLanguage.ts b/packages/mask/src/utils/theme/useThemeLanguage.ts index 55151ea76cf6..cc3bea16ad88 100644 --- a/packages/mask/src/utils/theme/useThemeLanguage.ts +++ b/packages/mask/src/utils/theme/useThemeLanguage.ts @@ -2,20 +2,25 @@ import { useValueRef } from '@masknet/shared-base-ui' import { LanguageOptions, SupportedLanguages } from '@masknet/public-api' import { jaJP, koKR, zhTW, zhCN, enUS, Localization } from '@mui/material/locale/index' import { languageSettings } from '../../settings/settings' +import { i18NextInstance, updateLanguage } from '@masknet/shared-base' +const langs: Record = { + [SupportedLanguages.enUS]: enUS, + [SupportedLanguages.jaJP]: jaJP, + [SupportedLanguages.koKR]: koKR, + [SupportedLanguages.zhTW]: zhTW, + [SupportedLanguages.zhCN]: zhCN, +} export function useThemeLanguage(): [loc: Localization, RTL: boolean] { let language = useValueRef(languageSettings) - // TODO: support auto language - if (language === LanguageOptions.__auto__) language = LanguageOptions.enUS - - const displayLanguage = language as any as SupportedLanguages - const langs: Record = { - [SupportedLanguages.enUS]: enUS, - [SupportedLanguages.jaJP]: jaJP, - [SupportedLanguages.koKR]: koKR, - [SupportedLanguages.zhTW]: zhTW, - [SupportedLanguages.zhCN]: zhCN, + if (language === LanguageOptions.__auto__) { + updateLanguage(language) + if (Object.values(SupportedLanguages).some((x) => x === i18NextInstance.language)) { + language = i18NextInstance.language as LanguageOptions + } } + + const displayLanguage = language as any as SupportedLanguages return [langs[displayLanguage] || enUS, false] } From 7883c7c8f73f0f21a8d9c72f9d230d5ef786b6e3 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Sat, 2 Apr 2022 15:28:38 +0800 Subject: [PATCH 14/20] chore: add tips --- packages/mask/background/tasks/setup.hmr.ts | 12 +++++++--- .../options-page/DashboardDialogs/Base.tsx | 7 ++++-- packages/mask/src/extension/popups/UI.tsx | 4 +++- .../Personas/components/ProfileList/index.tsx | 8 +------ packages/mask/src/setup.popup.ssr.tsx | 23 +++++++++++-------- packages/mask/src/utils/theme/MaskTheme.ts | 2 ++ .../theme/useClassicMaskFullPageTheme.ts | 7 ++++-- .../src/utils/theme/useClassicMaskSNSTheme.ts | 9 +++++--- .../mask/src/utils/theme/useThemeLanguage.ts | 8 +++---- 9 files changed, 48 insertions(+), 32 deletions(-) diff --git a/packages/mask/background/tasks/setup.hmr.ts b/packages/mask/background/tasks/setup.hmr.ts index 8e856f9778e0..e2c81d13ce27 100644 --- a/packages/mask/background/tasks/setup.hmr.ts +++ b/packages/mask/background/tasks/setup.hmr.ts @@ -11,11 +11,17 @@ type CancelableJob = { default: (signal: AbortSignal) => void } const CancelableJobs: CancelableJob[] = [ NewInstalled, process.env.manifest === '2' ? InjectContentScript : InjectContentScriptMV3, - process.env.manifest === '2' ? PopupSSR : PopupSSR_MV3, IsolatedDashboardBridge, - process.env.architecture === 'app' ? null! : CleanupProfileDatabase, NotificationsToMobile, -].filter(Boolean) +] + +if (process.env.architecture === 'web') { + CancelableJobs.push( + // Web only + process.env.manifest === '2' ? PopupSSR : PopupSSR_MV3, + CleanupProfileDatabase, + ) +} const abort = new AbortController() CancelableJobs.forEach((task) => task.default(abort.signal)) diff --git a/packages/mask/src/extension/options-page/DashboardDialogs/Base.tsx b/packages/mask/src/extension/options-page/DashboardDialogs/Base.tsx index 350d2b5a915e..3472eb2be29e 100644 --- a/packages/mask/src/extension/options-page/DashboardDialogs/Base.tsx +++ b/packages/mask/src/extension/options-page/DashboardDialogs/Base.tsx @@ -14,7 +14,7 @@ import { Theme, ThemeOptions, ThemeProvider } from '@mui/material/styles' import CloseIcon from '@mui/icons-material/Close' import { useMatchXS, useThemeLanguage } from '../../../utils' import { useValueRef } from '@masknet/shared-base-ui' -import { appearanceSettings } from '../../../settings/settings' +import { appearanceSettings, languageSettings } from '../../../settings/settings' import { cloneDeep, merge } from 'lodash-unified' import { useClassicMaskFullPageTheme } from '../../../utils/theme/useClassicMaskFullPageTheme' @@ -105,7 +105,10 @@ export function useModal diff --git a/packages/mask/src/extension/popups/UI.tsx b/packages/mask/src/extension/popups/UI.tsx index 83993f4ca4fe..82e574c3015c 100644 --- a/packages/mask/src/extension/popups/UI.tsx +++ b/packages/mask/src/extension/popups/UI.tsx @@ -11,9 +11,11 @@ import { MaskUIRoot } from '../../UIRoot' import { useThemeLanguage } from '../../utils/theme' import { useClassicMaskFullPageTheme } from '../../utils/theme/useClassicMaskFullPageTheme' import { useMyPersonas } from '../../components/DataSource/useMyPersonas' +import { useValueRef } from '@masknet/shared-base-ui' +import { languageSettings } from '../../settings/settings' function useAlwaysLightTheme() { - return useClassicMaskFullPageTheme(Appearance.light, useThemeLanguage()) + return useClassicMaskFullPageTheme(Appearance.light, useThemeLanguage(useValueRef(languageSettings))) } const Wallet = lazy(() => import('./pages/Wallet')) const Personas = lazy(() => import('./pages/Personas')) diff --git a/packages/mask/src/extension/popups/pages/Personas/components/ProfileList/index.tsx b/packages/mask/src/extension/popups/pages/Personas/components/ProfileList/index.tsx index b30e0f0327bc..5fa25b0858f8 100644 --- a/packages/mask/src/extension/popups/pages/Personas/components/ProfileList/index.tsx +++ b/packages/mask/src/extension/popups/pages/Personas/components/ProfileList/index.tsx @@ -2,7 +2,7 @@ import React, { memo, Suspense, useCallback, useState } from 'react' import { Avatar, Link, List, ListItem, ListItemText, Typography } from '@mui/material' -import type { ProfileIdentifier, ProfileInformation, NextIDPlatform, PersonaInformation } from '@masknet/shared-base' +import type { ProfileIdentifier, NextIDPlatform, PersonaInformation } from '@masknet/shared-base' import { makeStyles } from '@masknet/theme' import { useI18N } from '../../../../../../utils/i18n-next-ui' import { GrayMasks } from '@masknet/icons' @@ -136,12 +136,6 @@ export const ProfileList = memo((props: ProfileListProps) => { ) }) -export interface MergedProfileInformation extends ProfileInformation { - is_valid?: boolean - identity?: string - platform?: NextIDPlatform -} - interface ProfileListUIProps { onConnectProfile(network: string): void onConnectNextID(profile: ProfileIdentifier): void diff --git a/packages/mask/src/setup.popup.ssr.tsx b/packages/mask/src/setup.popup.ssr.tsx index b8242ed2c5cc..385207b7ef98 100644 --- a/packages/mask/src/setup.popup.ssr.tsx +++ b/packages/mask/src/setup.popup.ssr.tsx @@ -1,3 +1,13 @@ +// ! This file is used during SSR. DO NOT import new files that does not work in SSR + +import { Suspense } from 'react' +import { + FacebookColoredIcon, + InstagramColoredIcon, + MindsIcon, + TwitterColoredIcon, + OpenSeaColoredIcon, +} from '@masknet/icons' import { i18NextInstance, updateLanguage, EnhanceableSite, PopupRoutes } from '@masknet/shared-base' import { once, noop } from 'lodash-unified' import { TssCacheProvider, MaskThemeProvider } from '@masknet/theme' @@ -12,14 +22,6 @@ import { StaticRouter } from 'react-router-dom/server' import { PopupFrame } from './extension/popups/components/PopupFrame' import { PersonaHomeUI } from './extension/popups/pages/Personas/Home/UI' import { usePopupFullPageTheme } from './utils/theme/useClassicMaskFullPageTheme' -import { - FacebookColoredIcon, - InstagramColoredIcon, - MindsIcon, - TwitterColoredIcon, - OpenSeaColoredIcon, -} from '@masknet/icons' -import { Suspense } from 'react' const init = once(() => i18NextInstance.init().then(() => { @@ -63,10 +65,13 @@ const DEFINED_SITES = [ ] function PopupSSR(props: PopupSSR_Props) { const currentPersona = props.personas?.find((x) => x.identifier.equals(props.currentPersona)) + function useTheme() { + return usePopupFullPageTheme(props.language) + } return ( 'light'}> diff --git a/packages/mask/src/utils/theme/MaskTheme.ts b/packages/mask/src/utils/theme/MaskTheme.ts index e7a93479ba3d..3aad54159e25 100644 --- a/packages/mask/src/utils/theme/MaskTheme.ts +++ b/packages/mask/src/utils/theme/MaskTheme.ts @@ -1,3 +1,5 @@ +// ! This file is used during SSR. DO NOT import new files that does not work in SSR + import { unstable_createMuiStrictModeTheme, type ThemeOptions } from '@mui/material' import { grey, orange } from '@mui/material/colors' import { cloneDeep, merge } from 'lodash-unified' diff --git a/packages/mask/src/utils/theme/useClassicMaskFullPageTheme.ts b/packages/mask/src/utils/theme/useClassicMaskFullPageTheme.ts index 40fe44cbacae..8a7b629b48e7 100644 --- a/packages/mask/src/utils/theme/useClassicMaskFullPageTheme.ts +++ b/packages/mask/src/utils/theme/useClassicMaskFullPageTheme.ts @@ -1,3 +1,6 @@ +// ! This file is used during SSR. DO NOT import new files that does not work in SSR + +import type { LanguageOptions } from '@masknet/public-api' import { Appearance } from '@masknet/theme' import { PaletteMode, unstable_createMuiStrictModeTheme } from '@mui/material' import type { Localization } from '@mui/material/locale' @@ -22,6 +25,6 @@ export function useClassicMaskFullPageTheme( /** * @deprecated Should migrate to \@masknet/theme */ -export function usePopupFullPageTheme() { - return useClassicMaskFullPageTheme(Appearance.light, useThemeLanguage()) +export function usePopupFullPageTheme(language: LanguageOptions) { + return useClassicMaskFullPageTheme(Appearance.light, useThemeLanguage(language)) } diff --git a/packages/mask/src/utils/theme/useClassicMaskSNSTheme.ts b/packages/mask/src/utils/theme/useClassicMaskSNSTheme.ts index 28c49addb961..e8f23320ff84 100644 --- a/packages/mask/src/utils/theme/useClassicMaskSNSTheme.ts +++ b/packages/mask/src/utils/theme/useClassicMaskSNSTheme.ts @@ -7,19 +7,22 @@ import { MaskDarkTheme, MaskLightTheme } from './MaskTheme' import { useThemeLanguage } from './useThemeLanguage' import { SubscriptionFromValueRef } from '@masknet/shared-base' import { ValueRef } from '@dimensiondev/holoflows-kit' +import { useValueRef } from '@masknet/shared-base-ui' +import { languageSettings } from '../../settings/settings' const staticRef = SubscriptionFromValueRef(new ValueRef('light')) +const defaultUseTheme = (t: Theme) => t /** * @deprecated Should migrate to \@masknet/theme */ export function useClassicMaskSNSTheme() { - const { current: provider } = useRef(activatedSocialNetworkUI.customization.paletteMode?.current || staticRef) - const { current: usePostTheme = (t: Theme) => t } = useRef(activatedSocialNetworkUI.customization.useTheme) + const provider = useRef(activatedSocialNetworkUI.customization.paletteMode?.current || staticRef).current + const usePostTheme = useRef(activatedSocialNetworkUI.customization.useTheme || defaultUseTheme).current const palette = useSubscription(provider) const baseTheme = palette === 'dark' ? MaskDarkTheme : MaskLightTheme // TODO: support RTL? - const [localization, isRTL] = useThemeLanguage() + const [localization, isRTL] = useThemeLanguage(useValueRef(languageSettings)) const theme = unstable_createMuiStrictModeTheme(baseTheme, localization) return usePostTheme(theme) } diff --git a/packages/mask/src/utils/theme/useThemeLanguage.ts b/packages/mask/src/utils/theme/useThemeLanguage.ts index cc3bea16ad88..866aa67ced34 100644 --- a/packages/mask/src/utils/theme/useThemeLanguage.ts +++ b/packages/mask/src/utils/theme/useThemeLanguage.ts @@ -1,7 +1,7 @@ -import { useValueRef } from '@masknet/shared-base-ui' +// ! This file is used during SSR. DO NOT import new files that does not work in SSR + import { LanguageOptions, SupportedLanguages } from '@masknet/public-api' import { jaJP, koKR, zhTW, zhCN, enUS, Localization } from '@mui/material/locale/index' -import { languageSettings } from '../../settings/settings' import { i18NextInstance, updateLanguage } from '@masknet/shared-base' const langs: Record = { @@ -11,9 +11,7 @@ const langs: Record = { [SupportedLanguages.zhTW]: zhTW, [SupportedLanguages.zhCN]: zhCN, } -export function useThemeLanguage(): [loc: Localization, RTL: boolean] { - let language = useValueRef(languageSettings) - +export function useThemeLanguage(language: LanguageOptions): [loc: Localization, RTL: boolean] { if (language === LanguageOptions.__auto__) { updateLanguage(language) if (Object.values(SupportedLanguages).some((x) => x === i18NextInstance.language)) { From 02c303e6ad51616ed912af4d7a035e45fe5e1aa5 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Sat, 2 Apr 2022 16:45:56 +0800 Subject: [PATCH 15/20] chore: move to own entry --- packages/mask/.webpack/config.ts | 4 +- .../tasks/Cancellable/PopupSSR/index.ts | 2 +- packages/mask/public/patches.js | 6 ++- packages/mask/public/popups-ssr.html | 15 ------ packages/mask/public/popups-ssr.js | 25 --------- .../options-page/DashboardDialogs/Base.tsx | 7 +-- .../mask/src/extension/popups/SSR-render.ts | 52 +++++++++++++++++++ packages/mask/src/extension/popups/UI.tsx | 9 ++-- .../extension/popups/pages/Personas/index.tsx | 8 +-- .../extension/popups/pages/Wallet/index.tsx | 38 +++++++------- packages/mask/src/extension/popups/render.tsx | 4 +- packages/mask/src/manifest.json | 2 +- .../theme/useClassicMaskFullPageTheme.ts | 10 ++-- 13 files changed, 94 insertions(+), 88 deletions(-) delete mode 100644 packages/mask/public/popups-ssr.html delete mode 100644 packages/mask/public/popups-ssr.js create mode 100644 packages/mask/src/extension/popups/SSR-render.ts diff --git a/packages/mask/.webpack/config.ts b/packages/mask/.webpack/config.ts index 8fe5fbdd2ac9..5b76fab45b9c 100644 --- a/packages/mask/.webpack/config.ts +++ b/packages/mask/.webpack/config.ts @@ -279,7 +279,7 @@ export function createConfiguration(rawFlags: BuildFlags): Configuration { const plugins = baseConfig.plugins! const entries: Record = (baseConfig.entry = { dashboard: normalizeEntryDescription(join(__dirname, '../src/extension/dashboard/index.tsx')), - popups: normalizeEntryDescription(join(__dirname, '../src/extension/popups/render.tsx')), + popups: normalizeEntryDescription(join(__dirname, '../src/extension/popups/SSR-render.ts')), contentScript: normalizeEntryDescription(join(__dirname, '../src/content-script.ts')), debug: normalizeEntryDescription(join(__dirname, '../src/extension/debug-page/index.tsx')), }) @@ -353,7 +353,7 @@ function addHTMLEntry( if (options.sourceMap) { templateContent = templateContent.replace( ``, - ``, + ``, ) } return new HTMLPlugin({ diff --git a/packages/mask/background/tasks/Cancellable/PopupSSR/index.ts b/packages/mask/background/tasks/Cancellable/PopupSSR/index.ts index 52c411802602..709c8ea17a15 100644 --- a/packages/mask/background/tasks/Cancellable/PopupSSR/index.ts +++ b/packages/mask/background/tasks/Cancellable/PopupSSR/index.ts @@ -2,7 +2,7 @@ import { serializer } from '@masknet/shared-base' import { OnDemandWorker } from '../../../../utils-pure/OnDemandWorker' import { cache, startListen } from './cache' -const worker = new OnDemandWorker(new URL('./worker_init.ts', import.meta.url), { name: 'PopupSSR' }) +const worker = new OnDemandWorker(new URL('./worker_init.ts', import.meta.url), { name: 'PopupSSR-Worker' }) export default async function PopupSSR(signal: AbortSignal) { browser.runtime.onMessage.addListener(f) diff --git a/packages/mask/public/patches.js b/packages/mask/public/patches.js index 4e3f6866390a..b1876d0aa97f 100644 --- a/packages/mask/public/patches.js +++ b/packages/mask/public/patches.js @@ -83,13 +83,17 @@ globalThis.regeneratorRuntime = undefined } { - if (typeof trustedTypes === 'object') { + if (typeof trustedTypes === 'object' && location.protocol.includes('extension')) { trustedTypes.createPolicy('default', { createHTML: (string) => { console.trace('[Trusted Types](default policy): Possible XSS happened. Please remove it.', string) return string }, }) + + if (location.pathname !== '/popup-ssr.html') { + trustedTypes.createPolicy('ssr', {}) + } } } diff --git a/packages/mask/public/popups-ssr.html b/packages/mask/public/popups-ssr.html deleted file mode 100644 index 407b4fcd652d..000000000000 --- a/packages/mask/public/popups-ssr.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - Mask Network - - - - - - - - - - - diff --git a/packages/mask/public/popups-ssr.js b/packages/mask/public/popups-ssr.js deleted file mode 100644 index f67b6f46677b..000000000000 --- a/packages/mask/public/popups-ssr.js +++ /dev/null @@ -1,25 +0,0 @@ -if (location.hash === '') location.hash = '#/personas' - -if (location.hash === '#/personas') { - console.time('[SSR] Request') - browser.runtime.sendMessage({ type: 'popups-ssr' }).then(({ html, css }) => { - // Hmm, React goes first - if (document.querySelector('#root')) return - console.timeEnd('[SSR] Request') - console.time('[SSR] Hydrate') - document.head.insertAdjacentHTML('beforeend', css) - document.body.innerHTML = '
' + html + '
' - }) -} - -load() -async function load() { - const html = await fetch('/popups.html').then((x) => x.text()) - const parser = new DOMParser() - const doc = parser.parseFromString(html, 'text/html') - for (const script of doc.body.querySelectorAll('script')) { - import(new URL(script.src, location.href).toString()) - } -} -// As the return value of the executeScript -undefined diff --git a/packages/mask/src/extension/options-page/DashboardDialogs/Base.tsx b/packages/mask/src/extension/options-page/DashboardDialogs/Base.tsx index 3472eb2be29e..c343885b9ce5 100644 --- a/packages/mask/src/extension/options-page/DashboardDialogs/Base.tsx +++ b/packages/mask/src/extension/options-page/DashboardDialogs/Base.tsx @@ -12,7 +12,7 @@ import { import { makeStyles } from '@masknet/theme' import { Theme, ThemeOptions, ThemeProvider } from '@mui/material/styles' import CloseIcon from '@mui/icons-material/Close' -import { useMatchXS, useThemeLanguage } from '../../../utils' +import { useMatchXS } from '../../../utils' import { useValueRef } from '@masknet/shared-base-ui' import { appearanceSettings, languageSettings } from '../../../settings/settings' import { cloneDeep, merge } from 'lodash-unified' @@ -105,10 +105,7 @@ export function useModal diff --git a/packages/mask/src/extension/popups/SSR-render.ts b/packages/mask/src/extension/popups/SSR-render.ts new file mode 100644 index 000000000000..664d94986035 --- /dev/null +++ b/packages/mask/src/extension/popups/SSR-render.ts @@ -0,0 +1,52 @@ +// This file should not import any file!! +/// + +// If the current page is "", navigate to "#/personas", therefore we can avoid a Router skip when hydrating. +if (location.hash === '') location.assign('#/personas') + +declare const trustedTypes: any +let trustedHTML: (x: string) => string +{ + if (typeof trustedTypes === 'object') { + const policy = trustedTypes.createPolicy('ssr', { + createHTML: (x: string) => String(x), + }) + trustedHTML = (x) => policy.createHTML(x) + } else { + trustedHTML = (x) => x + } +} + +if (location.hash === '#/personas') { + console.time('[SSR] Request') + browser.runtime.sendMessage({ type: 'popups-ssr' }).then(({ html, css }) => { + // React go first, but is that possible? + if (document.querySelector('#root')) return + + // Push SSR code + document.head.insertAdjacentHTML('beforeend', trustedHTML(css)) + document.body.innerHTML = trustedHTML('
' + html + '
') + console.timeEnd('[SSR] Request') + + console.time('[SSR] Hydrate') + }) + setTimeout(() => { + import(/* webpackPreload: true */ './render') + }, 15) +} else { + import(/* webpackPreload: true */ './render') +} + +// this function is never called, but it will hint webpack to preload modules we need +function prefetch() { + // Pages + import(/* webpackPreload: true */ './pages/Personas') + import(/* webpackPreload: true */ './pages/Personas/Home') + import(/* webpackPrefetch: true */ './pages/Wallet') +} + +// To make prefecher not tree-shaked +if (''.toLowerCase() === 'hint') { + prefetch() +} +export {} diff --git a/packages/mask/src/extension/popups/UI.tsx b/packages/mask/src/extension/popups/UI.tsx index 82e574c3015c..5fa1f0953fb6 100644 --- a/packages/mask/src/extension/popups/UI.tsx +++ b/packages/mask/src/extension/popups/UI.tsx @@ -8,18 +8,17 @@ import { PopupWeb3Context } from '../../web3/context' import { PopupFrame } from './components/PopupFrame' import { Appearance } from '@masknet/theme' import { MaskUIRoot } from '../../UIRoot' -import { useThemeLanguage } from '../../utils/theme' import { useClassicMaskFullPageTheme } from '../../utils/theme/useClassicMaskFullPageTheme' import { useMyPersonas } from '../../components/DataSource/useMyPersonas' import { useValueRef } from '@masknet/shared-base-ui' import { languageSettings } from '../../settings/settings' function useAlwaysLightTheme() { - return useClassicMaskFullPageTheme(Appearance.light, useThemeLanguage(useValueRef(languageSettings))) + return useClassicMaskFullPageTheme(Appearance.light, useValueRef(languageSettings)) } -const Wallet = lazy(() => import('./pages/Wallet')) -const Personas = lazy(() => import('./pages/Personas')) -const SwapPage = lazy(() => import('./pages/Swap')) +const Wallet = lazy(() => import(/* webpackPrefetch: true */ './pages/Wallet')) +const Personas = lazy(() => import(/* webpackPrefetch: true */ './pages/Personas')) +const SwapPage = lazy(() => import(/* webpackPrefetch: true */ './pages/Swap')) const RequestPermissionPage = lazy(() => import('./RequestPermission')) const PermissionAwareRedirect = lazy(() => import('./PermissionAwareRedirect')) const ThirdPartyRequestPermission = lazy(() => import('./ThirdPartyRequestPermission')) diff --git a/packages/mask/src/extension/popups/pages/Personas/index.tsx b/packages/mask/src/extension/popups/pages/Personas/index.tsx index 8e1a5ead5ca1..788b2e7d2126 100644 --- a/packages/mask/src/extension/popups/pages/Personas/index.tsx +++ b/packages/mask/src/extension/popups/pages/Personas/index.tsx @@ -5,10 +5,10 @@ import { PersonaContext } from './hooks/usePersonaContext' import { PopupRoutes, relativeRouteOf } from '@masknet/shared-base' import { Route, Routes } from 'react-router-dom' -const Home = lazy(() => import('./Home')) -const Logout = lazy(() => import('./Logout')) -const PersonaRename = lazy(() => import('./Rename')) -const PersonaSignRequest = lazy(() => import('./PersonaSignRequest')) +const Home = lazy(() => import(/* webpackPrefetch: true */ './Home')) +const Logout = lazy(() => import(/* webpackPrefetch: true */ './Logout')) +const PersonaRename = lazy(() => import(/* webpackPrefetch: true */ './Rename')) +const PersonaSignRequest = lazy(() => import(/* webpackPrefetch: true */ './PersonaSignRequest')) const r = relativeRouteOf(PopupRoutes.Personas) const Persona = memo(() => { diff --git a/packages/mask/src/extension/popups/pages/Wallet/index.tsx b/packages/mask/src/extension/popups/pages/Wallet/index.tsx index 5da93e45c4dd..bba50776c50d 100644 --- a/packages/mask/src/extension/popups/pages/Wallet/index.tsx +++ b/packages/mask/src/extension/popups/pages/Wallet/index.tsx @@ -13,25 +13,25 @@ import SelectWallet from './SelectWallet' import { useWalletLockStatus } from './hooks/useWalletLockStatus' import urlcat from 'urlcat' -const ImportWallet = lazy(() => import('./ImportWallet')) -const AddDeriveWallet = lazy(() => import('./AddDeriveWallet')) -const WalletSettings = lazy(() => import('./WalletSettings')) -const WalletRename = lazy(() => import('./WalletRename')) -const DeleteWallet = lazy(() => import('./DeleteWallet')) -const CreateWallet = lazy(() => import('./CreateWallet')) -const SwitchWallet = lazy(() => import('./SwitchWallet')) -const BackupWallet = lazy(() => import('./BackupWallet')) -const AddToken = lazy(() => import('./AddToken')) -const TokenDetail = lazy(() => import('./TokenDetail')) -const SignRequest = lazy(() => import('./SignRequest')) -const GasSetting = lazy(() => import('./GasSetting')) -const Transfer = lazy(() => import('./Transfer')) -const ContractInteraction = lazy(() => import('./ContractInteraction')) -const Unlock = lazy(() => import('./Unlock')) -const SetPaymentPassword = lazy(() => import('./SetPaymentPassword')) -const WalletRecovery = lazy(() => import('./WalletRecovery')) -const LegacyWalletRecovery = lazy(() => import('./LegacyWalletRecovery')) -const ReplaceTransaction = lazy(() => import('./ReplaceTransaction')) +const ImportWallet = lazy(() => import(/* webpackPrefetch: true */ './ImportWallet')) +const AddDeriveWallet = lazy(() => import(/* webpackPrefetch: true */ './AddDeriveWallet')) +const WalletSettings = lazy(() => import(/* webpackPrefetch: true */ './WalletSettings')) +const WalletRename = lazy(() => import(/* webpackPrefetch: true */ './WalletRename')) +const DeleteWallet = lazy(() => import(/* webpackPrefetch: true */ './DeleteWallet')) +const CreateWallet = lazy(() => import(/* webpackPrefetch: true */ './CreateWallet')) +const SwitchWallet = lazy(() => import(/* webpackPrefetch: true */ './SwitchWallet')) +const BackupWallet = lazy(() => import(/* webpackPrefetch: true */ './BackupWallet')) +const AddToken = lazy(() => import(/* webpackPrefetch: true */ './AddToken')) +const TokenDetail = lazy(() => import(/* webpackPrefetch: true */ './TokenDetail')) +const SignRequest = lazy(() => import(/* webpackPrefetch: true */ './SignRequest')) +const GasSetting = lazy(() => import(/* webpackPrefetch: true */ './GasSetting')) +const Transfer = lazy(() => import(/* webpackPrefetch: true */ './Transfer')) +const ContractInteraction = lazy(() => import(/* webpackPrefetch: true */ './ContractInteraction')) +const Unlock = lazy(() => import(/* webpackPrefetch: true */ './Unlock')) +const SetPaymentPassword = lazy(() => import(/* webpackPrefetch: true */ './SetPaymentPassword')) +const WalletRecovery = lazy(() => import(/* webpackPrefetch: true */ './WalletRecovery')) +const LegacyWalletRecovery = lazy(() => import(/* webpackPrefetch: true */ './LegacyWalletRecovery')) +const ReplaceTransaction = lazy(() => import(/* webpackPrefetch: true */ './ReplaceTransaction')) const r = relativeRouteOf(PopupRoutes.Wallet) export default function Wallet() { diff --git a/packages/mask/src/extension/popups/render.tsx b/packages/mask/src/extension/popups/render.tsx index 45ab8a62e79b..2d2eb96e93d6 100644 --- a/packages/mask/src/extension/popups/render.tsx +++ b/packages/mask/src/extension/popups/render.tsx @@ -10,10 +10,8 @@ import { CacheProvider } from '@emotion/react' import { TssCacheProvider } from '@masknet/theme' import { initData } from './pages/Personas/hooks/usePersonaContext' -if (location.hash === '' || location.hash === '#/personas') { +if (location.hash === '#/personas') { async function hydrate() { - import('./pages/Personas') - import('./pages/Personas/Home') await Promise.all([ Services.Identity.queryCurrentPersona().then((x) => (initData.currentIdentifier = x?.toText())), Services.Identity.queryOwnedPersonaInformation().then((x) => (initData.personas = x)), diff --git a/packages/mask/src/manifest.json b/packages/mask/src/manifest.json index 2dde7cd12dc9..f436056eeecf 100644 --- a/packages/mask/src/manifest.json +++ b/packages/mask/src/manifest.json @@ -7,7 +7,7 @@ "background": { "page": "background.html" }, "options_ui": { "page": "dashboard.html", "open_in_tab": true }, "icons": { "16": "16x16.png", "48": "48x48.png", "128": "128x128.png", "256": "256x256.png" }, - "browser_action": { "default_popup": "popups-ssr.html" }, + "browser_action": { "default_popup": "popups.html" }, "homepage_url": "https://mask.io", "description": "The portal to the new & open Internet. Send encrypted message and decentralized Apps right on top of social networks.", "web_accessible_resources": ["js/*", "*.png", "*.css"], diff --git a/packages/mask/src/utils/theme/useClassicMaskFullPageTheme.ts b/packages/mask/src/utils/theme/useClassicMaskFullPageTheme.ts index 8a7b629b48e7..8a0da1724299 100644 --- a/packages/mask/src/utils/theme/useClassicMaskFullPageTheme.ts +++ b/packages/mask/src/utils/theme/useClassicMaskFullPageTheme.ts @@ -3,28 +3,24 @@ import type { LanguageOptions } from '@masknet/public-api' import { Appearance } from '@masknet/theme' import { PaletteMode, unstable_createMuiStrictModeTheme } from '@mui/material' -import type { Localization } from '@mui/material/locale' import { MaskDarkTheme, MaskLightTheme } from './MaskTheme' import { useThemeLanguage } from './useThemeLanguage' /** * @deprecated Should migrate to \@masknet/theme */ -export function useClassicMaskFullPageTheme( - userPreference: Appearance, - [localization]: [loc: Localization, RTL: boolean], -) { +export function useClassicMaskFullPageTheme(userPreference: Appearance, language: LanguageOptions) { const systemPreference: PaletteMode = 'matchMedia' in globalThis ? (matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : 'light' const finalPalette: PaletteMode = userPreference === Appearance.default ? systemPreference : userPreference const baseTheme = finalPalette === 'dark' ? MaskDarkTheme : MaskLightTheme - return unstable_createMuiStrictModeTheme(baseTheme, localization) + return unstable_createMuiStrictModeTheme(baseTheme, useThemeLanguage(language)) } /** * @deprecated Should migrate to \@masknet/theme */ export function usePopupFullPageTheme(language: LanguageOptions) { - return useClassicMaskFullPageTheme(Appearance.light, useThemeLanguage(language)) + return useClassicMaskFullPageTheme(Appearance.light, language) } From 659a8ab685c7d4df293b0b29c71b21aad446ce12 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Sat, 2 Apr 2022 16:48:08 +0800 Subject: [PATCH 16/20] chore: move to own entry --- packages/mask/public/patches.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mask/public/patches.js b/packages/mask/public/patches.js index b1876d0aa97f..15196a4545a8 100644 --- a/packages/mask/public/patches.js +++ b/packages/mask/public/patches.js @@ -91,7 +91,7 @@ globalThis.regeneratorRuntime = undefined }, }) - if (location.pathname !== '/popup-ssr.html') { + if (location.pathname !== '/popups.html') { trustedTypes.createPolicy('ssr', {}) } } From c2938ad33fd8039b6b0ce9a2bbb3af972e909700 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Sat, 2 Apr 2022 16:58:00 +0800 Subject: [PATCH 17/20] chore: move files --- packages/mask/.webpack/config.ts | 2 +- .../background/tasks/Cancellable/PopupSSR/loader.js | 5 +++-- .../extension/popups/{SSR-render.ts => SSR-client.ts} | 4 ++-- .../popups/SSR-server.tsx} | 10 +++++----- .../extension/popups/{render.tsx => normal-client.tsx} | 0 packages/shared/src/constants.tsx | 2 +- 6 files changed, 12 insertions(+), 11 deletions(-) rename packages/mask/src/extension/popups/{SSR-render.ts => SSR-client.ts} (92%) rename packages/mask/src/{setup.popup.ssr.tsx => extension/popups/SSR-server.tsx} (91%) rename packages/mask/src/extension/popups/{render.tsx => normal-client.tsx} (100%) diff --git a/packages/mask/.webpack/config.ts b/packages/mask/.webpack/config.ts index 5b76fab45b9c..5366a168b41b 100644 --- a/packages/mask/.webpack/config.ts +++ b/packages/mask/.webpack/config.ts @@ -279,7 +279,7 @@ export function createConfiguration(rawFlags: BuildFlags): Configuration { const plugins = baseConfig.plugins! const entries: Record = (baseConfig.entry = { dashboard: normalizeEntryDescription(join(__dirname, '../src/extension/dashboard/index.tsx')), - popups: normalizeEntryDescription(join(__dirname, '../src/extension/popups/SSR-render.ts')), + popups: normalizeEntryDescription(join(__dirname, '../src/extension/popups/SSR-client.ts')), contentScript: normalizeEntryDescription(join(__dirname, '../src/content-script.ts')), debug: normalizeEntryDescription(join(__dirname, '../src/extension/debug-page/index.tsx')), }) diff --git a/packages/mask/background/tasks/Cancellable/PopupSSR/loader.js b/packages/mask/background/tasks/Cancellable/PopupSSR/loader.js index c4aaaef1ab08..ea2f4d35168a 100644 --- a/packages/mask/background/tasks/Cancellable/PopupSSR/loader.js +++ b/packages/mask/background/tasks/Cancellable/PopupSSR/loader.js @@ -1,5 +1,6 @@ // This is a JS file to make TypeScript happy. -import { render as _ } from '../../../../src/setup.popup.ssr.tsx' +import { render as _ } from '../../../../src/extension/popups/SSR-server.tsx' export let render = _ -import.meta.webpackHot && import.meta.webpackHot.accept('../../../../src/setup.popup.ssr.tsx', () => (render = _)) +import.meta.webpackHot && + import.meta.webpackHot.accept('../../../../src/extension/popups/SSR-server.tsx', () => (render = _)) diff --git a/packages/mask/src/extension/popups/SSR-render.ts b/packages/mask/src/extension/popups/SSR-client.ts similarity index 92% rename from packages/mask/src/extension/popups/SSR-render.ts rename to packages/mask/src/extension/popups/SSR-client.ts index 664d94986035..0d114a91c3a2 100644 --- a/packages/mask/src/extension/popups/SSR-render.ts +++ b/packages/mask/src/extension/popups/SSR-client.ts @@ -31,10 +31,10 @@ if (location.hash === '#/personas') { console.time('[SSR] Hydrate') }) setTimeout(() => { - import(/* webpackPreload: true */ './render') + import(/* webpackPreload: true */ './normal-client') }, 15) } else { - import(/* webpackPreload: true */ './render') + import(/* webpackPreload: true */ './normal-client') } // this function is never called, but it will hint webpack to preload modules we need diff --git a/packages/mask/src/setup.popup.ssr.tsx b/packages/mask/src/extension/popups/SSR-server.tsx similarity index 91% rename from packages/mask/src/setup.popup.ssr.tsx rename to packages/mask/src/extension/popups/SSR-server.tsx index 385207b7ef98..6d13e392c62f 100644 --- a/packages/mask/src/setup.popup.ssr.tsx +++ b/packages/mask/src/extension/popups/SSR-server.tsx @@ -16,12 +16,12 @@ import { renderToString } from 'react-dom/server' import createCache from '@emotion/cache' import createEmotionServer from '@emotion/server/create-instance' import { initReactI18next } from 'react-i18next' -import { addMaskI18N } from '../shared-ui/locales/languages' -import type { PopupSSR_Props } from '../background/tasks/Cancellable/PopupSSR/type' +import { addMaskI18N } from '../../../shared-ui/locales/languages' +import type { PopupSSR_Props } from '../../../background/tasks/Cancellable/PopupSSR/type' import { StaticRouter } from 'react-router-dom/server' -import { PopupFrame } from './extension/popups/components/PopupFrame' -import { PersonaHomeUI } from './extension/popups/pages/Personas/Home/UI' -import { usePopupFullPageTheme } from './utils/theme/useClassicMaskFullPageTheme' +import { PopupFrame } from './components/PopupFrame' +import { PersonaHomeUI } from './pages/Personas/Home/UI' +import { usePopupFullPageTheme } from '../../utils/theme/useClassicMaskFullPageTheme' const init = once(() => i18NextInstance.init().then(() => { diff --git a/packages/mask/src/extension/popups/render.tsx b/packages/mask/src/extension/popups/normal-client.tsx similarity index 100% rename from packages/mask/src/extension/popups/render.tsx rename to packages/mask/src/extension/popups/normal-client.tsx diff --git a/packages/shared/src/constants.tsx b/packages/shared/src/constants.tsx index 99930ff4457e..37e1655d5a44 100644 --- a/packages/shared/src/constants.tsx +++ b/packages/shared/src/constants.tsx @@ -12,7 +12,7 @@ export const TWITTER_ID = 'twitter.com' export const INSTAGRAM_ID = 'instagram.com' export const OPENSEA_ID = 'opensea.io' -// When you add a new icon, don't forget to add it in packages/mask/src/setup.popup.ssr.tsx +// When you add a new icon, don't forget to add it in packages/mask/src/extension/popups/SSR-server.tsx export const SOCIAL_MEDIA_ICON_MAPPING: Record = { [TWITTER_ID]: , [FACEBOOK_ID]: , From 074a726d26e3cd8bc3f2382ba52b92ecec778dd0 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Sat, 2 Apr 2022 17:16:08 +0800 Subject: [PATCH 18/20] fix: more errors --- .../src/extension/popups/normal-client.tsx | 32 +++++++++++-------- .../SNSAdaptor/RiskWarningDialog/index.tsx | 10 +++--- .../mask/src/utils/theme/useThemeLanguage.ts | 14 +++++--- .../plugins/GoPlusSecurity/src/constants.ts | 1 - 4 files changed, 32 insertions(+), 25 deletions(-) diff --git a/packages/mask/src/extension/popups/normal-client.tsx b/packages/mask/src/extension/popups/normal-client.tsx index 2d2eb96e93d6..85252f332101 100644 --- a/packages/mask/src/extension/popups/normal-client.tsx +++ b/packages/mask/src/extension/popups/normal-client.tsx @@ -28,24 +28,28 @@ if (location.hash === '#/personas') { , ) + startPluginHost() import('./pages/Wallet') console.timeEnd('[SSR] Hydrate') } hydrate() } else { - status.then(() => createNormalReactRoot()) + status.then(() => createNormalReactRoot()).then(startPluginHost) } -// TODO: Should only load plugins when the page is plugin-aware. -startPluginDashboard( - createPluginHost(undefined, (pluginID, signal) => { - return { - createKVStorage(type, defaultValues) { - if (type === 'memory') return InMemoryStorages.Plugin.createSubScope(pluginID, defaultValues, signal) - else return PersistentStorages.Plugin.createSubScope(pluginID, defaultValues, signal) - }, - personaSign: Services.Identity.signWithPersona, - walletSign: Services.Ethereum.personalSign, - } - }), -) +function startPluginHost() { + // TODO: Should only load plugins when the page is plugin-aware. + startPluginDashboard( + createPluginHost(undefined, (pluginID, signal) => { + return { + createKVStorage(type, defaultValues) { + if (type === 'memory') + return InMemoryStorages.Plugin.createSubScope(pluginID, defaultValues, signal) + else return PersistentStorages.Plugin.createSubScope(pluginID, defaultValues, signal) + }, + personaSign: Services.Identity.signWithPersona, + walletSign: Services.Ethereum.personalSign, + } + }), + ) +} diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/RiskWarningDialog/index.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/RiskWarningDialog/index.tsx index 0c01a034f884..19b6b54280de 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/RiskWarningDialog/index.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/RiskWarningDialog/index.tsx @@ -50,9 +50,9 @@ const useStyles = makeStyles()((theme) => ({ marginTop: theme.spacing(2), padding: theme.spacing(2), borderRadius: theme.spacing(1), - '&> :first-child': { - paddingBottom: theme.spacing(1), - }, + }, + texts: { + paddingBottom: theme.spacing(1), }, })) @@ -104,10 +104,10 @@ export function WalletRiskWarningDialog() { children={{t('wallet_risk_warning_content')}} /> - + {t('nft_wallet_label')} - + {isMobile ? formatEthereumAddress(account, 5) : account} diff --git a/packages/mask/src/utils/theme/useThemeLanguage.ts b/packages/mask/src/utils/theme/useThemeLanguage.ts index 866aa67ced34..841c44fbcf6e 100644 --- a/packages/mask/src/utils/theme/useThemeLanguage.ts +++ b/packages/mask/src/utils/theme/useThemeLanguage.ts @@ -2,7 +2,8 @@ import { LanguageOptions, SupportedLanguages } from '@masknet/public-api' import { jaJP, koKR, zhTW, zhCN, enUS, Localization } from '@mui/material/locale/index' -import { i18NextInstance, updateLanguage } from '@masknet/shared-base' +import { updateLanguage } from '@masknet/shared-base' +import { startTransition, useEffect } from 'react' const langs: Record = { [SupportedLanguages.enUS]: enUS, @@ -12,11 +13,14 @@ const langs: Record = { [SupportedLanguages.zhCN]: zhCN, } export function useThemeLanguage(language: LanguageOptions): [loc: Localization, RTL: boolean] { + useEffect(() => { + if (language !== LanguageOptions.__auto__) return + startTransition(() => updateLanguage(language)) + }, [language]) + if (language === LanguageOptions.__auto__) { - updateLanguage(language) - if (Object.values(SupportedLanguages).some((x) => x === i18NextInstance.language)) { - language = i18NextInstance.language as LanguageOptions - } + // we've scheduled an update above. + language = LanguageOptions.enUS } const displayLanguage = language as any as SupportedLanguages diff --git a/packages/plugins/GoPlusSecurity/src/constants.ts b/packages/plugins/GoPlusSecurity/src/constants.ts index 313d7a66f428..4c8011695027 100644 --- a/packages/plugins/GoPlusSecurity/src/constants.ts +++ b/packages/plugins/GoPlusSecurity/src/constants.ts @@ -1,7 +1,6 @@ import { PluginId } from '@masknet/plugin-infra' export const PLUGIN_ID = PluginId.GoPlusSecurity -export const PLUGIN_META_KEY = `${PluginId.GoPlusSecurity}:1` export const PLUGIN_DESCRIPTION = 'Go+ Security Engine' export const PLUGIN_NAME = 'GoPlusSecurity' export const PLUGIN_OFFICIAL_WEBSITE = 'https://gopluslabs.io' From 2fd33cf37d7eb30665b3e8e16df9d4cfad8638d3 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Sat, 2 Apr 2022 17:23:17 +0800 Subject: [PATCH 19/20] fix: reachable button --- .../mask/src/extension/popups/SSR-server.tsx | 4 +++- .../components/EnterDashboard/index.tsx | 24 +++++++++---------- .../components/InitialPlaceholder/index.tsx | 8 ++++++- .../popups/hook/useEnterDashboard.ts | 1 + 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/packages/mask/src/extension/popups/SSR-server.tsx b/packages/mask/src/extension/popups/SSR-server.tsx index 6d13e392c62f..53d18969dcd9 100644 --- a/packages/mask/src/extension/popups/SSR-server.tsx +++ b/packages/mask/src/extension/popups/SSR-server.tsx @@ -43,7 +43,9 @@ export async function render(props: PopupSSR_Props) { , - ).replaceAll('href="/', 'href="#/') + ) + .replaceAll('href="/', 'href="#/') + .replaceAll('href="#/dashboard', 'href="/dashboard') const muiCSS = muiServer.constructStyleTagsFromChunks(muiServer.extractCriticalToChunks(html)) const tssCSS = tssServer.constructStyleTagsFromChunks(tssServer.extractCriticalToChunks(html)) return { html, css: muiCSS + tssCSS } diff --git a/packages/mask/src/extension/popups/components/EnterDashboard/index.tsx b/packages/mask/src/extension/popups/components/EnterDashboard/index.tsx index f391883dbba1..0deb253dd484 100644 --- a/packages/mask/src/extension/popups/components/EnterDashboard/index.tsx +++ b/packages/mask/src/extension/popups/components/EnterDashboard/index.tsx @@ -1,27 +1,27 @@ // ! This file is used during SSR. DO NOT import new files that does not work in SSR import { memo } from 'react' -import { Box, Typography } from '@mui/material' +import { styled, Typography } from '@mui/material' import { useEnterDashboard } from '../../hook/useEnterDashboard' import { useI18N } from '../../../../utils/i18n-next-ui' +const Button = styled('a')({ + padding: '12px 16px', + cursor: 'pointer', + backgroundColor: '#ffffff', + width: '100%', + position: 'fixed', + bottom: 0, + textDecoration: 'none', +}) export const EnterDashboard = memo(() => { const { t } = useI18N() const onEnter = useEnterDashboard() return ( - + ) }) diff --git a/packages/mask/src/extension/popups/components/InitialPlaceholder/index.tsx b/packages/mask/src/extension/popups/components/InitialPlaceholder/index.tsx index af60e271d6ac..ecdd85f9e420 100644 --- a/packages/mask/src/extension/popups/components/InitialPlaceholder/index.tsx +++ b/packages/mask/src/extension/popups/components/InitialPlaceholder/index.tsx @@ -60,7 +60,13 @@ export const InitialPlaceholder = memo(() => { })} - diff --git a/packages/mask/src/extension/popups/hook/useEnterDashboard.ts b/packages/mask/src/extension/popups/hook/useEnterDashboard.ts index f283318f6aab..e3c7866c7b37 100644 --- a/packages/mask/src/extension/popups/hook/useEnterDashboard.ts +++ b/packages/mask/src/extension/popups/hook/useEnterDashboard.ts @@ -3,6 +3,7 @@ import { useCallback } from 'react' export const useEnterDashboard = () => { return useCallback((event: React.MouseEvent) => { + event.preventDefault() if (event.shiftKey) { browser.tabs.create({ active: true, From e58bb8ecebcaf802ef4c531a47af94bafb6c1594 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Sat, 2 Apr 2022 17:25:18 +0800 Subject: [PATCH 20/20] fix: extra import --- packages/mask/src/extension/popups/normal-client.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/mask/src/extension/popups/normal-client.tsx b/packages/mask/src/extension/popups/normal-client.tsx index 85252f332101..aa27c1814c2f 100644 --- a/packages/mask/src/extension/popups/normal-client.tsx +++ b/packages/mask/src/extension/popups/normal-client.tsx @@ -29,7 +29,6 @@ if (location.hash === '#/personas') { , ) startPluginHost() - import('./pages/Wallet') console.timeEnd('[SSR] Hydrate') } hydrate()