Vue.js SDK

Install

Overview

The integration of Hawksearch using Vue.js is done by using the Hawksearch Vue SDK. It is a publicly distributed NPM package that is included as a dependency to the BigCommerce theme. The default Cornerstone theme is used in the following examples.

Prerequisite

  • Node.js version 11.0.0 or higher
  • NPM version 6.0.0 or higher
  • A Stencil theme
  • Stencil CLI

Steps to install

  1. Install the package in your theme using the command shell
npm install git+https://github.com/hawksearch/vue-hawksearch.git#latest
  1. Create a directory in your assets folder to include Vue.js resources (e.g. assets/js/hawksearch/vue).
  2. Create an index.js (e.g. assets/js/hawksearch/vue/index.js). It will include all necessary initializations and custom work that will be included in the later articles. At this point, the main class can be imported at the top of the file.

assets/js/hawksearch/vue/index.js

import HawksearchVue from '@hawksearch/vue';
  1. The initialization script should be included in theme scripts. The recommended approach is to include it in the theme app.js to maintain a single bundle structure. To do this the index.js must include a function export.

assets/js/hawksearch/vue/index.js

import HawksearchVue from '@hawksearch/vue';  
// Other imports

...

export default function () {  
  // Initialization code goes here  
}

assets/js/app.js

...

// Import the initializor function
import hawsearchInitialize from './hawksearch/vue';

...

window.stencilBootstrap = function stencilBootstrap(pageType, contextJSON = null, loadGlobal = true) {
    const context = JSON.parse(contextJSON || '{}');

    return {
        load() {
            $(() => {
                // Load globals
                if (loadGlobal) {
                    Global.load(context);
                }

                ...
                
                // Call the init function on load after the rest
                // of the script loads
                hawsearchInitialize();
            });
        },
    };
};
  1. The vue instance is also required for any additional customization, so it is a good practice to add it to the webpack config.

webpack.common.js

module.exports = {  
    ...  
    resolve: {  
        alias: {  
            ...  
            'vue$': 'vue/dist/vue.esm.js'  
        }  
    }  
};
  1. The package has default styles that are available from @hawksearch/vue/dist/vue-hawksearch.css and should be included and used as a base for further development.
  2. Run the stencil development environment to build the resources and review progress.
    Live Previewing a Theme - Stencil CLI - Stencil Docs

Setup configuration

Overview

The integration to the Hawksearch service requires several configuration parameters to be provided to the search request. These are usually set for a specific instance of the site integration. For instance, a website can have a configuration object common to all Hawksearch widgets, and its development, stage and production instances will have variations to that configuration corresponding to their appropriate APIs and settings.

Setup

Separate configuration file

A more generic approach is to create a separate file specifically for the Hawksearch configuration. It may be placed in the designated integration folder (e.g. assets/js/hawksearch), or in another convenient place. It should be a JSON file with the following structure:

hawksearch.config.json

{  
    "apiUrl": "<https://searchapi-dev.hawksearch.net/">,  
    "dashboardUrl": "<https://dev.hawksearch.net/">,  
    "clientGuid":  "9c2a78v6bc9977w0929w88rf576y4476",  
    "searchConfig": {  
        "scrollUpOnRefresh": false  
    }  
}

Using the theme settings file

Since most of the configurations for the theme are placed in the config.json file, it is a convenient place to set the Hawksearch settings alongside other general settings. This may additionally improve management since all other setups are common among the website instances and the config.json may provide any dedicated behavior per site.

config.json

{  
    "name": "Cornerstone",  
    "version": "4.12.1",  
    ...  
    "hawksearch-config": {  
        "apiUrl": "<https://searchapi-dev.hawksearch.net/">,  
        "dashboardUrl": "<https://dev.hawksearch.net/">,  
        "clientGuid": "9c2a78v6bc9977w0929w88rf576y4476",  
        "searchConfig": {  
            "scrollUpOnRefresh": true  
        }  
    },  
    ...  
}

Initialization

Overview

This article will provide basic information on how to initialize a Vue.js widget for Hawksearch. All additional custom functionalities go on top of this initialization and either expose or extend features of the Vue SDK.

Prerequisite

  1. Install
  2. Setup Configuration

Initialization process

Let’s overview the following initialization script

assets/js/hawksearch/vue/index.js

import HawksearchVue from '@hawksearch/vue';
import defaultConfig from 'hawksearch.config.json';

