Skip to content

Commit ee4eba5

Browse files
authored
feat: @deephaven/jsapi-nodejs loadDhModules() util (#2392)
DH-19067: Added a `loadDhModules()` function to simplify common usage. Also updated @deephaven/jsapi-nodejs README to reflect latest api. ### Testing I deployed an alpha and tested the changes in a sample repo: bmingles/deephaven-nodejs-experiments#1 Once the changes have been released, I plan to update VS Code extension to use the new apis as well
1 parent 99dfcab commit ee4eba5

4 files changed

Lines changed: 88 additions & 11 deletions

File tree

package-lock.json

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/jsapi-nodejs/README.md

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
# @deephaven/jsapi-nodejs
22

3-
Deephaven utils for consuming Jsapi from a server from a nodejs app. It can
4-
optionally convert the server module format from `ESM` -> `CJS` or `CJS` -> `ESM`
5-
if the server and consumer don't use the same module format.
3+
Deephaven utils for consuming Jsapi from a server from a nodejs app. The jsapi
4+
can be downloaded as an `ESM` or `CJS` module.
65

76
## Install
87

@@ -16,17 +15,30 @@ npm install --save @deephaven/jsapi-nodejs
1615
import fs from 'node:fs';
1716
import path from 'node:path';
1817

19-
import { loadModules } from '@deephaven/jsapi-nodejs';
18+
import { loadDhModules } from '@deephaven/jsapi-nodejs';
19+
20+
// Needed for esm modules
21+
if (typeof globalThis.__dirname === 'undefined') {
22+
globalThis.__dirname = import.meta.dirname
23+
}
2024

2125
const tmpDir = path.join(__dirname, 'tmp');
2226

23-
// Download jsapi `ESM` files from DH Community server and export as `CJS` module.
24-
const dhc = await loadModules({
27+
// Download jsapi from a Deephaven server
28+
const dhc = await loadDhModules({
2529
serverUrl: new URL('http://localhost:10000'),
26-
serverPaths: ['jsapi/dh-core.js', 'jsapi/dh-internal.js'],
27-
download: true,
2830
storageDir: tmpDir,
29-
sourceModuleType: 'esm',
30-
targetModuleType: 'cjs',
31+
targetModuleType: 'esm', // set to `cjs` to download as a CommonJS module
3132
});
33+
34+
const client = new dhc.CoreClient(serverUrl.href, {
35+
// Enable http2 transport (this is optional but recommended)
36+
transportFactory: NodeHttp2gRPCTransport.factory,
37+
})
38+
39+
await client.login({
40+
type: dhc.CoreClient.LOGIN_TYPE_ANONYMOUS,
41+
})
42+
43+
const cn = await client.getAsIdeConnection()
3244
```

packages/jsapi-nodejs/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"build:babel": "babel ./src --out-dir ./dist --extensions \".ts,.tsx,.js,.jsx\" --source-maps --root-mode upward"
2222
},
2323
"dependencies": {
24+
"@deephaven/jsapi-types": "^1.0.0-dev0.37.2",
2425
"@deephaven/log": "file:../log",
2526
"@deephaven/utils": "file:../utils",
2627
"ws": "^8.18.0"

packages/jsapi-nodejs/src/loaderUtils.ts

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import fs from 'node:fs';
22
import path from 'node:path';
3+
import type { dh as DhType } from '@deephaven/jsapi-types';
34

45
import { downloadFromURL, urlToDirectoryName } from './serverUtils.js';
56
import { polyfillWs } from './polyfillWs.js';
@@ -84,4 +85,65 @@ export async function loadModules<TMainModule>({
8485
return require(mainModulePath);
8586
}
8687

87-
export default loadModules;
88+
/**
89+
* Load `jsapi/dh-core.js` and `jsapi/dh-internal.js` modules from a Core Server.
90+
* @param serverUrl The URL of the server to load from.
91+
* @param storageDir The directory to store the downloaded modules.
92+
* @param targetModuleType The type of module to load. Can be either 'esm' or 'cjs'.
93+
* @returns The default export the `jsapi/dh-core.js` module.
94+
*/
95+
export async function loadDhModules({
96+
serverUrl,
97+
storageDir,
98+
targetModuleType,
99+
}: Pick<
100+
LoadModuleOptions,
101+
'serverUrl' | 'storageDir' | 'targetModuleType'
102+
>): Promise<typeof DhType> {
103+
if (targetModuleType === 'esm') {
104+
// These are needed in `esm` output until JSAPI is updated to not rely on
105+
// `window` and `self`.
106+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
107+
// @ts-ignore
108+
globalThis.self = globalThis;
109+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
110+
// @ts-ignore
111+
globalThis.window = globalThis;
112+
}
113+
114+
const coreModule = await loadModules<
115+
typeof DhType & { default?: typeof DhType }
116+
>({
117+
serverUrl,
118+
serverPaths: ['jsapi/dh-core.js', 'jsapi/dh-internal.js'],
119+
storageDir,
120+
targetModuleType,
121+
download:
122+
targetModuleType === 'esm'
123+
? // ESM does not need any transformation since the server modules are already ESM.
124+
true
125+
: // CJS needs a post-download transform to convert the ESM modules to CJS.
126+
(serverPath, content) => {
127+
if (serverPath === 'jsapi/dh-core.js') {
128+
return content
129+
.replace(
130+
`import {dhinternal} from './dh-internal.js';`,
131+
`const {dhinternal} = require("./dh-internal.js");`
132+
)
133+
.replace(`export default dh;`, `module.exports = dh;`);
134+
}
135+
136+
if (serverPath === 'jsapi/dh-internal.js') {
137+
return content.replace(
138+
`export{__webpack_exports__dhinternal as dhinternal};`,
139+
`module.exports={dhinternal:__webpack_exports__dhinternal};`
140+
);
141+
}
142+
143+
return content;
144+
},
145+
});
146+
147+
// ESM uses `default` export. CJS does not.
148+
return coreModule.default ?? coreModule;
149+
}

0 commit comments

Comments
 (0)