When developers embark on a new web application project, they often seek technical guidance for where to start, which technologies to use, how to work through platform integration issues, etc. New technologies are emerging at a record pace, so developers spend a lot of time and energy deciding which frameworks are the most trusted and well-established in the web community. As an example, many startups favor open source solutions, and follow some form of agile SDLC methodology to stand up a full-stack local web environment on-demand. Developers need an environment that provides the flexibility to easily swap frameworks while still allowing them to develop rapidly.
Another problem developers often face is the lack or delay of a stable test environment after development is complete. This leaves the sustainability of an app at a vulnerable state; code often needs to be refactored to be testable in a production-ready environment.
The Solution
The goal of this project was to provide developers with a framework to simplify the process of creating a modern web platform that includes the most common core requirements (listed below). After extensive research, prototyping and performance benchmarking, the following technologies were selected for each of the core requirements:
- Task management: Grunt
- A lightweight and robust front-end rendering toolset option: Bootstrap 3 + ReactJS
- Web engine: NodeJS
- Http Request / Socket Routing Management: Socket.io / Express
- Easy and reliable integration with ECMA 6: Babel
- Web API Generation: Sails Blueprints
- Asset Minification / Unification: Browserify
- Package management: NPM
- Continuous integration: Travis CI
- Automated unit testing: Mocha, PhantomJS, Protractor
- Code Coverage Reporting: Istanbul
- Code Quality Checks: ESLint
- One-Click Deployment: Kudu/Azure
An additional goal was to create a framework that is agnostic to any particular front-end strategy(s), and make it easy for developers to customize and plug in their open source platform(s) of choice.
Github Code Repo
https://github.com/erikschlegel/sails-generate-reactjs
Overview of the solution
Sails has a concept called “generators”, which allow developers to extend and create a templated solution to fit their needs. This project’s custom generator uses ReactJS as the toolset to create front-end components; also plugged in are other battle-tested open source products to cover testing, web asset management and continuous integration.
This project solves the need for developers to have a consistent working environment. The framework offers a powerful starting point that is easily extensible, and enables developers to reconfigure the project generator to plug in the tech stack they choose. This repo also comes packaged with Bootstrap 3 and LESS for CSS pre-processing, so you have the option available for a responsive and user-friendly front-end layout template to start with. Some noteworthy Bootstrap 3 sites are showcased in the Bootstrap Expo.
This repo supports test driven development practices, which encourages simple design and inspires confidence and reliability. The TDD cycle entails an iterative process of first writing unit tests that validate user features, then writing production code that’s continuously being validated (against unit tests); real-time testing results are provided throughout development. Test-driven development offers more than just simple validation, but can also drive the design of a service and/or program and makes refactoring a whole lot easier. By focusing on unit tests first, developers must think up front about how users will use their program. This also helps avoid conflicts where one developer’s local change(s) breaks another developer’s build. Mocha, Protractor, Istanbul and PhantomJS are bundled with this project as the test harness.
Because the framework uses Travis CI for build management, all unit tests are executed for each GIT commit and the team can be notified of any failed builds via Slack or email. We will also took a look at Deis as an exploration exercise to identify opportunities to take continuous integration one step further.
Potential future extensions using Microsoft Kudu to synchronize an Azure web site with a successful Travis CI build.
The steps to use this framework on your local environment are listed below.
Installation
- Update your .sailsrc file
- Create a file named .sailsrc
{ "generators" : { "modules" : { "frontend" : "sails-generate-reactjs" } } }
Note: for Linux or Ubuntu environments, you’ll need to run all the commands below with sudo (i.e. sudo npm install vs npm install).
On the command line
- Install the project from the published NPM module.
$ (Windows) npm install -g sails
$ (Windows) npm install -g sails-generate-reactjs
$ (Linux) sudo npm install -g sails
$ (Linux) sudo npm install -g sails-generate-reactjs
3.This command will create your Sails Site
$ (Windows) sails new <%-newAppName> --force
$ (Linux) sudo sails new <%-newAppName> --force
- This command will install all packages and dependencies.
$ cd <%-newAppName>
$ (Windows) npm install
$ (Linux) sudo npm install
- Fire up your web server
$ sails lift
You should see this message coming back from Sails to confirm that your site is ready for use.
You can access your new site by accessing it at http://localhost:1337
.
Implementation
Sails is delivered with a baseline site generator, and a standard set of GRUNT tasks for building and packaging the assets of your web site. This framework is an extension of that baseline, and provides a bower template and NPM package template file that can be overridden by the developer.
Asset Packages
Bower template file – templates/bower.ejs
{
"name": "<%= appName %>",
"version": "0.0.0",
"authors": [
"<%= author %>"
],
"moduleType": [
"globals"
],
"license": "MIT",
"dependencies": {
"bootstrap": "~3.3.4",
"fontawesome": "~4.3.0",
"sails.io.js" : "*"
}
}
The default provided bower file includes dependencies for fontawesome and bootstrap, which will be installed when you run Sails new.
Node Package Dependencies
Node Package.json template – templates/package.json
"dependencies": {
"sails": "~0.11.0",
"sails-disk": "~0.10.0",
"rc": "^0.5.5",
"include-all": "~0.1.3",
"ejs": "~0.8.4",
"grunt": "^0.4.2",
"grunt-sync": "0.0.8",
"grunt-contrib-copy": "^0.5.0",
"grunt-contrib-clean": "^0.5.0",
"grunt-contrib-concat": "^0.3.0",
"grunt-sails-linker": "^0.9.6",
"grunt-contrib-jst": "*",
"grunt-contrib-watch": "^0.5.3",
"grunt-contrib-uglify": "^0.4.1",
"lodash" : "*",
"grunt-contrib-cssmin": "^0.9.0",
"grunt-contrib-less": "^0.11.1",
"react": "^0.13.3",
"react-bootstrap": "^0.20.3",
"grunt-babel": "^5.0.0",
"grunt-browserify": "^3.8.0",
"grunt-react": "^0.12.2",
"grunt-shell": "^1.1.2",
"grunt-contrib-coffee": "^0.10.1"
},
"scripts": {
"start": "node app.js",
"debug": "node debug app.js",
"test": "mocha -b"
},
These are the default node packages installed with your app, and can be overridden by the developer. The baseline comes included with grunt modules necessary for build management tasks, testing(mocha) and code quality checks_(ESLint_).
Continuous Integration
Travis configuration template – .travis.yml
language: node_js
node_js:
- "0.12"
sudo: false
before_install:
- "export DISPLAY=:99.0"
- "npm install -g sails"
- "npm install -g sails-generate-reactjs"
- "sleep 10" # give server time to start
- "npm install -g grunt"
- "sails new travisSite --force"
install:
- "cd travisSite"
- "npm install"
script:
- "sails lift"
branches:
only:
- master
matrix:
fast_finish: true
- To enable continuous integration with Travis, your app will need two things. One, a .travis.yml file and two, an enabled account on the Travis portal (this part cannot be automated). You’ll find a .travis.yml file in your working directory that a developer controls. By default, Travis will invoke npm test (listed above) on every code commit, build your app on its VM, and a development team is notified of the results. Travis supports .NET builds as well.
Front End Assets / Layout (Bootstrap 3 + ReactJS Option is available)
The site will come bundled with a starter bootstrap template, which is fully customizable. The template location can be found within ‘working directory/views/homepage.ejs’. You’re free to use any other templating library, like Semantic UI, in place of bootstrap.
App.js (this is only an example to illustrate a sample react component)
var React = require('react');
var LikeButton = React.createClass({
getInitialState: function() {
return {liked: false};
},
handleClick: function(event) {
this.setState({liked: !this.state.liked});
},
render: function() {
var text = this.state.liked ? 'like' : 'haven't liked';
return (
<p onClick={this.handleClick}>
You {text} this. Click to toggle.
</p>
);
}
});
React.render(
<LikeButton />,
document.getElementById('example')
);
If a developer chooses to use ReactJS as its component framework, Browserify is setup to pull in React components referenced at ‘working directory/assets/app/app.js’ . A sample app.js file with a component defined is shown above. The Browserify location can be configured within ‘working directory/tasks/pipeline.js’
Test Driven Development
All unit tests are re-invoked when any of your source files change, and the result of the test run will be available on the node console. Mocha is flexible with providing fine-grained controls to developers with its reporting capabilities of test results.
/test/components/LikeButton.js
var assert = require("assert");
var React = require('react/addons');
var LikeButtonComponent = require('./components/LikeButton');
var TestUtils = React.addons.TestUtils;
describe('TestSet1', function(){
describe('#React Like Button Feature Test Suite()', function(){
it('Changes the text after click', function(){
// Render a sample like button onto te dom
var button = TestUtils.renderIntoDocument(
<LikeButton />
);
var buttonComp = TestUtils.findRenderedDOMComponentWithTag(button);
assert.equal(buttonComp.getDOMNode().textContent.indexOf('You havent''t liked')>-1, true);
TestUtils.Simulate.click(button);
buttonComp = TestUtils.findRenderedDOMComponentWithTag(button);
assert.equal(buttonComp.getDOMNode().textContent.indexOf('You like this')>-1, true);
})
})
})
Challenges
Sails is a powerful framework that scaffolds a fully functional enterprise Node app that’s easily configurable. The main challenge I faced when working with Sails was the limited documentation. This forced me to crawl through the source code to answer questions and address issues I encountered. There were also only a couple examples where other engineers built custom Sails Generators. I tried to simplify some of the SailsJS issues that I ran into by abstraction and customizable hooks into Sails that can be leveraged in the sails-generate-reactjs project.
Technologies used in this project
SailsJS, Socket.io, Express, Bower, NodeJS, NPM, Browserify, Handlerbars, ESLint, Babel, Kudu, Azure, Travis CI, Mocha, Protractor, Istanbul, ReactJS, Bootstrap
Opportunities for Reuse
This project provides developers with a starting point to scaffold a Node JS Web application, plug in additional packages, and customize the base install so the development environment fits the needs of their project.
0 comments