export default function () {
    var components = document.querySelectorAll('[data-hawksearch-component="results"], [data-hawksearch-component="search-box"]');
    var dataLayers = {};

    if (components) {
        components.forEach(component => {
            var config = defaultConfig;

            config.clientGuid = component.getAttribute('data-hawksearch-client-guid') || defaultConfig.clientGuid;
            config.indexName = component.getAttribute('data-hawksearch-index-name') || defaultConfig.indexName;
            config.apiUrl = component.getAttribute('data-hawksearch-search-api') || defaultConfig.apiUrl;
            config.dashboardUrl = component.getAttribute('data-hawksearch-dashboard-url') || defaultConfig.dashboardUrl;
            config.websiteUrl = component.getAttribute('data-hawksearch-website-url') || defaultConfig.websiteUrl;

            if (component.getAttribute('data-hawksearch-landingpage')) {
                config.additionalParameters = { "CustomUrl": component.getAttribute('data-hawksearch-landingpage') };
            }

            var dataLayer = ('index_' + component.getAttribute('data-hawksearch-index-name'));

            if (dataLayers.hasOwnProperty(dataLayer)) {
                var widgetStore = HawksearchVue.storeInstances[dataLayers[dataLayer]];

                if (widgetStore) {
                    var widget = HawksearchVue.createWidget(component, { config, store: widgetStore });
                }
            }
            else {
                var widget = HawksearchVue.createWidget(component, { config });
                dataLayers[dataLayer] = HawksearchVue.getWidgetStore(widget).state.storeId;
            }

            if (widget && component.getAttribute('data-hawksearch-component') == 'results') {
                HawksearchVue.initialSearch(widget);
            }
        });

    }
}
  • The script follows the structure noted in this article - imports the main class from the SDK and exports an anonymous function for the app.js invocation.
  • Also imported is the configuration file (line 2)
  • The widget’s root elements are queried by a designated data attribute selector (line 5). In this case a search box and a results widget.
  • For each of the root elements, a configuration object is created based on the general default configuration object. Any specific settings are additionally updated based on the available data attributes (line 10 through 16)
  • The landing page is parsed, if available (line 19)The data layer is fetched based on the index name. This is an optional step required for multiple widgets placed on the same page (line 22)
  • The basic initialization (line 32)
var widget = HawksearchVue.createWidget(component, { config });

creates the widget on top of the root element with the provided configuration object. This type of initialization can also be used when there is only one widget on the page (e.g. search box redirecting, single page application)

  • For the given example, it is presumed that there is more than one widget on this page (i.e. search box, results). For that reason, we save the newly created data layer (line 33)
  • If a widget is provided with the same index as another on the same page, the data layer is reused and this type of initialization is used (line 28)
var widget = HawksearchVue.createWidget(component, { config, store: widgetStore });
  • If the type of widget is results, it is preferable to make an initial search (line 37)

Create components

Overview

The Vue widgets can be implemented in all page or component templates in the Stencil theme as long as the appropriate root element is available. These structures can also be set as a separate template file and reused with similar configurations multiple times. Here are some samples on how to create an inline element in the page template along with some samples on different types of Hawksearch widgets.

Structure of Single Page Application

<div data-hawksearch-component="results">
    <div class="hawk">
        <div class="hawk__header">
            <search-box></search-box>
        </div>

        <div class="hawk__body">
            <facet-list></facet-list>

            <results></results>
        </div>
    </div>
</div>

This is the most basic implementation of the Vue.js widget. Its root element has only the data component attribute required for the initialization. The widget contains the three main Vue components - search box, facet list, results. They can be arranged in any convenient way using HTML markup. The root element can be updated with additional data attributes that serve as an integration point for the widget. For instance, having a data-hawksearch-index-name attribute will set the widget’s index name to a different value than the default config. Being an “all-purpose” widget, it is not used that often. Preferably, the integration structure should be achieved with several widgets, working synchronously.

Create search box

Overview

Standard practice is to create a predefined search box component to be subsequently placed on the desired page template. This is the specific configuration for this type of widget based on the common widget root element.

Steps to create

  1. Create a Stencil component template file in a desired directory (e.g. templates\components\hawksearch)
  2. Place the specific root element structure in the component file

templates\components\hawksearch\search-box.html

<div data-hawksearch-component="search-box">
    <div class="hawk">
        <div class="hawk__header">
            <search-box search-page="{{ searchpage }}"></search-box>
        </div>
    </div>
</div>
  • The element has the dedicated search box selector, thus differentiating it from other widgets like the results, which require an initial search.
  • The only available main Vue component is
  • There is an exposed variable for redirecting - searchpage. If available, the search request will redirect to a search results page where the results widget will display the output of the search. If this variable is not provided the search process will be executed on the current page.
  1. A frequently used placement of this widget using the redirect feature is in the heading of the page. For this, the component should be placed in templates\components\common\header.html. In this case “/search“ is the URL of the search results page.

