In the SuiteCommerce world, the commerce extension framework represents one of the biggest changes we've made in a while. Not only does it offer new levels of ease in terms of development, it also ushers in a new way to approach webstore customization.
This blog post is a write-up of a talk Joaquín Gatica and I gave at SuiteWorld 2018. In it, I want to talk about why it's so important, how it will change the way you work, and how you can — and should — work to migrate your existing functionality to use the extension framework.
The Story So Far
Up until now, you've been making customizations to your Kilimanjaro or older webstore using a lot of the methods I described in my list of essential customization tidbits. This meant template overrides, extending objects, wrapping methods, etc.
While we feel that this approach to customization still offers a number of benefits, there were a number of difficulties that they created. Broadly speaking, they can be split into two categories — administrator and developer — and are as follows:
|Look-and-feel actions are in the hands of developers||Look-and-feel is site-specific; version-specific|
|Functionality actions are in the hands of developers||Functionality is site-specific; version-specific|
|New release migration is a manual, developer-only process||Code is modularized, but not easily distributable|
These problems are obviously all related. For example, while a site administrator may be frustrated that they cannot implement a design change by themself, a developer might equally be annoyed that they have to spend their time changing a font color.
For smaller companies with limited resources, these issues are amplified. If you have no in-house developer, then approaching a third-party to make changes you feel you should be able to make yourself can be prohibitive. And what happens when a new release of SuiteCommerce is released, and you want it? A migration can be time-consuming and expensive.
The Future (Now)
We recognize the above problems, so this is where SuiteCommerce and the commerce extension framework come in.
SuiteCommerce (formerly SuiteCommerce Standard) runs from a managed bundle. This means two things: you cannot modify the source code yourself, but you are always running the latest code as we will update your site automatically.
But how you customize the site without modifying the source? The extension framework allows new functionality to be introduced without relying necessarily on the customization methods of yore. There are three key elements to it:
- Extensibility API — a stable, code-level API that offers access to key parts of a webstore via standardized objects and methods
- Refreshed developer experience — a familiar but improved developer environment that makes work easier, and code easier to manage
- Powerful UI — many actions that would previously have required a developer can now be performed by administrators through NetSuite and the site management tools
So, what do these three things mean? What can we expect to get out of them? Well, from a developer point of view, it means that you should now focus your efforts on creating themes and extensions — formalized packages of look-and-feel and functionality augmentations. These packages can be easily versioned, distributed, and activated across different sites and different versions of sites.
In terms of the redistribution of power between administrators and developers, it means that after developers have worked on and then shipped these packages, sites administrators are free to activate them on their site if they wish — they can then customize and configure them (if applicable), roll back to a previous version, and deactivate it entirely on their terms.
To summarize the changes that affect SuiteCommerce sites:
|Customizations||Mixed with core code||Layered on top of core code|
|Version upgrade||Manual migration||Automatic update (SC sites only)|
|Code reuse||Manual code copy and maintenance||Bundled as an extension|
|Adding new customization||Download existing (proprietary) codebase, code customization, and deploy||Pull down extension and theme, code customization, then version, deploy, and activate|
|Version dependency||Subject to change every release||Backwards-compatible|
And what this all means is we:
- Get closer to the software as a service (SaaS) model
- Minimize the effort of keeping a site up to date
- Ensure customizations keep working after a new release
- Enable the easy implementation of new features via extensions
A key thing to keep in mind is that regardless of whether you use SuiteCommerce or SuiteCommerce Advanced, the mechanisms and features of the extension framework are available to both products. The crucial difference is that with SCA, you are able to modify the source code — of course, we would still recommend that you use the framework (or at least the API) wherever possible though.
If you are going to 'edit the source' of SCA, as it were, we also still recommend that you follow the traditional way of not editing the source directly, and instead continue keeping your customizations in a separate parent folder, extending, wrapping and overriding as necessary.
Extensions and Themes Overview
OK, so now let's take a look at what extensions and themes actually are.
Extensions are micro-packages of modular SuiteCommerce code. They are bundles, in the NetSuite sense, and add new functionality to a site. They share the benefits that bundles typically have:
- Easy sharing between production and sandbox accounts
- Easy sharing to other accounts
- Can be made publicly available, shared, or private
- Can be set to 'managed', allowing updates to be pushed
- Activated on a site through the extensions management page
Themes are similar but different. They modify how the site looks, rather than behaves, and are:
- A sub-type of extension
- Control how a site looks, and what customizations a site administrator can make to their site's appearance via the theme customizer
- Typically branched from a 'base theme'
Because of this division of labor — where extensions handle functionality and themes handle appearance — we decided to make the difference formal.
Themes can also come in different flavors called skins. So, for example, while you may like a particular theme lays things out, you may wish to have a particular color scheme: with skins, you can have seasonal presets so that things are familiar but different depending on how you want to brand things. Keep things roughly the same but adjust colors and fonts for fall, winter, spring and summer, for example. Check out our documentation on skins for more information.
So, one of the key benefits of this paradigm shift is a high level of confidence in extension code continuing to work after an upgrade to the core code. It is the extensibility API that provides that assurance. But how?
In the past, if you wanted to a child view, then we'd tell you to find the view that you want, extend its prototype, wrap its
initialize, convert it to a composite view, then add a
childViews function, and then call your view there. Now, you can avoid most of that — you just find the component for the part of the site you want to change, and add a child view to that. You don't have to worry about what might happen if we change a name in a release — your code will still work!
The API will keep growing in each and every release. But know that this growth will be sideways, in the sense that we be adding in new methods, and fixes will happen behind the scenes. We want this to be the foundation for customization on SuiteCommerce sites, and we want that foundation to be stable.
Components are the classes from which the extensibility API draws its power. It's a relatively new concept, which adds a new layer of abstraction. We talked a bit about them around the release of Elbrus.
The idea is that instead of going through the source code and finding idiosyncratic solutions to typical problems, you rely on a number of a ready-made classes and methods that we provide. In other words, where you previously had to find a particular object to extend, or a function to wrap, now you can rely on simple, stable methods.
They're somewhere between modules and applications, and can be shared between applications. They are also usually contextual. For example, we have a component for the product details page, which is only available on the product detail page. The PDP component can be used, for example, to pull stock information or set the options (without the shopper having to click them); it can also be used to listen for specific events, for example after an option has been selected, or before a quantity change occurs.
At the time of writing we currently have components for:
- Product details page (PDP)
- Product list page (PLP)
- Cart — frontend
- Cart — backend
If you've coded a custom content type (CCT) before, then you'll already be familiar with the CMS component as we have to use its
registerCustomContent method in its entry point file. The principle for other components is the same.
Take a look at this very simple example: let's say we really want to automatically increase the quantity of the item on a PDP to 10 after the view's content has been rendered — how would we do that? If you had to write that code without using the extensibility API, would you even know how? Would you be sure it was the best way to do it? Would you be sure that it would continue to work on different sites, running different versions of code?
With the extensiblity API, it's this simple:
var PDP = Application.getComponent('PDP');
PDP.on('afterShowContent', function ()
We're using two separate two methods: we're setting up an event listener for when
showContent has finished, and then running a method for increase the quantity. This'll work on any site running at least this version of the API (at the time of writing), and will continue to work in the future.
Keep in mind that the general idea for components and the extensibility API is for us, NetSuite, to worry about the guts of making technical changes to your site, and then for us to provide you with an easy-to-use toolkit, so you can make the changes you want.
The behavior of the methods you see today probably won't change (or, at least, not drastically — we might add new parameters to existing methods, for example). Instead, the idea is grow their power sideways so that we will eventually encompass all conceivable areas of customization for all areas of the site. In the meantime, you can certainly sit down and get to work for areas of the site we already cover, with the methods and events we already provide.
Finally, feel free to make your own components. We have a base component that can be extended, and if you're creating your own self-contained bit of functionality, then there's no reason why you can't open it up for extensibility too! (Just be mindful of the components we might add in the future, and you namespace properly.)
For a full list of available components, see our frontend extensibility API documentation (you must be logged into NetSuite to access it).
Differences in Source Code and Development
One of the questions you probably have right now is, if there's a new way to add in customizations, does this mean that it will be a different experience to write them? The answer is: yes. I think there are five key differences:
- Directory structure and local development with new Gulp commands
- Manifests instead of package and distro files
- Versioning and activation
- New helpers to manage path to assets
- Reliance on components, rather than extending source code
When you develop on SuiteCommerce, you must use either the theme developer tools or the extension developer tools. Both are similar in the sense that they create a microcosmic workspace for you to work. Each one contains just what you need to work on that theme or extension, and nothing else.
If you're developing on SuiteCommerce Advanced, this means that you are potentially working with three different developer tools. Note that these are all kept separate, including the commands. For example, if you are in the context of the SuiteCommerce Advanced developer tools, Gulp commands for themes and extensions won't work!
Because of this small-slice approach, you don't have to deal with package and distro files. Instead, we have manifest files. These provide the indexes required for the compilers to understand where the files are meant to go. They also determine the metadata (name, description, version, etc) that is used in the extension manager.
One important thing to note with manifest files is that they almost entirely automatically generated by Gulp — the only time you need to manually intervene is when you want to add Sass entry points for any newly introduced Sass entry points. You can manually control the manifest but note that it will be overridden on deploy unless you supply a flag on deploy saying not to. For example, let's say you have included a new image asset in your theme, it will automatically be added to the manifest and included with the deploy; however, if after generation, you remember you don't want to include it, you can delete its entry and then specify that you don't want the manifest to be regenerated.
I'll mention the command for this in a moment, but let's look at the development flow in general and as a whole first.
Theme Development Flow
OK, so once you've got the source code — now what?
Before you can begin, you need to get the theme developer tools and install them.
The development process for a new theme should start with an existing theme. We have included a SuiteCommerce base theme, which is designed to work out of the box as well as being an excellent example of best practices. It's available as a bundle, which you install when you prepare an instance for SuiteCommerce, and can then be fetched for use within your development tools.
While working, you can use your local server to preview the changes prior to deploy, just like you would with normal extension or SCA development.
When you're done, you update your manifest and deploy your changes. It's important to remember that the deploying a theme or extension doesn't automatically apply it to the site, like in SCA development; instead, you will need to activate it on your site.
For theme development, note that we have new Gulp commands. They all begin with
gulp theme and have additional flags at the end, such as:
- gulp theme:fetch
- gulp theme:deploy
- gulp theme:local
In addition to these, some of the commands have additional flags that you can attach them. For example, the aforementioned command to prevent a regeneration of a theme's manifest file is
gulp theme:deploy --preserve-manifest — note that you can use with the
local keyword too.
See our section on the new Gulp Command Reference for Themes and Extensions documentation for a complete list.
Extension Development Flow
The development flow for extensions is largely similar, but note the differences.
You still need to fetch the current theme, so that you can use this when you start a local server on which to test your extension.
From there you can start work on a new extension, or fetch an existing one and continue working on that. If you do create a new one, you can use a new Gulp command to automate it. When you run
gulp extension:create you will be asked a series of questions about your proposed module — these range from basic metadata questions to questions about the types of files you're going to include. Based on that information, a number of dummy files (such as an entry point file, a view, etc) which are properly namespaced and correctly set up with dependencies. You don't have to run it if you don't want, but you may find it much easier to get started with.
From there you do your work, spin up a local server, and, when you're finished, deploy and activate. Simple.
Check out the documentation mentioned above for the Gulp commands associated with extension development — they're different but similar.
When you deploy your code to NetSuite, the system will check to see what version number is included in the manifest. If a version in NetSuite already exists with that version, it will overwrite any files in NetSuite that's already exist for that version. If it's a new version, NetSuite will go through the steps of creating new records for your theme or extension. This is important to keep in mind.
If you're working on a development version of your theme or extension, then you should feel free to overwrite the 'development version' number you've given it. However, once you're happy with a version and have 'released' it, then you should be wary of overwriting an existing version.
In other words, we strongly recommend that you employ versioning discipline to prevent old, stable versions of your work from being summarily replaced. For example, we recommend using a version control system (eg Git) for your work, in addition to the versioning offered by NetSuite.
Referencing Assets Across Versions
One issue that versioning introduces is to do with asset files, ie, fonts and images. After all, if they are updated in a version and you want to roll back to an older version, won't the old theme or extension use the new asset files?
The answer is no: when a new version is created, its files are stored separately from all other versions.
But, this begs the question: when working on template and Sass files, how you do reference the asset of the currently activated version? Special helpers for Sass and Handlebars.
Let's take a fantastical example: let's say you want to set an image as the background of your body tag. But, this image could change with each release — how can you mark up your Sass file so that the correct URL path is always generated?
/* Example Sass */
/* Example after evaluation */
/* Example with unevaluated placeholders */
background-image: url(<domain>/c.<company ID>/<SSP application>/extensions/<vendor>/<theme name>/<version>/img/<file name>)
In other words,
getThemeAssetsPath and its siblings do the hard work of resolving the correct URL paths. It still uses the traditional
_.getAbsoluteUrl, but it does some work before hand to ensure the correct extension (themes are extensions!) and version are included.
OK, let's talk about something I've mentioned a few times now: activation.
After your theme or extension has been deployed, it is not automatically applied to your site: it must be activated. This is true even if you're overwriting an existing version of code. This is one of the differences you will notice when working on extensions and themes; in this sense, you could consider these environments to be microcosmic.
When you've finished writing and testing your extension locally, your new code must be muxed with the SuiteCommerce base code — and any other theme or extension code — to produce to final compiled output. This process is called activation, and it takes place in the Extension Management page (Setup > SuiteCommerce Advanced > Extension Management).
After selecting what site you want to change, you're asked to select a theme and extensions to activate. Note that previously installed versions of an extension are saved and can be activated if you want to roll back.
Metadata about each extension is provided — name, description, version and provider — to aid you to make a decision. When you've made your choices, activation runs and recombination begins, which will output your site's final code.
Also note that while I have used the word 'site', you actually activate themes and extensions on a per domain basis. What this means is that if you operate multiple SSP applications for development, or otherwise have different domains for different versions of your site, activation on each occurs separately. (I will, however, continue to use the word 'site' in this post.)
So. With that in mind, how do all the bits connect together?
Unless you are developing on SuiteCommerce Advanced, the core SuiteCommerce source code is locked down. Any code-level customization you wish to make must plug into the extension manager, and, for extensions, this means talking to the extensibility API. If you are developing on SCA, you can (and should) use themes and extensions, but you do not have to.
But, yeah, for SuiteCommerce developers, the core SuiteCommerce code (and the extensibility API it provides) is locked and managed by us. If you want to communicate to it — ie add new functionality or change how it looks — then you add in a theme and extensions. You can activate as many extensions to your site as you wish, but only one theme.
Using best practices will ensure that your extensions take full advantage of the benefits of the framework. It means that as time goes on, your extensions will require less work to maintain and scale more easily. Remember, the key concepts here are to do with sustainability and upgradeability — using the extension framework to its fullest may mean having to re-learn the best ways of doing things.
First, avoid relying on activation order.
If you have multiple extensions and they depend on each other, they should not require one extension to be muxed into the code first.
Second, when you need to access the SuiteCommerce core, use the extensibility layer exclusively. When writing in the isolated extensions developer environment, it may be tempting to open up your other folder, which contains the SCA core code, and find particular functions to wrap or classes to extend — resist this temptation.
When an upgrade happens, you may find that a name has changed, or that module no longer exists, or is in the process of being deprecated. We will update the the extensibility API so that the methods you rely on can continue to be relied upon, but the guts of them may change.
The only real exceptions to this are to do with generic Backbone stuff. For example, if you need to create new routes, pages, views, collections, feel free to continue to work you normally would have. Just build your module out as you normally would.
Third, when interacting with a theme, it is best to depend on the templates, Sass variables, and classes that are bundled with SuiteCommerce. Again, think about what will happen when a site is upgraded: we (NetSuite) will test our work with the base theme to ensure it works, and we will certainly include updates to the base theme. You should, therefore, try to rely on the base theme as much as possible.
Finally, when working with other extensions, the answer depends on whether you own the extension or don't. So, if the extension is your own then we encourage you to consider making your own interface — perhaps your own component! — and then work with that. This allows you to apply the same principles we use for our code. Create a controlled, stable API for it that won't change, and then talk to it through that. That way, if you need to change the underlying code, you can minimize the impact it will have on the extensions that depend on it.
If you don't own it, try to attach as little as possible to it. Avoid unnecessary dependencies. You could create an adapter — but this is a pretty advanced software design topic that we don't cover, so you'll need to do some independent research on it yourself.
The above images illustrates these different approaches:
- Dealing with the SC core? Use the extensibility layer.
- Theme? Use core template and Sass files.
- Owned extension? Create an interface.
- Third-party extension? Create an adapter.
Scope of Extensions
When developing large customizations, the question arises as to whether you should put everything in one extension, or whether you should split them up into smaller ones. The answer is: it depends.
This is a question you'll have to answer for each project. We would counsel that you avoid the two extremes: avoid putting everything into one huge extension, and avoid putting everything into piecemeal ones. It's undesirable to maintain one mammoth extension; it's undesirable to maintain twenty small ones.
When deciding, consider three core principles:
- Reusability — could this parcel of functionality be used by something else? Perhaps it should be split off from the rest.
- Independence — if I extract this functionality, will it work standalone from the rest?
- Maintainability — what makes this code easier to maintain? Keeping it with its cohorts or separating it out?
Extension Code Structure
In general, follow similar coding standards that you would for SCA. Realistically, this means don't feel confined to a one-module/one-extension model: feel free to split up your functionality across multiple modules if it helps. Similarly, doing so consider the advice we just gave about the scope of extensions — is the new module you're creating reusable, independent and easy to maintain?
Templates and Sass
Templates and Sass that are specific to an extension should always go with that extension: do not put them into your theme.
Remember that a site's theme will contain a number of Sass variables (eg for colors) and you are free to use them in your extension's Sass files. This is why you must fetch the site's theme when developing, and part of the reason why we recombine files during the activation process: everything is joined up, so make use of all the bits!
However, the question arises about what to do when templates are shared between extensions. There are two options: extract part of the template into a child view to abstract that part, or voluntarily keep it in the theme. The latter may be preferable as its better for multiple extensions to depend on a theme rather than than a theme on an extension, or extensions between themselves. Remember, your theme can always be forked — taken off the vendor's upgrade path — and then tailored to fit your site's needs. Be wary, however, as this can cause maintenance headaches later on.
It's important to think long-term, for example:
- If you feel a specific area of a page might have a child view in the future, you can always add in a placeholder now and use it later on, as this will avoid you having to edit the theme later
- If you're developing something for the market, it's probably wise to try to keep your extension as contained as possible
Keep in mind things like what happens when a site is upgraded to a newer version, there's an upgrade to theme, or the extension is ported to another site with a whole different setup.
Handling New Releases
One thing to make clear: upgrades don't take effect until you activate them. However, be aware that if you're developing on a SuiteCommerce site then know that any activation will trigger a recombination with the latest core SuiteCommerce code.
Generally speaking, take advantage of test domains. You have access to a release preview account, plus you're free to setup your own test domains. These things should be relatively easy to test without it affecting your live site.
When a core NetSuite release is made available, it should have a minimal impact on your site, so testing in release preview should be fine.
For SuiteCommerce release, it's probably a good idea to test things on a test domain on the same account.
Finally, if you're using a theme or extension then, again, try it out on a test domain. Unmanaged bundles can be manually updated at a time to suit you, so take advantage of that.
We talked about this a bit already, so let's reiterate.
We always recommend versioning your code in a version control system outside of NetSuite, such as Git. A basic implementation is easy to get started with.
For more advanced users, consider what strategy you want for internal vs deployed code; ie, the code you're currently working on vs what is actually published. You could have a stable (master) branch in your VCS and, after each merge, publish your extension as a new version. Thus, this creates a map between merges and NetSuite versioning.
There's also a wider strategy to consider: what are the purposes of the extensions of your extensions? Do you want to have one big repository for all of your site-specific extensions and themes? Maybe you want to have individual repositories for each extension and theme? Maybe you even want some sort of hybrid, where reusable extensions are in one and site-specific ones are all grouped up together. We can't answer these questions for you — you will need to consider the scope of your work, and what makes most sense to you.
Migration From SCA
Perhaps the biggest question a lot of you will face: should I take my current site customizations and build them out into themes and extensions? In short, yes.
If you compare the source code of Kilimanjaro to Aconcagua, you will see that we've moved all of the templates and Sass into the base theme. You can do the same: follow the steps for creating a new theme, and then copy and paste each folder into your new theme workspace. Keep in mind, however, that there were likely some changes, additions and deletions in the Aconcagua release. You may want to do a full diff of the template and Sass files to see if you missed anything.
If you're interested in taking advantage of the new theme customizer in the site management tools, then you'll need to do some work to make it ready. We have developer docs on how to do this and it may well feature as a topic in future blog posts. It's an important feature of our push for administrator independence, so we encourage taking it up.
As for custom functionality, you may find that refactoring to be particularly hard work. In any case, be systematic and try to identify areas that could make use of the extensibility API. If you have customizations that don't yet cover areas supported by a component, consider keeping them separate from the rest of your extensions. For example, the account application does not currently have a component, but it (probably) will later on. If you have customizations here, try to keep them isolated for now.
Remember that anything that is already completely separate — for example if you have custom pages or features — can (and probably should) be their own extension. It can still have its own router, model, views, etc. Just keep in mind that you may be able to take advantage of some components along the way too.
Phew. That was a lot to take in and we hope you find it useful. It's still early days for the commerce extension framework and so some of this advice might change — they'll certainly be new additions when we and you get stuck into it.
If you have any questions, or any advice of your own to add, leave them below in the comments. You can also download the presentation.