Developing an HTML+JS Open Web App Quickly

Open Web Apps promise to transform OpenMRS development by letting devs with standard HTML+JS skills build apps (a) without needing any knowledge of Java or OpenMRS's server-side code, (b) with more efficient dev processes that don't require deploying an OpenMRS module each time you want to see a change.

This tutorial describes how you can quickly build a freestanding Open Web App on top of the OpenMRS Reference Application. (A future tutorial will talk about how to integrate Open Web App code with existing code.)

We assume that you have a development environment set up, to build JavaScript webapps, e.g. you have npm and git, and you have a suitable text editor.

In a hurry?

Want to skip this and just start writing code? Fork this git repo: https://github.com/djazayeri/openmrs-owa-tutorialexample or scaffold your app using the Yeoman generator.

Step 1 - Run OpenMRS locally

You need to be running OpenMRS locally to be able to do rapid development (because you need to be able to copy files from your dev environment to the "server"). You can run OpenMRS in a number of ways, but the easiest would be to download the latest Standalone version of the Reference Application.

To use the standalone:

  1. Download the latest Standalone release of the Reference Application from http://openmrs.org/download/ (at time of writing this is "OpenMRS 2.3.1 Standalone Edition").
  2. Unzip it, and run openmrs-standalone.jar (or run-on-linux.sh)
  3. Choose Demonstration Mode (so that you have access to demo patients).
  4. Wait a few minutes for OpenMRS to start up
  5. You can log in as admin/Admin123

Step 2 - Install the Open Web Apps module

This is described on the Open Web Apps Module page. It's the same as installing any other module.

Once this is done you should verify that a folder called "appdata/owa" has been created underneath your unzipped openmrs-standalone folder. To be able to develop rapidly, you'll want to know the path of that folder, to copy files into it. (You will need to know this in Step 5.)

Step 3 - Create the Skeleton of Your Open Web App

There is a Yeoman generator available to automatically create your skeleton. See the documentation here.


Create the folder where you will build your Open Web App, following the convention of "openmrs-owa-yourappname" (to make it easily recognizable on github).

$ mkdir openmrs-owa-tutorialexample
$ cd openmrs-owa-tutorialexample
$ git init

Within this folder, create your manifest.webapp file, as described on the Open Web Apps Module page. (If you want to use IntelliJ for this, create a "Static Web" project and consider this gitignore file.)

Next, create your index.html file (or some other filename if you specified something else as the launch_path in your manifest.webapp).

<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <h1>Tutorial Example</h1>
        If you see this, it works.
    </body>
</html>


We are going to use npm and gulp to build our webapp. Make sure you have npm installed (e.g. from the linked instructions).

// you only need to do these once ever
npm install --global gulp
npm install --global gulp-zip
 
npm init
// enter requested info (defaults will work fine); this creates package.json
 
npm install --save-dev gulp
npm install --save-dev gulp-zip
// this would be a good time to add "node_modules" to your .gitignore file
// while you are doing this, also add "dist" to your .gitignore file

Create your gulpfile, whose default task will build the Open Web App zip file:

'use strict';
var gulp = require('gulp');
var zip = require('gulp-zip');

var THIS_APP_NAME = 'tutorialexample'; // REPLACE THIS

var sources = ['manifest.webapp', '**/*.html', '**/*.js', '**/*.css', '**/*.png',
    '**/*.otf', '**/*.eot', '**/*.svg', '**/*.ttf', '**/*.woff', '**/*.woff2',
    '!node_modules', '!node_modules/**', '!gulpfile.js'];

gulp.task('default', function () {
    return gulp.src(sources)
        .pipe(zip(THIS_APP_NAME + '.zip'))
        .pipe(gulp.dest('dist'));
});

At this point you can run the "gulp" command, and you will see a zip file created in a /dist directory.

