IMPORTANT NOTE: This article is written for Vue Storefront 1.0. Some parts may be different in current VS version. If you have any problems with setting up your theme please take a look at our readme or join our slack where you can ask me and almost 500 developers for help.


In part 1 of the series we understood how Vue Storefront themes work in theory. In this article we’re gonna dive deeper into Vue Storefront code and try to understand how it works while creating very simple fashion theme Header.

It’s been a while since the previous article was released so we should get familiar with changes in Vue Storefront architecture that occured during this time (previous article was also updated):

  1. The core is now fully separated from the rest of the application in a core folder
  2. We switched to monorepo approach with lerma and yarn.
  3. The coreComponent and corePage methods has been replaced with traditional imports (details here).
  4. Vue Storefront is officially production ready with v1.0!
  5. We updated our build tools to webpack 4!

Now when we know what changed let’s get to work ;)

Creating new theme

As I mentioned in a previous article there are two ways of creating your own VS theme:

To keep things simple and learn something more about internals we will use theme-starter for our new shop.

Once we made our decision we need to copy theme-starter (or default) folder and rename it. Let’s say we are making a fashion store so we should name our theme accordingly

folder
Our /src folder should look like this

Next we need to modify package.json file inside our themes dir which holds the real themes name that we’ll use to register it in config/local.json.

file example
After some changes our package.json file should look more or less like this

Now when we have our new theme created we need to enable it in our monorepo by installing it with yarn install.

Once we have it installed we can register our theme in config/local.json by changing theme property to @vue-storefront/theme-fashion which is a name property that we defined in themespackage.json.

Voila! After running yarn dev we should see theme-starter’s homepage:

This will be a base for our new theme and from now we can start playing with it!

Getting familiar with theme-starter

Before we start customization of our fashion theme we should get familiar with theme-starter basics.

The App.vue file located in our themes root dir is a wrapper component for our application. As you can see it contains some very basic business logic (I’ve tried to make this tutorial future-proof but please keep in mind that some things can change over time)

// App.vue
// other imports
import Head from 'theme/resource/head'
export default {
// other properties
metaInfo: Head
}

As you probably noticed there is a bunch of other files inside our theme. Most of them are used to modify or extend the core functionalities and remains the same for every theme. You can read more about this files here.

Part of theme docs

The components and pages folders are the ones that will contain most of our application code. In the second one you’ll find Home.vue which is themes homepage by default (you can change homepage component in index.js file where you can modify and create application routes).

Now when we know something more about our theme it’s time to customize it!

Customizing our theme

Our theme-starter looks really awful right now. Before shipping it to production we should focus a little bit on the design and add some must-have features.

We can achieve quick results in this area by using one of many popular component libraries for Vue like Element.

To integrate Element with Vue Storefront we just need to import js components and stylesheets into our app.

  1. Install element with yarn add element-ui. You should be in src/themes/fashion folder while doing this so the dependency will be bundled only if fashion theme is the active one.
  2. Register the plugin in plugins/index.js file (the format in current develop branch has changed to Vue.use — see the docs ) so it will look like this:
// plugins/index.js
// other imports
import Element from 'element-ui'
Vue.use(Element)

3. Import Element stylesheet (we can do it in a few ways — lets play a little bit with resource/head.js and add it from CDN). Place the CDN link under link property (you can also import the css file in App.vue ormain.scss)

{ rel: 'stylesheet', href: 'https://unpkg.com/element-ui/lib/theme-chalk/index.css' }

…and that’s all you need to have Element integrated into your VS theme. Now let’s make use of it and get rid of the default theme-starter welcome screen.

To do it we should temporary delete this welcoming content inside<template> tag and remove the style tag entirely in our pages/Home.vue component.

// Home.vue
<template>
<div id="home">
Home
</div>
</template>
<script>
export default {
components: {
// Place page-specific components here
}
}
</script>

Let’s leave homepage for now and play a little bit with the header.

If you take a look at components/Header.vue you will see simple HTML template similar to this:

// Header.vue
<template>
<header>
Header:
<router-link :to="localizedRoute('/')">Homepage</router-link>
</header>
</template>

Note: The one thing that you’re probably not familiar with is localizeRoute function in router link component. It’s used to allow multistore support in Vue Storefront and can be ommited if you’re not interested in this feature.

For now our header is completely useless, let’s put something in there! We will start with logo and icon which will open our cart in a popover. Let’s start with the logo.

Let’s say that we want to use default Vue Storefront logo. You can find it under assets/logo.svg dir in VS /core folder. You can use it like it’s in your themes assets.

Note: If VS doesn’t find a file with a given name (in this case logo.svg) in your themes assets folder it will try to retrieve it from core/assets.

At this point our header should look like this

// Header.vue
<header>
<router-link :to="localizedRoute('/')">
<img src="/assets/logo.svg" alt="Fashion store logo">
</router-link>
</header>

