Infrastructure and Tools
What does actually happen when you navigate to a LaxarJS page using the browser?
How does LaxarJS load your widgets, their assets and styles?
And what is the difference between the
index.html in the application template?
Read on to understand the inner workings of a LaxarJS application.
The LaxarJS application template contains a
debug.html which helps to bootstrap you application.
Additionally, there is an
index.html that allows you to run the application using optimized scripts and assets.
Let us dissect the startup process of a LaxarJS application based on the
debug.html, only that we have removed everything that is not absolutely required:
<!DOCTYPE html> <html> <head><!-- ... optional: meta elements, title, page blocker styles go here ... --></head> <body> <div data-ax-page></div> <div data-ng-view></div> <script data-ax-application-mode="DEBUG" src="application/application.js"></script> <script src="require_config.js"></script> <script data-main="../init.js" src="bower_components/requirejs/require.js"></script> </body> </html>
What do the individual elements mean?
* The `axPage` directive determines where LaxarJS will place the layout for the current page. * The `ngView` directive integrates the [$ngRoute](https://docs.angularjs.org/api/ngRoute)-service, which the [LaxarJS flow](./flow_and_pages.md) uses for URL routing. * The `application/application.js` contains the [LaxarJS configuration](./configuration.md) for your application. The `data-ax-application-mode` attribute allows to differentiate configuration between _DEBUG_ and _RELEASE_ mode. It allows you to use bundled CSS, HTML and JSON assets for production, while always using their fresh source version during development. The attribute is not used by LaxarJS itself, but only by the `application.js` which is under your control, so using it is a convention rather than an API. * The `require_config.js` configures paths to libraries for [AMD-loading](http://requirejs.org/docs/whyamd.html). These may be your own libraries or 3rd party libraries installed through [Bower](http://bower.io/). * Finally, [RequireJS](http://requirejs.org) is loaded to bootstrap your application: The `data-main` tells RequireJS where to find the initialization code (`init.js`), which is the entry point to all AMD-modules for your application. AngularJS modules are automatically loaded for any [widgets/activities](./widgets_and_activities.md) and [controls](./providing_controls.md) that are reachable from your [flow](./flow_and_places.md): A LaxarJS grunt task prepares this list whenever you `npm install` your application or `npm start` the development server, so usually you will not to have manage AngularJS modules manually. For production (`grunt optimize`, see below), all RequireJS dependencies are combined and minified by default.
The HTML files in the application template also contain an optional
axPageFade and associated styles.
This creates an overlay that covers your application with a white layer during navigation and then fades out, to may make loading a bit nicer on the eyes.
However, this may not be right for all applications, so feel free to remove the overlay, or replace it with a custom version.
1. The `init.js` collects all AngularJS module dependencies for your application and passes them to `laxar.bootstrap()`. 2. `laxar.bootstrap()` just sets up a logging mechanism and invokes the AngularJS `ng.bootstrap` with the collected dependencies. This sets up your application modules and their dependencies as well as all internal LaxarJS services and `ngRoute`. During initialization, LaxarJS integrates with `ngRoute`, to take over navigation handling. 3. `ngRoute` triggers the LaxarJS _flow controller_ which selects a page from the [flow definition](./flow_and_places.md), based on the current URL. 4. The flow controller instantiates a _page controller_ for the current page. 5. The page controller loads and inserts the page layout and instantiates the controllers for widgets and activities. Also, it loads the widget HTML templates and their CSS (during development). Widgets and activities controllers may already start to make HTTP requests if they need to while the view is being setup. 6. After all controllers are instantiated, the page controller publishes the `beginLifecycleRequest` event to signal that widgets may start publishing events themselves. Now all widget templates are instantiated, inserted into the layout DOM and linked to their controllers' scopes. 7. Finally, the page controller signals to the flow controller that navigation is complete, upon which the flow controller publishes the `didNavigateEvent`. This allows widgets to handle their URL place parameters, and from now on they may publish navigate requests got further navigation.
From this point on, the LaxarJS runtime interacts only through the event bus with widgets and activities. The only exception to this rule is the page teardown caused by navigation, either indirectly through a widget, or directly by changing the URL in the browser.
Before navigating away from a page, widgets receive
endLifecycleRequest events, before their scope is destroyed through the regular AngularJS mechanism.
However, when the user simply closes the browser window, this is not always guaranteed.
If navigating to a new page, the startup process (described above) repeated, starting at step 3.
The File Resource Provider
Internally, LaxarJS uses a single service to provide HTML, CSS and JSON assets used to instantiate widgets and controls: The file resource provider is used to find out if a given template or stylesheet is available for the current theme. It uses file listings (JSON files) to answer these queries without actually going to the web server. File listings also contain bundled resources to avoid HTTP requests in production (not during development). If your application causes a lot of HTTP requests for widget templates and CSS, it is likely due to a misconfiguration of the file listings. The listings are generated by one of the LaxarJS grunt tasks, which are described subsequently.
LaxarJS Development Tools
Most modern single page applications are no longer developed using just a text editor, and instead relies on additional development- and build-tools.
The npm module grunt-laxar provides the tooling to run LaxarJS applications and to optimize their assets.
It consists of several grunt tasks that help to manage the assets and dependencies used by your application, as well as a development server to simplify the development process.
The application template contains a grunt configuration file (
Gruntfile.js) that will work for most scenarios, but feel free to modify the configuration if you would like to add your own tools to the build pipeline.
LaxarJS Grunt Tasks
Following are the most important LaxarJS grunt tasks.
To actually run the tasks, you will usually run one of the short, alias tasks defined to the end of the
Gruntfile.js (see below).
None of the tasks is strictly necessary to develop and run your application, but in concert they go a long way to help reduce boilerplate code and to allow for an optimized user experience.
In other words: you will not want to do without them.
The aliases make sure that task dependencies are observed, plus they are easier to remember and type than the full tasks.
The LaxarJS Development Server
The development server based on Connect middleware helps to run your application without having to setup a full-blown web server. It polls for changes to your widgets and automatically refreshes the browser by injecting a live reload script. By default, the development server runs on port 8000, but this can be configured in the Gruntfile. The directories that are watched for live reload can also be reconfigured. This may be necessary if you are developing a library within in your project, and that library does not belong to a single widget.
As you have seen, the LaxarJS tools provide a lot of useful functionality.
However the runtime does not require that grunt-laxar is installed, it just depends on the right files in the
In fact, when deploying your application to a web server, you should be able to omit the node modules entirely.
This means that nothing stops you from using a different toolchain, say one that is based on gulp.js, as long as it produces the right assets. Hopefully though, the tools provided with LaxarJS serve as a useful stepping stone towards your perfect build process.