diff --git a/src/background/actionListener/storage.ts b/src/background/actionListener/storage.ts index 1121a3f0..9059bb5f 100644 --- a/src/background/actionListener/storage.ts +++ b/src/background/actionListener/storage.ts @@ -2,7 +2,7 @@ import { IOperateStorageData, OperateStorageEnum, } from '@/isomorphic/background/storage'; -import Storage from '@/background/core/storage'; +import { storage } from '@/isomorphic/storage'; import { RequestMessage } from './index'; export async function createStorageActionListener( @@ -12,17 +12,17 @@ export async function createStorageActionListener( const { type, key, data } = request.data; switch (type) { case OperateStorageEnum.get: { - const res = await Storage.get(key); + const res = await storage.get(key); callback(res); break; } case OperateStorageEnum.remove: { - const res = await Storage.remove(key); + const res = await storage.remove(key); callback(res); break; } case OperateStorageEnum.update: { - const res = await Storage.update(key, data); + const res = await storage.update(key, data); callback(res); break; } diff --git a/src/background/actionListener/user.ts b/src/background/actionListener/user.ts index f0abe105..a6bf6749 100644 --- a/src/background/actionListener/user.ts +++ b/src/background/actionListener/user.ts @@ -5,7 +5,7 @@ import { OperateUserEnum, } from '@/isomorphic/background/user'; import { IUser } from '@/isomorphic/interface'; -import Storage from '@/background/core/storage'; +import { storage } from '@/isomorphic/storage'; import requestFn from '@/background/core/request'; import { STORAGE_KEYS, YUQUE_DOMAIN } from '@/config'; import { RequestMessage } from './index'; @@ -86,7 +86,7 @@ export async function createUserActionListener( ...value, login_at: Date.now(), }; - await Storage.update(STORAGE_KEYS.CURRENT_ACCOUNT, newValue); + await storage.update(STORAGE_KEYS.CURRENT_ACCOUNT, newValue); callback(newValue); } callback(null); diff --git a/src/background/core/configManager/clip.ts b/src/background/core/configManager/clip.ts index cc5515b7..b89eb127 100644 --- a/src/background/core/configManager/clip.ts +++ b/src/background/core/configManager/clip.ts @@ -6,12 +6,12 @@ import { ClipConfigKey, } from '@/isomorphic/constant/clip'; import { IConfigManagerOption } from '@/isomorphic/background/configManager'; -import Storage from '../storage'; +import { storage } from '@/isomorphic/storage'; class ClipConfigManager { async get() { const config: IClipConfig = - (await Storage.get(STORAGE_KEYS.SETTINGS.CLIP_CONFIG)) || {}; + (await storage.get(STORAGE_KEYS.SETTINGS.CLIP_CONFIG)) || {}; // 做一次 config 的合并,保证获取时一定包含 config 中的每一个元素 for (const _key of Object.keys(defaultClipConfig)) { diff --git a/src/background/core/configManager/levitate.ts b/src/background/core/configManager/levitate.ts index 9979b76a..88bbfd6d 100644 --- a/src/background/core/configManager/levitate.ts +++ b/src/background/core/configManager/levitate.ts @@ -7,12 +7,12 @@ import { } from '@/isomorphic/constant/levitate'; import { IConfigManagerOption } from '@/isomorphic/background/configManager'; import { STORAGE_KEYS } from '@/config'; -import Storage from '../storage'; +import { storage } from '@/isomorphic/storage'; class LevitateConfigManager { async get() { const config: ILevitateConfig = - (await Storage.get(STORAGE_KEYS.SETTINGS.LEVITATE_BALL_CONFIG)) || {}; + (await storage.get(STORAGE_KEYS.SETTINGS.LEVITATE_BALL_CONFIG)) || {}; // 做一次 config 的合并,保证获取时一定包含 config 中的每一个元素 for (const _key of Object.keys(defaultLevitateConfig)) { diff --git a/src/background/core/configManager/wordMark.ts b/src/background/core/configManager/wordMark.ts index b36684b1..60ba25cb 100644 --- a/src/background/core/configManager/wordMark.ts +++ b/src/background/core/configManager/wordMark.ts @@ -8,7 +8,7 @@ import { IConfigManagerOption } from '@/isomorphic/background/configManager'; import { ContentScriptEvents } from '@/isomorphic/event/contentScript'; import { STORAGE_KEYS } from '@/config'; import { WordMarkOptionTypeEnum } from '@/isomorphic/constant/wordMark'; -import Storage from '../storage'; +import { storage } from '@/isomorphic/storage'; class WordMarkConfigManager { async get() { @@ -56,7 +56,7 @@ class WordMarkConfigManager { private async getStorageConfig() { const config: IWordMarkConfig = - (await Storage.get(STORAGE_KEYS.SETTINGS.WORD_MARK_CONFIG)) || {}; + (await storage.get(STORAGE_KEYS.SETTINGS.WORD_MARK_CONFIG)) || {}; // 做一次 config 的合并,保证获取时一定包含 config 中的每一个元素 for (const _key of Object.keys(defaultWordMarkConfig)) { @@ -69,7 +69,10 @@ class WordMarkConfigManager { // 由于历史数据可能被写入 string 或者 string[] 如果判断出是这种数据的,将内容置空 if (key === 'disableUrl') { const tempValue = config[key]; - if (typeof tempValue === 'string' || typeof tempValue?.[0] === 'string') { + if ( + typeof tempValue === 'string' || + typeof tempValue?.[0] === 'string' + ) { config[key] = []; } } diff --git a/src/background/core/storage.ts b/src/background/core/storage.ts deleted file mode 100644 index 50f47d1e..00000000 --- a/src/background/core/storage.ts +++ /dev/null @@ -1,22 +0,0 @@ -import Chrome from '@/background/core/chrome'; - -class Storage { - async update(key: string, data: any) { - return await Chrome.storage.local.set({ - [key]: data, - }); - } - - async remove(key: string) { - return Chrome.storage.local.remove(key); - } - - async get(key: string) { - const valueMap = await Chrome.storage.local.get(key); - return valueMap[key]; - } -} - -const storage = new Storage(); - -export default storage; diff --git a/src/background/core/util.ts b/src/background/core/util.ts index 78ca989c..4fd5f5c3 100644 --- a/src/background/core/util.ts +++ b/src/background/core/util.ts @@ -1,9 +1,9 @@ import { IUser } from '@/isomorphic/interface'; -import Storage from './storage'; +import { storage } from '../../isomorphic/storage'; import { STORAGE_KEYS } from '@/config'; export const getCurrentAccount = async () => { - const account = await Storage.get(STORAGE_KEYS.CURRENT_ACCOUNT) as IUser; + const account = (await storage.get(STORAGE_KEYS.CURRENT_ACCOUNT)) as IUser; if (!account?.login_at) { return {}; } diff --git a/src/background/index.ts b/src/background/index.ts index dfa7af01..f579f6b7 100644 --- a/src/background/index.ts +++ b/src/background/index.ts @@ -1,11 +1,11 @@ -import Chrome from '@/background/core/chrome'; import LinkHelper from '@/isomorphic/link-helper'; -import { YUQUE_DOMAIN } from '@/config'; +import { STORAGE_KEYS, YUQUE_DOMAIN } from '@/config'; import { initI18N } from '@/isomorphic/i18n'; import { listenBrowserActionEvent } from './browser-action'; import { createContextMenu, listenContextMenuEvents } from './context-menu'; import { initBackGroundActionListener } from './actionListener'; import { listenShortcut } from './shortcut-listener'; +import { storage } from '@/isomorphic/storage'; console.log('-- in background.js'); @@ -15,20 +15,60 @@ listenBrowserActionEvent(); initBackGroundActionListener(); listenShortcut(); -Chrome.runtime.onInstalled.addListener(async details => { +chrome.runtime.onInstalled.addListener(async details => { console.log('-- runtime installed'); if (details.reason === 'install') { - Chrome.tabs.create({ + chrome.tabs.create({ url: LinkHelper.introduceExtension, }); } + /** + * 由于插件采用了 iframe 嵌入插件的页面,当插件更新时 + * 如果页面中依旧存在 iframe 会导致后台服务刷新异常 + * 所以在系统刷新时,去给每个 tab 执行一段脚本去除掉插件注入的 iframe + * 然后重新执行一次刷新去解决这类问题 + */ + if (details.reason === 'update') { + const lastForceUpdateTime = await storage.get( + STORAGE_KEYS.SYSTEM.LAST_BACKGROUND_UPDATE, + ); + if ( + lastForceUpdateTime && + new Date().getTime() - lastForceUpdateTime < 4000 + ) { + return; + } + const tabs = await chrome.tabs.query({}); + for (const tab of tabs) { + if (tab.id) { + try { + await chrome.scripting.executeScript({ + target: { tabId: tab.id }, + func: () => { + const element = document.querySelector( + '#yuque-extension-root-container', + ); + element?.remove(); + }, + }); + } catch (e) { + // + } + } + } + await storage.update( + STORAGE_KEYS.SYSTEM.LAST_BACKGROUND_UPDATE, + new Date().getTime(), + ); + chrome.runtime.reload(); + } createContextMenu(); updateDynamicRules(); }); -Chrome.runtime.setUninstallURL(LinkHelper.unInstallFeedback); +chrome.runtime.setUninstallURL(LinkHelper.unInstallFeedback); function updateDynamicRules() { const rules = [ @@ -59,9 +99,9 @@ function updateDynamicRules() { }, ]; - Chrome.declarativeNetRequest.getDynamicRules(previousRules => { + chrome.declarativeNetRequest.getDynamicRules(previousRules => { const previousRuleIds = previousRules.map(rule => rule.id); - Chrome.declarativeNetRequest.updateDynamicRules({ + chrome.declarativeNetRequest.updateDynamicRules({ removeRuleIds: previousRuleIds, addRules: rules, }); diff --git a/src/config.ts b/src/config.ts index 18ee4b64..92e36ca3 100644 --- a/src/config.ts +++ b/src/config.ts @@ -24,6 +24,9 @@ export const STORAGE_KEYS = { TIP: { READ_SHORTCUT: 'tip/read-shortcut', }, + SYSTEM: { + LAST_BACKGROUND_UPDATE: 'system/last-background-update', + }, }; export const YUQUE_DOMAIN = 'https://www.yuque.com'; export const YUQUE_CSRF_COOKIE_NAME = 'yuque_ctoken'; diff --git a/src/core/uitl.ts b/src/core/uitl.ts index 83f4e7fe..f86f595f 100644 --- a/src/core/uitl.ts +++ b/src/core/uitl.ts @@ -11,5 +11,5 @@ export function findCookieSettingPage() { } return ''; } - -export const isRunningInjectPage = window.self !== window.top; +export const isRunningInjectPage = + typeof window !== 'undefined' && typeof window; diff --git a/src/isomorphic/env.ts b/src/isomorphic/env.ts new file mode 100644 index 00000000..0f444919 --- /dev/null +++ b/src/isomorphic/env.ts @@ -0,0 +1,22 @@ +/** + * 后续所有环境判断的方法都迁移到这里来 + */ +class Env { + static get isBackground(): boolean { + return typeof window === 'undefined'; + } + + // 是否是插件的页面,插件的页面和 background 相类似,可以调用 chrome 系统的 api + static get isExtensionPage() { + if (!Env.isBackground) { + const url = window.location.href; + if (url.startsWith('chrome-extension://')) { + return true; + } + return false; + } + return true; + } +} + +export default Env; diff --git a/src/isomorphic/storage.ts b/src/isomorphic/storage.ts new file mode 100644 index 00000000..8bf3927d --- /dev/null +++ b/src/isomorphic/storage.ts @@ -0,0 +1,35 @@ +import { backgroundBridge } from '@/core/bridge/background'; +import Env from './env'; + +class Storage { + async update(key: string, data: any) { + if (Env.isBackground) { + const res = await chrome.storage.local.set({ + [key]: data, + }); + return res; + } + const res = await backgroundBridge.storage.update(key, data); + return res; + } + + async remove(key: string) { + if (Env.isBackground) { + const res = await chrome.storage.local.remove(key); + return res; + } + const res = await backgroundBridge.storage.remove(key); + return res; + } + + async get(key: string) { + if (Env.isBackground) { + const valueMap = await chrome.storage.local.get(key); + return valueMap[key]; + } + const res = await backgroundBridge.storage.get(key); + return res; + } +} + +export const storage = new Storage();