2 Understand the Web App Workflow

Developing client-side web apps with Oracle JET is designed to be simple and efficient using the development environment of your choice and starter templates to ease the development process.

Oracle JET supports creating web apps from a command-line interface:

  • Before you can create your first Oracle JET web app using the CLI, you must install the prerequisite packages if you haven’t already done so. For details, see Install Oracle JET Tooling.

  • Then, use the Oracle JET command-line interface package (ojet-cli) to scaffold a web app containing either a blank template or a complete pre-configured app that you can modify as needed.

  • After you have scaffolded the app, use the ojet-cli to build the app, serve it in a local web browser, and create a package ready for deployment.

You must not use more than one version of Oracle JET to add components to the same HTML document of your web app. Oracle JET does not support running multiple versions of Oracle JET components in the same web page.

Scaffold a Web App

Use the Oracle JET command-line interface (CLI) to scaffold an app that contains a blank template or one pre-configured Starter Template with a basic layout, navigation bar, or navigation drawer. Each Starter Template is optimized for responsive web apps. Additionally, Starter Templates support TypeScript development should you wish to create your app in TypeScript. After scaffolding, you can modify the app as needed.

Before you can create your first Oracle JET web app using the CLI, you must also install the prerequisite packages if you haven’t already done so. For details, see Install Oracle JET Tooling.

To scaffold an Oracle JET web app:
  1. At a command prompt, enter ojet create with optional arguments to create the Oracle JET app and scaffolding.
    ojet create [directory]
                [--template={template-name:[web]|template-url|template-file}] 
                [--typescript]
                [--use-global-tooling]
                [--help]

    Tip:

    You can enter ojet help at a terminal prompt to get additional help with the Oracle JET CLI.

    For example, the following command creates a web app in the my-web-app directory using the web version of the navbar template:

    ojet create my-web-app --template=navbar

    To scaffold the web app using the same Starter Template but with support for TypeScript version 5.3.2 development, add the --typescript argument to the command:

    ojet create my-web-app --template=navbar --typescript

    To scaffold the web app that will use the globally-installed @oracle/oraclejet-tooling rather than install it locally in the app directory, enter the following command:

    ojet create my-web-app --use-global-tooling 
  2. Wait for confirmation.

    The scaffolding will take some time to complete. When successful, the console displays:

    Oracle JET: Your app is ready! Change to your new app directory my-web-app and try ojet build and serve...
  3. In your development environment, update the code for your app.

    Tip:

    If you selected the blank template during scaffolding, you can still follow the same process to add cookbook samples or other content to your app. However, it will be up to you to create the appropriate view templates or viewModel scripts.

About ojet create Command Options for Web Apps

Use ojet create with optional arguments to create the Oracle JET web app and scaffolding.

The following table describes the available ojet create command options and provides examples for their use.

Option Description

directory

App location. If not specified, the app is created in the current directory. The directory will be created during scaffolding if it doesn’t already exist.

template

Template to use for the app. Specify one of the following:

  • template-name

    Predefined template. You can enter blank, basic, navbar or navdrawer . Defaults to blank if not specified.

  • template-URL

    URL to zip file containing the name of a zipped app: http://path-to-app/app-name.zip.

  • template-file

    Path to zip file on your local file system containing the name of a zipped app: "path-to-app/app-name.zip". For example:
    --template="C:\Users\SomeUser\app.zip"
    --template="/home/users/SomeUser/app.zip"
    --template="~/projects/app.zip"

    If the src folder is present in the zip file, then all content will be placed under the src directory of the app, except for the script folder which remains in the root. If no src folder is present, the contents of the zip file will be placed at the root of the new app.

use-global-tooling

If not specified, the Oracle JET CLI installs the Oracle JET tooling in appRootDir/node_modules/@oracle and the following dev dependency appears in the app's package.json file.

"devDependencies": {
    "@oracle/oraclejet-tooling": "https://.../ojet-dev-local/oracle-oraclejet-tooling-16.0.0.tgz"
  },

If you work with JET apps that use different versions of JET (11.0.0, 10.1.0, and so on), we recommend that you install the JET tooling locally in app.

If you scaffold an app using ojet create my-web-app --use-global-tooling, the scaffolded app uses the globally-installed tooling. On a Windows computer, the globally-installed tooling is in a directory similar to C:\Users\...\AppData\Roaming\npm\node_modules\@oracle\ojet-cli\node_modules\@oracle\oraclejet-tooling.

webpack

Specify --webpack if you want to scaffold an app that uses Webpack. See Use Webpack in Oracle JET App Development.

installer Specify --installer=yarn if you want to scaffold an app using the Yarn package manager rather than the default Node package manager (npm). See Yarn Package Manager.

help

Displays a man page for the ojet create command, including usage and options: ojet create --help.

About Scaffolding a Web App

Scaffolding is the process you use in the Oracle JET command-line interface (CLI) to create an app that contains a blank template or one pre-configured with a basic layout, navigation bar, or navigation drawer. Each pre-configured template is optimized for responsive web apps. After scaffolding, you can modify the app as needed.

The following image shows the differences between the pre-configured Starter Templates. The blank template contains an index.html file but no UI features. The basic:web template is similar to the blank template but adds responsive styling that will adjust the display when the screen size changes. The navbar:web and navdrawer:web templates contain sample content and follow best practices for layout, navigation, and styling that you can also modify as needed.

