ESM Module Compatibility#
matrix-js-sdk is published as an ES module package ("type": "module" in package.json) and its source is compiled to lib/ via Babel. Because Node ESM does not resolve bare directory imports, every internal import in src/ must use an explicit file extension and a full index.ts path for directory entry points.
The Rules#
1. Always include the .ts extension on relative imports.
// β
Correct
import { foo } from "./utils.ts";
// β Wrong β no extension
import { foo } from "./utils";
2. Never import a directory with a bare path; always spell out index.ts.
// β
Correct
import { Method } from "../http-api/index.ts";
// β Wrong β directory import, breaks Node ESM
import { Method } from "../http-api";
These two rules apply to all files under src/**/*.ts. Test files (spec/**) are exempt.
Enforcement#
ESLint#
The n/file-extension-in-import rule (from eslint-plugin-n) is set to "error" with tryExtensions: [".ts"] for all src/**/*.ts files . This catches missing extensions at lint time.
Run linting with:
yarn lint:js
TypeScript#
tsconfig.json sets "allowImportingTsExtensions": true, which lets TypeScript accept the .ts suffix without treating it as an error during type-checking.
Why This Matters#
When Babel compiles src/ to lib/, it replaces .ts extensions with .js. If a source file imports ../http-api (no extension), Babel emits the same bare directory path into lib/. Node ESM then throws ERR_UNSUPPORTED_DIR_IMPORT at runtime.
This exact failure occurred in PR #5390 ("Properly support Matrix v1.18 OAuth2 APIs"), which introduced src/oauth/authorize.ts and src/oauth/index.ts with bare ../http-api imports. The bug broke import { createClient } from "matrix-js-sdk" in any Node ESM project on versions 42.0.0 and 42.1.0-rc.0, and was fixed in PR #5460 by changing both lines to ../http-api/index.ts β matching the other 13 http-api imports already in src/.
Reference Examples#
Correct imports from existing source files:
src/oidc/tokenRefresher.tsline 19:import { ... } from "../http-api/index.ts";src/oidc/discovery.tslines 19β21: all imports carry explicit.tsextensionssrc/oidc/index.tslines 20β25: re-exports using./authorize.ts,./discovery.ts, etc.
Quick Reference#
| Concern | Where to look |
|---|---|
| ESLint rule | .eslintrc.cjs lines 137β144 |
| TypeScript config | tsconfig.json line 12 |
| Package ESM declaration | package.json line 33 |
| Violation example | PR #5390 |
| Fix example | PR #5460 |