(You can find all the code we've seen up to this point at https://github.com/djazayeri/openmrs-owa-tutorialexample/tree/skeleton-with-zip.)

Step 4 - Upload Your Open Web App Through the Web UI

You need to upload your Open Web App ZIP file through the OpenMRS web UI once. (It's okay, after this first time you'll be able to do this via a gulp command, which will speed things up.)

The Open Web Apps Module page describes how to do this. (The file you want to upload is the zip file created in the /dist directory.) Once you've done this, click on your app's icon (it will be a broken image if you've followed these instructions), and verify that you see the expected index.html page.

Step 5 - Set Up Your Project for Rapid Development

You want to be able rapidly iterate on the UI that you are building, and with Open Web Apps we can do this in a way that is much more efficient than by writing a server-side OpenMRS module. Since we are running a local OpenMRS server, we can just set up a gulp task that copies our files to the folder on disk where they are served from. This will let us see our code changes by running a single gulp task, and refreshing the browser window.

Modify your gulpfile to look like this (we are adding a new deploy-local task, and a new variable you have to set):

'use strict';
var gulp = require('gulp');
var zip = require('gulp-zip');

var LOCAL_OWA_FOLDER = '.../openmrs-standalone-2.3.1/appdataowa/'; // REPLACE THIS
var THIS_APP_NAME = 'tutorialexample'; // REPLACE THIS

var sources = ['manifest.webapp', '**/*.html', '**/*.js', '**/*.css', '**/*.png',
    '**/*.otf', '**/*.eot', '**/*.svg', '**/*.ttf', '**/*.woff', '**/*.woff2',
    '!node_modules', '!node_modules/**', '!gulpfile.js'];

gulp.task('default', function () {
    return gulp.src(sources)
        .pipe(zip(THIS_APP_NAME + '.zip'))
        .pipe(gulp.dest('dist'));
});

gulp.task('deploy-local', function () {
    return gulp.src(sources)
        .pipe(gulp.dest(LOCAL_OWA_FOLDER + THIS_APP_NAME));
});

Now, once you have made changes to your project in your text editor or IDE, you just need to run that task:

$ gulp deploy-local

...and then refresh your browser window, and you'll see your changes reflected.

You can test this out by making an edit to the index.html file, and verifying you see that change.

(You can find the skeleton code we've written so far at https://github.com/djazayeri/openmrs-owa-tutorialexample/tree/skeleton-with-deploy-local.)

Linking to Your Open Web App from the Home Screen

Since you've built a standalone app, you want to let people access it from the OpenMRS home screen. You can do this by going to System Administration -> Manage Apps -> Add App Definition and then adding a definition like:

{
    "id": "replace.with.something.unique",
    "description": "replace with your description",
    "order": 0,
    "extensions": [
        {
            "id": "replace.with.something.unique.homepageLink",
            "extensionPointId": "org.openmrs.referenceapplication.homepageLink",
            "type": "link",
            "label": "Replace with name of your App",
            "url": "owa/managerdashboard/index.html",
            "icon": "icon-bar-chart",
            "requiredPrivilege": "Replace with a privilege name, or else remove"
        }
    ]
}

You can see the available icons at http://demo.openmrs.org/openmrs/uicommons/icons.page.

To go along with this you probably want a link in the top left of your app, with a homepage icon, with an href of "../index.html" (or else use the value of openmrs.href from manifest.webapp as an absolute URL).

Contributions Welcome

Make This Better!

I am not primarily a JS developer, and I have never used gulp before doing this example. I'm sure there's a cleaner way to set up the gulpfile, and I welcome someone showing the better way!

Also, I'd love for someone to extend the tutorial with:

  • how to add a JS or CSS library by downloading it from npm
  • the best initial layout for an AngularJS application (ideally with routes that don't resolve until we've fetched openmrs.href from manifest.webapp)
  • how to combine and minify your JS
  • compass/sass instead of CSS
  • coffeescript instead of JS
  • jade instead of HTML
  • how to make REST calls against the OpenMRS API (and how to do this using the already-written AngularJS services in the uicommons module)
  • how to use the OpenMRS SDK as an alternative to the Standalone distribution
  • ...whatever else I haven't thought of that is obvious to a JavaScript developer

Of course it would be great to have a starter skeleton that includes Bootstrap CSS, Font Awesome, and AngularJS out of the box!

Edit this wiki page, or send me a pull request against https://github.com/djazayeri/openmrs-owa-tutorialexample, or just comment with a link to your own better starter code!