After scaffolding, you can perform the following tasks to customize your app:

About the Web App File Structure

The Oracle JET scaffolding process creates files and folders that you modify as needed for your app.

The new app will have a directory structure similar to the one shown in the following image.

The app folders contain the app and configuration files that you will modify as needed for your own app.

Directory or File Description

node_modules

Contains the Node.js modules used by the tooling.

scripts

Contains template hook scripts that you can modify to define new build and serve steps for your app. See Customize the Web App Tooling Workflow

src

Site root for your app. Contains the app files that you can modify as needed for your own app and should be committed to source control.

The content will vary, depending upon your choice of template. Each template, even the blank one, will contain an index.html file and a main.js RequireJS bootstrap file.

Other templates may contain view templates and viewModel scripts pre-populated with content. For example, if you specified the navbar template during creation, the js/views and js/viewModels folders will contain the templates and scripts for a web app that uses a nav bar for navigation.

.gitignore

Defines rules for app folders to ignore when using a GIT repository to check in app source. Users who do not use a GIT repository can use ojet strip to avoid checking in content that Oracle JET always regenerates. Note this file must not be deleted since the ojet strip command depends on it.

oraclejetconfig.json

Contains the default source and staging file paths that you can modify if you need to change your app's file structure.

package.json

Defines npm dependencies and project metadata.

After scaffolding, you can perform the following tasks to customize your app:

Modify the Web App’s File Structure

You can modify your scaffolded app’s file structure if the default structure doesn’t meet your needs.

The oraclejetconfig.json file in your app’s top level directory contains the default source and staging file paths that you can modify.

{
  "paths": {
    "source": {
      "common": "src",
      "web": "src-web",
      "hybrid": "src-hybrid",
      "javascript": "js",
      "typescript": "ts",
      "styles": "css",
      "themes": "themes"
    },
    "staging": {
      "web": "web",
      "hybrid": "hybrid",
      "themes": "themes"
    }
  },
  "defaultBrowser": "chrome",
  "sassVer": "8.0.0",
  "defaultTheme": "redwood",
  "architecture": "mvvm",
  "generatorVersion": "16.0.0"
}

Other entries in the oraclejetconfig.json file, such as the value of the architecture property are used by Oracle JET tooling to process the app source appropriately for the app architecture. You should not modify this property's value.

To change the web app’s file structure:

  1. In your app’s top level directory, open oraclejetconfig.json for editing.
  2. In oraclejetconfig.json, change the paths as needed and save the file.

    For example, if you want to change the default styles path from css to app-css, edit the following line in oraclejetconfig.json:

    "styles": "app-css"
  3. Rename the directories as needed for your app, making sure to change only the paths listed in oraclejetconfig.json.
    For example, if you changed styles to app-css in oraclejetconfig.json, change the app’s css directory to app-css.
  4. Update your app files as needed to reference the changed path.

    For example, if you modified the path to the CSS for your app to app-css, update the links appropriately in your app’s index.html.

    <link rel="icon" href="app-css/images/favicon.ico" type="image/x-icon" />
    
        <!-- This is the main css file for the default theme -->
        <!-- injector:theme -->
        <link rel="stylesheet" href="app-css/libs/oj/v16.0.0/redwood/oj-redwood-min.css" type="text/css"/>
        <!-- endinjector -->
  5. At the command prompt, from the app root directory, build your app to use the new paths.
    ojet build

Add Progressive Web App Support to Web Apps

Add Progressive Web App (PWA) support to your JET web app if you want to give users a native-like mobile app experience on the device where they access your JET web app.

Using the ojet add pwa command, you add both a service worker script and a web manifest to your JET web app. You can customize these artifacts to determine how your JET web app behaves when accessed as a PWA.

To add PWA support to your web app:
  1. At a terminal prompt, in your app's top level directory, enter the following command to add PWA support to your JET web app:
    ojet add pwa

When you run the command, Oracle JET tooling makes the following changes to your JET web app:

  • Adds the following two files to the app’s src folder:
    • manifest.json

      This file tells the browser about the PWA support in your JET web app, and how it should behave when installed on a user's desktop or mobile device. Use this file to specify the app name to appear on a user’s device, plus device-specific icons. For information about the properties that you can specify in this file, see Add a web app manifest.

    • sw.js

      This is the service worker script that the browser runs in the background. Use this file to specify any additional resources from your JET app that you want to cache on a user’s device if the PWA service worker is installed. By default, JET specifies the following resources to cache:

      const resourcesToCache = [
        'index.html',
        'manifest.json',
        'js/',
        'css/'
      ];
  • Registers the manifest file and the service worker script in the JET web app's ./src/index.html file:
    <html lang="en-us">
      <head>
      ...
      <link rel="manifest" href="manifest.json">
    </head>
    ...
    <script type="text/javascript">
      if ('serviceWorker' in navigator) {
        navigator.serviceWorker.register('sw.js').then(function(registration) { 
          // Registration was successful 
          console.log('myPWAapp ServiceWorker registration successful with scope: ', registration.scope); 
        }).catch(function(err) {
        // registration failed 
          console.log('myPWAapp ServiceWorker registration failed: ', err);
        });
      }
    </script>
    </body>

