perf: lazy-load computations (#1538)
* perf: lazy-load computations (experimental) * fix lint * add marks * fixup * lazy-load mixins too * add missing files * fix tests
This commit is contained in:
parent
8fbf38e974
commit
038dc27163
|
@ -144,7 +144,7 @@
|
|||
(name === 'notifications' && $hasNotifications) || (name === 'community' && $hasFollowRequests)
|
||||
),
|
||||
badgeNumber: ({ name, $numberOfNotifications, $numberOfFollowRequests }) => (
|
||||
(name === 'notifications' && $numberOfNotifications) || (name === 'community' && $numberOfFollowRequests)
|
||||
(name === 'notifications' && $numberOfNotifications) || (name === 'community' && $numberOfFollowRequests) || 0
|
||||
)
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -2,11 +2,14 @@
|
|||
<svelte:component this={composeBox} {realm} {hidden} />
|
||||
{/if}
|
||||
<script>
|
||||
import { importComposeBox } from '../../_utils/asyncModules'
|
||||
import { importComposeBox, importLoggedInStoreExtensions } from '../../_utils/asyncModules'
|
||||
|
||||
export default {
|
||||
async oncreate () {
|
||||
const composeBox = await importComposeBox()
|
||||
const [composeBox] = await Promise.all([
|
||||
importComposeBox(),
|
||||
importLoggedInStoreExtensions()
|
||||
])
|
||||
this.set({ composeBox })
|
||||
},
|
||||
data: () => ({
|
||||
|
|
|
@ -10,18 +10,19 @@
|
|||
</style>
|
||||
<script>
|
||||
import { store } from '../../_store/store'
|
||||
import { importTimeline } from '../../_utils/asyncModules'
|
||||
import { importLoggedInStoreExtensions, importTimeline } from '../../_utils/asyncModules'
|
||||
|
||||
export default {
|
||||
async oncreate () {
|
||||
console.log('LazyTimeline oncreate')
|
||||
const { currentInstance } = this.store.get()
|
||||
const { timeline } = this.get()
|
||||
const [timelineComponent] = await Promise.all([
|
||||
importTimeline(),
|
||||
importLoggedInStoreExtensions()
|
||||
])
|
||||
this.store.set({ currentTimeline: timeline })
|
||||
this.store.setForTimeline(currentInstance, timeline, { runningUpdate: false })
|
||||
console.log('importing timeline')
|
||||
const timelineComponent = await importTimeline()
|
||||
console.log('imported timeline')
|
||||
this.set({ timelineComponent })
|
||||
},
|
||||
store: () => store,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { get } from '../../_utils/lodash-lite'
|
||||
import { mark, stop } from '../../_utils/marks'
|
||||
|
||||
const MIN_PREFIX_LENGTH = 2
|
||||
// Technically mastodon accounts allow dots, but it would be weird to do an autosuggest search if it ends with a dot.
|
||||
|
@ -17,6 +18,7 @@ function computeForAutosuggest (store, key, defaultValue) {
|
|||
}
|
||||
|
||||
export function autosuggestComputations (store) {
|
||||
mark('autosuggestComputations')
|
||||
computeForAutosuggest(store, 'composeFocused', false)
|
||||
computeForAutosuggest(store, 'composeSelectionStart', 0)
|
||||
computeForAutosuggest(store, 'autosuggestSelected', 0)
|
||||
|
@ -59,4 +61,5 @@ export function autosuggestComputations (store) {
|
|||
!!(composeFocused && autosuggestSearchText && autosuggestNumSearchResults)
|
||||
)
|
||||
)
|
||||
stop('autosuggestComputations')
|
||||
}
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
import { instanceComputations } from './instanceComputations'
|
||||
import { timelineComputations } from './timelineComputations'
|
||||
import { navComputations } from './navComputations'
|
||||
import { autosuggestComputations } from './autosuggestComputations'
|
||||
|
||||
export function computations (store) {
|
||||
instanceComputations(store)
|
||||
timelineComputations(store)
|
||||
navComputations(store)
|
||||
autosuggestComputations(store)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { DEFAULT_THEME } from '../../_utils/themeEngine'
|
||||
import { mark, stop } from '../../_utils/marks'
|
||||
|
||||
function computeForInstance (store, computedKey, key, defaultValue) {
|
||||
store.compute(computedKey,
|
||||
|
@ -7,6 +8,7 @@ function computeForInstance (store, computedKey, key, defaultValue) {
|
|||
}
|
||||
|
||||
export function instanceComputations (store) {
|
||||
mark('instanceComputations')
|
||||
computeForInstance(store, 'currentTheme', 'instanceThemes', DEFAULT_THEME)
|
||||
computeForInstance(store, 'currentVerifyCredentials', 'verifyCredentials', null)
|
||||
computeForInstance(store, 'currentInstanceInfo', 'instanceInfos', null)
|
||||
|
@ -59,4 +61,6 @@ export function instanceComputations (store) {
|
|||
(currentInstanceInfo && currentInstanceInfo.max_toot_chars) || 500
|
||||
)
|
||||
)
|
||||
|
||||
stop('instanceComputations')
|
||||
}
|
||||
|
|
10
src/routes/_store/computations/loggedInComputations.js
Normal file
10
src/routes/_store/computations/loggedInComputations.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
// like loggedInObservers.js, these can be lazy-loaded once the user is actually logged in
|
||||
import { timelineComputations } from './timelineComputations'
|
||||
import { autosuggestComputations } from './autosuggestComputations'
|
||||
|
||||
import { store } from '../store'
|
||||
|
||||
export function loggedInComputations () {
|
||||
timelineComputations(store)
|
||||
autosuggestComputations(store)
|
||||
}
|
|
@ -1,4 +1,8 @@
|
|||
import { mark, stop } from '../../_utils/marks'
|
||||
|
||||
export function navComputations (store) {
|
||||
mark('navComputations')
|
||||
|
||||
store.compute(
|
||||
'pinnedListTitle',
|
||||
['lists', 'pinnedPage'],
|
||||
|
@ -89,4 +93,6 @@ export function navComputations (store) {
|
|||
]
|
||||
}
|
||||
)
|
||||
|
||||
stop('navComputations')
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import {
|
|||
NOTIFICATION_POLLS,
|
||||
NOTIFICATION_MENTIONS
|
||||
} from '../../_static/instanceSettings'
|
||||
import { mark, stop } from '../../_utils/marks'
|
||||
|
||||
function computeForTimeline (store, key, defaultValue) {
|
||||
store.compute(key,
|
||||
|
@ -45,6 +46,7 @@ function computeNotificationFilter (store, computationName, key) {
|
|||
}
|
||||
|
||||
export function timelineComputations (store) {
|
||||
mark('timelineComputations')
|
||||
computeForTimeline(store, 'timelineItemSummaries', null)
|
||||
computeForTimeline(store, 'timelineItemSummariesToAdd', null)
|
||||
computeForTimeline(store, 'runningUpdate', false)
|
||||
|
@ -191,4 +193,5 @@ export function timelineComputations (store) {
|
|||
['numberOfFollowRequests'],
|
||||
(numberOfFollowRequests) => !!numberOfFollowRequests
|
||||
)
|
||||
stop('timelineComputations')
|
||||
}
|
||||
|
|
8
src/routes/_store/loggedInStoreExtensions.js
Normal file
8
src/routes/_store/loggedInStoreExtensions.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
import { loggedInComputations } from './computations/loggedInComputations'
|
||||
import { loggedInObservers } from './observers/loggedInObservers'
|
||||
import { loggedInMixins } from './mixins/loggedInMixins'
|
||||
|
||||
console.log('imported logged in observers and computations')
|
||||
loggedInMixins()
|
||||
loggedInComputations()
|
||||
loggedInObservers()
|
27
src/routes/_store/mixins/composeMixins.js
Normal file
27
src/routes/_store/mixins/composeMixins.js
Normal file
|
@ -0,0 +1,27 @@
|
|||
import { get } from '../../_utils/lodash-lite'
|
||||
|
||||
export function composeMixins (Store) {
|
||||
Store.prototype.setComposeData = function (realm, obj) {
|
||||
const { composeData, currentInstance } = this.get()
|
||||
const instanceNameData = composeData[currentInstance] = composeData[currentInstance] || {}
|
||||
instanceNameData[realm] = Object.assign(
|
||||
instanceNameData[realm] || {},
|
||||
{ ts: Date.now() },
|
||||
obj
|
||||
)
|
||||
this.set({ composeData })
|
||||
}
|
||||
|
||||
Store.prototype.getComposeData = function (realm, key) {
|
||||
const { composeData, currentInstance } = this.get()
|
||||
return get(composeData, [currentInstance, realm, key])
|
||||
}
|
||||
|
||||
Store.prototype.clearComposeData = function (realm) {
|
||||
const { composeData, currentInstance } = this.get()
|
||||
if (composeData && composeData[currentInstance]) {
|
||||
delete composeData[currentInstance][realm]
|
||||
}
|
||||
this.set({ composeData })
|
||||
}
|
||||
}
|
|
@ -1,32 +1,6 @@
|
|||
import { get } from '../../_utils/lodash-lite'
|
||||
|
||||
export function instanceMixins (Store) {
|
||||
Store.prototype.setComposeData = function (realm, obj) {
|
||||
const { composeData, currentInstance } = this.get()
|
||||
const instanceNameData = composeData[currentInstance] = composeData[currentInstance] || {}
|
||||
instanceNameData[realm] = Object.assign(
|
||||
instanceNameData[realm] || {},
|
||||
{ ts: Date.now() },
|
||||
obj
|
||||
)
|
||||
this.set({ composeData })
|
||||
}
|
||||
|
||||
Store.prototype.getComposeData = function (realm, key) {
|
||||
const { composeData, currentInstance } = this.get()
|
||||
return composeData[currentInstance] &&
|
||||
composeData[currentInstance][realm] &&
|
||||
composeData[currentInstance][realm][key]
|
||||
}
|
||||
|
||||
Store.prototype.clearComposeData = function (realm) {
|
||||
const { composeData, currentInstance } = this.get()
|
||||
if (composeData && composeData[currentInstance]) {
|
||||
delete composeData[currentInstance][realm]
|
||||
}
|
||||
this.set({ composeData })
|
||||
}
|
||||
|
||||
Store.prototype.getInstanceSetting = function (instanceName, settingName, defaultValue) {
|
||||
const { instanceSettings } = this.get()
|
||||
return get(instanceSettings, [instanceName, settingName], defaultValue)
|
||||
|
|
12
src/routes/_store/mixins/loggedInMixins.js
Normal file
12
src/routes/_store/mixins/loggedInMixins.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { timelineMixins } from './timelineMixins'
|
||||
import { statusMixins } from './statusMixins'
|
||||
import { autosuggestMixins } from './autosuggestMixins'
|
||||
import { composeMixins } from './composeMixins'
|
||||
import { PinaforeStore as Store } from '../store'
|
||||
|
||||
export function loggedInMixins () {
|
||||
composeMixins(Store)
|
||||
timelineMixins(Store)
|
||||
statusMixins(Store)
|
||||
autosuggestMixins(Store)
|
||||
}
|
|
@ -1,11 +1,5 @@
|
|||
import { timelineMixins } from './timelineMixins'
|
||||
import { instanceMixins } from './instanceMixins'
|
||||
import { statusMixins } from './statusMixins'
|
||||
import { autosuggestMixins } from './autosuggestMixins'
|
||||
|
||||
export function mixins (Store) {
|
||||
instanceMixins(Store)
|
||||
timelineMixins(Store)
|
||||
statusMixins(Store)
|
||||
autosuggestMixins(Store)
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import { cleanup } from './cleanup'
|
|||
|
||||
// These observers can be lazy-loaded when the user is actually logged in.
|
||||
// Prevents circular dependencies and reduces the size of main.js
|
||||
export default function loggedInObservers () {
|
||||
export function loggedInObservers () {
|
||||
instanceObservers()
|
||||
timelineObservers()
|
||||
notificationObservers()
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
import { importLoggedInObservers } from '../../_utils/asyncModules'
|
||||
|
||||
let observedOnce = false
|
||||
import { importLoggedInStoreExtensions } from '../../_utils/asyncModules'
|
||||
|
||||
// An observer that calls an observer... this is a bit weird, but it eliminates
|
||||
// circular dependencies and also allows us to lazy load observers that are
|
||||
// only needed when you're logged in.
|
||||
// circular dependencies and also allows us to lazy load observers/computations
|
||||
// that are only needed when you're logged in.
|
||||
export function setupLoggedInObservers (store) {
|
||||
store.observe('isUserLoggedIn', isUserLoggedIn => {
|
||||
if (isUserLoggedIn && !observedOnce) {
|
||||
importLoggedInObservers().then(loggedInObservers => loggedInObservers())
|
||||
observedOnce = true
|
||||
if (isUserLoggedIn) {
|
||||
importLoggedInStoreExtensions()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ const nonPersistedState = {
|
|||
const state = Object.assign({}, persistedState, nonPersistedState)
|
||||
const keysToStoreInLocalStorage = new Set(Object.keys(persistedState))
|
||||
|
||||
class PinaforeStore extends LocalStorageStore {
|
||||
export class PinaforeStore extends LocalStorageStore {
|
||||
constructor (state) {
|
||||
super(state, keysToStoreInLocalStorage)
|
||||
}
|
||||
|
|
|
@ -24,9 +24,9 @@ export const importDatabase = () => import(
|
|||
/* webpackChunkName: 'database.js' */ '../_database/databaseApis.js'
|
||||
)
|
||||
|
||||
export const importLoggedInObservers = () => import(
|
||||
/* webpackChunkName: 'loggedInObservers.js' */ '../_store/observers/loggedInObservers.js'
|
||||
).then(getDefault)
|
||||
export const importLoggedInStoreExtensions = () => import(
|
||||
/* webpackChunkName: 'loggedInStoreExtensions.js' */ '../_store/loggedInStoreExtensions.js'
|
||||
)
|
||||
|
||||
export const importNavShortcuts = () => import(
|
||||
/* webpackChunkName: 'NavShortcuts' */ '../_components/NavShortcuts.html'
|
||||
|
|
|
@ -3,12 +3,13 @@
|
|||
import { store } from './_store/store'
|
||||
import { goto } from '../../__sapper__/client'
|
||||
import { decodeURIComponentWithPluses } from './_utils/decodeURIComponentWithPluses'
|
||||
import { importLoggedInStoreExtensions } from './_utils/asyncModules'
|
||||
|
||||
const SHARE_KEYS = ['title', 'text', 'url']
|
||||
|
||||
export default {
|
||||
store: () => store,
|
||||
oncreate () {
|
||||
async oncreate () {
|
||||
const params = new URLSearchParams(location.search)
|
||||
|
||||
const text = SHARE_KEYS
|
||||
|
@ -16,6 +17,7 @@
|
|||
.filter(Boolean)
|
||||
.join(' ')
|
||||
|
||||
await importLoggedInStoreExtensions()
|
||||
this.store.set({ openShareDialog: true })
|
||||
this.store.clearComposeData('dialog')
|
||||
this.store.setComposeData('dialog', { text })
|
||||
|
|
Loading…
Reference in a new issue