Deploying an EmberJS mobile web application with Mobile Hub

Ember.js is a popular open source JavaScript framework for developing rich, dynamic web applications. It supports dependancy injection model and has been a is a stable contender in the JavaScript community. Ember.js also ships with its own CLI which supports building, testing, and deploying your applications. The Ember CLI supports installing plugins and the bundling of those plugins within your application, it has a built in web server to serve your application locally.

AWS Mobile Hub is an AWS service that guides you through feature selection and configuration, it automatically provisions the AWS services required. Mobile Hub generates working code that helps you integrate the AWS SDK for JavaScript with your application in minutes. When using Mobile Hub to develop JavaScript-based applications, JavaScript configuration files as well as a sample web application are generated for you, and placed in your Amazon S3 bucket. These configuration files can then be copied directly to your application environment for use. The files can be continuously updated when your AWS environment changes via Mobile Hub. This is useful for developing JavaScript web applications because your AWS configuration can be dynamically updated by Mobile Hub and your application can immediately realize and support those updates when hosted in Amazon S3.

Mobile Hub will copy a new aws-config.js and aws-exports.js to the Amazon S3 bucket associated with your application after you update your configuration. In order to utilize these in your local development environment, you need to download them from your S3 bucket. The files will be copied to the root of the S3 bucket, which may require you to copy them elsewhere for your application to properly include them.

Amazon Cognito lets you add user sign-up and sign-in to your mobile and web applications. This sample application uses Cognito User Pools for user management and storage, and Amazon Cognito Federated Identities for authentication the user pool. The application then uses Amazon DynamoDB directly through the AWS SDK for JavaScript. The sample application uses a custom Ember.js Adapter to abstract the API logic and allow utilization of Ember.js Models.

Then, click the following button to import the MobileHub.zip file and create the AWS back-end:

Alternatively you can download the .zip file from the GitHub repository and from the Mobile Hub console click Import your project and drag and drop the .zip file to create a new project.

After the import is complete the AWS environment is ready. Click Hosting and Streaming, and then click Download aws-config.js file. Copy the aws-config.js file to the ./vendor/aws-config.js directory of your application.

You can also download the file with the AWS CLI. You first need to know the Amazon S3 hosting bucket. You can see the bucket name by going to Resources from within you Mobile Hub project. Then from within the root directory of your application project run:

Now that the aws-config.js file is copied to your vendor directory, run the following:

ember serve

Your application should now be available at localhost:4200. If you ever change your AWS Mobile Hub configuration, simply cp the configuration file again and deploy.

To retrieve the generated S3 bucket name for the cli commands, navigate to your project in the Mobile Hub console, click Hosting and Streaming, and then click Manage Files. Note the bucket name at the top of the screen.

To deploy your web application to Amazon S3, run the following:

ember build
aws s3 cp --recursive ./dist s3://your-s3-hosting-bucket/

Your web application is now available at the web hosting URL of the Amazon S3 bucket that Mobile Hub generated. To view your application:

Goto Mobile Hub and click Hosting and Streaming

Click View from S3

After about a minute, the file changes you pushed propagate to the CloudFront distribution. You can click View from CloudFront and browse the site from a CDN for faster performance. You can force this refresh to happen immediately from the Hosting and Streaming page:

Click Edit your CDN distribution

Click the Invalidations tab

Select Create Invalidation and enter an asterisk (*) to refresh all the content

After the process completes, click View from CloudFront in the Hosting and Streaming section of Mobile Hub.

Making changes

We detail the application architecture at the end of this blog post. You can change parts of the application to meet your needs. Each time you deploy the application you must build and copy to Amazon S3, as follows:

ember build
aws s3 cp --recursive ./dist s3://your-s3-hosting-bucket/

Then either wait for a CloudFront distribution refresh or force one with an invalidation.

Walking through the sample

The Ember sample is a TODO or “notes” application. It walks through functionality for registering user accounts into your application (including email confirmation), login and logout functionality, session information and saving notes to a database. To demonstrate, first select Create User to register a new user account in the system. Enter the following:

Unique username

Complex password

Valid email address

This process registers a user in the system with Amazon Cognito User Pools. A registration confirmation code is sent to the email address. Type that code in the page and select Confirm Registration at the bottom. The workflow for this sample allows you to immediately press Login with the previously entered credentials to access the application.

In the main page create a new note by clicking the plus sign (+) in the lower right corner. Type a title for the note and some content. Click Save Note, your data is written to Amazon DynamoDB. These notes are secured where only the users who create them can read or edit them after logging in.

Select the user’s name in the upper right corner of the page. Here you see information about the user session, such as JWT token details from Amazon Cognito User Pools. This is a great place to store user-specific attributes that can be read-only or editable by the user. Click User Attributes on the left side to view your email address.

Application Anatomy

