diff --git a/apps/web/src/components/blocksuite/workspace-header/download-tips.tsx b/apps/web/src/components/blocksuite/workspace-header/download-tips.tsx index 1e56f270cd..0763df3bc3 100644 --- a/apps/web/src/components/blocksuite/workspace-header/download-tips.tsx +++ b/apps/web/src/components/blocksuite/workspace-header/download-tips.tsx @@ -1,12 +1,11 @@ import { DownloadTips } from '@affine/component/affine-banner'; -import { getEnvironment } from '@affine/env'; +import { env } from '@affine/env'; import { useAtom } from 'jotai'; import { useCallback } from 'react'; import { guideDownloadClientTipAtom } from '../../../atoms/guide'; export const DownloadClientTip = () => { - const env = getEnvironment(); const [showDownloadClientTips, setShowDownloadClientTips] = useAtom( guideDownloadClientTipAtom ); diff --git a/apps/web/src/components/blocksuite/workspace-header/utils.tsx b/apps/web/src/components/blocksuite/workspace-header/utils.tsx index 212bdaa07e..63c1c65bad 100644 --- a/apps/web/src/components/blocksuite/workspace-header/utils.tsx +++ b/apps/web/src/components/blocksuite/workspace-header/utils.tsx @@ -1,4 +1,4 @@ -import { getEnvironment } from '@affine/env'; +import { env } from '@affine/env'; import { Trans } from '@affine/i18n'; import { useAFFiNEI18N } from '@affine/i18n/hooks'; import type React from 'react'; @@ -7,7 +7,6 @@ import { useEffect, useState } from 'react'; const minimumChromeVersion = 102; export const shouldShowWarning = () => { - const env = getEnvironment(); if (env.isDesktop) { // even though desktop have compatibility issues, we don't want to show the warning return false; @@ -28,7 +27,6 @@ export const OSWarningMessage: React.FC = () => { const [notChrome, setNotChrome] = useState(false); const [notGoodVersion, setNotGoodVersion] = useState(false); useEffect(() => { - const env = getEnvironment(); setNotChrome(env.isBrowser && !env.isChrome); setNotGoodVersion( env.isBrowser && env.isChrome && env.chromeVersion < minimumChromeVersion diff --git a/apps/web/src/components/pure/help-island/index.tsx b/apps/web/src/components/pure/help-island/index.tsx index afa317d004..9645be5c12 100644 --- a/apps/web/src/components/pure/help-island/index.tsx +++ b/apps/web/src/components/pure/help-island/index.tsx @@ -1,5 +1,5 @@ import { MuiFade, Tooltip } from '@affine/component'; -import { config, getEnvironment } from '@affine/env'; +import { config, env } from '@affine/env'; import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { CloseIcon, NewIcon, UserGuideIcon } from '@blocksuite/icons'; import { useAtom } from 'jotai'; @@ -15,7 +15,6 @@ import { StyledIsland, StyledTriggerWrapper, } from './style'; -const env = getEnvironment(); const ContactModal = lazy(() => import('@affine/component/contact-modal').then(({ ContactModal }) => ({ default: ContactModal, diff --git a/apps/web/src/components/pure/quick-search-modal/index.tsx b/apps/web/src/components/pure/quick-search-modal/index.tsx index b6744ccb92..f6ed37be6e 100644 --- a/apps/web/src/components/pure/quick-search-modal/index.tsx +++ b/apps/web/src/components/pure/quick-search-modal/index.tsx @@ -1,5 +1,5 @@ import { Modal, ModalWrapper } from '@affine/component'; -import { getEnvironment } from '@affine/env'; +import { env } from '@affine/env'; import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { Command } from 'cmdk'; import type { NextRouter } from 'next/router'; @@ -27,7 +27,6 @@ import { } from './style'; const isMac = () => { - const env = getEnvironment(); return env.isBrowser && env.isMacOs; }; diff --git a/apps/web/src/components/pure/shortcuts-modal/index.tsx b/apps/web/src/components/pure/shortcuts-modal/index.tsx index 33fbd20405..28c01c253e 100644 --- a/apps/web/src/components/pure/shortcuts-modal/index.tsx +++ b/apps/web/src/components/pure/shortcuts-modal/index.tsx @@ -3,7 +3,7 @@ import { MuiClickAwayListener, MuiSlide, } from '@affine/component'; -import { getEnvironment } from '@affine/env'; +import { env } from '@affine/env'; import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { useEffect, useState } from 'react'; @@ -27,7 +27,6 @@ type ModalProps = { }; const checkIsMac = () => { - const env = getEnvironment(); return env.isBrowser && env.isMacOs; }; diff --git a/apps/web/src/providers/modal-provider.tsx b/apps/web/src/providers/modal-provider.tsx index 2e64588540..874cc126e7 100644 --- a/apps/web/src/providers/modal-provider.tsx +++ b/apps/web/src/providers/modal-provider.tsx @@ -1,4 +1,4 @@ -import { getEnvironment } from '@affine/env'; +import { env } from '@affine/env'; import { rootCurrentWorkspaceIdAtom, rootWorkspacesMetadataAtom, @@ -56,7 +56,6 @@ export function CurrentWorkspaceModals() { openOnboardingModalAtom ); - const env = getEnvironment(); const onCloseOnboardingModal = useCallback(() => { setOpenOnboardingModal(false); }, [setOpenOnboardingModal]); diff --git a/apps/web/src/utils/create-emotion-cache.ts b/apps/web/src/utils/create-emotion-cache.ts index d35453df26..14b808e72b 100644 --- a/apps/web/src/utils/create-emotion-cache.ts +++ b/apps/web/src/utils/create-emotion-cache.ts @@ -1,7 +1,7 @@ -import { getEnvironment } from '@affine/env'; +import { env } from '@affine/env'; import createCache from '@emotion/cache'; -const isBrowser = getEnvironment().isBrowser; +const isBrowser = env.isBrowser; export default function createEmotionCache() { let insertionPoint; diff --git a/packages/component/src/components/app-sidebar/app-updater-button/index.jotai.ts b/packages/component/src/components/app-sidebar/app-updater-button/index.jotai.ts index 64702247a5..1a44e51399 100644 --- a/packages/component/src/components/app-sidebar/app-updater-button/index.jotai.ts +++ b/packages/component/src/components/app-sidebar/app-updater-button/index.jotai.ts @@ -1,4 +1,4 @@ -import { getEnvironment } from '@affine/env/config'; +import { env } from '@affine/env/config'; import { atomWithObservable, atomWithStorage } from 'jotai/utils'; import { Observable } from 'rxjs'; @@ -21,9 +21,8 @@ function rpcToObservable< ) { return new Observable(subscriber => { subscriber.next(initialValue); - const environment = getEnvironment(); onSubscribe?.(); - if (typeof window === 'undefined' || !environment.isDesktop || !event) { + if (typeof window === 'undefined' || !env.isDesktop || !event) { subscriber.complete(); return () => {}; } diff --git a/packages/component/src/components/app-sidebar/index.tsx b/packages/component/src/components/app-sidebar/index.tsx index 14b51dc78d..487063ed8c 100644 --- a/packages/component/src/components/app-sidebar/index.tsx +++ b/packages/component/src/components/app-sidebar/index.tsx @@ -1,4 +1,4 @@ -import { getEnvironment } from '@affine/env'; +import { env } from '@affine/env'; import { Skeleton } from '@mui/material'; import { assignInlineVars } from '@vanilla-extract/dynamic'; import { useAtom, useAtomValue } from 'jotai'; @@ -79,8 +79,7 @@ export function AppSidebar(props: AppSidebarProps): ReactElement { // disable animation to avoid UI flash const enableAnimation = useEnableAnimation(); - const environment = getEnvironment(); - const isMacosDesktop = environment.isDesktop && environment.isMacOs; + const isMacosDesktop = env.isDesktop && env.isMacOs; if (initialRender) { // avoid the UI flash return
; diff --git a/packages/component/src/components/app-sidebar/quick-search-input/index.tsx b/packages/component/src/components/app-sidebar/quick-search-input/index.tsx index 11974d77cc..3195e3be74 100644 --- a/packages/component/src/components/app-sidebar/quick-search-input/index.tsx +++ b/packages/component/src/components/app-sidebar/quick-search-input/index.tsx @@ -1,4 +1,4 @@ -import { getEnvironment } from '@affine/env/config'; +import { env } from '@affine/env/config'; import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { SearchIcon } from '@blocksuite/icons'; import clsx from 'clsx'; @@ -13,8 +13,7 @@ interface QuickSearchInputProps extends React.HTMLAttributes { // Although it is called an input, it is actually a button. export function QuickSearchInput({ onClick, ...props }: QuickSearchInputProps) { const t = useAFFiNEI18N(); - const environment = getEnvironment(); - const isMac = environment.isBrowser && environment.isMacOs; + const isMac = env.isBrowser && env.isMacOs; return (
{ const open = useAtomValue(appSidebarOpenAtom); - const environment = getEnvironment(); return (
- {environment.isDesktop && ( + {env.isDesktop && ( <> - {environment.isMacOs &&
} + {env.isMacOs &&
} { - {!environment.isMacOs &&
} + {!env.isMacOs &&
} )} {open && } diff --git a/packages/debug/src/index.ts b/packages/debug/src/index.ts index 9e65e1e5ee..c56dcfcd80 100644 --- a/packages/debug/src/index.ts +++ b/packages/debug/src/index.ts @@ -1,8 +1,7 @@ -import { getEnvironment } from '@affine/env'; +import { env } from '@affine/env'; import debug from 'debug'; type LogLevel = 'debug' | 'info' | 'warn' | 'error'; -const env = getEnvironment(); const SESSION_KEY = 'affine:debug'; const development = env.isDebug; diff --git a/packages/env/src/api.ts b/packages/env/src/api.ts index ff4c4f6bef..0d03894577 100644 --- a/packages/env/src/api.ts +++ b/packages/env/src/api.ts @@ -1,8 +1,8 @@ -import { config, getEnvironment } from './config'; +import { config, env } from './config'; import { isValidIPAddress } from './is-valid-ip-address'; let prefixUrl = '/'; -if (typeof window === 'undefined' || getEnvironment().isDesktop) { +if (typeof window === 'undefined' || env.isDesktop) { // SSR or Desktop const serverAPI = config.serverAPI; if (isValidIPAddress(serverAPI.split(':')[0])) { diff --git a/packages/env/src/config.ts b/packages/env/src/config.ts index 75e5b56f47..10c24ccc8b 100644 --- a/packages/env/src/config.ts +++ b/packages/env/src/config.ts @@ -106,54 +106,51 @@ interface Desktop extends ChromeBrowser { export type Environment = Browser | Server | Desktop; -let environment: Environment | null = null; - -export function getEnvironment() { - if (environment) { - return environment; - } - const isDebug = process.env.NODE_ENV === 'development'; - if (typeof window === 'undefined' || typeof navigator === 'undefined') { - environment = { - isDesktop: false, - isBrowser: false, - isServer: true, - isDebug, - } satisfies Server; - } else { - const uaHelper = new UaHelper(navigator); - - environment = { - origin: window.location.origin, - isDesktop: !!window.appInfo?.electron, - isBrowser: true, - isServer: false, - isDebug, - isLinux: uaHelper.isLinux, - isMacOs: uaHelper.isMacOs, - isSafari: uaHelper.isSafari, - isWindows: uaHelper.isWindows, - isFireFox: uaHelper.isFireFox, - isMobile: uaHelper.isMobile, - isChrome: uaHelper.isChrome, - isIOS: uaHelper.isIOS, - } as Browser; - // Chrome on iOS is still Safari - if (environment.isChrome && !environment.isIOS) { - assertEquals(environment.isSafari, false); - assertEquals(environment.isFireFox, false); +export const env: Environment = (()=>{ + let environment = null + const isDebug = process.env.NODE_ENV === 'development'; + if (typeof window === 'undefined' || typeof navigator === 'undefined') { environment = { - ...environment, - isSafari: false, - isFireFox: false, - isChrome: true, - chromeVersion: uaHelper.getChromeVersion(), - } satisfies ChromeBrowser; + isDesktop: false, + isBrowser: false, + isServer: true, + isDebug, + } satisfies Server; + } else { + const uaHelper = new UaHelper(navigator); + + environment = { + origin: window.location.origin, + isDesktop: !!window.appInfo?.electron, + isBrowser: true, + isServer: false, + isDebug, + isLinux: uaHelper.isLinux, + isMacOs: uaHelper.isMacOs, + isSafari: uaHelper.isSafari, + isWindows: uaHelper.isWindows, + isFireFox: uaHelper.isFireFox, + isMobile: uaHelper.isMobile, + isChrome: uaHelper.isChrome, + isIOS: uaHelper.isIOS, + } as Browser; + // Chrome on iOS is still Safari + if (environment.isChrome && !environment.isIOS) { + assertEquals(environment.isSafari, false); + assertEquals(environment.isFireFox, false); + environment = { + ...environment, + isSafari: false, + isFireFox: false, + isChrome: true, + chromeVersion: uaHelper.getChromeVersion(), + } satisfies ChromeBrowser; + } } - } - globalThis.environment = environment; - return environment; -} + globalThis.environment = environment; + return environment; +})(); + function printBuildInfo() { console.group('Build info'); @@ -185,8 +182,8 @@ export function setupGlobal() { if (globalThis.$AFFINE_SETUP) { return; } - globalThis.environment = getEnvironment(); - if (getEnvironment().isBrowser) { + globalThis.environment = env; + if (env.isBrowser) { printBuildInfo(); globalThis.editorVersion = config.editorVersion; } diff --git a/packages/jotai/src/resource.ts b/packages/jotai/src/resource.ts index 34fc99781f..12533be237 100644 --- a/packages/jotai/src/resource.ts +++ b/packages/jotai/src/resource.ts @@ -1,11 +1,11 @@ -import { getEnvironment } from '@affine/env'; +import { env } from '@affine/env'; import type { EditorContainer } from '@blocksuite/editor'; import { atom } from 'jotai'; export const lottieAtom = atom(import('lottie-web').then(m => m.default)); export const editorContainerModuleAtom = atom>( - getEnvironment().isServer + env.isServer ? async () => import('@blocksuite/editor').then(module => module.EditorContainer) : (import('@blocksuite/editor').then( diff --git a/packages/workspace/src/affine/login.ts b/packages/workspace/src/affine/login.ts index 73dee13923..ebfca959d1 100644 --- a/packages/workspace/src/affine/login.ts +++ b/packages/workspace/src/affine/login.ts @@ -1,5 +1,5 @@ import { DebugLogger } from '@affine/debug'; -import { getEnvironment } from '@affine/env'; +import { env } from '@affine/env'; import { assertExists } from '@blocksuite/global/utils'; import { Slot } from '@blocksuite/store'; import { initializeApp } from 'firebase/app'; @@ -165,7 +165,6 @@ export function createAffineAuth(prefix = '/') { method: SignMethod ): Promise => { const auth = getAuth(); - const environment = getEnvironment(); if (!auth) { throw new Error('Failed to initialize firebase'); } @@ -189,7 +188,7 @@ export function createAffineAuth(prefix = '/') { } try { let idToken: string | undefined; - if (environment.isDesktop) { + if (env.isDesktop) { idToken = await signInWithElectron(auth); } else { const response = await signInWithPopup(auth, provider);