Migrate to esm style - #1396
Conversation
|
Size Change: +3.66 kB (+0.02%) Total Size: 19.6 MB 📦 View Changed
|
There was a problem hiding this comment.
Pull request overview
Migrates the SDK to be ESM-primary while maintaining CommonJS compatibility via a dual-output layout, updating build/test/tooling to work under "type": "module" and Node’s ESM resolution rules.
Changes:
- Switch package publishing to ESM-first with conditional exports and a generated CJS subtree under
lib/**/cjs. - Convert build/tooling configs and scripts to ESM and update source imports to explicit
.jsspecifiers formoduleResolution: nodenext. - Update test utilities and HTTP client wiring to work with ESM imports and the axios/fetch variants.
Reviewed changes
Copilot reviewed 79 out of 81 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| yarn.lock | Removes dependencies tied to dropped ghooks and related transitive packages. |
| test/test-utils/stellar-sdk-import.ts | Switches test harness from require() to dynamic import() and uses top-level await for exports. |
| src/webauth/utils.ts | Updates relative import specifiers to .js. |
| src/webauth/index.ts | Updates exports to .js specifiers. |
| src/webauth/challenge_transaction.ts | Updates relative imports to .js specifiers. |
| src/stellartoml/index.ts | Updates imports for http-client/config to ESM-friendly .js paths. |
| src/rpc/transaction.ts | Updates internal imports to .js specifiers. |
| src/rpc/server.ts | Updates internal imports and adjusts type-only imports for ESM. |
| src/rpc/parsers.ts | Updates internal import specifier to .js. |
| src/rpc/jsonrpc.ts | Converts HttpClient import to type-only and ESM .js specifier. |
| src/rpc/index.ts | Updates exports to .js specifiers and removes module.exports default hack. |
| src/rpc/browser.ts | Updates exports to ESM .js specifiers and removes CJS default export hack. |
| src/rpc/axios.ts | Updates imports to ESM .js specifiers and type-only usage. |
| src/index.ts | Updates all top-level exports to explicit .js paths and removes module.exports default hack. |
| src/http-client/index.ts | Updates exports to .js specifiers. |
| src/http-client/fetch-client.ts | Adds interop normalization for feaxios default export shape across ESM/CJS. |
| src/http-client/axios.ts | Updates exports to .js specifiers. |
| src/horizon/types/trade.ts | Updates type import to .js specifier. |
| src/horizon/types/offer.ts | Converts AssetType to type-only import and updates .js specifier. |
| src/horizon/types/effects.ts | Updates imports to .js specifiers and uses type-only where appropriate. |
| src/horizon/types/assets.ts | Converts AssetType to type-only import and updates .js specifier. |
| src/horizon/transaction_call_builder.ts | Updates imports to .js specifiers and type-only HttpClient. |
| src/horizon/trades_call_builder.ts | Updates imports to .js specifiers and type-only HttpClient. |
| src/horizon/trade_aggregation_call_builder.ts | Updates imports to .js specifiers and type-only HttpClient. |
| src/horizon/strict_send_path_call_builder.ts | Updates imports to .js specifiers and type-only HttpClient. |
| src/horizon/strict_receive_path_call_builder.ts | Updates imports to .js specifiers and type-only HttpClient. |
| src/horizon/server_api.ts | Updates imports to .js specifiers and uses type-only for record types. |
| src/horizon/server.ts | Updates all internal imports to .js specifiers and type-only HttpClient. |
| src/horizon/payment_call_builder.ts | Updates imports to .js specifiers and type-only HttpClient. |
| src/horizon/path_call_builder.ts | Updates imports to .js specifiers and type-only HttpClient. |
| src/horizon/orderbook_call_builder.ts | Updates imports to .js specifiers and type-only HttpClient. |
| src/horizon/operation_call_builder.ts | Updates imports to .js specifiers and type-only HttpClient. |
| src/horizon/offer_call_builder.ts | Updates imports to .js specifiers and type-only HttpClient. |
| src/horizon/liquidity_pool_call_builder.ts | Updates imports to .js specifiers and type-only HttpClient. |
| src/horizon/ledger_call_builder.ts | Updates imports to .js specifiers and type-only HttpClient. |
| src/horizon/index.ts | Updates exports to .js specifiers and removes module.exports default hack. |
| src/horizon/horizon_axios_client.ts | Updates http-client import to ESM .js specifier and type-only imports. |
| src/horizon/horizon_api.ts | Converts Horizon types to type-only imports. |
| src/horizon/friendbot_builder.ts | Updates imports to .js specifiers and type-only HttpClient. |
| src/horizon/effect_call_builder.ts | Updates imports to .js specifiers and type-only HttpClient. |
| src/horizon/claimable_balances_call_builder.ts | Updates imports to .js specifiers and type-only HttpClient. |
| src/horizon/call_builder.ts | Updates imports to .js specifiers (including URITemplate) and type-only imports. |
| src/horizon/assets_call_builder.ts | Updates imports to .js specifiers and type-only HttpClient. |
| src/horizon/account_response.ts | Updates imports to .js specifiers. |
| src/horizon/account_call_builder.ts | Updates imports to .js specifiers and type-only HttpClient. |
| src/federation/server.ts | Updates imports to .js specifiers and type-only Api. |
| src/federation/index.ts | Updates exports to .js specifiers. |
| src/federation/api.ts | Updates type-only import to .js specifier. |
| src/errors/not_found.ts | Updates internal import to .js specifier. |
| src/errors/network.ts | Updates internal import to .js specifier. |
| src/errors/index.ts | Updates exports to .js specifiers. |
| src/errors/bad_response.ts | Updates internal import to .js specifier. |
| src/errors/bad_request.ts | Updates internal import to .js specifier. |
| src/contract/wasm_spec_parser.ts | Updates internal import to .js specifier. |
| src/contract/utils.ts | Updates internal imports to .js specifiers and type-only usage. |
| src/contract/types.ts | Converts MemoType to type-only and updates internal imports to .js. |
| src/contract/spec.ts | Converts ScIntType to type-only and updates internal imports to .js. |
| src/contract/sent_transaction.ts | Updates internal imports to .js specifiers and type-only usage. |
| src/contract/index.ts | Updates exports to .js specifiers. |
| src/contract/client.ts | Updates internal imports to .js specifiers. |
| src/contract/basic_node_signer.ts | Updates internal imports to .js specifiers and type-only usage. |
| src/contract/assembled_transaction.ts | Updates internal imports to .js specifiers. |
| src/cli/util.ts | Updates imports to .js specifiers and type-only usage. |
| src/cli/index.ts | Updates imports to .js specifiers. |
| src/browser.ts | Updates imports/exports to ESM .js specifiers and removes CJS default hack. |
| src/browser-axios.ts | Updates imports/exports to ESM .js specifiers and removes CJS default hack. |
| src/bindings/wasm_fetcher.ts | Updates imports to .js specifiers. |
| src/bindings/types.ts | Updates imports to .js specifiers. |
| src/bindings/index.ts | Updates exports to .js specifiers. |
| src/bindings/generator.ts | Updates imports to .js specifiers. |
| src/bindings/client.ts | Updates imports to .js specifiers. |
| prettier.config.js | Converts Prettier config to ESM default export. |
| package.json | Sets "type":"module", updates entrypoints/exports for dual ESM+CJS layout, updates build scripts, drops ghooks. |
| eslint.config.js | Converts ESLint flat config to ESM default export and ESM imports. |
| config/write-module-type.js | Adds helper script to write package.json { type } sentinel into emitted CJS subtrees. |
| config/webpack.config.browser.js | Converts webpack browser config to ESM and adds extensionAlias for .js→.ts source specifiers. |
| config/set-output-dir.js | Converts TS outDir setter script to ESM. |
| config/build.config.js | Converts build config to ESM default export. |
| config/babel-plugin-alias-http-client.js | Converts custom Babel plugin to ESM and updates rewrite patterns for .js specifiers. |
| bin/stellar-js | Converts CLI entry from require() to ESM import. |
| babel.config.js | Converts Babel config to ESM and updates caching to vary by BABEL_MODULES. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| plugins.push( | ||
| path.resolve(__dirname, "config/babel-plugin-alias-http-client.js"), | ||
| path.resolve( | ||
| import.meta.dirname, | ||
| "config/babel-plugin-alias-http-client.js", | ||
| ), |
There was a problem hiding this comment.
import.meta.dirname is not a standard Node ESM feature (Node exposes import.meta.url), so this will be undefined at runtime and break Babel config resolution. Compute a dirname equivalent via fileURLToPath(import.meta.url) (as done in scripts/download-sac-spec.js) and use that for path.resolve here.
| const OUTPUT_DIR = process.env.OUTPUT_DIR || "lib"; | ||
| const configDir = import.meta.dirname; | ||
| const tempTsconfigPath = path.resolve(configDir, "tsconfig.tmp.json"); |
There was a problem hiding this comment.
import.meta.dirname is not defined in Node ESM; this script will fail when invoked by build:ts. Replace it with an ESM-safe dirname implementation derived from import.meta.url (e.g., fileURLToPath + path.dirname).
| @@ -17,8 +19,8 @@ const version = packageJson.version; | |||
| // import of `./http-client` (or `../http-client`) to `./http-client/axios`, | |||
| // so Horizon/rpc/stellartoml/federation all pick up axios in the same bundle. | |||
| const entryPath = buildConfig.useAxios | |||
| ? path.resolve(__dirname, '../src/browser-axios.ts') | |||
| : path.resolve(__dirname, '../src/browser.ts'); | |||
| ? path.resolve(import.meta.dirname, "../src/browser-axios.ts") | |||
| : path.resolve(import.meta.dirname, "../src/browser.ts"); | |||
There was a problem hiding this comment.
This config relies on import.meta.dirname, which is not provided by Node’s ESM implementation and will cause the webpack build to crash. Use an ESM-safe dirname computed from import.meta.url (e.g., fileURLToPath + path.dirname) and replace all path.resolve(import.meta.dirname, ...) occurrences.
| crypto: import.meta.resolve("crypto-browserify"), | ||
| stream: import.meta.resolve("stream-browserify"), | ||
| buffer: import.meta.resolve("buffer"), |
There was a problem hiding this comment.
import.meta.resolve() returns a URL string (e.g. file:///...), but webpack’s resolve.fallback expects filesystem paths like require.resolve() returns. Convert the resolved URL to a path (e.g., via fileURLToPath(new URL(import.meta.resolve(...)))) or use createRequire(import.meta.url).resolve(...).
| // Node.js environment - dynamically import the lib module. Top-level await | ||
| // in this file's module body makes this usable as a synchronous const below, | ||
| // and vitest handles the propagated async boundary transparently. | ||
| return (await import(getNodeLibPath())) as unknown as StellarSdkModule; |
There was a problem hiding this comment.
In Node ESM, import("../../lib") (a directory import) and extensionless relative imports don’t resolve the way require() does, so this dynamic import is likely to throw at runtime. Import an explicit entry file (e.g. ../../lib/index.js / ../../lib/axios/index.js) or build the specifier with a .js filename.
| typeof process !== "undefined" && process.env?.TRANSPORT === "axios" | ||
| ? "/http-client/axios" | ||
| : "/http-client"; | ||
| // eslint-disable-next-line import/no-dynamic-require, global-require | ||
| const httpClientModule = require(`${getNodeLibPath()}${subpath}`); | ||
| const httpClientModule = await import(`${getNodeLibPath()}${subpath}`); | ||
| return httpClientModule.httpClient; |
There was a problem hiding this comment.
This dynamic import uses an extensionless specifier like .../http-client / .../http-client/axios, which is not resolvable under Node’s ESM rules. Use explicit .js file specifiers (e.g. /http-client/index.js and /http-client/axios.js) when constructing the import path.
What
Migrates the SDK to ESM-primary with a dual-package layout
consumers work.
lib/cjs/ (BABEL_MODULES=commonjs). A new config/write-module-type.js drops a {"type":"commonjs"}
sentinel into the CJS subtree so Node interprets those .js files correctly under the root
"type":"module".
config/webpack.config.browser.js converted to ESM (import/export, import.meta.dirname,
import.meta.resolve). Babel cache keyed on BABEL_MODULES so ESM and CJS passes don't stomp each other.
nodenext). Dead code removed: USE_AXIOS global, module.exports re-exports from src/index.ts and
src/browser.ts.
import(); test/setup-browser.ts picks one bundle based on VITE_TRANSPORT instead of probing variants.
Why
Packages across the JS ecosystem are going ESM-only, and until this PR the SDK couldn't be consumed
cleanly from ESM projects — it shipped CJS-only output with a module.exports default hack and a
runtime require() branch that tripped up bundlers and breaks outright under Node's ESM loader. Going
ESM-primary with a CJS variant under lib/cjs/ means modern consumers get native ESM (tree-shaking,
top-level await, no interop shims) while existing CJS consumers keep working through the require
export condition. Bundling the fetch-default work into the same release avoids shipping two
back-to-back majors that each change public entry points.