Handlebars Syntax and Helpers
Handlebars.js
Handlebars Helpers
Stencil Object Model
Stencil Objects

Implementing a Custom React.js Checkout to Cornerstone using the BigCommerce Checkout SDK

Tutorial Overview

This tutorial will take you through the steps to implement a custom checkout built with React to the Cornerstone Theme. The checkout will utilize BigCommerce’s Checkout SDK. This tutorial assumes Cornerstone 2.4.0 as a starting point.

Checkout Example NOT production ready!

Please note that the provided checkout example is a good starting and reference point, but is NOT production ready. You should not use this custom checkout in production as it stands.

Steps to Implement a Custom React Checkout in Cornerstone

Tutorial Prerequisites

Before beginning this tutorial, you will need to have the Stencil CLI installed.

If you do not yet have Stencil CLI installed, complete the steps in Installing Stencil.

Install Dependencies

The React app used to demonstrate the Checkout SDK has a few additional dependencies. In your theme directory (e.g. /stencil/cornerstone), run the following command:

npm install --save react react-dom react-text-mask classnames accounting babel-preset-react css-loader node-sass sass-loader style-loader @bigcommerce/checkout-sdk

Update webpack.common.js

The React app includes .jsx files which will not be resolved using the default webpack configuration in Cornerstone. Additionally, loaders must be registered for .jsx and .scss files.

Note: Cornerstone 2.0 and above uses Webpack 4 which does not use a webpack.conf.js file like earlier Webpack versions. Instead, we will modify webpack.common.js.

Register .jsx and .scss loaders

In webpack.common.js, add the following objects to the rules array:

{
  test: /\.jsx$/,
  exclude: /node_modules/,
  use: {
      loader: "babel-loader",
      options: {
          presets: ['react'],
      },
  }
},

{
  test: /\.scss$/,
  use:  [
      'style-loader',
      {
          loader: 'css-loader',
          options: {
              modules: true
          }
      },
      'sass-loader'
  ],
},

Next, in webpack.common.js, add the following property to the resolve object:

extensions: ['.js', '.jsx']

Add React Checkout Components to Theme

  1. Clone or download BigCommerce’s Checkout SDK JS Example outside of your theme directory

git clone https://github.com/bigcommerce/checkout-sdk-js-example.git

If the above command fails, and you are accessing GitHub anonymously, give the URL this alternate prefix:

git clone git@github.com:bigcommerce/checkout-sdk-js-example.git

  1. In your theme directory, navigate to /assets/js/ and create a checkout-app directory (i.e. /assets/js/checkout-app)

  2. Copy the contents of /checkout-sdk-js-example/src into your new /assets/js/checkout-app directory

Import Dependencies

Edit /assets/js/app.js and add the following lines toward the beginning with the other import statements:

import React from 'react';
import ReactDOM from 'react-dom';
import Checkout from './checkout-app/Checkout/checkout';

Define a Function to Initialize React

Edit /assets/js/app.js and add the following lines to the end:

window.initReact = function initReact() {
    ReactDOM.render(
        React.createElement(Checkout, null, null),
        document.getElementById('checkout-app')
    );
};

Customize the Checkout Template

  1. Edit /templates/pages/checkout.html and add the following lines between {{{ footer.scripts }}} and {{/partial}}
<script src="{{cdn 'assets/dist/theme-bundle.main.js'}}"></script>
 
<script type="text/javascript" defer>
    // Exported in app.js
    window.initReact();
</script>
  1. In /templates/pages/checkout.html, replace {{{ checkout.checkout_content }}} with the following:

<div id="checkout-app"></div>

Congratulations!

You should now be able to view your example React checkout by running the stencil start command in your theme directory and navigating to your storefront at http://localhost:3000.

You can make further customizations to the checkout by modifying the React components in /assets/js/checkout-app.

Examples of files after completing this tutorial
webpack.common.js
LodashPlugin = require('lodash-webpack-plugin'),
path = require('path'),
webpack = require('webpack');

// Common configuration, with extensions in webpack.dev.js and webpack.prod.js.
module.exports = {
bail: true,
context: __dirname,
entry: {
  main: './assets/js/app.js',
},
module: {
  rules: [
      {
          test: /\.js$/,
          include: /(assets\/js|assets\\js|stencil-utils)/,
          use: {
              loader: 'babel-loader',
              options: {
                  plugins: [
                      'dynamic-import-webpack', // Needed for dynamic imports.
                      'lodash', // Automagically tree-shakes lodash.
                      'transform-regenerator', // Transforms async and generator functions.
                  ],
                  presets: [
                      ['env', {
                          loose: true, // Enable "loose" transformations for any plugins in this preset that allow them.
                          modules: false, // Don't transform modules; needed for tree-shaking.
                          useBuiltIns: true, // Tree-shake babel-polyfill.
                      }],
                  ],
              },
          },
      },
      {
          test: /jquery-migrate/,
          use: 'imports-loader?define=>false',
      },
      {
          test: /\.jsx$/,
          exclude: /node_modules/,
          use: {
              loader: "babel-loader",
              options: {
                  presets: ['react'],
              },
          }
      },
      {
          test: /\.scss$/,
          use:  [
              'style-loader',
              {
                  loader: 'css-loader',
                  options: {
                      modules: true
                  }
              },
              'sass-loader'
          ]
      }
  ],
},
output: {
  chunkFilename: 'theme-bundle.chunk.[name].js',
  filename: 'theme-bundle.[name].js',
  path: path.resolve(__dirname, 'assets/dist'),
},
plugins: [
  new CleanPlugin(['assets/dist'], {
      verbose: false,
      watch: false,
  }),
  new LodashPlugin, // Complements babel-plugin-lodash by shrinking its cherry-picked builds further.
  new webpack.ProvidePlugin({
      $: 'jquery',
      jQuery: 'jquery',
      'window.jQuery': 'jquery',
  }),
],
resolve: {
  alias: {
      'jquery-migrate': path.resolve(__dirname, 'node_modules/jquery-migrate/dist/jquery-migrate.min.js'),
      jstree: path.resolve(__dirname, 'node_modules/jstree/dist/jstree.min.js'),
      lazysizes: path.resolve(__dirname, 'node_modules/lazysizes/lazysizes.min.js'),
      pace: path.resolve(__dirname, 'node_modules/pace/pace.min.js'),
      'slick-carousel': path.resolve(__dirname, 'node_modules/slick-carousel/slick/slick.min.js'),
      'svg-injector': path.resolve(__dirname, 'node_modules/svg-injector/dist/svg-injector.min.js'),
      sweetalert2: path.resolve(__dirname, 'node_modules/sweetalert2/dist/sweetalert2.min.js'),
  },
  extensions: ['.js', '.jsx'],
},
};

Additional Resources