Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
bc1f6c8
Add `build-package` patch
zbrydon Dec 27, 2025
f0a6f3a
Changeset
zbrydon Dec 27, 2025
ac5507b
Clean up
zbrydon Dec 27, 2025
c601ef1
Fix scope
zbrydon Dec 27, 2025
e812e3a
Less words
zbrydon Dec 27, 2025
0173ea8
Keep `skuba build-package` and add `tsdown.config.ts`
zbrydon Dec 29, 2025
45f5038
Merge branch 'main' of github.com:seek-oss/skuba into build-package-p…
zbrydon Dec 30, 2025
c2f9c2d
Merge branch 'main' into build-package-patch
zbrydon Jan 10, 2026
bdeb718
Merge branch 'main' of github.com:seek-oss/skuba into build-package-p…
zbrydon Feb 7, 2026
57e026a
Merge branch 'build-package-patch' of github.com:seek-oss/skuba into …
zbrydon Feb 7, 2026
81fd6d9
Shuffle internal lints to correct version
zbrydon Feb 7, 2026
2e7685b
Fix dodgy snapshot merge
zbrydon Feb 7, 2026
b0f47d8
Run in parallel
zbrydon Feb 11, 2026
7bb70d9
Remove assets field
zbrydon Feb 12, 2026
656d831
Update src/cli/lint/internalLints/upgrade/patches/14.0.1/patchPackage…
zbrydon Feb 12, 2026
a62123b
Fix
zbrydon Feb 12, 2026
86b09e7
Merge branch 'main' of github.com:seek-oss/skuba into build-package-p…
zbrydon Feb 12, 2026
1906142
Update src/cli/lint/internalLints/upgrade/patches/14.0.1/patchPackage…
zbrydon Feb 12, 2026
dc8098c
Run `skuba format`
seek-oss-ci Feb 12, 2026
3d67fda
Merge branch 'main' into build-package-patch
zbrydon Feb 14, 2026
a9b9248
Update patch location to get it to run
zbrydon Feb 14, 2026
782aba1
Forgot one
zbrydon Feb 14, 2026
148a946
Merge branch 'main' of github.com:seek-oss/skuba into build-package-p…
zbrydon Feb 14, 2026
431cadd
Format
zbrydon Feb 14, 2026
53a0724
Format more
zbrydon Feb 14, 2026
f6058e1
Add more `package.json` patches & refactor
zbrydon Feb 15, 2026
3e4c578
Fix trailing comma bug
zbrydon Feb 15, 2026
30b6d10
Stop eating tsdowns lunch
zbrydon Feb 16, 2026
92e8481
Run `pnpm install` to get the hoisted `tsdown` version
zbrydon Feb 16, 2026
26b812d
This is so scuffed
zbrydon Feb 16, 2026
3c5e661
Run `pnpm tsdown` in the correct directory
zbrydon Feb 16, 2026
29a4a42
Fix tests
zbrydon Feb 16, 2026
0c09491
Merge branch 'main' into build-package-patch
samchungy Feb 20, 2026
706fa28
Merge branch 'main' into build-package-patch
samchungy Feb 20, 2026
c7e02e4
Add `skipLibCheck: true` if there's a `tsconfig.json` in the same dir…
zbrydon Feb 21, 2026
a29c0ab
Swap to offline install
zbrydon Feb 22, 2026
4a27167
Merge branch 'main' into build-package-patch
samchungy Feb 26, 2026
792d385
add exports true
samchungy Feb 26, 2026
de3f7a9
add new logic
samchungy Feb 27, 2026
117653b
fix
samchungy Feb 27, 2026
ec643b7
Merge branch 'main' into build-package-patch
samchungy Feb 27, 2026
d890add
fix up some logic
samchungy Feb 27, 2026
8d664ac
Merge branch 'build-package-patch' of github.com:seek-oss/skuba into …
samchungy Feb 27, 2026
bb041c9
try this
samchungy Feb 27, 2026
872ceec
Remove publishConfig
samchungy Feb 27, 2026
0abebab
update logic
samchungy Feb 27, 2026
f1cb906
set unbundle to true
samchungy Feb 27, 2026
4067a91
Remove tsconfig.build.json
samchungy Mar 1, 2026
abfe8ed
update docs
samchungy Mar 2, 2026
0078580
align
samchungy Mar 2, 2026
4f61f16
changesets
samchungy Mar 2, 2026
e1bedcd
Merge branch 'main' into build-package-patch
samchungy Mar 2, 2026
4c6a861
sort
samchungy Mar 2, 2026
6a07691
Merge branch 'build-package-patch' of github.com:seek-oss/skuba into …
samchungy Mar 2, 2026
fa5a274
sort?
samchungy Mar 2, 2026
ba5e164
delete that
samchungy Mar 2, 2026
492b311
Run `skuba format`
seek-oss-ci Mar 2, 2026
32ed3db
restore
samchungy Mar 2, 2026
94d4a56
Merge branch 'build-package-patch' of github.com:seek-oss/skuba into …
samchungy Mar 2, 2026
cc4602f
Handle niche edge case
samchungy Mar 2, 2026
38aaa77
add `copy` docs
samchungy Mar 2, 2026
72fbcff
Wordsmith
samchungy Mar 2, 2026
b62396d
Okay try this
samchungy Mar 2, 2026
682dc06
add snippet to build docs
samchungy Mar 2, 2026
4f97399
update diff
samchungy Mar 2, 2026
f25aebc
Add package build checks
zbrydon Mar 2, 2026
c45e556
add lints to api
samchungy Mar 2, 2026
505661d
add node engine
samchungy Mar 2, 2026
873d0ef
add lint
samchungy Mar 2, 2026
0b44f66
add changeset
samchungy Mar 3, 2026
9446aec
Merge branch 'main' into build-package-patch
samchungy Mar 3, 2026
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
7 changes: 7 additions & 0 deletions .changeset/bright-camels-live.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'skuba': major
---

