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!
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.
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:
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):
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()).
... 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)
... 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.
Yes, but com.inductiveautomation.reporting would be your own module ID, which by convention should be a similar/the same reverse DNS name as your Java package(s) used in your module code.
There's two distributions in the snippet I copied above because one is for the Perspective components added by the reporting module, and one is for the custom React page used as the Reporting module's gateway status page. They are both React, but in different contexts and don't share any common code. If you're not doing anything like that, you probably don't have any need for a second path.
@paul-griffith Hi, could you expand some on the systemjs-config.json file? I’m trying to get hot reloading of the same webui sample project so I can start developing a gateway UI for a module for 8.3.
Running it locally doesn’t really work, I just get an error in the log from IgnitionWebUI, probably since it cant get the data from the gateway for the page. This is how im running it, maybe this is not correct:
npm run run:dev (which then calls)
webpack serve --env isStandalone
Would I use the systemjs-config to point to the localhost:9999 url? I tried and it didnt work. Could you send an example of the systemjs-config?
Update, i was able to get the hot reloading working, at least for it to change the page in the gateway but now I just get
ERROR: Failed to Load
module: the.module.path
Component: HelloIgnition
This is still due to the error with the reading 30
The neutral palette in the debugger is undefined seems to be the cause. I havent changed anything about the webui project yet, so I’m not sure why this error shows up.
You need to change e the root.component.js and add this.
EDIT: had to also change the webpack setting to not use isStandalone, this makes it so you dont get the page in a browser at localhost, but works if you load the json to the gateway. trying to do both probably isnt worth it, but this does what i need
I wouldn't go down the "have webpack serve your files and try to intermingle that into the gateway context" route, I would go down "have webpack watch and continuously build your output into a known directory that the gateway can pick up" route. The latter is what we use internally, the former requires you to blaze your own trail.
Hm, im confused then. I couldnt seem to get this working with local directories. Do you mean I should instead put the path of my generated-resources/mounted folder here?
Can you provide some details on your current project? Are you working on a singleton resource or a list resource?
Looking through the thread, there are a few things I would like to point out. Our systemjs-config file is used for overriding the source location of where we import our web packages from. The example you have looks fine, assuming those are the correct identifiers/names. What you can do is use webpack to create a temporary dev server to serve up those your bundled package. This can be achieved by running webpack serve --port <port-number-here>. The undefined issue you are running into is an issue with modules not being able to access our internal theme’s augmented types. In order to fix that issue include this import at the top of your root component file. import type {} from '@inductiveautomation/ignition-web-ui/typings/Theme';
Hey Ayu, I’m trying to create a Gateway webpage for configuring a module. It’s development tools for Ignition we use internally, hoping to release publicly at some point.
My root.component.js file? I was able to fix the theme issue with the theme provider as above, I cant import types as its a JS file
Hmm. I was under the impression that our SDK example was using Typescript, but it doesn’t look like that’s the case. The undefined issue might be something else. Let me reach out to the team. Thanks.