Vercel's frontend cloud gives developers the workflows and infrastructure to build faster with SAP Composable Storefront. Within minutes, you can host, deploy at the edge, and iterate on all of your Composable Storefronts in an environment adapted to maximize the developer experience and provide blazing fast speeds for your sites.
Before getting started, ensure that your development environment meets the requirements described in Front End Development Requirements, and that you have access to the Repository Based Shipment Channel (RBSC), as described in Installing Composable Storefront Libraries from the Repository Based Shipment Channel.
The following steps leverage ready-made libraries and packages for running Composable Storefront.
1. Verify that you have the front end development requirements as well as access to the RBSC.
2. Create a new Angular app named sap-store
without routing and using SCSS styling:
ng new sap-store --style=scss --routing=false
3. For local development, ensure that you have an .npmrc
configuration file in the project directory that references the SAP NPM registry. Set _auth
to a local NPM_TOKEN
environment variable containing the access token for downloading Composable Storefront libraries. The following is an example of the .npmrc
file:
@spartacus:registry=https://73554900100900004337.npmsrv.base.repositories.cloud.sap///73554900100900004337.npmsrv.base.repositories.cloud.sap/:_auth=${NPM_TOKEN}always-auth=true
4. Install the latest official release of Composable Storefront using schematics. To see the schematics for the latest version of Composable Storefront, see Setting Up Your Project Using Schematics. The following is an example:
ng add @spartacus/schematics@6.0.0
5. Set baseUrl
in src/app/spartacus/spartacus-configuration.module.ts
to point to the SAP Commerce Cloud Server. By default, it is set to localhost:9002
.
6. Update the context configuration in spartacus-configuration.module.ts
with the following settings:
context: { urlParameters: ['baseSite', 'language', 'currency'], baseSite: ['electronics-spa', 'apparel-uk-spa'], currency: ['USD', 'GBP'],}
7. Build and run the project to verify the solution is working locally by running the following commands:
npm run buildnpm run start
The following configuration steps describe how to deploy Composable Storefront to Vercel using client-side rendering. If you wish to deploy Composable Storefront using other rendering methods, such as server-side rendering, static site generation, and incremental static regeneration, see the Deploying Composable Storefront to Vercel with Additional Rendering Methods section.
1. Ensure that your local project is pushed to a repository on GitHub, Bitbucket, or GitLab.
2. Grant Vercel access to the repository to enable deployment.
3. Create a new Vercel project and choose the option to "Import from an Existing Repository".
4. During the project configuration in Vercel, make sure to include the NPM_TOKEN
environment variable with valid NPM credentials. This allows Vercel to install the necessary SAP NPM packages.
5. Leave the remaining build settings at their default values.
6. Click on the "Deploy" button to initiate the deployment process.
In addition to CSR, Vercel supports various other rendering methods, such as server-side rendering (SSR), static site generation (SSG), and incremental static regeneration (ISR), which can be utilized with a hosted Composable Storefront application. Follow these configuration steps to deploy Composable Storefront on Vercel using these rendering methods.
1. Install the Composable Storefront packages using the ssr
flag. The following is an example: ng add @spartacus/schematics@6.0.0 --ssr
2. Ensure that the configuration settings in spartacus-configuration.module.ts
are not overridden.
3. Open server.ts
and update the ngExpressEngine
rendering strategy to be ALWAYS_SSR
. Modify the code as shown below:
const ngExpressEngine = NgExpressEngineDecorator.get(engine, { renderingStrategyResolver: (req) => { return RenderingStrategy.ALWAYS_SSR; },});
4. Run npm run build:ssr
followed by npm run start:ssr
to verify locally that the Angular application is running via SSR.
The following steps leverage Vercel’s Build Output API to add SSG, SSR, and ISR functionality to Composable Storefront and make it capable of running on Vercel. The Build Output API is a file-system-based specification for a directory structure that can produce a Vercel deployment.
Engineering teams can output this directory structure from the application’s build command, so that the Angular application may use all of the Vercel platform features. The following steps walk through how to implement this.
1. Create a JavaScript file named vercel-output.js
at the root of the Composable Storefront application. This file is a script for outputting the JavaScript bundles to a location where Vercel can create serverless functions for running the application.
2. Paste in the following JavaScript code to vercel-output.js
. This is the script that will run and perform several actions necessary for running on Vercel:
- It creates a new
.vercel/output
directory containing all necessary bundled JavaScript and assets. - From a pre-set example of the product detail pages (included in the below
vercel-output.js
file), it creates the necessary serverless functions (.func
files) for rendering a given page via SSG, SSR, and ISR. - It creates a build
config.json
file that configures the behavior of a deployment on Vercel.
This script uses example SSG and ISR routes at the top of the file that need to be specified in order for Vercel to use the correct rendering method for the associated URL. These routes should be replaced with the desired routes in the Composable Storefront application based on its rendering requirements.
const { lstatSync, readdirSync, copyFileSync, writeFileSync, mkdirSync } = require("fs");const { dirname } = require("path");
const OUT_DIR = ".vercel/output";const PROJECT_DIST = "dist/sap-store";
// This is the array of pages that are prerendered, specified in prerender-routes.txt// Updates to these pages require a Vercel deploymentconst SSG_PAGES = [ { route: "/electronics-spa/en/USD/product/1934398/HDR-XR105E$", staticHTML: "/product/1934398/HDR-XR105E/index.html", }, { route: "/electronics-spa/en/USD/product/1986316/LEGRIA%20HF%20S100", staticHTML: "/product/1986316/LEGRIA%20HF%20S100/index.html", }, { route: "/electronics-spa/en/USD/product/1432722/Gigashot%20K80H", staticHTML: "/product/1432722/Gigashot%20K80H/index.html", }, { route: "/electronics-spa/en/USD/product/1776948/Camileo%20S10%20EU", staticHTML: "/product/1776948/Camileo%20S10%20EU/index.html", }, { route: "/electronics-spa/en/USD/product/1934406/HDR-CX105E%20%20Red", staticHTML: "/product/1934406/HDR-CX105E%20%20Red/index.html", }, { route: "/electronics-spa/en/USD/product/1776947/Camileo%20H20%20EU", staticHTML: "/product/1776947/Camileo%20H20%20EU/index.html", }]
// This is the array of pages that leverage Incremental Static Regeneration (ISR)// The fallbackHTML is the path to the static HTML file that will be used for the initial render// Subsequent renders will be generated by the ISR function and updated on a rolling interval (60 seconds)const ISR_PAGES = [ { id: "home", route: "/electronics-spa/en/USD/", fallbackHTML: "../static/index.html", }, { id: "nv10", route: "/electronics-spa/en/USD/product/553637/NV10", fallbackHTML: "../static/product/553637/NV10/index.html", }, { id: "dsc-n1", route: "/electronics-spa/en/USD/product/358639/DSC-N1", fallbackHTML: "../static/product/358639/DSC-N1/index.html", }]
// Utility function for writing content to a filefunction write(file, data) { try { mkdirSync(dirname(file), { recursive: true }); } catch {}
writeFileSync(file, data);}
// Utility function for copying files from one directory to anotherfunction copyFiles(source, target) { const files = readdirSync(source); for (const file of files) { const curSource = `${source}/${file}`; if (lstatSync(curSource).isDirectory()) { mkdirSync(`${target}/${file}`, { recursive: true }); copyFiles(curSource, `${target}/${file}`); } else { copyFileSync(curSource, `${target}/${file}`); } }}
// Utility function that will create the SSR function and copy all files to the Vercel output folderfunction createSSRFunction() { const fn_dir = `${OUT_DIR}/functions/ssr.func`; write( `${fn_dir}/.vc-config.json`, JSON.stringify({ runtime: "nodejs18.x", handler: "index.js", launcherType: "Nodejs", }) );
copyFiles(`${PROJECT_DIST}/server`, fn_dir);
write(`${fn_dir}/index.js`, `module.exports = require("./main.js").app();`);
// static files also need to be copied to the function dir because the server runtime uses them mkdirSync(`${fn_dir}/${PROJECT_DIST}/browser`, { recursive: true }); copyFiles(`${PROJECT_DIST}/browser`, `${fn_dir}/${PROJECT_DIST}/browser`);}
// Utility function that will create the ISR function and copy all files to the Vercel output folderfunction createISRFunction(name, group, fallback) { const funcDir = `${OUT_DIR}/functions/${name}.func`; write( `${funcDir}/.vc-config.json`, JSON.stringify({ runtime: "nodejs18.x", handler: "index.js", launcherType: "Nodejs", }) );
copyFiles(`${PROJECT_DIST}/server`, funcDir);
write(`${funcDir}/index.js`, `module.exports = require("./main.js").app();`);
// static files also need to be copied to the function dir because the server runtime uses them mkdirSync(`${funcDir}/${PROJECT_DIST}/browser`, { recursive: true }); copyFiles(`${PROJECT_DIST}/browser`, `${funcDir}/${PROJECT_DIST}/browser`);
// Create prerender config json file write( `${OUT_DIR}/functions/${name}.prerender-config.json`, JSON.stringify({ // For this example, we are hardcoding the revalidation interval to 60 seconds expiration: 60, group, allowQuery: ["__pathname"], passQuery: true, fallback, }) );}
// Create the static Vercel foldermkdirSync(`${OUT_DIR}/static`, { recursive: true });
// Copy the static files to the Vercel foldercopyFiles(`${PROJECT_DIST}/browser`, `${OUT_DIR}/static`);
// Create the SSR serverless function responsible for all pages that are not SSG or ISRcreateSSRFunction();
// Create an ISR serverless function for each specified ISR page with specified fallback HTMLISR_PAGES.forEach((page, i) => { createISRFunction(`isr-func-${page.id}`, ++i, page.fallbackHTML);});
// Write the Vercel Build Output config file.write( `${OUT_DIR}/config.json`, JSON.stringify({ version: 1, routes: [ ...SSG_PAGES.map(page => { return { src: `${page.route}$`, dest: page.staticHTML, } }), ...ISR_PAGES.map(page => { return { src: `${page.route}$`, dest: `/isr-func-${page.id}?__pathname=${page.route}` } }), // Specify that SSR should be used for all other pages { src: "/.*", dest: "/ssr" }, ], }));
3. Update the value of the variable PROJECT_DIST
in the vercel-output.js
script with the existing dist
output directory path of your Composable Storefront application.
4. Update server.ts
to handle the __pathname
query parameter used by the ISR serverless functions, as follows:
server.get('*', (req, res) => { if (req.url) { const [path, search] = req.url.split('?');
const params = new URLSearchParams(search); const pathname = params.get('__pathname');
if (pathname) { params.delete('__pathname'); req.url = pathname; } } res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }], });});
5. Create a prerender-routes.txt
file at the root of the application (same level as package.json
) and insert a route per line for every SSG and ISR route in the application. This file will be specified in angular.json
in the following step to prerender the necessary pages. In this guide, the following is specified in prerender-routes.txt
.
/product/1986316/LEGRIA%20HF%20S100/product/1432722/Gigashot%20K80H/product/1776948/Camileo%20S10%20EU/product/1934398/HDR-XR105E/product/1934406/HDR-CX105E%20%20Red/product/1776947/Camileo%20H20%20EU/product/358639/DSC-N1/product/553637/NV10/
6. Update the prerender
section in angular.json
and set the routesFile
value to prerender-routes.txt
, as follows:
"options": { "routesFile": "prerender-routes.txt" }
7. Update the build and start commands in Vercel to run an SSR build, prerender the configured routes, then run the Vercel output script, as follows:
build: "npm run build:ssr && npm run prerender && node ./vercel-output.js", start: "ng serve:ssr"
8. Commit your changes and deploy the application to Vercel.
Following the build and deployment, Vercel will use SSG for the URLs specified in the SSG_PAGES
array and ISR with a fallback for the URLs specified in the ISR_PAGES
array within the Vercel output script. Initial requests to the ISR pages will display the prerendered version of the HTML and subsequent requests will see updates on a 60 second revalidation interval. SSR is leveraged for all other routes on the application.
In this guide, you have navigated through the process of configuring SAP Composable Storefront to run on Vercel. The application now uses Angular Universal for providing SSR and with the Vercel Build Output API it is capable of rendering pages with SSR, SSG, and ISR. These rendering methods can be leveraged for providing performance and SEO benefits without compromising on the end user experience.