diff --git a/package.json b/package.json
index cbbcb170..fb157fae 100644
--- a/package.json
+++ b/package.json
@@ -32,6 +32,7 @@
"click-outside-vue3": "4.0.1",
"cropperjs": "1.5.13",
"escape-html": "1.0.3",
+ "hash-sum": "^2.0.0",
"js-cookie": "3.0.5",
"localforage": "1.10.0",
"parse-link-header": "2.0.0",
diff --git a/src/boot/after_store.js b/src/boot/after_store.js
index bfb671ed..bcab7a66 100644
--- a/src/boot/after_store.js
+++ b/src/boot/after_store.js
@@ -14,7 +14,7 @@ import { windowWidth, windowHeight } from '../services/window_utils/window_utils
import { getOrCreateApp, getClientToken } from '../services/new_api/oauth.js'
import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js'
import { CURRENT_VERSION } from '../services/theme_data/theme_data.service.js'
-import { applyTheme, applyConfig } from '../services/style_setter/style_setter.js'
+import { applyTheme, applyConfig, tryLoadCache } from '../services/style_setter/style_setter.js'
import FaviconService from '../services/favicon_service/favicon_service.js'
import { initServiceWorker, updateFocus } from '../services/sw/sw.js'
@@ -353,21 +353,25 @@ const afterStoreSetup = async ({ store, i18n }) => {
await setConfig({ store })
- const { customTheme, customThemeSource } = store.state.config
+ const { customTheme, customThemeSource, forceThemeRecompilation } = store.state.config
const { theme } = store.state.instance
const customThemePresent = customThemeSource || customTheme
- if (customThemePresent) {
- if (customThemeSource && customThemeSource.themeEngineVersion === CURRENT_VERSION) {
- applyTheme(customThemeSource)
- } else {
- applyTheme(customTheme)
- }
+ if (!forceThemeRecompilation && tryLoadCache()) {
store.commit('setThemeApplied')
- } else if (theme) {
- // do nothing, it will load asynchronously
} else {
- console.error('Failed to load any theme!')
+ if (customThemePresent) {
+ if (customThemeSource && customThemeSource.themeEngineVersion === CURRENT_VERSION) {
+ applyTheme(customThemeSource)
+ } else {
+ applyTheme(customTheme)
+ }
+ store.commit('setThemeApplied')
+ } else if (theme) {
+ // do nothing, it will load asynchronously
+ } else {
+ console.error('Failed to load any theme!')
+ }
}
applyConfig(store.state.config)
diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue
index f56fa8e0..424ee7e4 100644
--- a/src/components/settings_modal/tabs/general_tab.vue
+++ b/src/components/settings_modal/tabs/general_tab.vue
@@ -200,6 +200,14 @@
{{ $t('settings.post_look_feel') }}
+ -
+
+ {{ $t('settings.force_theme_recompilation_debug') }}
+
+
-
{
return { lazyProcessFunc: processChunk }
}
-export const applyTheme = async (input) => {
+export const tryLoadCache = () => {
+ const json = localStorage.getItem('pleroma-fe-theme-cache')
+ if (!json) return null
+ let cache
+ try {
+ cache = JSON.parse(json)
+ } catch (e) {
+ console.error('Failed to decode theme cache:', e)
+ return false
+ }
+ if (cache.checksum === getChecksum()) {
+ const styleSheet = new CSSStyleSheet()
+ const lazyStyleSheet = new CSSStyleSheet()
+
+ cache.data[0].forEach(rule => styleSheet.insertRule(rule, 'index-max'))
+ cache.data[1].forEach(rule => lazyStyleSheet.insertRule(rule, 'index-max'))
+
+ document.adoptedStyleSheets = [styleSheet, lazyStyleSheet]
+
+ return true
+ } else {
+ console.warn('Checksum doesn\'t match, cache not usable, clearing')
+ localStorage.removeItem('pleroma-fe-theme-cache')
+ }
+}
+
+export const applyTheme = async (input, onFinish = (data) => {}) => {
const styleSheet = new CSSStyleSheet()
+ const styleArray = []
const lazyStyleSheet = new CSSStyleSheet()
+ const lazyStyleArray = []
const { lazyProcessFunc } = await generateTheme(
input,
@@ -97,8 +125,10 @@ export const applyTheme = async (input) => {
onNewRule (rule, isLazy) {
if (isLazy) {
lazyStyleSheet.insertRule(rule, 'index-max')
+ lazyStyleArray.push(rule)
} else {
styleSheet.insertRule(rule, 'index-max')
+ styleArray.push(rule)
}
},
onEagerFinished () {
@@ -106,6 +136,9 @@ export const applyTheme = async (input) => {
},
onLazyFinished () {
document.adoptedStyleSheets = [styleSheet, lazyStyleSheet]
+ const cache = { checksum: getChecksum(), data: [styleArray, lazyStyleArray] }
+ onFinish(cache)
+ localStorage.setItem('pleroma-fe-theme-cache', JSON.stringify(cache))
}
}
)
diff --git a/src/services/theme_data/theme_data_3.service.js b/src/services/theme_data/theme_data_3.service.js
index 7457ab99..844e951a 100644
--- a/src/services/theme_data/theme_data_3.service.js
+++ b/src/services/theme_data/theme_data_3.service.js
@@ -1,4 +1,5 @@
import { convert, brightness } from 'chromatism'
+import sum from 'hash-sum'
import { flattenDeep } from 'lodash'
import {
alphaBlend,
@@ -142,8 +143,12 @@ componentsContext.keys().forEach(key => {
components[component.name] = component
})
+const checksum = sum(components)
+
const ruleToSelector = genericRuleToSelector(components)
+export const getChecksum = () => checksum
+
export const init = (extraRuleset, ultimateBackgroundColor) => {
const staticVars = {}
const stacked = {}
@@ -463,6 +468,7 @@ export const init = (extraRuleset, ultimateBackgroundColor) => {
return {
lazy: result.filter(x => typeof x === 'function'),
eager: result.filter(x => typeof x !== 'function'),
- staticVars
+ staticVars,
+ checksum
}
}