Cx Walkthrough Part 1: Setting Up a New Cx Project

Marko Stijak
Codaxy
Published in
6 min readNov 14, 2016

--

This is the first post in the Cx Walkthrough series in which you’re going to learn how to set up new Cx applications.

Cx requires tools such as babel and webpack which are plugin-based and require a significant amount of work to configure properly. Luckily, here at Codaxy, we went through this process a number of times already and know how to do it.

When dealing with complicated stacks, people usually rely on boilerplate projects. These projects contain the project structure and all required tools and configuration code. We created one such project and put it inside the Cx command line tool. This tool helps you start and evolve your application — it is the quickest way for setting things up, so we’re going to use it here.

md employee-directory
cd employee-directory
md client
md server
cd client
npm init
npm install cx-cli -G
cx scaffold
cx start

Using the snippet above, create a new directory for your project. Within that directory, create folders for client-side code and server-side code called client and server. Inside the client folder, initialize an npm package, install Cx command line tools and use it to set up the application. After that, start the application to make sure everything was set up properly.

The scaffold command copies the boilerplate code into your project and installs Cx, Babel, Webpack, and Sass related packages. It also adds basic Babel and Webpack configurations and sets up start and build scripts in your package.

If everything works out, you should see a small verification checklist. First, check if routing works — green CSS item on the page indicates that SCSS files are compiled into CSS and loaded correctly. You should also check if hot module reloading works. To do that, for example, you can replace the word HMR with HMR works and save. The page should automatically update itself by the magic of webpack.

Project Structure

Now that you have the application in place, we can examine its structure.

Inside the client folder, you can see the package.json file as well as the app and config folders.

The config folder contains babel and webpack configuration files. There are plenty of online resources on webpack and babel configuration, so I’ll skip the details.

The app folder contains three index files. These are the application entry points for HTML, JavaScript, and SCSS.

Additionally, you can see layout and routes. The layout folder usually contains the static layout code. The application may contain a single layout or multiple page layouts which can be nested. If you missed the outer layout concept, it’s a good time to become familiar with it by visiting Cx Docs.

Applications usually contain multiple pages located in the routes folder. The general rule is that URL that you see in a browser should match the path in the routes folder, with the exception of the home page which is defined in the default folder (route).

index.js

This is the main entry point so we’ll go through everything.

First, you’ll see two strange import statements:

import 'whatwg-fetch';
import "./index.scss";

whatwg-fetch is a polyfill for the fetch function which is not available in IE and Safari. The next statement imports the index.scss file. This probably looks weird if you haven’t worked with webpack before. Long story short, applications require not only JavaScript, but CSS, images, and other files. Webpack allows you to load (process) whatever you want in your application if you have an appropriate plugin (loader). In that sense, importing CSS (or SASS) feels perfectly natural.

Next, create a Cx data store which will hold the application state and provide notifications on state changes.

import {Store} from 'cx/data/Store';
const store = new Store();

Whenever you make a code change, the application will reload. This part leverages webpack’s API functionalities to preserve the application state between runs.

if (module.hot) {
// accept itself
module.hot.accept();

// remember data on dispose
module.hot.dispose(function (data) {
data.state = store.getData();
if (stop)
stop();
});

//apply data on hot replace
if (module.hot.data)
store.load(module.hot.data);
}

In practice, this is seamless and it looks like the application is updated in place.

Then, you need to configure Cx:

import {Url} from 'cx/app/Url';
import {History} from 'cx/app/History';
import {Widget} from 'cx/ui/Widget';
import {Timing} from 'cx/util/Timing'
import {Debug} from 'cx/util/Debug'
Url.setBaseFromScript('app.js');
History.connect(store, 'url');
Widget.resetCounter();
Timing.enable('app-loop');
Debug.enable('app-data');

First, initialize the base URL (~). Base URL determines how routes are resolved. For example, this application is hosted at test.codaxy.com/employees/. If you want to go to the About page (~/about) that would translate to test.codaxy.com/employees/about, which means that the base is test.codaxy.com/employees/ (or just /employees/). You can initialize the base by examining the scripts, and, in this case, look for a script app.js in the HTML and use its path as a base. Next, History.connect connects the browser’s URL address and the store. Whenever URL changes, the value will be reflected in the store under the url key. Widget.resetCounter() is a helper method which enables that widget identifiers are the same in different runs. This enables you to do cool things, like preserving the scroll position or focus on inputs. App-loop timing will show you in the console how much each render takes and app-data debug will output application state in the console on each change. This is useful for debugging purposes.

Finally, you’re ready to start the application loop.

import {startAppLoop} from 'cx/app/startAppLoop';
import Routes from './routes';

const stop = startAppLoop(document.getElementById('app'), store, Routes);

Application loop goes like this. Use the application state to render the application (Routes) into the given DOM element (app). After that, wait for the next state change and repeat everything again.

routes/index.js

This file is the main crossroad. Here you decide where you want to go.

import {Route} from 'cx/ui/nav/Route';
import {PureContainer} from 'cx/ui/PureContainer';

import AppLayout from '../layout';

import Default from './default';
import About from './about';

export default <cx>
<PureContainer outerLayout={AppLayout}>
<Route route="~/" url:bind="url">
<Default/>
</Route>
<Route route="~/about" url:bind="url">
<About/>
</Route>
</PureContainer>
</cx>

There are a couple of important things to learn here. The most important one is to notice how to use the Route widget properly. Routes activate certain parts of your application if the url matches the given path (route). As you remember from the previous section, we connected the browser’s URL path and our store using the History.connect(store, ‘url’), and that allows us to use it for route’s url parameter. Also, note that routing doesn’t have to be tied to the browser’s URL and you can use hash-based routing or something else.

Next, notice the PureContainer and AppLayout. PureContainer doesn’t render any markup, instead, it outputs its children. However, you may assign some attributes like visible, layout, outerLayout, controller, etc. In your case, outerLayout is applied to all routes.

layout/index.js

This file defines the application layout, and it’s dead simple by default.

import {HtmlElement} from 'cx/ui/HtmlElement';
import {ContentPlaceholder} from 'cx/ui/layout/ContentPlaceholder';

export default <cx>
<div class="app">
<header class="header">
<h1>Cx App</h1>
</header>
<ContentPlaceholder />
</div>
</cx>

Note the ContentPlaceholder widget. This is where the content will be placed.

Recap

In this post, I explained how to generate Cx applications from scratch and what typical project structure looks like.

In Cx Walkthrough Part 2: Creating and Accessing an API, I’ll point out things more specific to the Employee Directory application.

--

--