Once we have our logo it’s time to use VS core functions and allow users to open their Microcart.

To add this functionality to our Header we need to:

// Header.vue
<template>
<header>
<router-link :to="localizedRoute('/')">
<img src="/assets/logo.svg" alt="Fashion store logo">
</router-link>
<el-button @click="openMicrocart">{{ $t('Cart') }}</el-button>
</header>
</template>
<script>
import MicrocartIcon from 'core/components/blocks/Header/MicrocartIcon'
export default {
mixins: [MicrocartIcon]
}
</script>

As we can see in core MicrocartIcon code we have now access to openMicrocart method which dispatches Vuex action from UI store.

Note: UI store is responsible for keeping the apps interface state. It hold informations about currently open popups etc.

We bounded this method to our button so after clicking it you should see that UIstore state has changed (the screen is from Vue devtools which i highly recommend for debugging Vue apps).

Pro tip: There is one more big advantage of Vue devtools. You can inspect the default theme to quickly check which core components were used to achieve particular features.

code example
UI Store state after clicking Cart button

Note: The $t() function that you probably noticed is used to handle multiple languages with vue-i18n and multistore (you can translate the strings under resource/i18n and specify the multilanguage options in your config file).

You also probably noticed that we are using webpack aliases to resolve core components. It’s a recommended way to interact with VS core imports. In case of any changes in the core they will still point to the right folders so you can upgrade the app without worrying that changes would break your shop. You can check here which aliases you can use.

Even tho our state is changing we still don’t have any Microcart popup to open. Before doing it let’s make use of the flexbox-grid available in theme-starter and make our header a little bit prettier!

// Header.vue
<header>
<div class="row">
<div class="col-xs-6">
<router-link :to="localizedRoute('/')">
<img src="/assets/logo.svg" alt="Fashion store logo">
</router-link>
</div>
<div class="col-xs-6 end-xs middle-xs">
<el-button @click="openMicrocart">{{ $t('Cart') }}</el-button>
</div>
</div>
</header>
This is how our shop looks now. It’s still awful

Now it’s time to play with our Microcart.vue component which can be found under components/Microcart directory of our theme.

If we take a look inside it we will find well-known structure with core Microcart component injected into theme component and v-for loop iterating through items in cart:

// Microcart.vue
<template>
<div class="microcart">
<h3>Microcart</h3>
<div v-for="(item, index) in items" :key="index"> {{ item.name }} ({{ item.qty }}) </div>
</div>
</template>
<script>
import Microcart from 'core/components/blocks/Microcart/Microcart'
export default {
mixins: [Microcart]
}
</script>

We’re gonna use ElementUI diialog component to display our popup with Microcart. After adding the HTML markup we also need to tell the dialog when it should open and thats a great occasion to show how you can check methods and properties available in Vue components.

First and most in-depth (but not the fastest) way to check it is via core components code or docs. The second way which I personally recommend if you only want to see the available data fields is via Vue devtools.

Note: Please be aware that devtools are not showing available methods, only data properties, computed properties and Vuex bindings.

A quick inspect at Microcart component will tell us everything we need:

Microcart component
Microcart component

As we can see there is isOpen property which is set to false by default. After clicking on our previously created button in Header.vue with openMicrocart method bounded to it we can see that this propertys value changed to true which is what we wanted to see.

We also want to set this value to false after closing the modal. A quick look at dialog component docs will tell us that we can use before-close property to trigger closeMicrocart method (which can be found in components source code) so after clicking ‘close’ button or any element outside the modal this method will be called and Microcarts isOpen state prop will be set to false.

Microcart example

With dialog component added and isOpen property bounded to it our Microcart.vue component should look like this:

// Microcart.vue
<template>
<div class="microcart">
<el-dialog title="Microcart" :visible.sync="isOpen" :before-close="(done) => closeMicrocart()" >
<div v-for="(item, index) in items" :key="index"> {{ item.name }} ({{ item.qty }}) </div>
</el-dialog>
</div>
</template>
<script>
import Microcart from 'core/components/blocks/Microcart/Microcart'
export default {
mixins: [Microcart]
}
</script>

Which will be reflected in a view similar to the one below after clicking our ‘cart’ button:

Bottom line

In this article i’ve tried to explain what are the best ways to play with Vue Storefront themes and how easy it is. If you have any questions about techniques described in the article don’t hesitate to ask about it on our slack channel with almost 400 developers ready to help you.

As you probably noticed we still don’t have any products displayed on our page so we can’t add anything to the cart yet. This article was focused mostly on understanding how to interact with Vue Storefront core and themes. In the next part we’re gonna write much more code and see how fast we can build fully-featured shop.

You can find the source code of fashion theme here. You can also follow me on twitter where I’m tryimg to share interesting articles about Vue Storefront and PWA.