Skip to content

Commit

Permalink
feat: Removed esbuild runtime dependency (#2327)
Browse files Browse the repository at this point in the history
DH-18191: Removed esbuild runtime dependency and replaced it with an
optional `PostDownloadTransform` function. Files now get downloaded
directly to the `serverStorageDir` instead of `target` subdirectory.

BREAKING CHANGES: @deephaven/jsapi-nodejs `loadModules` arguments has
changed. Transformation of module types is now the responsibility of the
consumer.
  • Loading branch information
bmingles authored Jan 3, 2025
1 parent b6e4eb2 commit f33ab5a
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 74 deletions.
25 changes: 1 addition & 24 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 1 addition & 5 deletions packages/jsapi-nodejs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,7 @@
},
"devDependencies": {
"@types/node": "^22.7.5",
"@types/ws": "^8.5.12",
"esbuild-wasm": "^0.24.0"
},
"peerDependencies": {
"esbuild-wasm": "^0.24.0"
"@types/ws": "^8.5.12"
},
"files": [
"dist"
Expand Down
71 changes: 26 additions & 45 deletions packages/jsapi-nodejs/src/loaderUtils.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import fs from 'node:fs';
import path from 'node:path';
import esbuild, { type BuildOptions } from 'esbuild-wasm';

import { downloadFromURL, urlToDirectoryName } from './serverUtils.js';
import { polyfillWs } from './polyfillWs.js';
import { ensureDirectoriesExist, getDownloadPaths } from './fsUtils.js';

type NonEmptyArray<T> = [T, ...T[]];

/** Transform downloaded content */
export type PostDownloadTransform = (
serverPath: string,
content: string
) => string;

export type LoadModuleOptions = {
serverUrl: URL;
serverPaths: NonEmptyArray<string>;
download: boolean;
download: boolean | PostDownloadTransform;
storageDir: string;
sourceModuleType: 'esm' | 'cjs';
targetModuleType?: 'esm' | 'cjs';
esbuildOptions?: Omit<
BuildOptions,
'entryPoints' | 'format' | 'outdir' | 'platform'
>;
targetModuleType: 'esm' | 'cjs';
};

/**
Expand All @@ -27,73 +27,54 @@ export type LoadModuleOptions = {
* @param serverPaths The paths of the modules on the server.
* @param download Whether to download the modules from the server. If set to false,
* it's assumed that the modules have already been downloaded and still exist in
* the storage directory.
* the storage directory. If set to `true` or a `PostDownloadTransform` function,
* the modules will be downloaded and stored. If set to a `PostDownloadTransform`
* function, the downloaded content will be passed to the function and the result
* saved to disk.
* @param storageDir The directory to store the downloaded modules.
* @param sourceModuleType module format from the server.
* @param targetModuleType (optional) module format to be exported. Defaults to
* sourceModuleType.
* @param esbuildOptions (optional) Additional options to pass to esbuild.
* @param targetModuleType The type of module to load. Can be either 'esm' or 'cjs'.
* @returns The default export of the first module in `serverPaths`.
*/
export async function loadModules<TMainModule>({
serverUrl,
serverPaths,
download,
storageDir,
sourceModuleType,
targetModuleType = sourceModuleType,
esbuildOptions,
targetModuleType,
}: LoadModuleOptions): Promise<TMainModule> {
polyfillWs();

const serverStorageDir = path.join(storageDir, urlToDirectoryName(serverUrl));
const targetDir = path.join(serverStorageDir, 'target');

if (download) {
const needsTranspile = sourceModuleType !== targetModuleType;
const sourceDir = path.join(serverStorageDir, 'source');

ensureDirectoriesExist(
needsTranspile ? [sourceDir, targetDir] : [targetDir]
);
if (download !== false) {
ensureDirectoriesExist([serverStorageDir]);

// Download from server
const serverUrls = serverPaths.map(
serverPath => new URL(serverPath, serverUrl)
);
const contents = await Promise.all(
let contents = await Promise.all(
serverUrls.map(url => downloadFromURL(url))
);

// Post-download transform
if (typeof download === 'function') {
contents = contents.map((content, i) =>
download(serverPaths[i], content)
);
}

// Write to disk
const downloadPaths = getDownloadPaths(
needsTranspile ? sourceDir : targetDir,
serverPaths
);
const downloadPaths = getDownloadPaths(serverStorageDir, serverPaths);
downloadPaths.forEach((downloadPath, i) => {
fs.writeFileSync(downloadPath, contents[i]);
});

// Transpile if source and target module types differ
if (needsTranspile) {
await esbuild.build({
// These can be overridden by esbuildOptions
bundle: false,
logLevel: 'error',
...esbuildOptions,
// These cannot be overridden
entryPoints: downloadPaths,
format: targetModuleType,
outdir: targetDir,
platform: 'node',
});
}
}

// We assume the first module is the main module
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const firstFileName = serverPaths[0].split('/').pop()!;
const mainModulePath = path.join(targetDir, firstFileName);
const mainModulePath = path.join(serverStorageDir, firstFileName);

if (targetModuleType === 'esm') {
return import(mainModulePath);
Expand Down

0 comments on commit f33ab5a

Please sign in to comment.