With these changes, a user on a mobile device, such as an Android phone, can initially access your JET web app through its URL using the Chrome browser, add it to the Home screen of the device, and subsequently launch it like any other app on the phone. Note that browser and platform support for PWA is not uniform. To ensure an optimal experience, test your PWA-enabled JET web app on your users' target platforms (Android, iOS, and so on) and the browsers (Chrome, Safari, and so on).

PWA-enabled JET web apps and service workers require HTTPS. The production environment where you deploy your PWA-enabled JET web app will serve the app over HTTPS. If, during development, you want to serve your JET web app to a HTTPS-enabled server, see Serve a Web App to a HTTPS Server Using a Self-signed Certificate.

Build a Web App

Use the Oracle JET command-line interface (CLI) to build a development version of your web app before serving it to a browser. This step is optional.

Change to the app’s root directory and use the ojet build command to build your app.

ojet build [--cssvars=enabled|disabled 
            --theme=themename
            --themes=theme1,theme2,...
            --sass]

Tip:

You can enter ojet help at a terminal prompt to get help for specific Oracle JET CLI options.
The command will take some time to complete. If it’s successful, you’ll see the following message:
Done.

The command will also create a web folder in your app’s root to contain the built content.

Note:

You can also use the ojet build command with the --release option to build a release-ready version of your app. For information, see Package Web Apps.

About ojet build Command Options for Web Apps

Use the ojet build command with optional arguments to build a development version of your web app before serving it to a browser.

The following table describes the available options and provides examples for their use.

Option Description

--theme

Theme to use for the app. The theme defaults to redwood.

You can also enter a different themename for a custom theme as described in About CSS Variables and Custom Themes in Oracle JET.

--themes

Themes to include in the app, separated by commas.

If you don’t specify the --theme flag as described above, Oracle JET will use the first element that you specify in --themes as the default theme.

--cssvars

Injects a Redwood theme CSS file that supports working with CSS custom properties when you want to override CSS variables to customize the Redwood theme, as described in About CSS Variables and Custom Themes in Oracle JET.

--sass

Manages Sass compilation. If you add Sass and specify the --theme or --themes option, Sass compilation occurs by default and you can use --sass=false or --no-sass to turn it off.

If you add Sass and do not specify a theme option, Sass compilation will not occur by default, and you must specify --sass=true or --sass to turn it on.

Serve a Web App

Use ojet serve to run your web app in a local web server for testing and debugging. By default, the Oracle JET live reload option is enabled which lets you make changes to your app code that are immediately reflected in the browser.

To run your web app from a terminal prompt:
  1. At a terminal prompt, change to the app’s root directory and use the ojet serve command with optional arguments to launch the app.
    ojet serve [--server-port=server-port-number --livereload-port=live-reload-port-number
                --livereload
                --sass
                --build
                --cssvars=enabled|disabled
                --theme=themename --themes=theme1,theme2,...
                --server-only
               ]
    
    For example, the following command launches your app in the default web browser with live reload enabled.
    ojet serve
  2. Make any desired code change in the src folder, and the browser will update automatically to reflect the change unless you set the --no-livereload flag.

    While the app is running, the terminal window remains open, and the watch task waits for any changes to the app. For example, if you change the content in src/js/views/dashboard.html , the watch task will reflect the change in the terminal as shown below on a Windows desktop.

    Starting watcher...
    Listening on port 35729...
    Server ready: http://localhost:8000
    Watching files....
    Watcher: sass is ready...
    Watcher: sourceFiles is ready...
    Watcher: themes is ready...
    Changed: c:\web-app-navbar\src\js\views\dashboard.html
    Page reloaded resume watching...
    
  3. To terminate the process, close the app and press Ctrl+C at the terminal prompt. You may need to enter Ctrl+C a few times before the process terminates.

The ojet serve command supports a variety of optional arguments that you can use to run the app for specific platforms and with custom themes. Also, when you finish development of your JET app, you use the ojet serve command with the --release option to serve a release-ready version of your app. See Package Web Apps.

To get additional help for the supported ojet serve options, enter ojet serve --help at a terminal prompt.

About ojet serve Command Options and Express Middleware Functions

Use ojet serve to run your web app in a local web server for testing and debugging.

The following table describes the available ojet serve options and provides examples for their use.

Oracle JET tooling uses Express, a Node.js web app framework, to set up and host the web app when you run ojet serve. If the ready-to-use ojet serve options do not meet your requirements, you can add Express configuration options or write Express middleware functions in Oracle JET’s before_serve.js hook point. For an example that demonstrates how to add Express configuration options, see Serve a Web App to a HTTPS Server Using a Self-signed Certificate.

The before_serve hook point provides options to determine whether to replace the existing middleware or instead prepend and append a middleware function to the existing middleware. Typically, you’ll prepend a middleware function (preMiddleware) that you write if you want live reload to continue to work after you serve your web app. Live reload is the first middleware that Oracle JET tooling uses. You must use the next function as an argument to any middleware function that you write if you want subsequent middleware functions, such as live reload, to be invoked by the Express instance. In summary, use one of the following arguments to determine when your Express middleware function executes:

  • preMiddleware: Execute before the default Oracle JET tooling middleware. The default Oracle JET tooling middleware consists of connect-livereload, serve-static, and serve-index, and executes in that order.
  • postMiddleware: Execute after the default Oracle JET tooling middleware.
  • middleware: Replaces the default Oracle JET tooling middleware. Use if you need strict control of the order in which middleware runs. Note that you will need to redefine all the default middleware that was previously added by Oracle JET tooling.
