Best Practices from Oracle Development's A‑Team

Optimize Oracle JET - Continue

Lyudmil Pelov


It seams to be a lot of interest about my previous article, regarding Oracle JET optimization techniques. In this second post of the same journey I would like to continue with the optimization. As I mention in the previous article it is possible by using the Require JS Optimizer, to reduce the requests to only one CSS file and one JS file for the project. In the previous article I used the Oracle JET Getting Started project and optimized it up to 9 requests. I will continue now with the same project and optimizations and will reduce the JET dependencies to be loaded with only 2 requests.

Main Article

I would continue from the previous state, just to remind you our project now looks with optimizations like this:


We have only 9 requests, however as you can see, there is more we can do here. We will go forward and merge all CSS files into one. Also we will merge the template demoAppHeaderOffCanvasTemplate.tmpl.html into the main.min.js file, as well as the require.js file. On the end we will have to load only one JS and one CSS file to run the project. I will achieve this all by continue using the Require JS Optimizer and only extend the script from my previous blog post.

Note that the approach here is not suitable for all cases. In case you have a big Oracle JET project, you may want to have for the very first load again only one JS file but this file does not necessary has to contains all modules. You can separate the project into sub modules and load them partially. For example imagine that the People tab has complicate functionality which will require more JavaScript code. You can merge this code in separate people.min.js file which you can load once the user clicked on the the People tab. I would go in details for how to make that possible in separate article.

For the purposes of completeness I will again share the complete build file here. Note that the file is now renamed to build-js.js. The reason to do so is that we will have a second separate build file for the CSS files.

The complete modified build-js.js file:

