An introduction to building a web application with itsa-react-server

Marco Asbreuk
Aug 22, 2017 · 5 min read

Itsa-react-server is a MVC framework for building server side rendered single page apps (SPAs) with React.js. In case you missed it: see here.

This article is about how to build a RESTful web application

Setup

Before you start, you need to define your project in a new folder. Because itsa-react-server requires a several pieces (files and folders) to be there, the best thing to do, is to create a new project with our command line interface itsa-cli. We assume you already have node.js (version 8+) and npm installed before you proceed.

Install itsa-cli

npm install -g itsa-cli

You only need to do this once. After that you can create as many projects you want.

Create a new project

From within your projects folder, go to the terminal and type:

itsa create appname

appname is the name of the folder where your new application/project gets stored.

Now you already have a whole directory structure and a working web application. To view your new application, you will need to build and run it.

Build and run your app

Your new app needs to be built first. Itsa-react-server has multiple ways to do this, depending on your needs:

Just building:

npm run build

Just running the application (using the last build):

npm run server

Build and run the application:

npm run start

For development: build, run and watch for changes:

npm run watch

The console shows that you can view your app on http://localhost:3001. Congratulations: you have built a working web app with itsa-react-server!

Creating the pages (views)

Itsa-react-server is designed to have dedicated view for every webpage. A visitor can load these pages by specific urls, which we will explain later on (routes). The pages that the project needs are views for the MVC framework. Basically, they are just React.js Components that will receive the proper this.props (more about that later).

The default project already has 3 views. Let us just focus on index.jsx and information.jsx and manipulate them a bit. Note that any relative file reference starts from within the src directory (or node_modules).

src/views/index.jsx:

import 'assets/css/index.scss';import React from 'react';
import PropTypes from 'prop-types';
import Menu from 'client-modules/menu.jsx';
class PageIndex extends React.Component {
render() {
return (
<div>
<Menu appProps={this.props.__appProps} />
<h1>Page index.html</h1>
{this.props.pagecontent}
</div>
);
}
}
PageIndex.propTypes = {
__appProps: PropTypes.object,
pagecontent: PropTypes.string
};
export default PageIndex;

src/views/information.jsx:

import 'assets/css/information.scss';import React from 'react';
import PropTypes from 'prop-types';
import Menu from 'client-modules/menu.jsx';
class PageInformation extends React.Component {
render() {
return (
<div>
<Menu appProps={this.props.__appProps} />
<h1>Page information.html</h1>
{this.props.pagecontent}
</div>
);
}
}
PageInformation.propTypes = {
__appProps: PropTypes.object,
pagecontent: PropTypes.string
};
export default PageInformation;

As you might have noticed, we refer to (import) 3 files that we need to define as well. Actually, client-modules/menu.jsx itself refers to assets/css/client-modules/menu.scss, so lets create those 4 files:

src/assets/css/index.scss:

h1 {
color: #900;
}

src/assets/css/information.scss

h1 {
color: #009;
}

src/assets/css/client-modules/menu.scss

.mymenu {
font-size: 1.25em;
}

src/client-modules/menu.jsx:

import 'assets/css/client-modules/menu.scss';const React = require('react'),
PropTypes = require('prop-types'),
MENU_ITEMS = [
{label: 'home', link: '/'},
{label: 'information', link: '/information'}
];
class Menu extends React.Component {
render() {
const menuitems = this.renderMenuItems();
return (
<div className="mymenu pure-menu pure-menu-horizontal">
<ul className="pure-menu-list">
{menuitems}
</ul>
</div>
);
}
renderMenuItems() {
const appProps = this.props.appProps,
currentPath = appProps.path;
return MENU_ITEMS.map(menuitem => {
let classname = 'pure-menu-item';
const link = appProps.langprefix+menuitem.link,
label = menuitem.label;
if (currentPath===menuitem.link) {
classname += ' pure-menu-selected';
}
return (
<li
className={classname}
key={link}>
<a className="pure-menu-link" href={link}>
{label}
</a>
</li>
);
});
}
}
Menu.propTypes = {
appProps: PropTypes.object
};
export default Menu;

As you may have noticed, we are using styles from purecss. We need to make sure our project loads it on every page. Itsa-react-server makes this very easy: install the library and make a reference in the web app config file (src/manifest.json) as an external module:

install purecss:

npm i -S purecss

update src/manifest.json (also for the different environments):

{
...
"external-modules": [
"purecss/build/pure-min.css",
...
],
...
"environments": {
"local": {
...
"external-modules": [
"purecss/build/pure-min.css",
...
],
...
},
...
"development": {
...
"external-modules": [
"purecss/build/pure-min.css",
...
],
...
},
}
...
}

Creating the models

Every view needs a “this.props” as a model, because the views are React.js Components. A view always gets a basic model that holds some specific server and client information in the member __appProps. The basic model looks like this:

{
__appProps: {
...
}
}

This model can be extended with properties that you want to add. You can do this by defining a related file inside the models folder. Every view that finds a matching file (with same filename, .js) inside de models folder, will use this model and extend it to the basic object.

In our project, we will (re)define 2 files:

Note: itsa-react-server requires CommonJS style instead of ES6 modules for the models.

models/index.js:

const model = async () => {
return {
pagecontent: 'Hello World!'
};
};
module.exports = model;

models.information.js:

const model = async () => {
return {
pagecontent: 'This is some extra information'
};
};
module.exports = model;

Note: you can await (Promise) inside the models. This is handy f.e. when reading from a database. The view (and therefore the server-response) will wait for the Model data asynchronously.

Defining the routes

itsa-react-server assumes that every page can be requested RESTful with an unique url. We only need to make sure that we bind the urls to the proper views. Therefore, we maintain the file src/routes.js:

src/routes.js:

var routes = [
{
method: 'GET',
path: '/',
handler: function(request, reply) {
reply.reactview('index');
}
},
{
method: 'GET',
path: '/information',
handler: function(request, reply) {
reply.reactview('information');
}
}
];module.exports = routes;

Note: reply.reactview() is a special method defined by itsa-react-server. Its only argument is the name of the view (without .jsx). You may set up a sub directory structure inside the views folder, in which case the argument should have the foldername specified. F.e. views/projects/project1.jsx can be referred to as reply.reactview(‘projects/project1’)

Showing the results

From the terminal (command prompt), inside the root of your web app folder, you can built and start the app:

npm run watch

Now open the browser and go to http://localhost:3001

The webpage should be up and running! You can make changes now and save them: itsa-react-server will rebuild and the changes are updated in the browser automatically.

In the next article, I will discuss how the client can interact with the server.

)

Marco Asbreuk

Written by

VP Engineering, LINEA System LLC

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade