Quite often, the first place you will notice that something is wrong is when you visit a page on your site. A good place to start, therefore, are the developer tools that are built into your web browser.

This article contains two kinds of content:

  1. General pointers to things ‘under the hood’ that can be very useful when trying to diagnose a problem
  2. Advice for specific problems a developer may encounter

Note that for the purposes of this article, I’m going to be using Chrome’s developer tools (also known as Chrome DevTools), but other browsers have similar functions. It is recommended that you familiarize yourself with those tools before using them; for example, you may wish to refer to the documentation.

Note that a number of code snippets in this article will teach you how to directly access objects and global variables. These can be used for debugging purposes, but should not be used in production code.

Using the JavaScript Console to Analyze the Global SC Variable

To open the console, open the tools (press Command+Option+I (Mac) or Control+Shift+I (Windows, Linux)) and then click on the Console tab.

We don't typically use global variables, but we have one that runs on every site: SC. If you type SC into the console, it'll return a number of objects.

You can click through each one and see data and settings about the current state of the site as your current user. Some of these things will be context specific, which means that they will be affected by your current user (or if you're not logged in at all) and what page you're currently on, and some will be global.

Use the Environment Object to Check Site Settings

A good place to start is with some site settings. We make them available as properties to the ENVIRONMENT object attached to SC. To access it, you can type in SC.ENVIRONMENT.

From there, you can do something like this to access site settings:

SC.ENVIRONMENT.siteSettings

Remember, this is case-sensitive.

A screenshot of the JavaScript console while in a browser's developer tools. After entering the code for the 'Environment' object, we can see a whole list of various settings we can look up.

One interesting thing about DevTools is that it will 'eagerly' evaluate what you type in, to show you the results of functions, the available properties of an object, and the values of those properties. You can see in the above gif how you might check the values of certain site settings.

Get the Site Configuration

Another common issue is that you make a change to a site's configuration record, but it doesn't seem to be affecting the frontend of the website. Is the value making it to the frontend? Is it being cached in your browser? You can find out by querying the configuration object.

SC.CONFIGURATION

From there, you can access a number of properties, just like you could with the ENVIRONMENT object:

A screenshot of the JavaScript console while in a browser's developer tools. After entering the code for the 'Configuration' object, we can see a variety of various settings we can look up.

Now you can look for the configuration value and see if it's coming through to the frontend.

Access the Main Parent View

The main parent view (or the ‘layout view’) is the main container view for the page you are currently looking at. For example, if you are the homepage you will be accessing an instance of Home.View; if you are on a search results page, you will be accessing an instance of Facets.Browse.View.

// Newer sites
SC.Application('Shopping').getLayout().getCurrentView()

// Older sites
SC._applications.Shopping._layoutInstance.currentView

In this example (and future examples) you can substitute Shopping for the name of the application (eg MyAccount or Checkout).

Accessing an instance of a view is useful because it shows how the page is being rendered in actuality, rather than the specification based on the JavaScript/TypeScript file.

Bonus tip: you can check if a view (or any object) is an instanced version of a module by requiring the module and comparing them.

For example:

SC.Application('Shopping').getLayout().getCurrentView() instanceof require('Facets.Browse.View')

This will return true if you are currently on a product list page.

Get the Current Model

Common customizations to web stores involve adding extra data to the model before it's sent to the view and then to the template. If your data, such as a custom field, doesn't show up on the frontend, it can be tricky to figure out what exactly is the problem.

One thing you can do is check the model and see if the data has been sent from NetSuite to your site's frontend. Type in:

// Newer sites
SC.Application('Shopping').getLayout().getCurrentView().model

// Older sites
SC._applications.Shopping._layoutInstance.currentView.model.attributes

Depending on where you are, you'll see different things. If you're on a product detail page, you can click on item > attributes to see if the field is there. If you're on a product list or search results page, you can click on items > models and then find the specific item in the array.

Bonus tip: if it's not there, make sure you've updated the relevant field set and refreshed your search index!

List All Loaded Files

Now we're getting a bit more advanced.

When you use define() in your code, you're creating a new class in your application. If it's included in your compiled JavaScript, then it will have a 'definition' and will be made available to be called by the application.

You might sometimes get an error where it says something like:

Uncaught Error: No MyCustomization.View

Where MyCustomization.View is the name of a class you've tried to call in your code. In simple terms, it returns this if it hasn't been loaded by RequireJS, the library we use for managing dependencies. You can get a full list of every file loaded into the application by typing in:

requirejs._defined

This will return everything that is currently loaded into the application. Of course, you might get other areas where you suspect that the problem is because the file has not been loaded into the application.

Log a View's Context Object to the Console

The getContext() method returns an object of data that the template is going to render. If text isn't showing, or conditionals aren't returning the correct values, then it's possible that they're not receiving the correct values.

We've touched on accessing the application, layout and view objects in passing, and another part of that is accessing their context objects:

// Get the context object for the current parent view
SC._applications.Shopping._layoutInstance.currentView.getContext()

// Get the context object of a specific child view in modern versions of SC/SCA
SC._applications.Shopping._layoutInstance.currentView.childViewInstances['Product.Price']['Product.Price'].childViewInstance.getContext()

// Get the context object of a specific child view in older versions of SCA
SC._applications.Shopping._layoutInstance.currentView.childViewInstances['Item.Price'].getContext()

The childViewInstances will return the actual child views that have been constructed. You can use childViews instead to return the views that are listed in the parent file itself (ie pre-construction).

Access Extensibility API Components

These tips only apply if you're using SuiteCommerce, or SCA Aconcagua or newer (2018.1+).

Make a Simple Change with a Component

When you're coding, you typically access the components from an argument available from the mountToApp function in an entry point file. However, you can also access them through the JavaScript console by accessing the same object we used for the model. For example, if I wanted to test out some code using the PDP component, I can use:

var PDP = SC.Application('Shopping').getComponent('PDP')

I'm using SC.Application('Shopping') instead of SC._applications.Shopping to make a point (the old way will still work). In newer versions of SuiteCommerce Advanced, we obviously discourage the access of private methods/functions/objects and instead the encourage the use of our API. While we're only using this method for testing, I just wanted to point this out so that you're aware. There are a number of other examples where this is the case; for example, we might use getLayout() instead of _layoutInstance. Remember: we recommend the use of our best practices because they're stable; the use of private methods is not recommended.

Anyway, back on track and looking at the code example, this will make the PDP component available as PDP in my console (assuming, of course, that you are on a product detail page — some components such as the PDP, PLP and checkout only work when you're in those contexts). From there, you can use all of its available methods to quickly test out changes. For example, if I wanted to try out changing the selected color option of a matrix item on a PDP, I could use:

var PDP = SC.Application('Shopping').getComponent('PDP')
PDP.setOption('custcol_gen_color', '1')

The values you'll enter on your site will depend on your site's custom fields, setup and the item you're viewing.

An animated gif of a web browser's JavaScript console. It shows a developer accessing the PDP component, displaying its many properties and methods, before demonstrating them by changing the item's currently selected color.

Test a New Child View

Let's say you've created a new view and template and they don't seem to be working correctly. You've checked and they're being loaded into the application (see above), so you just want to add them to your current page and see how they will look. How do you do this?

In this example, I've already created the view and template and I want to load it into my login page. You can also do this through the console, including re-rendering the main view so that it shows in the page.

In my example, I'm going to be adding this to the login page.

An animated gif of a web browser's JavaScript console. It shows a developer access the layout component, require a pre-built view, and then using addChildView to add it to the current view. Once that's done, they re-render the parent view.

How do we do this?

Here's the view:

define('Vendor.Extension.Module.SimpleView'
, [
    'vendor_extension_module_simple.tpl'
  ]
, function
  (
    vendor_extension_module_simple_tpl
  )
{
  'use strict';


  return Backbone.View.extend({
    template: vendor_extension_module_simple_tpl

  , getContext: function getContext ()
    {
      return {
        message: 'I\'m a child view added via the extensibility API! Go me!'
      }
    }
  })
})

And here's the template:

<h2>Test!</h2>
<p>{{message}}</p>

After adding these to an extension, I can use the these console commands:

var Layout = SC.Application('Checkout').getComponent('Layout') // Note we're using the checkout application because we're on the login page
var SimpleView = require('Vendor.Extension.Module.SimpleView'); // The view you want to render (I created mine earlier)
Layout.addChildView('Login', function () { // The place you want the view to render
  return new SimpleView();
});
Layout.application.getLayout().getCurrentView().render(); // Re-render the main view

After calling the layout component (on the checkout application because we're on the login page), we create a version of the view we want to render by using require() and passing it its class name. This is essentially what happens when you pass class names in a define() statement, listing your dependencies — ie, "load this file".

Then we use addChildView() to add the view to the place where we want to render it, and then re-render the main view. The getLayout() method gets the current layout, which is the skeleton of the application, and then we call getCurrentView() to call the main view currently being used. Then we just re-render it.

Bonus tip: while I don't think it's going to be useful, you can create a confirmation dialog or modal in the console too!

An animated gif of a web browser's JavaScript console. The developer pastes in code that causes a confirmation dialog to appear.

How do we do this?

var Layout = SC.Application('Shopping').getComponent('Layout')
, ConfirmationView = require('GlobalViews.Confirmation.View')
, confirmation = new ConfirmationView(
  {
    title: 'Test Confirmation Popup'
  , body: 'Did you create this in your developer console?'
  , autohide: true
  });
Layout.showContent(confirmation, {showInModal: true});

Like before, we are creating variables for the layout component and our confirmation view. Then we create a final one, creating a new instance of the confirmation view with our test properties.

To create it, we use the familiar showContent() method, which is used to render views. You'll note that after passing it our newly constructed view, we also pass an object of options; specifically, we passed it showInModal: true, which tells it to create it in the modal.

See Show Content in a Modal for more information on confirmation dialogs.

Use the Network Tab to Analyze Requests

We've spent a lot of time looking at the JavaScript console, and there's still plenty of interesting things to play around with in there, but let's move onto another useful aspect of the developer tools: the network tab.

As long as you have the developer tools open, all HTTP requests will be logged in it (requests made before you opened the tools are not logged).

A screenshot of the Network tab in a web browser's developer tools. It shows a number of network requests that were made by the web store.

All kinds of requests are logged by the tools, and you can filter them by clicking on the specific buttons (eg, XHR, JS, CSS, images, etc).

If you filter by XHR (XMLHttpRequests — eg, AJAX requests to the items API) and then click one of the requests you will be shown the specific details of the request being made. This is particularly valuable

To debug issues in the applications, we will typically use the Headers and Preview sub-tabs. The HTTP headers are the bits of information about the request being made as well as any additional information that might be required. By inspecting the headers, you can see the basics of your requests, such as the query string parameters, which are the bits of data at the end of a URL. For example, the request URL for the items API is api/items/ and everything else included afterwards are the specifics of the request, such as the item URL we want (or keyword for searching), as well as information such as currency and country.

To review the response from the server, we can use the Response sub-tab, but we prefer the Preview tab because it formats JSON responses so they can be clicked through and explored more easily.

A screenshot of the Preview tab in a web browser's developer tools. This is available when you inspect a particular network request.

This can be quite useful for troubleshooting search results. If you ever wonder what data is being returned from the API after performing a keyword search, or when a shopper hits a commerce category, you can right-click on the XHR and then click on Open in a new tab to get a full-screen look at the API results.

An animated gif of a developer inspected a response from an items search API request.

The above gif shows a developer clicking through a sample XHR. Note that when the API response was opened in a new tab, there was a brief moment when it was unformatted and then formatted — this is a plugin that formats JSON responses and there are many available in the Chrome web store.

Any service that is called by an application can be inspected to see the request/response, not just the items API. Important services to check include LiveOrder.Service.ss (the XHR for the cart) and Categories.Service.ss (the XHR for commerce categories). As with the checking with did earlier with JavaScript console, you can check the API/service responses to see if the correct data is being sent and if the correct data is being returned.

Use the Network Tab to Analyze Performance

There are a lot of resources on this site that cover how to analyze performance problems, so we won't go into too much detail about this.

A screenshot of dialog that appears when a developer hovers their cursor over the waterfall of a specific request in the Network tab of a web browser's developer tools.

However, something worth reiterating is that performance is important. Search engines prefer faster sites, and so do shoppers. Very slow sites can be problematic and you can get simple stats from the developer tools.

For more information, see our performance guidelines.

Check Site Metadata

Every time a page is rendered on a SuiteCommerce web store, some metadata will be printed at the bottom of the body tag. Generally speaking, it is not particularly valuable but can be useful in getting information on how quickly the page took to generate and getting exact version information.

Here is an example:

<!-- SuiteCommerce Advanced [ prodbundle_id "333161" ] [ baselabel "SCA_2020.2.0" ] [ version "2020.2.0" ] [ datelabel "2019.00.00" ] [ buildno "0" ] -->
<!-- 775 s: 45% #173 cache: 1% #26 -->
<!-- Host [ sh24.prod.sv ] App Version [ 2020.2.0.78 ] -->
<!-- COMPID [ TSTDRV123456 ] URL [ /s.nl ] Time [ Thu Nov 19 07:09:14 PST 2020 ] -->
<!-- Not logging slowest SQL -->

The first line will list the specific web store application that is being used. This is followed by the specific bundle ID and then some version numbers. This can be useful if you don’t know which product is being served, or are unsure about specific version numbers.

The second line is performance information. The first number is the time it took in milliseconds to generate the page and is the single biggest contributor to the ‘time to first byte’ (TTFB) metric. The lower these numbers are, the better the page is performing:

  • s: nn% #mmm describes how many database resources were used
    • nn is the percentage of the page time spent accessing Oracle
    • mmm is the number of Oracle queries made
  • cache: nn% #mmm describes how many distributed cache resources were used
    • nn is the percentage of the page time spent accessing the cache infrastructure
    • mmm is the number of cache requests made

The third line indicates the specific server, which is not important, but it does list the version of the NetSuite application running the web store. This can be useful in troubleshooting whether a particular backend feature is available to the web store, or if you need to compare how a particular web store works on different backend versions.

The fourth line lists the account number of the application running the web store, the URL the handled the request, and the time the page was generated.

Finally, there is an SQL debug comment that will almost always show the same message. You can ignore this as we sometimes use it for internal testing.

Troubleshooting Specific Problems

I See a Blank Page When I Visit a Secure Part of My Local Site

This is probably an issue you'll notice when you first start developing or if you've just opened your local server in a new tab/window. As you're viewing a secure page but loading scripts through an insecure protocol (eg, http://localhost:7777/javascript/...), your browser will block them unless you add an exception. In Chrome, this can be overridden by clicking the silver shield in the address bar and then Load unsafe scripts.

A screenshot of a web browser. It shows a shield in the address bar, indicatign that the web browser has blocked scripts that were loaded insecurely.

This may not always result in a blank page, but you may notice "Mixed Content" errors if a script has been blocked.

I Reloaded the Page But the Content Hasn’t Changed

Clear Caches

The most likely culprit will be caching. Caching occurs at numerous stages throughout your site including in your browser and on our servers. To check whether the issue is your browser, empty the cache and hard reload.

To do this in Chrome, have the developer tools open and click-and-hold on the Reload icon, then select Empty Cache and Hard Reload. This will ensure all stored resources are cleared and requested fresh again.

If this is a site hosted on NetSuite (as opposed to one you’re serving locally) then you should also submit a cache invalidation request for the domain (or specific paths) via the NetSuite application.

Check for Errors in the Console

The developer console should return any errors with your site’s JavaScript. Check to see if a resource has failed to load (perhaps there’s a typo?) or if there are syntax errors.

You can also use the debugger command in your JavaScript to create breakpoints in your JavaScript, or console.log() to send messages, at various points in your code’s execution.

I Don’t Think the Call to My Service File is Working

When you're trying to connect the frontend of your site with the backend, you may experience difficulties in getting / creating / updating / deleting data on the server. You can use your browser's Network tab to view all network operations, such as the getting of files.

If you filter for XHR (XMLHttpRequest requests) after performing your CRUD operation, you'll see a small selection of requests that have been made to the server. You should see the name of the service being used, the appropriate method and the correct status. Following that you can dive deeper by examining the Preview or Response, which will show the payload of the operation (such as JSON data of a GET).

A screenshot of a web browser's developer tools, open to the Network tab. The requests have been filtered to XHRs, highlighting the service calls that were made.

What Template Do I Need to Edit?

If you want to make an aesthetic change to your site or close in on a bug in a template, you may find it difficult to find the right template to edit. The first place to start is to inspect the page that you want to change. Then, go through the DOM elements until you find a comment that begins "TEMPLATE STARTS". This will have the name of the template being rendered by a view.

A screenshot of a web browser's developer tools, open to the Elements tab. A code comment has been highlighted, showing the name of the template that has been rendered.

Note, however, that the template may use other templates within it if, for example, the main template shows a list and another template is used to show each item in that list. To do this, Backbone uses a child view as part of a collection view. A key characteristic to look out for is the use of the data-view parameter on elements within the template; these are used to load in additional templates from the collection. Once you have that name you can look in the view that calls the template and then look at the childViews function. With that name you can reference the view and, in that, the template that's being used.

A screenshot of a text editor. It shows a code snippet that is a constructor function for the view that renders the aforementioned template.