Skip to content

Commit c4528f3

Browse files
committed
feat: publish to NPM instead of JSR
The package is published to NPM now, instead of JSR. The TypeScript sources are compiled to JavaScript using `@swc/core` and the type declarations are emitted using TypeScript 7. Both steps run from the `prepublishOnly` hook into the `npm/` folder, which is what `exports` points to. This mirrors the setup used in `nRFCloud/billing-service-proto`. `semantic-release` publishes via `@semantic-release/npm` instead of `@sebbo2002/semantic-release-jsr`.
1 parent 9656941 commit c4528f3

12 files changed

Lines changed: 801 additions & 31 deletions

.github/workflows/test-and-release.yaml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ on: push
44

55
env:
66
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
7-
JSR_TOKEN: ${{ secrets.JSR_TOKEN }}
87

98
permissions:
109
contents: write
@@ -22,14 +21,16 @@ jobs:
2221
with:
2322
node-version: ">=24.18.1 <25"
2423
cache: "npm"
24+
registry-url: "https://registry.npmjs.org"
2525

2626
- name: Install dependencies
2727
run: npm ci --no-audit
2828

29+
- name: Compile TypeScript
30+
run: npx tsc
31+
2932
- name: Test
3033
run: npm test
3134

3235
- name: Semantic release
33-
run: |
34-
npm install -D @sebbo2002/semantic-release-jsr
35-
npx semantic-release
36+
run: npx semantic-release

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
node_modules/
2+
npm/

.npm/compile.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Compile source for NPM
3+
*/
4+
5+
import swc from '@swc/core'
6+
import { mkdirSync, rmSync, writeFileSync } from 'node:fs'
7+
import { glob } from 'node:fs/promises'
8+
import path, { dirname } from 'node:path'
9+
import { fileURLToPath } from 'node:url'
10+
import tsconfig from './tsconfig.npm.json' with { type: 'json' }
11+
import { updateImports } from './updateImports.ts'
12+
13+
const __dirname = dirname(fileURLToPath(import.meta.url))
14+
15+
const outDir = path.join(__dirname, '..', 'npm')
16+
17+
try {
18+
rmSync(outDir, { recursive: true, force: true })
19+
} catch {
20+
// pass
21+
}
22+
23+
for await (const file of glob(
24+
tsconfig.include.map((include) => path.join('.npm', include)),
25+
)) {
26+
if (file.endsWith('.spec.ts') || file.endsWith('.test.ts')) continue
27+
let compiled = (
28+
await swc.transformFile(file, {
29+
jsc: {
30+
parser: {
31+
syntax: 'typescript',
32+
},
33+
target: 'es2024',
34+
},
35+
module: {
36+
type: 'es6',
37+
},
38+
})
39+
).code
40+
41+
compiled = updateImports(compiled)
42+
43+
const targetFile = path.join(outDir, file.replace(/\.ts$/, '.js'))
44+
45+
mkdirSync(dirname(targetFile), { recursive: true })
46+
47+
writeFileSync(targetFile, compiled, 'utf8')
48+
49+
console.log(file)
50+
}

.npm/tsconfig.npm.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"extends": "../tsconfig.json",
3+
"compilerOptions": {
4+
"emitDeclarationOnly": true,
5+
"declaration": true,
6+
"noEmit": false,
7+
"rootDir": ".."
8+
},
9+
"include": ["../*.ts"],
10+
"exclude": ["../*.spec.ts", "../*.test.ts"]
11+
}

.npm/updateImports.spec.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import assert from 'node:assert'
2+
import { describe, it } from 'node:test'
3+
import { updateImports } from './updateImports.ts'
4+
5+
void describe('updateImports', () => {
6+
void it('replaces .ts with .js in relative imports', () => {
7+
const input = `import { foo } from './bar.ts';`
8+
const expected = `import { foo } from './bar.js';`
9+
assert.equal(updateImports(input), expected)
10+
})
11+
})

.npm/updateImports.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export const updateImports = (source: string): string =>
2+
source.replace(/from ['"](.+?)\.ts['"]/g, "from '$1.js'")

CONTRIBUTING.md

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
# Contributing to `@nrfcloud/wait-for-it`
22

33
This is a published library
4-
([`@nrfcloud/wait-for-it`](https://jsr.io/@nrfcloud/wait-for-it) on JSR). The
5-
sections below cover the development setup, how to test your changes, and how a
6-
new version gets released.
4+
([`@nrfcloud/wait-for-it`](https://www.npmjs.com/package/@nrfcloud/wait-for-it)
5+
on NPM). The sections below cover the development setup, how to test your
6+
changes, and how a new version gets released.
77

88
## Development setup
99

@@ -16,8 +16,9 @@ new version gets released.
1616

1717
## Testing
1818

19-
Run `npm test` for the unit tests. They run on Node.js' built-in test runner
20-
(`node --test`) directly against the TypeScript sources.
19+
1. Run `npx tsc` to type-check the project.
20+
1. Run `npm test` for the unit tests. They run on Node.js' built-in test runner
21+
(`node --test`) directly against the TypeScript sources.
2122

2223
## Squash your commits
2324

@@ -29,12 +30,25 @@ Run `npm test` for the unit tests. They run on Node.js' built-in test runner
2930
1. Get the code reviewed.
3031
1. Once approved and CI passes, rebase or squash away!
3132

33+
## Building the NPM package
34+
35+
The package is published as compiled JavaScript with type declarations in the
36+
`npm/` folder, which is created by the `prepublishOnly` hook:
37+
38+
1. [`.npm/compile.ts`](.npm/compile.ts) transpiles the TypeScript sources using
39+
[`@swc/core`](https://www.npmjs.com/package/@swc/core) and rewrites the `.ts`
40+
import specifiers to `.js`.
41+
1. [TypeScript 7](https://www.npmjs.com/package/typescript) emits the type
42+
declarations, using [`.npm/tsconfig.npm.json`](.npm/tsconfig.npm.json).
43+
44+
Run `npm run prepublishOnly` to build it locally.
45+
3246
## Releasing a new version
3347

3448
1. [`semantic-release` in the Test&Release workflow](.github/workflows/test-and-release.yaml)
3549
takes care of determining the next version from the conventional commits,
3650
creating a new GitHub release and publishing the package to
37-
[JSR](https://jsr.io/@nrfcloud/wait-for-it).
51+
[NPM](https://www.npmjs.com/package/@nrfcloud/wait-for-it).
3852

3953
Once a new version is published, consumers can bump the dependency to pick it
4054
up.

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
# `@nrfcloud/wait-for-it`
22

3-
<https://jsr.io/@nrfcloud/wait-for-it>
3+
<https://www.npmjs.com/package/@nrfcloud/wait-for-it>
44

55
## Install with NPM
66

77
```bash
8-
npx jsr add (--save-prod|--save-dev) @nrfcloud/wait-for-it
8+
npm i (--save-prod|--save-dev) @nrfcloud/wait-for-it
99
```
1010

1111
## Usage

jsr.json

Lines changed: 0 additions & 7 deletions
This file was deleted.

0 commit comments

Comments
 (0)