ESM and CJS dual support by gms1 · Pull Request #16 · gms1/node-sqlite3 · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/ci.yml
75 changes: 72 additions & 3 deletions .github/workflows/test-npm-package.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
name: Test npm package
on:
workflow_call:
inputs:
target_run_id:
description: 'The Run ID of the upstream CI workflow'
required: true
type: string
node_version:
description: 'Node.js version to test with'
required: false
default: '20'
type: string
workflow_dispatch:
inputs:
target_run_id:
Expand Down Expand Up @@ -35,15 +46,15 @@ jobs:
- name: Download artifact from specific run
uses: actions/download-artifact@v5
with:
run-id: ${{ github.event.inputs.target_run_id }}
run-id: ${{ inputs.target_run_id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
name: npm-package-tarball
path: ./downloads

- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version: ${{ github.event.inputs.node_version || '20' }}
node-version: ${{ inputs.node_version || '20' }}

- name: Install tarball and verify
shell: bash
Expand Down Expand Up @@ -93,4 +104,62 @@ jobs:
await db.close();
}
main().catch(err => { console.error(err); process.exit(1); });
"
"

- name: Smoke test - ESM default import
shell: bash
run: |
cd test-project
cat > test-esm.mjs << 'EOF'
import sqlite3 from '@homeofthings/sqlite3';
console.log('ESM: sqlite3 version:', sqlite3.VERSION);
const db = new sqlite3.Database(':memory:');
db.serialize(() => {
db.run('CREATE TABLE test (id INT, name TEXT)');
db.run("INSERT INTO test VALUES (1, 'hello')");
db.get('SELECT * FROM test', (err, row) => {
if (err) { console.error('Query failed:', err); process.exit(1); }
console.log('ESM default import result:', JSON.stringify(row));
db.close();
});
});
EOF
node test-esm.mjs

- name: Smoke test - ESM named imports
shell: bash
run: |
cd test-project
cat > test-named.mjs << 'EOF'
import { Database, OPEN_READWRITE, OPEN_CREATE } from '@homeofthings/sqlite3';
console.log('ESM named: OPEN_READWRITE=', OPEN_READWRITE);
const db = new Database(':memory:');
db.serialize(() => {
db.run('CREATE TABLE test (id INT, name TEXT)');
db.run("INSERT INTO test VALUES (2, 'world')");
db.get('SELECT * FROM test', (err, row) => {
if (err) { console.error('Query failed:', err); process.exit(1); }
console.log('ESM named import result:', JSON.stringify(row));
db.close();
});
});
EOF
node test-named.mjs

- name: Smoke test - ESM promise API
shell: bash
run: |
cd test-project
cat > test-promise.mjs << 'EOF'
import { SqliteDatabase } from '@homeofthings/sqlite3/promise';
async function main() {
const db = await SqliteDatabase.open(':memory:');
await db.run('CREATE TABLE test (id INT, name TEXT)');
await db.run("INSERT INTO test VALUES (3, 'esm')");
const row = await db.get('SELECT * FROM test');
console.log('ESM promise API result:', JSON.stringify(row));
await db.close();
}
main().catch(err => { console.error(err); process.exit(1); });
EOF
node test-promise.mjs
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Asynchronous, non-blocking [SQLite3](https://sqlite.org/) bindings for [Node.js]
- Written in modern C++
- Is built using hardening flags
- Promise-based API
- supports ESM and CJS
- Bundles SQLite v3.53.0, or you can build using a local SQLite

# Installing
Expand Down Expand Up @@ -108,6 +109,37 @@ async function main() {
main().catch(console.error);
```

## ESM and CJS Support

This package supports both CommonJS (CJS) and ECMAScript Modules (ESM):

### CJS (CommonJS)

```js
// Default import
const sqlite3 = require('@homeofthings/sqlite3');

// Destructured import
const { Database, SqliteDatabase } = require('@homeofthings/sqlite3');

// Promise subpath import
const { SqliteDatabase } = require('@homeofthings/sqlite3/promise');
```

### ESM (ECMAScript Modules)

```js
// Default import
import sqlite3 from '@homeofthings/sqlite3';

// Named imports
import { Database, OPEN_CREATE, SqliteDatabase } from '@homeofthings/sqlite3';

// Promise subpath import
import { SqliteDatabase } from '@homeofthings/sqlite3/promise';
```


# Usage

**Note:** the module must be [installed](#installing) before use.
Expand Down
46 changes: 45 additions & 1 deletion docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ This document describes the API for `@homeofthings/sqlite3`, a Node.js binding f

- [Installation](#installation)
- [Quick Start](#quick-start)
- [Module Systems (CJS & ESM)](#module-systems-cjs--esm)
- [Callback API](#callback-api)
- [Database Class](#database-class-callback)
- [Statement Class](#statement-class-callback)
Expand Down Expand Up @@ -67,6 +68,40 @@ main().catch(console.error);

---

## Module Systems (CJS & ESM)

This package supports both CommonJS (CJS) and ECMAScript Modules (ESM) via conditional exports in `package.json`.

### CJS (CommonJS) — Traditional

```javascript
// Default import
const sqlite3 = require('@homeofthings/sqlite3');

// Destructured import
const { Database, SqliteDatabase, OPEN_CREATE } = require('@homeofthings/sqlite3');

// Promise subpath import
const { SqliteDatabase } = require('@homeofthings/sqlite3/promise');
```

### ESM (ECMAScript Modules) — Modern

```javascript
// Default import
import sqlite3 from '@homeofthings/sqlite3';

// Named imports
import { Database, OPEN_CREATE, SqliteDatabase } from '@homeofthings/sqlite3';

// Promise subpath import
import { SqliteDatabase } from '@homeofthings/sqlite3/promise';
```

> **Note:** The ESM wrappers use native CJS→ESM interop (`import` from `.js` files), so ESM imports work seamlessly alongside CJS requires. Both module systems share the same underlying native addon instance.

---

## Callback API

The traditional callback-based API is compatible with the original `node-sqlite3` API.
Expand Down Expand Up @@ -942,11 +977,20 @@ const sqlite3 = require('@homeofthings/sqlite3').verbose();

## TypeScript Support

TypeScript definitions are included in the package:
TypeScript definitions are included in the package. Both CJS and ESM import styles are supported:

```typescript
// CJS style
const sqlite3 = require('@homeofthings/sqlite3');
const { Database, SqliteDatabase } = require('@homeofthings/sqlite3');

// ESM style
import sqlite3 from '@homeofthings/sqlite3';
import { Database, Statement, Backup } from '@homeofthings/sqlite3';
import { SqliteDatabase, SqliteStatement, SqliteBackup } from '@homeofthings/sqlite3';

// Promise subpath
import { SqliteDatabase } from '@homeofthings/sqlite3/promise';
```

---
Expand Down
4 changes: 2 additions & 2 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export default [
ignores: ['node_modules/', 'build/', 'prebuilds/', 'deps/'],
},
{
files: ['**/*.js'],
files: ['**/*.js', '**/*.mjs'],
languageOptions: {
ecmaVersion: 2020,
sourceType: 'module',
Expand All @@ -24,7 +24,7 @@ export default [
},
},
{
files: ['test/**/*.js'],
files: ['test/**/*.js', 'test/**/*.mjs'],
languageOptions: {
globals: {
...globals.mocha,
Expand Down
2 changes: 1 addition & 1 deletion lib/promise/database.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

'use strict';

const { Database } = require('../sqlite3.js');
const { Database } = require('../sqlite3-callback.js');
const { SqliteStatement } = require('./statement');
const { SqliteBackup } = require('./backup');

Expand Down
1 change: 1 addition & 0 deletions lib/promise/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { SqliteDatabase, SqliteStatement, SqliteBackup, SqlRunResult } from '../sqlite3';
9 changes: 9 additions & 0 deletions lib/promise/index.mjs
Loading
Loading