Goal

In this tutorial, we show you how to deploy the Hello World application. We use webpack to bundle the JavaScript and HTML files of our application.

Although webpack is used in this tutorial, you can choose to use other bundlers, such as Rollup or Parcel, in your LuciadRIA application.

Once you have set up the LuciadRIA license loading as explained in the Hello World tutorial, you can use LuciadRIA just as you would use any other third-party library.

Creating a webpack production bundle

In the package.json file within our hello-world project, we add an NPM script to create a production build:

{
  "scripts": {
    "build": "webpack --mode production"
  }
}

Now, we can run the build script:

npm run build

webpack will generate a production version of our application in the dist folder.

You’ll notice that the dist folder now holds an index.html and a main.js file. dist/main.js is different from`src/main.js`, though. The dist/main.js bundle is a lot larger because it contains all JavaScript modules needed to run your application. That includes imported modules from your application’s dependencies, like LuciadRIA. When webpack is run in production mode, it will apply additional optimizations to the bundle, reducing the size of the bundle.

Deploying the application

To deploy the application, just copy the dist folder to your favorite web server for static files, Apache or NGINX for example.

For demonstration purposes, we start a simple NodeJS HTTP server that serves the dist directory.

First, make sure that http-serve is installed on your machine:

npm install -g http-serve

Feel free to uninstall http-serve after you’ve finished the tutorial. You can do so with npm uninstall -g http-serve.

Now, we can start a simple HTTP server that serves our dist directory:

http-serve ./dist -p 8000

When we browse to http://localhost:8000, we should see our Hello World application. We have successfully deployed a production build of our application.

Using your deployment license in production

You must use your deployment license in production mode, but you will probably still want to use your development license for development.

One of the ways to set this up is by defining a webpack module alias for the license file. In production mode, this alias will resolve to your deployment license file. In development, it will resolve to the development license file.

In the Hello World application, open the webpack.config.js file, and find these settings:

module.exports = {
  devServer: {
    contentBase: path.join(__dirname, 'dist')
  },
};

Let’s switch the export configuration so that the command line options are passed in through the argv argument. That allows us to check if we’re running in production mode or not, and set up our license alias accordingly.

module.exports = (env, argv) => {
  const isProduction = argv.mode === "production";
  const riaDeploymentLicense = path.resolve(__dirname, "src/luciadria_deployment.txt");
  const riaDevelopmentLicense = path.resolve(__dirname, "src/luciadria_development.txt");

  return {
    devServer: {
      contentBase: path.join(__dirname, 'dist')
    },
    resolve: {
      alias: {
        "ria-license": isProduction ?  riaDeploymentLicense : riaDevelopmentLicense
      }
    }
  }
};

Next, update the license import in src/license-loader.js:

import {setLicenseText} from "@luciad/ria/util/License";
import license from 'raw-loader!ria-license'; // alias for actual license, see webpack.config.js' resolve.alias

setLicenseText(license);

Now the deployment license file is used in production mode, while the development license file is used during development.

Trading off build times and bundle sizes

In this section we’ll take a look at how we can trade off build time against bundle size, and how our choice of rendering technology affects bundle size.

The configuration updates in this section are optional. The webpack configuration of the previous sections will serve you just fine, because it gives you the most optimal bundle size, but it comes at the cost of longer build times. This section only gives you some insight in how to reduce build time and bundle sizes.

Production builds can take some time to run. This is especially true when you are using WebGLMap, because in comparison it pulls in more code than the non-WebGL Map. Note that each LuciadRIA module is already optimized, so re-optimizing those modules will only result in a minor reduction in bundle size. To speed up our production build, we can set up webpack to skip all, or some, of the optimization of LuciadRIA modules.

Because webpack optimization only works at the level of 'chunks', we’ll put each LuciadRIA module in its own chunk, and tell webpack to skip the optimization of that chunk:

const path = require('path');
const TerserPlugin = require('terser-webpack-plugin');

module.exports = (env, argv) => {
  const isProduction = argv.mode === "production";
  const riaDeploymentLicense = path.resolve(__dirname, "src/luciadria_deployment.txt");
  const riaDevelopmentLicense = path.resolve(__dirname, "src/luciadria_development.txt");

  return {
    devServer: {
      contentBase: path.join(__dirname, 'dist')
    },
    resolve: {
      alias: {
        "ria-license": isProduction ? riaDeploymentLicense : riaDevelopmentLicense
      }
    },
    optimization: {
      splitChunks: {
        cacheGroups: {
          "ria-modules": { // split LuciadRIA into its own chunk
            test: /@luciad.(ria|ria-geometry|ria-milsym)/,
            name: 'ria-modules',
            enforce: true,
            chunks: 'all'
          }
        }
      },
      minimizer: [
        new TerserPlugin({ // disable optimization for the LuciadRIA chunk
          exclude: [/ria-modules/]
        })
      ]
    },
  }
};

If you now run npm run build, you’ll notice that it is dramatically faster. However, the total bundle size is slightly larger than if we had put everything into one big chunk. Instead of doing no optimizations at all on the LuciadRIA chunk, we can choose to only mangle the bundle, and skip the more advanced 'compress' optimizations. This gives us a middle-ground solution between bundle size and production build time:

const path = require('path');
const TerserPlugin = require('terser-webpack-plugin');

module.exports = (env, argv) => {
  const isProduction = argv.mode === "production";
  const riaDeploymentLicense = path.resolve(__dirname, "src/luciadria_deployment.txt");
  const riaDevelopmentLicense = path.resolve(__dirname, "src/luciadria_development.txt");

  return {
    devServer: {
      contentBase: path.join(__dirname, 'dist')
    },
    resolve: {
      alias: {
        "ria-license": isProduction ? riaDeploymentLicense : riaDevelopmentLicense
      }
    },
    optimization: {
      minimizer: [
        new TerserPlugin({ // run the default optimization on non-RIA chunks
          exclude: [/ria-modules/]
        }),
        new TerserPlugin({ // only mangle the RIA chunk
          include: [/ria-modules/],
          terserOptions: {
            mangle: true,
            compress: false
          }
        })
      ],
      splitChunks: {
        cacheGroups: {
          "ria-modules": {
            test: /@luciad.(ria|ria-geometry|ria-milsym)/,
            name: 'ria-modules',
            enforce: true,
            chunks: 'all'
          }
        }
      }
    },
  }
};

We’ll let you choose how you trade off build time against bundle size. In the table below you can see an overview of some build timings and resulting bundle sizes, for the different options. This should give you an idea of how much effect these options have:

Table 1. Overview of build times and bundle sizes for different optimization options
Map type Optimizations Build time Bundle size

Map

Everything in one chunk, all optimizations

8 seconds

1.3MB

Map

Everything in one chunk, only mangle

5 seconds

1.39MB

Map

Split off each LuciadRIA modules in a separate chunk, no optimization

2 seconds

1.88MB

Map

Split off each LuciadRIA modules in a separate chunk, only mangle LuciadRIA

5 seconds

1.41MB

WebGLMap

Everything in one chunk, all optimizations

111 seconds

12.6MB

WebGLMap

Everything in one chunk, only mangle

64 seconds

13.2MB

WebGLMap

Split off each LuciadRIA modules in a separate chunk, no optimization

8 seconds

13.9MB

WebGLMap

Split off each LuciadRIA modules in a separate chunk, only mangle LuciadRIA

61 seconds

13.2MB