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