David Smiley created SOLR-18485:
-----------------------------------
Summary: js-client: build with pure Java, not Node
Key: SOLR-18485
URL: https://issues.apache.org/jira/browse/SOLR-18485
Project: Solr
Issue Type: Improvement
Components: Build, clients - js
Reporter: David Smiley
The Admin UI depends on the OpenAPI-generated JS client
({{libs/solr/index.js}}, global {{solrApi}}) (as of 10.1). Building it is the
only reason the main Solr build needs Node and npm, notwithstanding the
ref-guide. This causes trouble:
* Builds download a native Node distribution and run {{npm install}} against
the npm registry. Both might be blocked or need a proxy in corporate/CI
environments. Gradle's own dependency handling (mirrors, proxies, verification,
offline mode) doesn't apply to them.
* The build has {{-PdisableJsClient=true}}. With that flag set, the *AngularJS
Admin UI silently fails to start* (in 10.1): {{solrApi}} is undefined, so
{{MainController}} can't be created and the page renders raw {{ \{\{ \}\} }}
templates. Downstream builds that set the flag to avoid Node end up shipping a
broken UI.
* *Moreover*: It adds a second, differently-behaving toolchain and dependency
ecosystem to an otherwise pure-JVM build.
Proposal: produce the bundle with pure-Java tooling only, with no Node, no npm
registry and no native binaries. [Google Closure
Compiler|https://github.com/google/closure-compiler] (a pure-Java library)
compiles the generated client. The one runtime JS dependency, superagent, comes
from [mvnpm|https://mvnpm.org] (npm packages published as Maven jars).
h2. Current state
In {{solr/webapp/js-client}}, using the node-gradle plugin:
# {{:solr:api}} generates ES6 sources with openapi-generator's {{javascript}}
generator (Java; unchanged by this proposal).
# {{npm install}} installs the generated {{package.json}} deps: {{superagent}}
at runtime, plus about 20 Babel packages, mocha and sinon.
# {{npm run build}} uses Babel to transpile {{src}} to {{dist}}.
# {{npx browserify dist/index.js -s solrApi}} writes the single-file bundle
that {{:solr:webapp}} puts into the war.
h2. Proposed approach
The bundle becomes the concatenation of two parts:
# *superagent's own prebuilt browser build* ({{dist/superagent.min.js}}), taken
as-is from the {{org.mvnpm:superagent}} jar (non-transitive; a WebJar would
work too). As a plain script it sets the global {{superagent}}.
# *The generated client, compiled by Closure Compiler*
({{com.google.javascript:closure-compiler}}, run with {{JavaExec}}). Closure
only processes the generated ES modules plus two tiny build-generated files:
** a shim that resolves {{import superagent from "superagent"}} to the global:
{{module.exports = globalThis.superagent;}}
** an entry module that keeps the {{solrApi}} global contract that
{{services.js}} relies on: {{import * as api from './src/index.js';
globalThis.solrApi = api;}}
** flags: {{--module_resolution=NODE --process_common_js_modules
--package_json_entry_names=main --dependency_mode=PRUNE --entry_point=entry.js
--compilation_level=SIMPLE --isolation_mode=IIFE
--language_out=ECMASCRIPT_2017}} (or whatever browser baseline the Admin UI
assumes)
Also:
* *Gradle wiring*: keep the existing {{jsClientBundle}} outgoing artifact, so
{{:solr:webapp}} doesn't change.
* *Cleanup*: remove the node-gradle plugin usage and the {{browserify}} version
from the js-client. {{gradle/node.gradle}} stays for the ref guide (Antora) for
now. Consider removing {{disableJsClient}}: once the bundle no longer needs
Node, there's little reason to skip it, and skipping it breaks the (original)
admin UI.
* *Licensing*: superagent (MIT) ships inside the war, so add it to
{{solr/licenses}} and NOTICE as usual. This is an _existing_ policy gap --
it's in the war today.
h2. Spike results
A throwaway spike against branch_10x confirmed the approach:
* Closure compiles the generated client in about 2.5s with no errors. The one
remaining warning is the client's guarded {{require('fs')}}, which is dead code
in browsers.
* The bundle is 332 KB, compared with 1.6 MB (unminified) from Babel+browserify.
* In headless Chrome, the Admin UI starts with no console errors. The rendered
page text matches the npm-built bundle exactly. {{solrApi}} exposes the same
191 exports. Real v2 calls ({{SystemApi.getNodeSystemInfo}},
{{CoresApi.getAllCoreStatus}}) return the same results.
* Rejected alternative: having Closure bundle superagent and its npm dependency
tree from source. Closure ignores object-valued {{browser}} maps and
{{exports}} fields in {{package.json}}, and its CommonJS rewrite breaks
superagent's {{exports = module.exports}} pattern. Using superagent's prebuilt
browser build sidesteps all of this.
h2. Validation
* The existing Selenium Admin UI tests ({{-Ptests.selenium=true}}).
* A clean build with no Node on PATH and no access to the npm registry, with
Gradle offline after the first resolve.
h2. Open questions / risks
* *superagent version*: the generated client asks for {{^5.3.0}}, but mvnpm has
no 5.x (it has 3.8.3, 7.1.6, 10.x). The spike used 7.1.6 successfully. Options:
adopt 7.x or 10.x after the Selenium tests pass, or request that mvnpm sync
5.3.1. Also consider bumping the version openapi-generator emits.
* The generated client's mocha tests aren't run today. Leave them unrun, and
rely on the Selenium tests.
* Out of scope: the ref guide's Antora/Node usage.
🤖 This plan was AI-generated.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]