Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

On initial page load run init before turbo:load has been fired #646

Merged
merged 10 commits into from
Nov 26, 2024
192 changes: 104 additions & 88 deletions resources/js/package.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,39 @@ import './cookies'
import './callbacks'
import './vue-components'

if (import.meta.env.VITE_DEBUG === 'true') {
document.addEventListener('vue:loaded', () => {
window.app.$on('notification-message', function (message, type, params, link) {
switch (type) {
case 'error':
console.error(...arguments)
break
case 'warning':
console.warn(...arguments)
break
case 'success':
case 'info':
default:
console.log(...arguments)
}
})
})
}

document.addEventListener('vue:loaded', () => {
const lastStoreCode = useLocalStorage('last_store_code', window.config.store_code)
if (lastStoreCode.value !== window.config.store_code) {
clearAttributes()
clearSwatches()
lastStoreCode.value = window.config.store_code
}
})

function init() {
if (document.body.contains(window.app.$el)) {
return;
}

// https://vuejs.org/api/application.html#app-config-performance
Vue.config.performance = import.meta.env.VITE_PERFORMANCE == 'true'
Vue.prototype.window = window
Expand Down Expand Up @@ -59,96 +91,80 @@ function init() {
custom_attributes: [],
}

window.app = new Vue({
el: '#app',
data: {
custom: {},
config: window.config,
loadingCount: 0,
loading: false,
loadAutocomplete: false,
csrfToken: document.querySelector('[name=csrf-token]').content,
cart: useCart(),
order: useOrder(),
user: useUser(),
mask: useMask(),
showTax: window.config.show_tax,
swatches: swatches,
scrollLock: useScrollLock(document.body),
},
methods: {
search(value) {
if (value.length) {
Turbo.visit(window.url('/search?q=' + encodeURIComponent(value)))
}
},
setSearchParams(url) {
window.history.pushState(window.history.state, '', new URL(url))
},
toggleScroll(bool = null) {
if (bool === null) {
this.scrollLock = !this.scrollLock
} else {
this.scrollLock = bool
}
},
resizedPath(imagePath, size, store = null) {
if (!store) {
store = window.config.store
}

let url = new URL(imagePath)
url = url.pathname.replace('/media', '')

return `/storage/${store}/resizes/${size}/magento${url}`
},
},
computed: {
// Wrap the local storage in getter and setter functions so you do not have to interact using .value
guestEmail: wrapValue(
useLocalStorage('email', window.debug ? '[email protected]' : '', { serializer: StorageSerializers.string }),
),

loggedIn() {
return this.user?.is_logged_in
},

hasCart() {
return this.cart?.id && this.cart.items.length
},
},
watch: {
loadingCount: function (count) {
window.app.$data.loading = count > 0
},
},
})
requestAnimationFrame(
() => {
window.app = new Vue({
el: '#app',
data: {
custom: {},
config: window.config,
loadingCount: 0,
loading: false,
loadAutocomplete: false,
csrfToken: document.querySelector('[name=csrf-token]').content,
cart: useCart(),
order: useOrder(),
user: useUser(),
mask: useMask(),
showTax: window.config.show_tax,
swatches: swatches,
scrollLock: useScrollLock(document.body),
},
methods: {
search(value) {
if (value.length) {
Turbo.visit(window.url('/search?q=' + encodeURIComponent(value)))
}
},
setSearchParams(url) {
window.history.pushState(window.history.state, '', new URL(url))
},
toggleScroll(bool = null) {
if (bool === null) {
this.scrollLock = !this.scrollLock
} else {
this.scrollLock = bool
}
},
resizedPath(imagePath, size, store = null) {
if (!store) {
store = window.config.store
}

const lastStoreCode = useLocalStorage('last_store_code', window.config.store_code)
if (lastStoreCode.value !== window.config.store_code) {
clearAttributes()
clearSwatches()
lastStoreCode.value = window.config.store_code
}
let url = new URL(imagePath)
url = url.pathname.replace('/media', '')

if (window.debug) {
window.app.$on('notification-message', function (message, type, params, link) {
switch (type) {
case 'error':
console.error(...arguments)
break
case 'warning':
console.warn(...arguments)
break
case 'success':
case 'info':
default:
console.log(...arguments)
}
})
}
return `/storage/${store}/resizes/${size}/magento${url}`
},
},
computed: {
// Wrap the local storage in getter and setter functions so you do not have to interact using .value
guestEmail: wrapValue(
useLocalStorage('email', window.debug ? '[email protected]' : '', { serializer: StorageSerializers.string }),
),

const event = new CustomEvent('vue:loaded', { detail: { vue: window.app } })
document.dispatchEvent(event)
loggedIn() {
return this.user?.is_logged_in
},

hasCart() {
return this.cart?.id && this.cart.items.length
},
},
watch: {
loadingCount: function (count) {
window.app.$data.loading = count > 0
},
},
})

setTimeout(() => {
const event = new CustomEvent('vue:loaded', { detail: { vue: window.app } })
document.dispatchEvent(event)
})
}
)
}

document.addEventListener('turbo:load', init)
setTimeout(init)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This specific order of setTimeout and requestAnimationFrame ensures LCP is not impacted.
And ensures small task time for the turbo:load/evaluate script, and vue:loaded events by scheduling them all in their own task.

Using a setTimeout for both, a requestAnimationFrame for both, or executing this immediately and booting Vue in a requestAnimationFrame all has impact on the LCP

Loading