A CRA-eject upgraded to Webpack 5 with MMGIS-specific patches for Cesium and Node-core polyfills, fed by a pre-build code-generation step that scans plugin-drop directories.
In development the SPA is on PORT+1 (8889) while Express is on PORT (8888) — opening the wrong port loads the shell but never finishes booting Essence.
The plugin manifest is a generated, gitignored file (src/pre/tools.js) — drop in a new plugin directory and you must restart the build, since webpack only sees what was generated before it ran.
What this is
configuration/webpack.config.js is a forked Create-React-App eject that has been
upgraded to Webpack 5. The CRA hallmarks are everywhere: react-dev-utils helpers,
babel-preset-react-app, the oneOf rule list, ModuleScopePlugin, the
getStyleLoaders helper, and the paths.js / modules.js / env.js triplet. Read
this with that lineage in mind — most of the file is stock CRA, and the interesting
edits are MMGIS-specific patches.
The notable MMGIS additions to the otherwise-vanilla config:
- A
crypto.createHashshim that rewritesmd4tosha256so the config runs on Node 18+. ModuleScopePluginallow-listingnode_modules/cesium( imports Cesium CSS and source).CopyWebpackPlugincopying Cesium'sWorkers,ThirdParty,Assets, andWidgetsintostatic/cesium/, plus aDefinePluginsettingCESIUM_BASE_URL.resolve.fallbackdisabling Node core polyfills (Webpack 5 no longer auto-shims them) and amarkjsalias to the jQuery build.- An
--analyzeflag that turns onBundleAnalyzerPluginin dev.
This config bundles the main Essence app only. The Configure admin SPA
ships its own webpack pipeline under configure/.
scripts/build.js vs the dev server
scripts/build.js is the production-build entry, run via npm run build. It calls
updateTools() and updateComponents() (see below) to regenerate the dynamic
plugin manifests, empties build/, copies public/, then drives a one-shot
webpack(config).run(...). After compilation it generates a build/index.pug
copy of the HTML for the Express server's view layer.
Development is different: npm start runs scripts/server.js, which — when
NODE_ENV !== 'production' — instantiates WebpackDevServer from
configuration/webpackDevServer.config.js alongside the Express API. There is no
separate react-scripts start equivalent; the dev server lives inside the
backend process.
Dual-port dev convention
In development, MMGIS runs on two ports (README §Quick Start):
PORT(default8888) — the Express server. Hosts/configure,/docs, the API under/api, and other ancillary pages.PORT + 1(default8889) — the WebpackDevServer. Hosts the Essence SPA with HMR.
This is hard-coded in webpackDevServer.config.js:
const port = parseInt(process.env.PORT || "8888", 10);
return { port: port + 1, /* ... */ };
The onListening log message reflects the split: the SPA is at :8889, "the rest
of the pages" at :8888. Production collapses both onto the single Express port
serving the static build/.
paths.js, modules.js, env.js
Stock CRA scaffolding, lightly customized:
paths.jscentralizes filesystem locations (appBuild,appPublic,appHtml,appIndexJs = src/index,appSrc = src/, etc.) and computespublicUrlOrPathfrompackage.json#homepage("build").modules.jsreadstsconfig.json/jsconfig.json, derives webpackadditionalModulePathsandwebpackAliasesfrom anybaseUrl, and exposes them to the main config.env.jsloads the.env*cascade and, ingetClientEnvironment, picks up everyREACT_APP_*variable plus a curated MMGIS allow-list (AUTH,VERSION,HOSTS,WITH_TITILER,MAIN_MISSION, …) and stringifies them forwebpack.DefinePlugin. That allow-list is the canonical answer to "which env vars reach the browser?"
Plugin glob loading
The plugin system is not implemented in webpack itself — it is implemented in
API/updateTools.js, called from scripts/build.js before compilation. Two
functions, identical in shape:
updateTools()scanssrc/essence/for any directory matching*Private-Tools*or*Plugin-Tools*, reads each child tool'sconfig.json, merges them with the built-in tools undersrc/essence/Tools/, sorts bytoolbarPriority, and writes the merged set tosrc/pre/tools.jsas a generated module ofimportstatements plus exportedtoolConfigs/toolModulesmaps.updateComponents()does the same for*Private-Components*/*Plugin-Components*, generatingsrc/pre/components.js.
Webpack then bundles src/pre/tools.js and src/pre/components.js like any
other source. The "plugin manifest" is therefore a code-generation step that
runs before webpack, not a runtime registry. See Mapping tools
for how the core runtime consumes these
generated maps. Both generated files are gitignored.
The main MMGIS browser app, under src/essence/. Bundled by the custom Webpack
pipeline. Not an idiomatic React app — a hybrid of jQuery-era imperative modules and
React 16 islands.
How Essence boots, wires up the global L_ map state, manages the panel layout, and switches between Leaflet (2D), Cesium-based Globe (3D), and the image Viewer.
Related
- Frontend (Essence) — Core runtime and map enginesHow Essence boots, wires up the global L_ map state, manages the panel layout, and switches between Leaflet (2D), Cesium-based Globe (3D), and the image Viewer.
- Frontend (Essence) — Mapping toolsSelf-contained tool modules (Draw, Measure, Layers, Identifier, …) loaded by the ToolController, plus the plugin-drop convention used to add new ones.
- Configure (admin SPA)A separate React app served at /configure for managing missions, layers, datasets, and users. Has its own webpack build.