SGJC Overview

Features specific to SGJC can be unfamiliar if storefront is based on an earlier version of SiteGenesis. Most of the features described here focus on reusability of code and can be useful when migrating your storefront code. Additional information is available in SiteGenesis Model-View-Controller Development Model and SiteGenesis Standards Compliance. If you are interested in the differences between the controller and pipeline version of SiteGenesis, see Comparing Pipelines and Controllers.

SiteGenesis uses the following features:

CommonJS Modules and Require

CommonJS modules let you create scripts with reusable functionality. A module is a .ds or .js file. You can place a module either in a cartridge’s script folder or in a modules folder that is at the same level as other cartridges. You can access modules that are in your cartridge, in other cartridges, and in the modules folder.

The modules folder is a peer of cartridge folders. Salesforce recommends using it for globally shared modules, such as third-party modules.

+-- modules
		+-- mymodule1.js
   	+-- My_Cartridge_1
   		+-- cartridge
       		+-- scripts
				+-- mymodule2.js
   	+-- My_Cartridge_2
   		+-- cartridge
       		+-- scripts
				+-- mymodule3.js

Accessing Modules

Salesforce B2C Commerce supports CommonJS paths to access modules and relative paths.

Use the following syntax:

~ - the current cartridge name. Example: require ('~/cartridge/scripts/guard')

. - same folder (as with CommonJS). Example: require('./shipping');

.. - parent folder (as with CommonJS). Example: require('../../util')

ImportPackage vs. Require

In previous versions of SiteGenesis, the ImportPackage statement was always used to import B2C Commerce packages into your scripts.

You can also use require to import B2C Commerce script packages. For example: require(‘dw/system/Transaction’)

Salesforce recommends using the require method to import B2C Commerce script packages, or other JavaScript or B2C Commerce script modules instead of ImportPackage.

Important:

Using the require() function to load a module has an impact on performance. To handle a request, a controller is loaded and then executed on a global level, just as exported methods are executed. When the controller module is initialized, the actual controller function is invoked.

If the dependencies to other modules are initialized on a global level, many modules can be loaded unnecessarily. If possible, place require() statements in the most limited scope that is appropriate (for example, as local variables within a function body). If your require() statements are placed at a global level, they are loaded for every request. For example, require() statements at the top of a controller file are loaded with each request. Globally required modules are loaded even if they are not needed in the current execution context.

If all modules execute their require() statements globally, all modules are loaded for every request. This overhead can significantly degrade performance, depending on the number of modules. We suggest, instead, that you move the require() calls for non-API modules into the function bodies so that they are resolved only when necessary. A require() isn't an import; it's a real function call. An import in Java, in contrast, is only a compiler directive and has no effect at run time.

Hooks

Hooks configure a piece of functionality to be called at a specific point in your application flow or at a specific event.

There are three types of hooks you can use with SiteGenesis:

Hook Definition

The package.json file points to the hook file for a cartridge, using the hooks keyword.

Example: package.json

{
   "hooks": "./cartridge/scripts/hooks.json"
}

The hook file defines a uniquely named extension point and a script to run. Hook scripts must be implemented as CommonJS modules. Therefore, the script identifier is a module identifier and can be a relative path or any other valid module identifier.

Example: hook.json

{
	"hooks": [
       	{
			"name": "dw.ocapi.shop.basket.calculate",
			"script": "./cart/calculate.js"
       	},
        {
			"name": "dw.system.request.onSession",
            "script": "./request/OnSession"
       	},
        {
			"name": "app.payment.processor.default",
			"script": "./payment/processor/default"
       	}
	]
}

This example shows an OCAPI hook, a controller hook, and a custom hook. The OCAPI hook runs a script to calculate the cart. The controller hook calls the OnSession.js script in the scripts/request directory. You can call the custom hook by using the HookMgr class’s callHook method.

Example: calling a custom hook

return dw.system.HookMgr.callHook('app.payment.processor.default', 'Handle', {
            Basket : cart
        });

Running Multiple Hooks for an Extension Point

It's possible to register multiple scripts to call for an extension point. However, you can't control the order in which the scripts are called. Also, if you call multiple scripts, only the last hook called returns a value.

At run time, B2C Commerce runs all hooks registered for an extension point in all cartridges in your cartridge path. It runs them in the order of the cartridges on the path.

Note: Hooks are called in the order of the cartridges on the path. Therefore, if you change the order of the cartridges, you also change the order in which hooks are called.

Error Logging

Controller and script logging is available in the:

Example: Custom error log

Error while executing script 'test_cartridge_treatascustom/cartridge/controllers/TestController.js': Wrapped com.demandware.beehive.core.internal.template.ServletAbortException: Requested template 'controller/testController' not found! (test_cartridge_treatascustom/cartridge/controllers/TestController.js#21)
    at test_cartridge_treatascustom/cartridge/controllers/TestController.js:21 (isml)
    at test_cartridge_treatascustom/cartridge/controllers/TestController.js:52 (anonymous)

Back to top.