Hot Reloading / Faster Iteration for Module React UI Development

Hello,

I’m currently developing a React UI for my module and was wondering if there’s a way to enable hot reloading (or a similar workflow for faster iteration).

I noticed that the package.json in the example web-ui project includes a dev server script alias:

"run:dev": "webpack serve --env isStandalone"

However, running this in my own repository doesn’t seem to do anything.

At the moment, I have to recompile the module, install it, and restart Ignition every time I make a change to the UI. I can’t imagine this is how UI development is done internally, so I’m hoping there’s a more efficient approach I can take.

Any tips or guidance on how to improve this workflow would be greatly appreciated!

1 Like

If you run your gateway with a system property override (e.g. via wrapper.java.additional in the ignition.conf file) following a format of res.path.moduleID, pointing to a semicolon delimited list of absolute file paths, the module's contained resources will be skipped and we'll go directly to those paths to try to load contained resources.

That's a long sentence, but tl;dr:
-Dres.path.com.inductiveautomation.reporting=/Users/pgriffith/Projects/ignition-81/Modules/reporting/web/reporting-components/build/dist;/Users/pgriffith/Projects/ignition-81/Modules/reporting/web/status/build/dist

The folder(s) you point to must match the final structure that would be delivered in your module's return from getMountedResourceFolder call.

Also, all this is different in 8.3. I can explain that in another post.

1 Like

Thanks for the response. I realize I should have clarified that my module is targeting 8.3. Would you be able to share how this behavior differs in 8.3?

Ah, actually, looks like the 8.3 solution is backwards compatible with the override format from 8.1 - so the same working code should apply. The 'new' thing that I was aware of but hadn't studied in depth is two new parameters:

-Dignition.gateway.resourceOverrideFile=/Users/pgriffith/Projects/ignition/config/resources/resource-config.json
-Dignition.gateway.systemJsOverrideFile=/Users/pgriffith/Projects/ignition/config/resources/systemjs-config.json

But they're an intermediary looked at after checking the res.path.moduleId, per internal documentation (reproduced below) so I would just continue using the 8.1 style.

/config/resources files

This directory contains files that can be specified to override various default behaviors about how resources are loaded
at runtime. These files are not part of the build - they are used in the development environment only, and not
distributed
.

resource-config.json

Specify this file using -Dignition.gateway.resourceOverrideFile=<filepath>
This file is used by the ResourceServlet to override resource loading logic. The ResourceServlet loads files using the
following three methods (in reverse order of precedence):

  1. Normally, resources are loaded by the
    classloader, because they are embedded in production jar files. So, if a request comes in for /res/module-id/filename
    the servlet will ask module-id's classloader to look for mounted/filename.
    (See GatewayModuleHook.getMountedResourceFolder()).
  2. ... unless there is a system property -Dignition.gateway.resourceOverrideFile= specified, and that file contains an entry for
    module-id in it, which points to a spot on the local disk. Then the ResourceServlet will look for the file in
    that local folder instead (new since 8.3.0)
  3. ... unless there is a System property like -Dres.path.module-id=<path/to/local/folder>. In this case,
    ResourceServlet will load the resource /res/module-id/filename from new File("path/to/local/folder/filename")

So, in summary, the location of a resource will first honor the -Dres.path.module-id system property, if specified.
If not, it will look in the file at -Dignition.gateway.resourceOverrideFile, if specified. If not, it will have the resource load
from the classloader.

systemjs-config.json

Specify this file using -Dignition.gateway.systemJsOverrideFile=<filepath>
This file will be used by the WebUIServlet when generating the
import map that is embedded in the main page that
mounts the 8.3+ react-based web ui for the gateway.

Normally, the URLs for the systemjs modules (fancy term for a named javascript file) are registered by modules and the
platform using the SystemJsModuleRegistry class which can be found on the gateway context's WebResourceManager.

Using this file and the "imports" key, one can override the URLs for each named module. Reasons one might want to do
this:

  • The module may be being watched, built, and hosted at localhost:some-port by the webpack
    dev-server. By specifying this alternate location, the developer has faster hot-reloading.
  • It may be that a minified, production version of the js module is embedded into the platform or module, but during
    development, a non-minified or "development" build is more convenient. The URL to the dev version of the module (which)
    may be hosted on a CDN) can be specified instead.

Using the "scripts" key, one can override the default scripts that are placed directly on the page.