({   insertRequire: false,   baseUrl: 'public/js',   mainConfigFile: 'public/js/main.js',   out: 'public/js/main.min.js',   findNestedDependencies: true,   //optimize: 'none',   optimize: "uglify2",   name: "main",   paths: {     requireLib: 'libs/require/require',     'knockout': 'libs/knockout/knockout-3.3.0',     'jquery': 'libs/jquery/jquery-2.1.3.min',     'jqueryui-amd': 'libs/jquery/jqueryui-amd-1.11.4.min',     'promise': 'libs/es6-promise/promise-1.0.0.min',     'hammerjs': 'libs/hammer/hammer-2.0.4.min',     'ojdnd': 'libs/dnd-polyfill/dnd-polyfill-1.0.0.min',     'ojs': 'libs/oj/v1.1.2/min',     'ojL10n': 'libs/oj/v1.1.2/ojL10n',     'ojtranslations': 'libs/oj/v1.1.2/resources',     'signals': 'libs/js-signals/signals.min',     'text': 'libs/require/text'   },   shim: {     jquery: {       exports: '$'     }   },   include: [     'requireLib',     //'modules/app',     'modules/footer',     'modules/graphics',     'modules/header',     'modules/home',     'modules/library',     'modules/people',     'modules/performance',     'ojs/ojcore',         'knockout',         'jquery',         'ojs/ojrouter',         'ojs/ojknockout',         'ojs/ojbutton',         'ojs/ojtoolbar',         'ojs/ojmenu',         'ojs/ojmodule',     'text!templates/compContent.tmpl.html',     'text!templates/demoAppHeaderOffCanvasTemplate.tmpl.html',     'text!templates/footer.tmpl.html',     'text!templates/graphics.tmpl.html',     'text!templates/header.tmpl.html',     'text!templates/home.tmpl.html',     'text!templates/library.tmpl.html',     'text!templates/navContent.tmpl.html',     'text!templates/people.tmpl.html',     'text!templates/performance.tmpl.html',   ],   bundles: {       "main.min": []   }, })

The notable changes here are following:

  • requireLib: 'libs/require/require' - to merge the require.js file into the main.min.js file, so we don't have to load it separately and spare a request.
  • within the include section, we now have 'requireLib', to indicate that the requirejs dependency will be included and should be loaded from the same location.
  • we now include the template 'text!templates/demoAppHeaderOffCanvasTemplate.tmpl.html' into the main.min.js file as well


Also we need to change the main.js file to use the new partials and to tell the bundles where to find the require JS dependencies. We have to change the requirejs.config bundles:

requirejs.config({   bundles: {     'main.min': [       'require',       //'modules/app',       'modules/footer',       'modules/graphics',       'modules/header',       'modules/home',       'modules/library',       'modules/people',       'modules/performance',           'ojs/ojcore',           'knockout',           'jquery',           'ojs/ojrouter',           'ojs/ojknockout',           'ojs/ojbutton',           'ojs/ojtoolbar',           'ojs/ojmenu',           'ojs/ojmodule',       'text!templates/compContent.tmpl.html',       'text!templates/demoAppHeaderOffCanvasTemplate.tmpl.html',       'text!templates/footer.tmpl.html',       'text!templates/graphics.tmpl.html',       'text!templates/header.tmpl.html',       'text!templates/home.tmpl.html',       'text!templates/library.tmpl.html',       'text!templates/navContent.tmpl.html',       'text!templates/people.tmpl.html',       'text!templates/performance.tmpl.html',     ]   },   // Path mappings for the logical module names   paths: {     'knockout': 'libs/knockout/knockout-3.3.0',     'jquery': 'libs/jquery/jquery-2.1.3.min',     'jqueryui-amd': 'libs/jquery/jqueryui-amd-1.11.4.min',     'promise': 'libs/es6-promise/promise-1.0.0.min',     'hammerjs': 'libs/hammer/hammer-2.0.4.min',     'ojdnd': 'libs/dnd-polyfill/dnd-polyfill-1.0.0.min',     'ojs': 'libs/oj/v1.1.2/min',     'ojL10n': 'libs/oj/v1.1.2/ojL10n',     'ojtranslations': 'libs/oj/v1.1.2/resources',     'signals': 'libs/js-signals/signals.min',     'text': 'libs/require/text'   },   // Shim configurations for modules that do not expose AMD   shim: {     'jquery': {       exports: ['jQuery', '$']     }     /*,'crossroads': {         deps: ['signals'],         exports: 'crossroads'     }*/   },   // This section configures the i18n plugin. It is merging the Oracle JET built-in translation   // resources with a custom translation file.   // Any resource file added, must be placed under a directory named "nls". You can use a path mapping or you can define   // a path that is relative to the location of this main.js file.   config: {     ojL10n: {       merge: {         //'ojtranslations/nls/ojtranslations': 'resources/nls/menu'       }     }   } });

We done here two changes:

  • we add require, to notify the requirejs will be included in the main.min.js
  • we add the 'text!templates/demoAppHeaderOffCanvasTemplate.tmpl.html' template

As I mention we will have also a second build file, which I called build-css.js. We will use it to automatically merge the 3 CSS files. The build file has following content:

({   cssIn: "public/css/override.css",   out: "public/css/override.min.css",   optimizeCss: "standard", })


To make the build-css.js file working, there is one additional change required within the override.css file from the Oracle JET Quick Start project. We have to indicate that we want to import other files, so that the Require JS Optimizer do this job for us. Open the override.css project and on the top of the file add following:

@import url('libs/oj/v1.1.2/alta/oj-alta-min.css'); @import url('demo-alta-patterns-min.css');

You should add the imports at the very top of the file before any custom css class, to make sure that the two css files will be concatenated before your css overrides.

The two builds are ready to execute. To run the build-js.js file, execute from the commend like: r.js -o build-js.js, and you should see following console output:

Tracing dependencies for: main Uglify2 file: /Users/lypelov/development/JET/oraclejetonnodejs/public/js/main.min.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/main.min.js ---------------- /Users/lypelov/development/JET/oraclejetonnodejs/public/js/libs/require/require.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/libs/oj/v1.1.2/ojL10n.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/libs/oj/v1.1.2/resources/nls/ojtranslations.js ojL10n!ojtranslations/nls/ojtranslations /Users/lypelov/development/JET/oraclejetonnodejs/public/js/libs/oj/v1.1.2/min/ojcore.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/libs/knockout/knockout-3.3.0.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/libs/jquery/jquery-2.1.3.min.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/libs/js-signals/signals.min.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/libs/es6-promise/promise-1.0.0.min.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/libs/oj/v1.1.2/min/ojrouter.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/libs/oj/v1.1.2/min/ojknockout.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/libs/jquery/jqueryui-amd-1.11.4.min/core.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/libs/jquery/jqueryui-amd-1.11.4.min/widget.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/libs/oj/v1.1.2/min/ojmessaging.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/libs/oj/v1.1.2/min/ojcomponentcore.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/libs/oj/v1.1.2/min/ojbutton.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/libs/oj/v1.1.2/min/ojtoolbar.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/libs/jquery/jqueryui-amd-1.11.4.min/position.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/libs/oj/v1.1.2/min/ojpopupcore.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/libs/oj/v1.1.2/min/ojmenu.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/libs/oj/v1.1.2/min/ojmodule.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/main.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/modules/footer.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/modules/graphics.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/libs/oj/v1.1.2/min/ojlistview.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/libs/oj/v1.1.2/min/ojnavigationlist.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/libs/hammer/hammer-2.0.4.min.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/libs/oj/v1.1.2/min/ojjquery-hammer.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/libs/oj/v1.1.2/min/ojoffcanvas.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/libs/oj/v1.1.2/min/ojdatacollection-common.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/libs/jquery/jqueryui-amd-1.11.4.min/mouse.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/libs/jquery/jqueryui-amd-1.11.4.min/draggable.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/libs/oj/v1.1.2/min/ojdialog.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/modules/header.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/modules/home.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/modules/library.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/modules/service.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/modules/people.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/modules/performance.js /Users/lypelov/development/JET/oraclejetonnodejs/public/js/libs/require/text.js text!templates/compContent.tmpl.html text!templates/demoAppHeaderOffCanvasTemplate.tmpl.html text!templates/footer.tmpl.html text!templates/graphics.tmpl.html text!templates/header.tmpl.html text!templates/home.tmpl.html text!templates/library.tmpl.html text!templates/navContent.tmpl.html text!templates/people.tmpl.html text!templates/performance.tmpl.html

Then run the build-css.js file run: r.js -o build-css.js, and you should see following console output:

/Users/lypelov/development/JET/oraclejetonnodejs/public/css/override.min.css ---------------- /Users/lypelov/development/JET/oraclejetonnodejs/public/css/libs/oj/v1.1.2/alta/oj-alta-min.css /Users/lypelov/development/JET/oraclejetonnodejs/public/css/demo-alta-patterns-min.css /Users/lypelov/development/JET/oraclejetonnodejs/public/css/override.css

To be able to use the two new files we have to do few changes in in the Oracle JET Quick Start Project. We have to change the index.html file to use the new minified files. First remove the css loads and change to have only one which now should load only the override.min.css.

<link rel="stylesheet" href="css/override.min.css" type="text/css"/>

Also change the way the main.min.js file is loaded to only this:

<script src="js/main.min.js"></script>

We also merge the 'text!templates/demoAppHeaderOffCanvasTemplate.tmpl.html' into the main.min.js file, however if you run the project now you may get following error message:


You get the error message because the template expects to load into a HTML element having the ID app_nav_template, however it is not able to find it. The module is inside the header, which is now injected from the main.min.js file. To fix the issue we will cut following code from the header.tmpl.html file:

<!-- template for rendering app nav data -->             <script type="text/html" id="app_nav_template">                 <li>                     <a href="#">                         <span                             data-bind="css: $data['iconClass']">                         </span>                         <!-- ko text: $data['name'] --> <!--/ko-->                     </a>                 </li>             </script>

... and past it into the index.html file after the header tag, like this:

            <!-- Header section which contains the Global Branding, Global Navigation,             ** and Application Navigation code. Template is located in /templates/header.tmpl.html             -->             <header id="headerWrapper" role="banner" data-bind="ojModule: { name: 'header' }"></header>             <!-- template for rendering app nav data -->             <script type="text/html" id="app_nav_template">                 <li>                     <a href="#">                         <span                             data-bind="css: $data['iconClass']">                         </span>                         <!-- ko text: $data['name'] --> <!--/ko-->                     </a>                 </li>             </script>

Now the project is ready. Open in the browser and you should see following:


That's now a totally different picture. To load the project now we have only one CSS file, the override.min.css, and only one JS file, the main.min.js. From here "some hard core optimizer" could go even one step further and after the optimization of the CSS and the JS file they could even inject the code in the HTML markup returned from the initial page request, the very first from the console above, to reduce the project server round trips to only one. Also the two images loaded could be reduced to one requests by using CSS Sprites.

Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.Captcha

Recent Content