build-package: Migrate to tsdown

As part of our [migration to ESM](https://seek-oss.github.io/skuba/docs/deep-dives/esm.html), we are updating our package build process to support generating both CJS and ESM outputs, regardless of whether projects use CJS or ESM. Since our current tsc-based build does not support this, we are switching to [tsdown](https://tsdown.dev/) for package builds.
92 changes: 92 additions & 0 deletions .changeset/smart-lamps-deny.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
---
'skuba': major
---

lint: Migrate `skuba build-package` usage to use [tsdown](https://tsdown.dev/) for building packages

This patch will attempt to do a best effort migration of your `skuba build-package` usage to use [tsdown](https://tsdown.dev/) for building packages. This includes:

1. Adding a `tsdown.config.mts` file to your package directories with a basic configuration
2. Adding a `customConditions` entry to your root `tsconfig.json` file
3. Adding `skipLibCheck` to your package `tsconfig.json` files to work around issues with type checking against `tsdown`.
4. Updating your package `package.json` files to point to the new build outputs
5. Removing redundant `tsconfig.build.json` files

## File changes

The output between what `skuba build-package` generates before and after this change will be different, so you may need to update any references to the output files in your project.

For example the output for a simple `src/index.ts` file produces the following outputs:

```diff
-lib-commonjs/index.js
-lib-es2015/index.js
-lib-types/index.d.ts
+lib/index.cjs
+lib/index.mjs
+lib/index.d.cts
+lib/index.d.mts
```

This change may break consumers who directly access these output paths.

To check if your consumers are affected, search GitHub with: `org:SEEK-Jobs content:"@seek/MY_PACKAGE/"`

If needed, export those references from your package entry point to help consumers migrate to the new build outputs.

Note: if you choose to remove the `unbundle: true` option from `tsdown.config.mts`, tsdown may emit bundled/chunked outputs and internal `lib/...` file paths can change between builds. Consumers should avoid importing from build output files directly, and instead import from the package entry point (or explicitly exported sub paths)

## Format changes

`tsdown` selects what ECMAScript target version to build for based on the `engines.node` field in your `package.json`.

This means that for consumers previously relying on the `lib-es2015` output may need to update their runtime to match your package's `engines.node` field.

An example changeset you may want to include for a package:

````md
---
'my-package': major
---

Update npm package build outputs

This release changes published build output paths. If you were previously importing from nested paths within the build output you will need to update imports to use the package entry point (for example, `@seek/my-package`).

```diff
-import type { SomeType } from '@seek/my-package/lib-types/...';
+import type { SomeType } from '@seek/my-package';
```
````

## Debugging

If your project utilises a `main` field which points to a `.ts` file within a monorepo setup, eg.

```json
"main": "src/index.ts",
```

You may need to create a `moduleNameMapper` entry in your Jest config files to point to the source file, eg.

```json
{
"moduleNameMapper": {
"^@seek/my-package": "<rootDir>/packages/my-package/src/index.ts"
}
}
```

This will work natively with custom conditions when we migrate to `vitest` in the future, but is required for Jest to continue working with the new build outputs.

```ts
import { defineConfig } from 'vitest/config';

export default defineConfig({
ssr: {
resolve: {
conditions: ['@seek/my-repo/source'],
},
},
});
```
5 changes: 5 additions & 0 deletions .changeset/social-pigs-search.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'eslint-plugin-skuba': patch
---

build: Export type declarations
38 changes: 19 additions & 19 deletions docs/cli/build.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,37 +84,37 @@ In this example, all `*.vocab/*translations.json` files found within `src` will

## skuba build-package

Compiles your project for compatibility with CommonJS and ES2015 modules.
Compiles your project with [tsdown] to produce CJS, ESM, and type declaration outputs.

This is useful for building isomorphic npm packages.

`tsdown` selects what ECMAScript target version to build for based on the `engines.node` field in your `package.json`.

```shell
skuba build-package

# commonjs │ TSFILE: ...
# commonjs │ tsc exited with code 0
# es2015 │ TSFILE: ...
# es2015 │ tsc exited with code 0
# types │ TSFILE: ...
# types │ tsc exited with code 0
Comment on lines -94 to -99
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have a good idea of how the output of these outdated targets compare to the modern output that tsdown now gives us? Does it include "good" improvements that are nonetheless a breaking change to the least discerning consumer?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, definitely worth a call-out. It reads your package.json engine and sets the format appropriately according to that!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the behaviour if there's no engine set (which is also unfortunately a thing 🥹)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like it just preserves the syntax

If you don't specify a target and your package.json doesn't have an engines.node field, tsdown will behave as if target: false was set, preserving all modern syntax.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're now patching an engine into the package.json if it does not have one

# ℹ entry: src/index.ts
# ℹ target: node22.14.0
# ℹ [CJS] lib/index.cjs
# ℹ [CJS] lib/index.d.cts
# ℹ [ESM] lib/index.mjs
# ℹ [ESM] lib/index.d.mts
```

`skuba build-package` runs operations concurrently up to your [CPU core count].
On a resource-constrained Buildkite agent,
you can limit this with the `--serial` flag.
See our [Buildkite guide] for more information.

To bundle additional assets alongside your package, view the [bundling assets](#bundling-assets) section above.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we replace this with a link on how to copy additional assets with tsdown?

Assets can be bundled by configuring the [copy] field in the `tsdown.config.mts` file. Depending on your how your application interprets asset paths, the `unbundle` option may need to be set to `true`.

These files will be copied into the corresponding `lib-commonjs` and `lib-es2015` directories.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this well-intentioned move from lib-* to lib will "break" those relying on submodule imports. While it's correct to say that such submodules were never intended to be a stable interface, unfortunately very few have cared about that in practice: https://github.com/search?q=org%3ASEEK-Jobs+%28lib-commonjs+OR+lib-es2015+OR+lib-types%29+language%3ATypeScript&type=code&l=TypeScript

So I think we should be very upfront about this change in behaviour, and encourage all package authors to release a new version to the same effect. Maybe we could even provide a little excerpt that they can copy-paste into their changeset 🤔

```ts
import { defineConfig } from 'tsdown/config';

| Option | Description |
| :--------- | :----------------------------------------------- |
| `--serial` | Force serial execution of compilation operations |
export default defineConfig({
unbundle: true,
copy: ['**/*.vocab/*translations.json'],
});
```

[`skuba configure`]: ./configure.md#skuba-configure
[buildkite guide]: ../deep-dives/buildkite.md
[compiler option]: https://www.typescriptlang.org/docs/handbook/compiler-options.html#compiler-options
[cpu core count]: https://nodejs.org/api/os.html#os_os_cpus
[copy]: https://tsdown.dev/reference/api/Interface.UserConfig#copy
[esbuild]: ../deep-dives/esbuild.md
[tsc]: https://www.typescriptlang.org/docs/handbook/compiler-options.html
[tsdown]: https://tsdown.dev/
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
]
},
"dependencies": {
"@arethetypeswrong/core": "~0.18.1",
"@ast-grep/lang-json": "^0.0.6",
"@ast-grep/napi": "^0.41.0",
"@esbuild-plugins/tsconfig-paths": "^0.1.0",
Expand Down Expand Up @@ -115,6 +116,7 @@
"picomatch": "^4.0.0",
"prettier": "~3.8.0",
"prettier-plugin-packagejson": "^3.0.0",
"publint": "~0.3.17",
"read-pkg-up": "^7.0.1",
"semantic-release": "^25.0.2",
"simple-git": "^3.5.0",
Expand Down Expand Up @@ -167,6 +169,6 @@
"entryPoint": "src/index.ts",
"template": null,
"type": "package",
"version": "14.1.0"
"version": "14.1.1"
}
}
1 change: 1 addition & 0 deletions packages/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"url": "git+ssh://[email protected]/seek-oss/skuba.git",
"directory": "packages/api"
},
"license": "MIT",
"exports": {
".": {
"@seek/skuba/source": "./src/index.ts",
Expand Down
7 changes: 6 additions & 1 deletion packages/api/tsdown.config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,10 @@ export default defineConfig({
exports: {
devExports: '@seek/skuba/source',
},
failOnWarn: false,
inlineOnly: false,
checks: {
legacyCjs: false,
},
attw: true,
publint: true,
});
2 changes: 1 addition & 1 deletion packages/eslint-config-skuba/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,6 @@
"entryPoint": "index.js",
"template": "oss-npm-package",
"type": "package",
"version": "14.1.0"
"version": "14.1.1"
}
}
7 changes: 2 additions & 5 deletions packages/eslint-plugin-skuba/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,7 @@
"module": "./lib/index.mjs",
"types": "./lib/index.d.cts",
"files": [
"lib*/**/*.d.ts",
"lib*/**/*.js",
"lib*/**/*.js.map",
"lib*/**/*.mjs"
"lib"
],
"scripts": {
"build": "tsdown",
Expand Down Expand Up @@ -72,6 +69,6 @@
"entryPoint": "src/index.ts",
"template": "oss-npm-package",
"type": "package",
"version": "14.1.0"
"version": "14.1.1"
}
}
7 changes: 6 additions & 1 deletion packages/eslint-plugin-skuba/tsdown.config.mts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { defineConfig } from 'tsdown/config';

export default defineConfig({
dts: true,
entry: ['src/index.ts'],
exports: {
devExports: '@seek/skuba/source',
},
format: ['cjs', 'esm'],
outDir: 'lib',
failOnWarn: false,
checks: {
legacyCjs: false,
},
publint: true,
attw: true,
});
2 changes: 1 addition & 1 deletion packages/skuba-dive/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,6 @@
"entryPoint": "src/index.ts",
"template": "oss-npm-package",
"type": "package",
"version": "14.1.0"
"version": "14.1.1"
}
}
Loading