Building a Mobile Site: Project Structure

This module will go through the typical structure of a Moovweb project. This should help you get an idea of how to manage your code.

Prerequisites: Planning a Site


Set Up Mappings

Remember in the Planning a Site module where we identified important page types? We did this because we wanted to know which pages we could transform using the same Tritium scripts.

For example, since all of the product pages are similar to each other in structure, we can transform them using a single Tritium script.

The mappings.ts file is where page types are matched to determine which scripts we want imported depending on the URL.

We do this using match statements.

Match statements are Tritium’s version of “if/then” logic. They use regular expressions to check against the provided variable, in this case the $path variable (which contains the current path in the URL) and then execute Tritium scripts if the expression matches the variable. Page types often have a common element in their URL — for example, all the product pages will have “/product” in the URL. We can match against this unique part of the URL to import a Tritium script for that page type.

Look at the match() statement below:

match($path) {
  with(/^\/$|^\/\?/) {
    log("--> Importing pages/home.ts in mappings.ts")
    @import pages/home.ts
  else() {
    log("--> No page match in mappings.ts")

That complicated regular expression in the first with() statement is looking for a URL path that consists of only a “/” or begins with “/?” and then importing the homepage if that is true.

Otherwise Tritium will default to the else() statement.

Let’s try and set up some different matchings for different page types on the iGadget site. We’ll work on the “category page” first — one example of which is

First, create a category.ts file in your scripts/pages folder.

Start in mappings.ts, right after we match the homepage:

  1. Use the with() function to match a path — in our case, all brand pages have a path including the word “shop”:

  2. Use the log() function to help keep track of what files are being imported by the server:

    with(/shop/) {
      log("--> Importing pages/category.ts in mappings.ts")
  3. Use the @import function to import a file. Make sure to create a file named category.ts in your scripts/pages folder or Tritium will throw an error!

    with(/shop/) {
      log("--> Importing pages/category.ts in mappings.ts")
      @import pages/category.ts

Test your match() statement by going to a category page on the local version of the iGadget site. You should see the “Importing …” log message appear in your dashboard logs or in the Moovweb Toolkit Chrome extension.

Now that we’ve got the category mapping set up, we’ll be able to transform those pages properly in the future.

What if there are no URL patterns?

In these cases, we map based on content rather than the URL. This is less preferable to mapping based on URL as it is usually more time-consuming (it requires searching through the HTML). In some situations it is unavoidable.

To map on content, find an element — such as a <div> with an ID, or a particular image — that is unique to every page you want to map. On iGadgetCommerce, the product pages have a <div> with the ID "ProductDetails" which can be used to distinguish them from other pages.

Go into the else() statement in your mappings.ts — after all other URLs have been matched. Select the item you want to map with in the following manner:

else() {
  $("//div[@id='ProductDetails']/ancestor::html") {
    log("--> Importing product.ts - mapping on content")
    @import pages/product.ts

This selects the <div> with the ID "ProductDetails". If the <div> is selected, it means we are on a product page so the product.ts file is imported.

You may notice that the XPath selector uses “ancestor::html” at the end. This is to make sure that when the file gets imported, we start from the HTML node, rather than the #ProductDetails node.

For more information about the match() function check out this in-depth tutorial.

Dashboard Logs

Understanding the dashboard logs in your browser is probably the most important skill in debugging problems with Moovweb.

When you first start your project if you hit the “Logs” button, you’ll see the server print messages to your browser every time you load or refresh a project page. Let’s take a look at some of these messages.

Dashboard Logs

Using Moovweb SDK version 4.7 or earlier?

These same logs will show up in your terminal and also in the Moovweb Toolkit Chrome Extension. They have the same definitions as the logs below.

When accessing or refreshing a page, you will get the following messages:

Incoming Request URL: /wiki/Main_Page

tells us we are requesting the Wikipedia homepage to be served through the Moovweb server.

--> STATUS: 200

This is a log of the status code. Log statements tell us where we are at in our Tritium script. They are a great way of marking your place in the code if you need to be sure that a certain script was executed.

This is going to be a critical part of how you debug your projects. Log statements are generated using the log() function. They are comparable to, say, console.log() statements in JavaScript.

Debugging Tritium

Tritium errors occur in both your browser and your terminal window.

Here are some examples of Tritium errors you might see:

Error: /html.ts:14 -- found unexpected LEXICAL ERROR: unrecognized token

This is usually a syntax mistake — you’ve made a typo in one of your functions.

Error: No tritium file found at: /mapping.ts

This means you’ve imported a script file that doesn’t exist.


The log() function is one of the most useful tools in assisting your understanding of the server output. It will help you keep track of what scripts are being run and where specifically they might be breaking.

We already came across the log() function when laying out the mappings file.

You can put log statements after certain selectors to see if those nodes have actually been selected and are being manipulated.

If a node isn’t found by Tritium, that code is simply passed over without being executed. For example, take this bit of Tritium:

$("./a[contains(@class, 'foo']") {
  move_to("../span", "top")

For some reason, the <a> isn’t being moved. We can check our selector like so:

$("./a[contains(@class, 'foo')]") {
  log("--------- Selecting the a tag with the class containing foo.")
  move_to("../span", "top")

Note that we’ve added a lot of dashes at the front that make the message stick out in the server output. If the log message doesn’t show up, it’s because our selector is broken in some way. Play around with it until it’s fixed.

If the log message does appear, it’s our use of the move_to() function that is the problem.

It’s standard practice to put log statements before each time you @import another Tritium script.

Remember, you have to use XPath’s double-dot (“..”) notation in order to select nodes above you in the DOM hierarchy. If you try to select a node’s parent without traversing up the node tree, it won’t be found.

When working with Uranium, make sure the hierarchy of all your nodes is correct and follows the documentation on the Uranium website.

Organize Stylesheets

Why do we structure stylesheets? Chiefly for two reasons: maintenance and readability.

Notice the structural similarities between the scripts folder (pages, sections) and the assets/stylesheets folder. Both have a pages subfolder, where we put page-specific files, and a sections subfolder, for the header and footer. Make sure to create page-specific stylesheets for every page type where you have a Tritium file. Create .scss files for the brands and products pages that we made in the mappings section of the lesson!

The assets/stylesheets/globals folder is for mixins and styles that will be used on multiple pages.

The _base.scss file is where we put all our basic styles such as buttons we repeat on multiple pages.

We can do page-specific styling by adding a class to the body using Tritium:

Adding a Class

then using the scoping feature of Sass to apply styles only when the <body> has the correct class.

Page Specific Styling

You may remember that we did this in the previous lesson when we added some short snippets of code to the home.ts file (to add a class to the <body>) and the home.scss file.

Don’t forget to import every stylesheet in main.scss! We only add one stylesheet (the compiled version of main.scss) to every page — we do this to keep HTTP GET requests to a minimum. So, to ensure that the styles in any non-main.scss file are compiled, we must use @import to add them to main.scss.