Option Description

server-port

Server port number. If not specified, defaults to 8000.

livereload-port

Live reload port number. If not specified, defaults to 35729.

livereload

Enable the live reload feature. Live reload is enabled by default (--livereload=true).

Use --livereload=false or --no-livereload to disable the live reload feature.

Disabling live reload can be helpful if you’re working in an IDE and want to use that IDE’s mechanism for loading updated apps.

You can also configure the interval at which the live reload feature polls the Oracle JET project for updates by configuring a value for the watchInterval property in the oraclejetconfig.json file. The default value is 1000 milliseconds.

build

Build the app before you serve it. By default, an app is built before you serve it (--build=true).

Use --build=false or --no-build to suppress the build if you’ve already built the app and just want to serve it.

theme

Theme to use for the app. The theme defaults to redwood.

themes

Themes to use for the app, separated by commas.

If you don’t specify the --theme flag as described above, Oracle JET will use the first element that you specify in --themes as the default theme. Otherwise Oracle JET will serve the app with the theme specified in --theme.

server-only

Serves the app, as if to a browser, but does not launch a browser. Use this option in cloud-based development environments so that you can attach your browser to the app served by the development machine.

Serve a Web App to a HTTPS Server Using a Self-signed Certificate

You can customize the JET CLI tooling to serve your web app to a HTTPS server instead of the default HTTP server that the Oracle JET ojet serve command uses.

Do this if, for example, you want to approximate your development environment more closely to a production environment where your web app will eventually be deployed. Requests to your web app when it is deployed to a production environment will be served from an SSL-enabled HTTP server (HTTPS).

To implement this behavior, you’ll need to install a certificate in your web app directory. You’ll also need to configure the before_serve.js hook to do the following:

  • Create an instance of Express to host the served web app.

  • Set up HTTPS on the Express instance that you’ve created. You specify the HTTPS protocol, identify the location of the self-signed certificate that you placed in the app directory, and specify a password.
  • Pass the modified Express instance and the SSL-enabled server to the JET tooling so that ojet serve uses your middleware configuration rather than the ready-to-use middleware configuration provided by the Oracle JET tooling.
  • To ensure that live reloads works when your web app is served to the HTTPS server, you’ll also create an instance of the live reload server and configure it to use SSL.

If you can’t use a certificate issued by a certificate authority, you can create your own certificate (a self-signed certificate). Tools such as OpenSSL, Keychain Access on Mac, and the Java Development Kit’s keytool utility can be used to perform this task for you. For example, using the Git Bash shell that comes with Git for Windows, you can run the following command to create a self-signed certificate with the OpenSSL tool:

openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes

Once you've obtained the self-signed certificate that you want to use, install it in your app's directory. For example, place the two files generated by the previous command in your app’s root directory:

...
.gitignore
cert.pem
key.pem
node_modules
...

Once you have installed the self-signed certificates in your app, you configure the script for the before_serve hook point. To do this, open the AppRootDir/scripts/hooks/before_serve.js with your editor and configure it as described by the comments in the following example configuration.


'use strict';

module.exports = function (configObj) {
  return new Promise((resolve, reject) => {
    console.log("Running before_serve hook.");

    // Create an instance of Express, the Node.js web app framework that Oracle 
    // JET tooling uses to host the web apps that you serve using ojet serve
    const express = require("express");

    // Set up HTTPS 
    const fs = require("fs");
    const https = require("https");
    
    // Specify the self-signed certificates. In our example, these files exist 
    // in the root directory of our project.
    const key = fs.readFileSync("./key.pem");
    const cert = fs.readFileSync("./cert.pem");
    // If the self-signed certificate that you created or use requires a 
    // password, specify it here:
    const passphrase = "1234";

    const app = express();

    // Pass the modified Express instance and the SSL-enabled server to the Oracle JET tooling
    configObj['express'] = app;
    configObj['urlPrefix'] = 'https';
    configObj['server'] = https.createServer({
      key: key,
      cert: cert,
      passphrase: passphrase
    }, app);

    // Enable the Oracle JET live reload option using its default port number so that
    // any changes you make to app code are immediately reflected in the browser after you
    // serve it
    const tinylr = require("tiny-lr");
    const lrPort = "35729";

    // Configure the live reload server to also use SSL
    configObj["liveReloadServer"] = tinylr({ lrPort, key, cert, passphrase });

    resolve(configObj);
  });
};

Once you have completed these configuration steps, run the series of commands (ojet build and ojet serve, for example) that you typically run to build and serve your web app. As the certificate that you are using is a self-signed certificate rather than a certificate issued by a certificate authority, the browser that you use to access the web app displays a warning the first time that you access the web app. Acknowledge the warning and click the options that allow you to access your web app. On Google Chrome, for example, you click Advanced and Proceed to localhost (unsafe) if your web app is being served to https://localhost:8000/.

Once your web app opens in the browser, you'll see that the HTTPS protocol is used and an indicator that the connection is not secure, because you are not using a certificate from a certificate authority. You can also view the certificate information to confirm that it is the self-signed certificate that you created. In Google Chrome, click Not secure and Certificate to view the certificate information.

Description of httpsserver.png follows
Description of the illustration httpsserver.png

