Skip to content

Commit

Permalink
Improved Vue/Turbo loading speed (#653)
Browse files Browse the repository at this point in the history
  • Loading branch information
indykoning authored Nov 26, 2024
1 parent 43961e9 commit 7a66444
Show file tree
Hide file tree
Showing 8 changed files with 184 additions and 146 deletions.
257 changes: 139 additions & 118 deletions resources/js/package.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,47 @@ import useMask from './stores/useMask'
import { swatches, clear as clearSwatches } from './stores/useSwatches'
import { clear as clearAttributes } from './stores/useAttributes.js'
import './vue'
import { computed } from 'vue'
import './fetch'
import './filters'
import './mixins'
import './turbolinks'
;(() => import('./turbolinks'))()
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 @@ -51,128 +82,118 @@ 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(),
user: useUser(),
mask: useMask(),
showTax: window.config.show_tax,
swatches: swatches,
scrollLock: useScrollLock(document.body),
checkout: {
step: 1,
totals: {},

shipping_address: useLocalStorage('shipping_address', address_defaults, {
mergeDefaults: true,
serializer: StorageSerializers.object,
}),
billing_address: useLocalStorage('billing_address', address_defaults, {
mergeDefaults: true,
serializer: StorageSerializers.object,
}),
hide_billing: useLocalStorage('hide_billing', true),

shipping_method: null,
shipping_methods: [],

payment_method: null,
payment_methods: [],

agreement_ids: [],

// This can be used to prevent the checkout from going
// to the next step which is useful in combination
// with the "CheckoutPaymentSaved" event to
// implement payment providers.
doNotGoToTheNextStep: false,
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(),
user: useUser(),
mask: useMask(),
showTax: window.config.show_tax,
swatches: swatches,
scrollLock: useScrollLock(document.body),
checkout: {
step: 1,
totals: {},

shipping_address: useLocalStorage('shipping_address', address_defaults, {
mergeDefaults: true,
serializer: StorageSerializers.object,
}),
billing_address: useLocalStorage('billing_address', address_defaults, {
mergeDefaults: true,
serializer: StorageSerializers.object,
}),
hide_billing: useLocalStorage('hide_billing', true),

shipping_method: null,
shipping_methods: [],

payment_method: null,
payment_methods: [],

agreement_ids: [],

// This can be used to prevent the checkout from going
// to the next step which is useful in combination
// with the "CheckoutPaymentSaved" event to
// implement payment providers.
doNotGoToTheNextStep: false,
},
},
},
methods: {
search(value) {
if (value.length) {
Turbo.visit(window.url('/search?q=' + encodeURIComponent(value)))
}
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}`
},
},
setSearchParams(url) {
window.history.pushState(window.history.state, '', new URL(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 Boolean(this.user?.id)
},

hasCart() {
return this.cart?.id && this.cart.items.length
},

canOrder() {
return this.cart.items.every((item) => item.is_available)
},
},
toggleScroll(bool = null) {
if (bool === null) {
this.scrollLock = !this.scrollLock
} else {
this.scrollLock = bool
}
watch: {
loadingCount: function (count) {
window.app.$data.loading = count > 0
},
},

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 Boolean(this.user?.id)
mounted() {
setTimeout(() => {
const event = new CustomEvent('vue:mounted', { detail: { vue: window.app } })
document.dispatchEvent(event)
})
},

hasCart() {
return this.cart?.id && this.cart.items.length
},

canOrder() {
return this.cart.items.every((item) => item.is_available)
},
},
watch: {
loadingCount: function (count) {
window.app.$data.loading = count > 0
},
},
})

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
}

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)
}
})
}

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

document.addEventListener('turbo:load', init)
setTimeout(init)
2 changes: 1 addition & 1 deletion resources/views/components/productlist.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

<div slot="renderNoResults"></div>

<div class="relative" slot="render" slot-scope="{ data, loading }" v-if="!loading">
<div class="relative" slot="render" slot-scope="{ data, loading }" v-if="!loading && data?.length">
<slider>
<div slot-scope="{ navigate, showLeft, showRight, currentSlide, slidesTotal }">
<div class="-mx-2 flex mt-5 overflow-x-auto snap-x scrollbar-hide scroll-smooth snap-mandatory" ref="slider">
Expand Down
17 changes: 6 additions & 11 deletions tests/Browser/CartTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ class CartTest extends DuskTestCase
public function addSimpleProduct()
{
$this->browse(function (Browser $browser) {
$this->addProduct($browser, $this->testProduct->url)
$browser->addProductToCart($this->testProduct->url)
->visit('/cart')
->waitUntilVueLoaded()
->waitUntilIdle()
->waitFor('@cart-content', 15)
->waitUntilIdle()
Expand All @@ -29,8 +30,8 @@ public function addMultipleSimpleProduct()
{
$this->browse(function (Browser $browser) {
$browser->script('localStorage.clear();');
$this->addProduct($browser, $this->testProduct->url);
$this->addProduct($browser, $this->testProduct->url);
$browser->addProductToCart($this->testProduct->url);
$browser->addProductToCart($this->testProduct->url);
$browser->assertSeeIn('@minicart-count', 2);
});
}
Expand All @@ -42,6 +43,7 @@ public function changeProductQty()
{
$this->browse(function (Browser $browser) {
$browser->visit('/cart')
->waitUntilVueLoaded()
->waitUntilIdle()
->waitFor('@cart-content', 15)
->waitUntilIdle()
Expand All @@ -59,6 +61,7 @@ public function removeProduct()
{
$this->browse(function (Browser $browser) {
$browser->visit('/cart')
->waitUntilVueLoaded()
->waitUntilIdle()
->waitFor('@cart-content', 15)
->waitUntilIdle()
Expand All @@ -67,12 +70,4 @@ public function removeProduct()
->assertDontSee('@cart-item-name');
});
}

public function addProduct($browser, $url)
{
return $browser->visit($url)
->waitUntilIdle()
->pressAndWaitFor('@add-to-cart', 60)
->waitForText('Added', 60);
}
}
20 changes: 5 additions & 15 deletions tests/Browser/CheckoutTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class CheckoutTest extends DuskTestCase
public function checkoutAsGuest()
{
$this->browse(function (Browser $browser) {
$this->addProductToCart($browser);
$browser->addProductToCart($this->testProduct->url);
$this->doCheckout($browser, 'wayne+' . mt_rand() . '@enterprises.com');
});
}
Expand All @@ -27,39 +27,29 @@ public function checkoutAsUser()

// Go through checkout as guest and register.
$this->browse(function (Browser $browser) use ($email) {
$this->addProductToCart($browser);
$browser->addProductToCart($this->testProduct->url);
$this->doCheckout($browser, $email, 'IronManSucks.91939', true);
});

// Go through checkout as guest and log in.
$this->browse(function (Browser $browser) use ($email) {
$browser->waitForReload(fn ($browser) => $browser->visit('/'), 4)
->waitUntilVueLoaded()
->waitUntilIdle()
->waitFor('@account_menu')
->click('@account_menu')
->click('@logout')
->waitUntilIdle();
$this->addProductToCart($browser);
$browser->addProductToCart($this->testProduct->url);
$this->doCheckout($browser, $email, 'IronManSucks.91939', false);
});
}

public function addProductToCart($browser)
{
$browser
->visit($this->testProduct->url)
->waitUntilIdle()
->click('@add-to-cart')
->waitUntilIdle();

return $browser;
}

public function doCheckout(Browser $browser, $email = false, $password = false, $register = false)
{
$browser
->visit('/checkout')
->pause(5000)
->waitUntilVueLoaded()
->waitUntilIdle()
->type('@email', $email ?: '[email protected]')
->click('@continue')
Expand Down
Loading

0 comments on commit 7a66444

Please sign in to comment.