# v1.2.0 release notes
# Introduction
In this release, we:
- upgraded
@vue-storefront/core
package to version2.5.12
, which added an optionalmiddlewareUrl
property to define the URL of the Server Middleware. See its migration guide (opens new window) for more information. Cache control is no longer included into@vue-storefront/core
package. To use caching see tips and tricks. - upgraded
@storefront-ui/vue
package to version0.13.0
, which removedmobileObserver
andSfSlidingSection
and requires addingtype="submit"
toSfButton
s in forms. - fixed an issue with SfSearchBar and
@keydown.enter
# Migration guide
# Migrating to @vue-storefront/core
with v2.5.12
# nuxt.config.js
publicRuntimeConfig: {
theme,
+ middlewareUrl:
+ process.env.NODE_ENV === 'production'
+ ? process.env.API_BASE_URL
+ : 'http://localhost:3000/api/'
},
# .env
+ API_BASE_URL=<URL to the Server Middleware>
# Migrating to @storefront-ui/vue
with 0.13.0
# Exclude core-js
package
Exclude the core-js
package from Babel transpilation, as shown below:
# nuxt.config.js
babel: {
plugins: [
[
'@babel/plugin-proposal-private-methods',
{ loose: true }
]
],
+ exclude: [/\bcore-js\b/, /\bwebpack\/buildin\b/]
},
# pages/Home.vue
# pages/Category.vue
# pages/Product.vue
- middleware: cacheControl({
- 'max-age': 60,
- 'stale-when-revalidate': 5
- }),
# Update SfButton
The SfButton
component used in forms now requires the type="submit"
attribute. The following components use it in the default theme:
AddReview
componentReserPasswordForm
componentProfileUpdateForm
componentMyNewsletter
page
<form>
- <SfButton>
+ <SfButton type="submit">
Submit
</SfButton>
</form>
# Remove mobileObserver
# components/AppHeader
<template #navigation>
- <HeaderNavigation :categories="navigation" :isMobile="isMobile" />
+ <HeaderNavigation :categories="navigation" />
</template>
...
- import {
- mapMobileObserver,
- unMapMobileObserver
- } from '@storefront-ui/vue/src/utilities/mobile-observer.js';
...
- const isMobile = ref(mapMobileObserver().isMobile.get());
...
- const closeOrFocusSearchBar = () => {
- if (isMobile.value) {
- return closeSearch();
- } else {
- term.value = '';
- return searchBarRef.value.$el.children[0].focus();
- }
+ const clearAndFocusSearchBar = () => {
+ term.value = '';
+ return searchBarRef.value.$el.children[0]?.children[0]?.focus();
...
const onSearchBarIconClick = computed(() =>
term.value
- ? closeOrFocusSearchBar
+ ? clearAndFocusSearchBar
: () => {
isSearchOpen.value
? (isSearchOpen.value = false)
...
- watch(
- () => term.value,
- (newVal, oldVal) => {
- const shouldSearchBeOpened =
- !isMobile.value &&
- term.value.length > 0 &&
- ((!oldVal && newVal) ||
- (newVal.length !== oldVal.length && isSearchOpen.value === false));
- if (shouldSearchBeOpened) {
- isSearchOpen.value = true;
- }
- }
- );
- onBeforeUnmount(() => {
- unMapMobileObserver();
- });
...
return {
accountIcon,
cartTotalItems,
handleAccountClick,
toggleCartSidebar,
toggleWishlistSidebar,
term,
isSearchOpen,
isCheckoutPage,
closeSearch,
handleSearch,
loading,
result,
- closeOrFocusSearchBar,
+ clearAndFocusSearchBar,
searchBarRef,
- isMobile,
isMobileMenuOpen,
products,
navigation,
wishlistTotalItems,
searchBarIcon,
onSearchBarIconClick
};
# components/HeaderNavigation.vue
<template>
- <div class="sf-header__navigation desktop" v-if="!isMobile">
- <SfHeaderNavigationItem
- v-for="(category, key) in categories"
- :key="key"
- class="nav-item"
- v-e2e="`app-header-url_${category.slug}`"
- :label="category.label"
- :link="localePath(`/c${category.slug}`)"
- />
- </div>
- <SfModal v-else :visible="isMobileMenuOpen">
+ <div>
+ <div class="sf-header__navigation desktop">
+ <SfHeaderNavigationItem
+ v-for="(category, key) in categories"
+ :key="key"
+ class="nav-item"
+ v-e2e="`app-header-url_${category.slug}`"
+ :label="category.label"
+ :link="localePath(`/c${category.slug}`)"
+ />
+ </div>
+ <SfModal :visible="isMobileMenuOpen" class="smartphone-only">
<SfHeaderNavigationItem
v-for="(category, key) in categories"
:key="key"
class="nav-item"
v-e2e="`app-header-url_${category.slug}`"
>
<template #desktop-navigation-item>
<SfMenuItem
:label="category.label"
class="sf-header-navigation-item__menu-item"
@click="navigate(`/c${category.slug}`)"
/>
</template>
<template #mobile-navigation-item>
<SfMenuItem
:label="category.label"
class="sf-header-navigation-item__menu-item"
@click="navigate(`/c${category.slug}`)"
/>
</template>
</SfHeaderNavigationItem>
</SfModal>
+ </div>
</template>
...
props: {
- isMobile: {
- type: Boolean,
- default: false
- },
categories: {
type: Array as PropType<Array<SearchResultNavigationItem>>,
default: () => []
}
},
# components/RelatedProducts.vue
- :imageWidth="isMobile ? 154 : 216"
- :imageHeight="isMobile ? 154 : 216"
+ :imageWidth="216"
+ :imageHeight="216"
...
- import {
- mapMobileObserver,
- unMapMobileObserver
- } from '@storefront-ui/vue/src/utilities/mobile-observer.js';
...
import {
defineComponent,
- onBeforeUnmount,
- PropType,
- ref
+ PropType
} from '@nuxtjs/composition-api';
...
- const isMobile = ref(mapMobileObserver().isMobile.get());
...
- onBeforeUnmount(() => {
- unMapMobileObserver();
- });
return {
productData,
wishlistHelpers,
wishlist,
isInWishlist,
addItemToWishlist,
removeItemFromWishlist,
isInCart,
addItemToCart,
- getPurchasableDefaultVariant,
- isMobile
+ getPurchasableDefaultVariant
};
...
&__item {
margin: 1.9375rem 0 2.4375rem 0;
}
+
+ ::v-deep .sf-product-card__image .sf-image {
+ --image-width: 9.625rem;
+ --image-height: 9.625rem;
+ @include for-desktop {
+ --image-width: 13.5rem;
+ --image-height: 13.5rem;
+ }
+ }
}
</style>
# layouts/error.vue
- :width="isMobile ? 230 : 412"
- :height="isMobile ? 230 : 412"
+ :width="412"
+ :height="412"
...
- import { computed, useRouter } from '@nuxtjs/composition-api';
+ import { useRouter } from '@nuxtjs/composition-api';
-import { mapMobileObserver } from '@storefront-ui/vue/src/utilities/mobile-observer.js';
...
- const isMobile = computed(() => mapMobileObserver().isMobile.get());
return {
router,
- isMobile,
addBasePath
};
...
- .image {
+
+ ::v-deep .sf-image {
--image-width: 14.375rem;
+ --image-height: 14.375rem;
padding: var(--spacer-xl) 0;
@include for-desktop {
--image-width: 25.75rem;
+ --image-height: 25.75rem;
}
}
# pages/Category.vue
- :imageWidth="isMobile ? 150 : 216"
- :imageHeight="isMobile ? 150 : 216"
+ :imageWidth="216"
+ :imageHeight="216"
...
- :imageWidth="isMobile ? 85 : 140"
- :imageHeight="isMobile ? 113 : 200"
+ :imageWidth="140"
+ :imageHeight="200"
...
import {
computed,
defineComponent,
- onBeforeUnmount,
ref,
useContext,
useMeta
} from '@nuxtjs/composition-api';
- import {
- mapMobileObserver,
- unMapMobileObserver
- } from '@storefront-ui/vue/src/utilities/mobile-observer.js';
...
- import cacheControl from './../helpers/cacheControl';
...
- const isMobile = ref(mapMobileObserver().isMobile.get());
...
- onBeforeUnmount(() => {
- unMapMobileObserver();
- });
...
&__product-card {
--product-card-title-margin: var(--spacer-base) 0 0 0;
--product-card-title-font-weight: var(--font-weight--medium);
--product-card-title-margin: var(--spacer-xs) 0 0 0;
flex: 1 1 50%;
@include for-desktop {
--product-card-title-font-weight: var(--font-weight--normal);
--product-card-add-button-bottom: var(--spacer-base);
--product-card-title-margin: var(--spacer-sm) 0 0 0;
}
+ ::v-deep .sf-image {
+ --image-width: 9.375rem;
+ --image-height: 9.375rem;
+ @include for-desktop {
+ --image-width: 13.5rem;
+ --image-height: 13.5rem;
+ }
+ }
}
&__product-card-horizontal {
flex: 0 0 100%;
- @include for-mobile {
- ::v-deep .sf-image {
- --image-width: 5.3125rem;
- --image-height: 7.0625rem;
+ ::v-deep .sf-image {
+ --image-width: 5.3125rem;
+ --image-height: 7.0625rem;
+ @include for-desktop {
+ --image-width: 8.75rem;
+ --image-height: 12.5rem;
}
}
}
# Fixing SfSearchBar component
# components/AppHeader.vue
<SfSearchBar
ref="searchBarRef"
:placeholder="$t('Search for items')"
aria-label="Search"
class="sf-header__search"
:class="{ 'search-hidden': isCheckoutPage }"
:value="term"
@input="handleSearch"
- @keydown.enter="handleSearch($event)"
+ @keyup.enter="handleSearch($event)"
@focus="isSearchOpen = true"
@keydown.esc="closeSearch"
:icon="searchBarIcon"
@click:icon="onSearchBarIconClick"
/>