The before_serve hook point is one of a series of script hook points that you can use to customize the tooling workflow for Oracle JET apps. See Customize the Web App Tooling Workflow.

Serve a Web App Using Path-based Routing

Oracle JET apps use parameter-based routing by default. With a couple of changes, you can use path-based routing instead.

With parameter-based routing, the URLs that appear in a user’s browser may not be descriptive or easy to remember. For example, a JET app that uses the navbar template displays the following URLs in the browser when served locally:

  • http://localhost:8000/?ojr=dashboard
  • http://localhost:8000/?ojr=incidents

By way of contrast, the same app configured to use path-based routing uses the following URLs when the app displays the Dashboard or Incidents page:

  • http://localhost:8000/dashboard
  • http://localhost:8000/incidents

To implement this behavior, you need to configure the JET app so that when it receives a request from the client for a page, it rewrites the URL before it serves the request. Specifically, you’ll need to do the following:

  • Update the appController.js file so that your app uses path-based routing by creating an instance of the UrlPathAdapter class that takes the base URL from which the app is served as a parameter.
  • Configure the before_serve.js hook to do the following:
    • Write an Express function to inspect the path of the requested URL. If the request is for any of the typical file extensions (.js, .ts, and so on), the Express instance handles these requests while other requests are passed to the app's index.html file for JET's CoreRouter to manage.
    • Invoke the Express middleware function that you write using the before_serve.js hook point’s configObj['preMiddleware'] option so that the new Express middleware function is invoked before the default middleware used by Oracle JET tooling, such as live reload.

To update the appController.js file so that your app uses path-based routing, open the AppRootDir/src/js/appController.js with your editor and configure it as described by the comments in the following example configuration.