templates\components\common\header.html

...

<div class="hawksearch-heading-search">
  {{> components/hawksearch/search-box searchpage="/search"}}
</div>
...
  1. The same invocation can be executed in any of the other template files. If there is an available results widget on the same page, use without the searchpage parameter.
...  
{{> components/hawksearch/search-box }}  
...

...  
{{> components/hawksearch/results }}  
...

Create search results

Overview

Creating a reusable results component can be done in a similar manner to the search box component. The results component is a derivation of the single page application with the search box either not required, or placed as a separate widget.

Steps to create

  1. Create a Stencil component template file in a desired directory (e.g. templates\components\hawksearch)
  2. Place the specific root element structure in the component file

templates\components\hawksearch\results.html

<div data-hawksearch-component="results">
    <div class="hawk">
        <div class="hawk__body">
            <facet-list></facet-list>

            <results></results>
        </div>
    </div>
</div>
  • The element has the dedicated selector that enables the initial search
  • There are two main Vue components - and
  • In this case, it doesn’t have a search field that may trigger a search by keyword and should be placed on page that is a redirect target or a landing page.
  1. The results component can be placed in any of the theme templates.
...  
{{> components/hawksearch/results }}  
...
  1. Since Hawksearch has the option of setting landing pages, this widget can be configured to display data for a specific landing page. This setup may vary, but in essence, is adding an additional data attribute for the custom URL of the landing page.
<div data-hawksearch-component="results" data-hawksearch-landingpage="/top-sellers">
    <div class="hawk">
        <div class="hawk__body">
            <facet-list></facet-list>

            <results></results>
        </div>
    </div>
</div>

Extend component templates

Overview

All of the available main and inner components are available for modifications at a template level. This is usually used when site-specific styles and markup are applied. For this sample, the result item from the list of fetched results is extended.

Steps to extend

  1. Open the initialization file for edit (assets/js/hawksearch/vue/index.js)
  2. Import all components requiring template extending (e.g. ResultItem)

assets/js/hawksearch/vue/index.js

...  
import { ResultItem } from '@hawksearch/vue';  
...
  1. Set a template override id for the component
ResultItem.templateOverride = "#vue-hawksearch-result-item";
  1. Place the template override layout alongside the widget template. For the result item this should be the results widget.
<div data-hawksearch-component="results">
    <div class="hawk">
        <div class="hawk__body">
            <facet-list></facet-list>

            <results></results>
        </div>
    </div>
</div>

<script id="vue-hawksearch-result-item" type="x-template">
    <div class="custom-classes" v-on:click="onClick">
        <p>\{{ getField('custom_search_field') }}</p>
    </div>
</script>
  • The script tag contains the new layout for the result item. Note that it is defined by id and therefore should be the only override for this component on a page.
  • All Vue.js directives are available for this override. To prevent conflicts with the Stencil theme parser, the fields in {{ }} are escaped.

Extend component functionalities

Overview

Although extending only the template is usually enough for most customizations, some features may require extending the functionalities of the component. For this sample, again the updated component will be ResultItem.

Prerequisite

Node dependencies:

  • vue-loader: "^15.9.6"
  • vue-template-compiler: "^2.6.12"

Steps for customizations

  1. Create a subfolder alongside the Vue SDK initialization file (e.g. assets/js/hawksearch/vue/components)
  2. Create a ResultItem Vue single file component in it.

assets/js/hawksearch/vue/components/ResultItem.vue

<template>
    <div class="custom-classes" v-on:click="onClick">
        <p>{{ customMethod() }}</p>
    </div>
</template>

<script>
    import { ResultItem } from '@hawksearch/vue';

    export default {
        extends: ResultItem,
        methods: {
            customMethod: function () {
                return 'Lorem ipsum';
            }
        }
    };
</script>
  • Note that in this file both template and scripts are initialized
  • The default _ResultItem _component is imported from the Vue SDK and the custom one extends it
  • A _customMethod _is additionally defined for this component
  1. The newly created file must be included in the initialization script and attached to his parent

assets/js/hawksearch/vue/index.js

...  
import { ResultListing } from '@hawksearch/vue';  
import ResultItem from './components/ResultItem.vue';

ResultListing.components.ResultItem = ResultItem;  
...

📘

Note

For additional information on component customizations, follow this article, or review the publicly available Vue SDK at GitHub