Now that the sample application is up and running we dive a little deeper and explain the structure of an Ember application. You can incorporate pieces of the sample into your own projects.

There are two types of initializers in Ember: application initializers and application instance initializers.

Application initializers while your application boots and have no access to internal services. The application initializer performs a dependency injection process to ensure that everything your application needs is setup before loading UI or user state. This is also great for security control and separation of concerns in your application architecture.

Application instance initializers run while the application instance itself loads. This provides a way to configure the initial state of the application and inject values into application services. For example you can customize the UI based on a theme for users and control state.

Application Initializers

This application uses both types of initializers. The initializers allow us to initialize the AWS SDK for JavaScript before the application instance loads. The instance initializer allows us to inject values into services. We also use the deferReadiness and advanceReadiness in the application initializer to defer loading of the application until we have temporary credentials for making AWS API calls. The main application initializer is located in the app/initializers directory, as follows:

app/initializers/aws.js

To generate an initilizer runember g initializer myInitializer. This creates a new initializer .js file named app/initializers/myInitializer.js. It also create a unit test in tests/unit/initializers/myInitializer.js.

The AWS initializer instantiates the AWS SDK using the variables that are instantiated in the configuration file that Mobile Hub generated. This file was copied from your Amazon S3 bucket. Then, the initializer checks if there is a current session with Amazon Cognito User Pools. It retrieves temporary SDK credentials. The initializer uses these credentials to make AWS API calls with the SDK. The initializer then registers values for the application to use, and finally advanceReadiness to continue loading the application instance.

The initializer determines if there is a logged in user with the Amazon Cognito Identity SDK (included in ./vendor/amazon-cognito). If a session exists, register the session credentials and JWT tokens on the application instance. These are injected by the instance initializer.

Application Instance Initializers

The instance initializer is located in the instance-initializers directory, as shown next:

app/instance-initializers/auth.js

When the instance initializer runs, it has access to application services, as well as access to any values we previously registered within the application initializer.

You can generate instance-initializers with the ember-cli using ember g instance-initializer myInstanceInitializer. This generates a myInstanceInitializer.js in the instance-initializers folder. It also generates a unit test in test/unit/instance-initializers.

The auth instance initializer first retrieves the values registered in the application initializer, as well as the service we have created (app/services/cognito.js). Ember services are referenced using the prefix “service:”. The application-registered values that we registered in the initializer are completely custom (for example “auth:session”). It then injects those dependencies into the applicable service within our instantiated application instance: in this case, our custom cognito service.

Application Components

Within this application we use a service, model, adapter, and serializer to abstract the AWS logic away from the presentation level logic. This allows us to work with data using ember models, while the application adapter and serializer hold AWS-specific back-end logic. This architecture allows us to potentially swap adapters that communicate with different back-ends, or to even load and serialize different types of data (for example JSON vs. XML responses). The serializer takes whatever is retrieved via the adapter and serializes it to a uniform format (based on the extended ember class) for our routes and components to use.

Models, Adapters, and Serializers

The note adapter in this application is specifically tied to the note model, and note serializer. Ember uses this file-level naming convention to determine which components work together. For example, the note model utilizes the note adapter and serializer if the similarly named .js files are found in app/serializers or app/adapters. You can also define an “application” adapter and serializer which serves as a catch-all for any model actions.

You can generate a model by running ember g model myModel, which does not generate an adapter or serializer. You can generate these with ember g serializer|adapter. As long as you name them appropriately, they will are used. Otherwise, the model uses an application adapter or serializer if you generated one.

Data is initially requested via the note route. This route provides the result from the adapters call, serialized, to the Ember component, which in this case is directly used within the view. This model.notes dataset is then sent into the ui-note-list component for use within the view component.

Components and Controllers

Components can reference and call methods on the higher level component or controller that instantiated the component. This abstracts away the model or data level logic, making the component more dynamic and re-usable. Components should never work with models or data. They should work with specific view logic and the data that is provided to them, allowing the components to be more de-coupled and re-usable. Components can also work with services directly.

Components can be generated via the ember-cli ember g component myComponent. This creates an app/components/my-component.js logic file, and an app/templates/components/my-component.hbs view template. Since Ember components adhere to the W3C Custom Elements spec, they require a “-” in their name.

To learn more about developing with Ember, see Guides and Tutorials on the Ember website.

Wrapping up

Using the Hosting and Streaming features of Mobile Hub is a great way to quickly provision a fully functioning back-end for your mobile web application. The application includes end-to-end functionality, including user life-cycle and application state. Using the provided sample should help you get started with building an Ember application. You can make changes to this application and get your site running quickly. You can also use the sample and the Deploy from GitHub Button, like this repository shows, to fork this application and create your own version. Others can use your version to quickly spin up a fully functioning back-ends.