// Replace the entries that the JET tooling generates for 'ojs/ojurlparamadapter' and UrlParamAdapter 
// with entries for 'ojs/ojurlpathadapter' and UrlPathAdapter
define(... 'ojs/ojurlpathadapter', 'ojs/ojarraydataprovider', 'ojs/ojknockouttemplateutils', 'ojs/ojmodule-element', 'ojs/ojknockout'],
  function(... UrlPathAdapter, ArrayDataProvider, KnockoutTemplateUtils) {   
....
let baseUrl = "/";
       let router = new CoreRouter(navData, {
        urlAdapter: new UrlPathAdapter(baseUrl)
      });
      router.sync();
....

To configure the script for the before_serve hook point, open the AppRootDir/scripts/hooks/before_serve.js with your editor and configure it as described by the comments in the following example configuration.


'use strict';

module.exports = function (configObj) {

    /* Write an Express middleware function to inspect the path of the requested 
    URL. If the request is for any of the extensions (js, ts, and so on), 
    the Express instance handles these requests while other requests are
    passed to the app’s index.html file for the JET CoreRouter to manage. 
    */
  function urlRewriteMiddleware(req, res, next) {
    const matchStaticFiles = req.url.match(/\/(js|css)\/.*/);
    req.url = matchStaticFiles ? matchStaticFiles[0] : '/index.html';
    next();
  }
  return new Promise((resolve, reject) => {
    /* Call the Express middleware function that inspects the URL to rewrite 
       and prepend it to JET’s default middleware so that other options provided 
       by JET’s default middleware, such as live reload continue to work. 
    */	    	
    configObj['preMiddleware'] = [urlRewriteMiddleware]
    resolve(configObj);
  });
};

Customize the Web App Tooling Workflow

Hook points that Oracle JET tooling defines let you customize the behavior of the JET build and serve processes when you want to define new steps to execute during the tooling workflow using script code that you write.

When you create an app, Oracle JET tooling generates script templates in the /scripts/hooks app subfolder. To customize the Oracle JET tooling workflow, you can edit the generated templates with the script code that you want the tooling to execute for specific hook points during the build and serve processes. If you do not create a custom hook point script, Oracle JET tooling ignores the script templates and follows the default workflow for the build and serve processes.

To customize the workflow for the build or serve processes, you edit the generated script template file named for a specific hook point. For example, to trigger a script at the start of the tooling's build process, you would edit the before_build.js script named for the hook point triggered before the build begins. That hook point is named before_build.

Therefore, customization of the build and serve processes that you enforce on Oracle JET tooling workflow requires that you know the following details before you can write a customization script.

  • The Oracle JET build or serve mode that you want to customize:

    • Debug — The default mode when you build or serve your app, which produces the source code in the built app.

    • Release — The mode when you build the app with the --release option, which produces minified and bundled code in a release-ready app.

  • The appropriate hook point to trigger the customization.

  • The location of the default hook script template to customize.

About the Script Hook Points for Web Apps

The Oracle JET hooks system defines various script trigger points, also called hook points, that allow you to customize the create, build, serve, package, and restore workflow across the various command-line interface processes. Customization relies on script files and the script code that you want to trigger for a particular hook point.

The following table identifies the hook points and the workflow customizations they support in the Oracle JET tooling create, build, serve, and restore processes. Unless noted, hook points for the build and serve processes support both debug and release mode.

Hook Point Supported Tooling Process Description

after_app_create

create

This hook point triggers the script with the default name after_app_create.js immediately after the tooling concludes the create app process.

after_app_restore

restore

This hook point triggers the script with the default name after_app_restore.js immediately after the tooling concludes the restore app process.

before_build

build

This hook point triggers the script with the default name before_build.js immediately before the tooling initiates the build process.

before_release_build

build (release mode only)

This hook point triggers the script with the default name before_release_build.js before the minification step and the requirejs bundling step occur.

before_app_typescript

build / serve

This hook point triggers the script with the default name before_app_typescript.js after the build process or serve process steps occur and before the app is transpiled. Use the hook to update, add or remove TypeScript compiler options defined by your app's tsconfig.json compiler configuration file. The hook system passes your reference to the modified tsconfig object to the TypeScript compiler. A script for this hook point can only be used with a TypeScript app.

after_app_typescript

build / serve

This hook point triggers the script with the default name after_app_typescript.js after the build process or serve process steps occur and immediately after the before_app_typescript hook point executes. This hook provides an entry point for apps that require further processing, such as compiling generated .jsx output using babel. A script for this hook point can only be used with a TypeScript app.

before_component_typescript

build / serve

This hook point triggers the script with the default name before_component_typescript.js after the build process or serve process steps occur and before the component is transpiled. Use the hook to update, add or remove TypeScript compiler options defined by your app's tsconfig.json compiler configuration file. The hook system passes your reference to the modified tsconfig object to the TypeScript compiler. A script for this hook point can only be used with a TypeScript app.

after_component_typescript

build / serve

This hook point triggers the script with the default name after_component_typescript.js after the build process or serve process steps occur and immediately after the before_component_typescript hook point executes. This hook provides an entry point for apps that require further processing, such as compiling generated .jsx output using babel. A script for this hook point can only be used with a TypeScript app.

before_injection

build / serve

This hook point triggers the script with the default name before_injection.js after the tooling concludes the before build process and before the tooling performs the tasks to insert the CSS theme into the app. In other words, this hook point provides an entry point to customize the main.js/index.html/theme injection process in the build.

before_optimize

build / serve (release mode only)

This hook point triggers the script with the default name before_optimize.js before the release mode build/serve process minifies the content.

before_component_optimize

build / serve

This hook point triggers the script with the default name before_component_optimize.js before the build/serve process minifies the content. A script for this hook point can be used to modify the build process specifically for a project that defines a Web Component.

after_build

build

This hook point triggers the script with the default name after_build.js immediately after the tooling concludes the build process.

after_component_create

build

This hook point triggers the script with the default name after_component_create.js immediately after the tooling concludes the create Web Component process. A script for this hook point can be used to modify the build process specifically for a project that defines a Web Component.

after_component_build

build (debug mode only)

This hook point triggers the script with the default name after_component_build.js immediately after the tooling concludes the Web Component build process. A script for this hook point can be used to modify the build process specifically for a project that defines a Web Component.

before_serve

serve

This hook point triggers the script with the default name before_serve.js before the web serve process connects to and watches the app.

after_serve

serve

This hook point triggers the script with the default name after_serve.js after all build process steps complete and the tooling serves the app.

before_watch

serve

This hook point triggers the script with the default name before_watch.js after the tooling serves the app and before the tooling starts watching for app changes.

after_watch

serve

This hook point triggers the script with the default name after_watch.js after the tooling starts the watch and after the tooling detects a change to the app.

after_component_package package This hook point triggers the script with the default name after_component_package.js immediately after the tooling concludes the component package process.
before_component_package package This hook point triggers the script with the default name before_component_package.js immediately before the tooling initiates the component package process.

About the Process Flow of Script Hook Points

The Oracle JET hooks system defines various script trigger points, also called hook points, that allow you to customize the create, build, serve, and restore workflow across the various command-line interface processes.

The following diagram shows the script hook point flow for the create process.

This image shows the create process hook points for an application and for a component.

The following diagram shows the script hook point flow for the build process.

This image shows the build process hook points for an application and for a component.

The following diagram shows the script hook point flow for the serve and restore processes.

This image shows the serve and restore process hook points for an application and for a component.

Change the Hooks Subfolder Location

When you create an app, Oracle JET tooling generates script templates in the /scripts/hooks app subfolder. Your development effort may require you to relocate hook scripts to a common location, for example to support team development.

By default, the hooks system locates the scripts in the hooks subfolder using a generated JSON file (hooks.json) that specifies the script paths. When the tooling reaches the hook point, it executes the corresponding script which it locates using the hooks.json file. If you relocate hook script(s) to a common location, you must edit the hooks.json file to specify the new location for the hook scripts that you relocated, as illustrated by the following example.

{
    "description": "OJET-CLI hooks configuration file",
    "hooks": {
        "after_app_create": "scripts/hooks/after_app_create.js",
	...
        "after_serve": "http://example.com/cdn/common/scripts/hooks/after_serve.js "
    }
}

Create a Hook Script for Web Apps

You can create a hook point script to define a new command-line interface process step for your web app. To create a hook script, you edit the hook script template associated with a specific hook point in the tooling build and serve workflow.

The Oracle JET hooks system defines various script trigger points, also called hook points, that allow you to customize the build and serve workflow across the various build and serve modes. Customization relies on script files and the script code that you want to trigger for a particular hook point. Note that the generated script templates that you modify with your script code are named for their corresponding hook point.

To customize the workflow for the build or serve processes, you edit the generated script template file named for a specific hook point. For example, to trigger a script at the start of the tooling's build process, you would edit the before_build.js script named for the hook point triggered before the build begins. That hook point is named before_build.

A basic example illustrates a simple customization using the before_optimize hook, which allows you to control the RequireJS properties shown in bold to modify the app's bundling configuration.

requirejs.config(
{
  baseUrl: "web/js",
  name: "main-temp",
  paths: {
  // injector:mainReleasePaths
    "knockout":"libs/knockout/knockout-3.x.x.debug",
    "jquery":"libs/jquery/jquery-3.x.x",
    "jqueryui-amd":"libs/jquery/jqueryui-amd-1.x.x",
     ...
  }
  // endinjector
  out: "web/js/main.js"
}
...

A script for this hook point might add one line to the before_optimize script template, as shown below. When you build the app with this customization script file in the default location, the tooling triggers the script before calling requirejs.out() and changes the out property setting to a custom directory path. The result is that the app-generated main.js is created in the named directory instead of the default web/js/main.js location.

module.exports = function (configObj) {
  return new Promise((resolve, reject) => {
    console.log("Running before_optimize hook.");
    configObj.requirejs.out = 'myweb/js/main.js';
    resolve(configObj);
  });
};

You can retrieve more information about the definition of configObj that is passed into many script hook points as a parameter by making the following modification in one of the build-related hook points and then running ojet build. For example, the before_build.js hook point can be modified as follows:

module.exports = function (configObj) {
  return new Promise((resolve, reject) => {
  	console.log("Running before_build hook.", configObj);
  	resolve(configObj);
   });
};

The console from where you run the ojet build command then displays the available options that you can customize in configObj.

Cleaning staging path.
Running before_build hook {
  buildType: 'dev',
  opts: {
    stagingPath: 'web',
    injectPaths: {
      startTag: '// injector:mainReleasePaths',
. . . 

Elsewhere, read examples that illustrate how to use the configObj to customize a hook point to, for example, add Express configuration options or write Express middleware functions in the before_serve.js hook point if the ready-to-use ojet serve options do not meet your requirements. See Serve a Web App to a HTTPS Server Using a Self-signed Certificate and Serve a Web App Using Path-based Routing.

Tip:

If you want to change app path mappings, it is recommended to always edit the path_mappings.json file. An exception might be when you want app runtime path mappings to be different from the mappings used by the bundling process, then you might use a before_optimize hook script to change the requirejs.config paths property.

The following example illustrates a more complex build customization using the after_build hook. This hook script adds a customize task after the build finishes.

'use strict’;

const fs = require('fs');
const archiver = require('archiver');

module.exports = function (configObj) {
  return new Promise((resolve, reject) => {
   console.log("Running after_build hook.");

    //Set up the archive
    const output = fs.createWriteStream('my-archive.war');
    const archive = archiver('zip');

    //Callbacks for the archiver
    output.on('close', () => {
      console.log('Files were successfully archived.');
      resolve();
    });
  
    archive.on('warning', (error) => {
      console.warn(error);
    });
  
    archive.on('error', (error) => {
      reject(error);
    });
  
    //Archive the web folder and close the file
    archive.pipe(output);
    archive.directory('web', false);
    archive.finalize();
  });
};

In this example, assume the script templates reside in the default folder generated when you created the app. The goal is to package the app into a ZIP file. Because packaging occurs after the app build process completes, this script is triggered for the after_build hook point. For this hook point, the modified script template after_build.js will contain the script code to ZIP the app, and because the .js file resides in the default location, no hooks system configuration changes are required.

Tip:

Oracle JET tooling reports when hook points are executed in the message log for the build and serve process. You can examine the log in the console to understand the tooling workflow and determine exactly when the tooling triggers a hook point script.

Pass Arguments to a Hook Script for Web Apps

You can pass extra values to a hook script from the command-line interface when you build or serve the web app. The hook script that you create can use these values to perform some workflow action, such as creating an archive file from the contents of the web folder.

You can add the --user-options flag to the command-line interface for Oracle JET to define user input for the hook system when you build or serve the web app. The --user-options flag can be appended to the build or serve commands and takes as arguments one or more space-separated, string values:
ojet build --user-options="some string1" "some string2" "some stringx"
For example, you might write a hook script that archives a copy of the build output after the build finishes. The developer might pass the user-defined parameter archive-file set to the archive file name by using the --user-options flag on the Oracle JET command line.
ojet build web --user-options="archive-file=deploy.zip"
If the flag is appended and the appropriate input is passed, the hook script code may write a ZIP file to the /deploy directory in the root of the project. The following example illustrates this build customization using the after_build hook. The script code parses the user input for the value of the user defined archive-file flag with a promise to archive the app after the build finishes by calling the NodeJS function fs.createWriteStream(). This hook script is an example of taking user input from the command-line interface and processing it to achieve a build workflow customization.
'use strict';
const fs = require('fs');
const archiver = require('archiver');
const path = require('path');

module.exports = function (configObj) {
  return new Promise((resolve, reject) => {
    console.log("Running after_build hook.");

    //Check to see if the user set the flag 
    //In this case we're only expecting one possible user defined
    //argument so the parsing can be simple
    const options = configObj.userOptions;
    if (options){
      const userArgs = options.split('=');
      if (userArgs.length > 1 && userArgs[0] === 'archive-file'){
        const deployRoot = 'deploy';
        const outputArchive = path.join(deployRoot,userArgs[1]);

        //Ensure the output folder exists
        if (!fs.existsSync(deployRoot)) {
          fs.mkdirSync(deployRoot);
        }

        //Set up the archive
        const output = fs.createWriteStream(outputArchive);
        const archive = archiver('zip');

        //callbacks for the archiver
        output.on('close', () => {
          console.log(`Archive file ${outputArchive} successfully created.`);
          resolve();
        });

        archive.on('error', (error) => {
          console.error(`Error creating archive ${outputArchive}`);
          reject(error);
        });

        //Archive the web folder and close the file
        archive.pipe(output);
        archive.directory('web', false);
        archive.finalize();
      }
      else {
        //Unexpected input - fail with information message
        reject(`Unexpected flags in user-options: ${options}`);
      }
    }
    else {
  	//nothing to do
  	resolve();
    }
  });
};

Use Webpack in Oracle JET App Development

You can use Webpack to manage your Oracle JET app, as well as the build and serve tasks.

If you decide to use Webpack, Oracle JET passes responsibility to Webpack to build and serve the source files of your Oracle JET project. Before you decide to use Webpack, note that it is not possible to use Webpack with Oracle JET apps that need to build, package or publish web components.

If you decide to use Webpack in your Oracle JET app, you can specify it as a command-line argument when you scaffold the project, as demonstrated by the following example command:

ojet create <app-name> --template=basic --webpack

To build and serve the app with Webpack, simply run ojet build and ojet serve respectively. You cannot use the ojet serve --release command. To run a release build from your local development environment, use the ojet build --release command, and then use a static server of your choice (for example, http-server) from the /web folder.

To add Webpack to an existing Oracle JET app, run the following command from the root directory of your Oracle JET project:

ojet add webpack

The files and directories in an Oracle JET project that uses Webpack differ to a project an app generated without specifying the --webpack argument. The following table describes the differences that result from use of the --webpack argument.

Option Description

ojet.config.js

This file manages Oracle JET's default webpack configuration. For more detail about this file and how to configure it, see Configure Oracle JET's Default Webpack Configuration.

tsconfig.json

In constrast to the tsconfig.json generated for apps without Webpack, the esModuleInterop and resolveJsonModule flags are set to true. The esModuleInterop flag allows apps to standardize on default imports for all module types. Calls such as import * as <importName> from "path/to/import" should be written as import <importName> from "path/to/import". The resolveJsonModule flag allows apps to directly import JSON files. Paired with Webpack's automatic support for resolving JSON file imports, you do not have to use the RequireJs text! plugin followed by JSON.parse to consume JSON files in the Oracle JET app.

As mentioned at the start of this topic, it is not possible to use Webpack in Oracle JET projects that build, package or publish web components, or projects that need use JET theming. In other words, this means that you cannot use the following commands from the Oracle JET CLI:

  • ojet build (component|pack)
  • ojet package (component|pack)
  • ojet publish (component|pack)

One other thing to note is that when you serve your Oracle JET app in development mode (the default), the Oracle JET app loads styles from memory and styles appear in the <styles> tag in the HTML of your browser. In contrast, when you serve an Oracle JET app that you have built in release mode (ojet build --release), styles come from the CSS file link that is included in the HTML file. In the following image, with an Oracle JET app instance that runs in development mode and release mode instance, you can see the different entries using the browser’s developer tools.


CSS references in development and release mode

Configure Oracle JET's Default Webpack Configuration

You can configure the default Webpack configuration generated by the Oracle JET CLI through the webpack function in the ojet.config.js file.

The webpack function receives an object with the Oracle JET build context (context) and Webpack configuration (config). Note the buildType property which indicates whether Webpack executes in development or release mode. As for config, the default Webpack configuration generated by Oracle JET, you can customize it to fit your needs.

To view the default options in the ojet.config.js file, add a console log statement to the ojet.config.js file, as demonstrated by the following examples:

. . .
webpack: ({ context, config }) => {
  if (context.buildType === "release") {
    // update config with release / production options
  } else {
    // Print out the default webpack configuration options 
    // as a JSON string
    console.log(JSON.stringify(config));
    // Or let your terminal console determine how to 
    // present the configuration
    console.log(config);
  }
. . .

Then build your Oracle JET project using the following command to render the default configuration in the terminal console:

ojet build

Tip:

Create a JSON-formatted file in Visual Studio Code to view the default configuration in a more readable form to that returned by the terminal.

The default Webpack configuration for an Oracle JET app built in development mode includes the following top-level nodes:

{
  "entry": { },
  "output": { },
  "module": {},
  "resolve": {},
  "resolveLoader": {    },
  "plugins": [],
  "mode": "development",
  "devServer": { }
}

Once you have identified the configuration setting in Oracle JET's default Webpack configuration that you want to change, you add the alternative value in the ojet.config.js file. The following example illustrates how to change the port number when you serve your Oracle JET app in development mode using Webpack.

module.exports = {

  webpack: ({ context, config }) => {
    if (context.buildType === 'release') {
      // update config with release / production options
    } else {

      // update config with development options. In the following example, we specify
      // a different server port number to the default of 8000
      config.devServer.port = 3000;
	
     // Print out the default webpack configuration options as a JSON string
     console.log(JSON.stringify(config));
     // Or let your terminal console determine how to present the configuration
     console.log(config);
    }
    return config;
  }
};