From 352d1b9fcf2d62fc401a5bda747f14b1f5cfabe1 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Mon, 16 Dec 2024 14:17:44 +0100 Subject: [PATCH] Ensure `Symbol.dispose` and `Symbol.asyncDispose` are available (#15404) We recently introduced some better instrumentation (https://github.com/tailwindlabs/tailwindcss/pull/15303) which uses the new `using` keyword. I made sure that this was compiled correctly for environments where `using` is not available yet. The issue is that this also relies on `Symbol.dispose` being available. In my testing on our minimal required Node.js version (18) it did work fine. However, turns out that I was using `18.20.x` locally where `Symbol.dispose` **_is_** available, but on older version of Node.js 18 (e.g.: `18.17.x`) it is **_not_** available. This now results in some completely broken builds, e.g.: when running on Cloudflare Pages. See: #15399 I could reproduce this error in CI, by temporarily downgrading the used Node.js version to `18.17.0`. See: image Implementing the proper polyfill, as recommended by the TypeScript docs ( see: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-2.html#:~:text=Symbol.dispose,-??=%20Symbol(%22Symbol.dispose ), the error goes away. (If you look at CI after the polyfill, it still fails but for different reasons unrelated to this change) Fixes: #15399 --- ## Test plan 1. I reproduced it in CI, and I kept the commits so that you can take a look where it fails with the `Object not disposable`. 2. Using the provided reproduction from #15399: ### Before It works on Node.js v18.20.x, but switching to Node.js v18.17.x you can see it fail: image ### After Using pnpm's overrides, we can apply the fix from this PR and test it in the reproduction. You'll notice that it now works in both Node.js v18.20.x and v18.17.x image --- CHANGELOG.md | 5 ++++- packages/@tailwindcss-node/src/instrumentation.ts | 10 +++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a6787ae2da43..4c7c910be788 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -- Nothing yet! +### Fixed + +- Ensure `Symbol.dispose` and `Symbol.asyncDispose` are polyfilled ([#15404](https://github.com/tailwindlabs/tailwindcss/pull/15404)) ## [4.0.0-beta.7] - 2024-12-13 @@ -763,3 +765,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Move the CLI into a separate `@tailwindcss/cli` package ([#13095](https://github.com/tailwindlabs/tailwindcss/pull/13095)) ## [4.0.0-alpha.1] - 2024-03-06 + diff --git a/packages/@tailwindcss-node/src/instrumentation.ts b/packages/@tailwindcss-node/src/instrumentation.ts index c408c4db786f..d27858d888bd 100644 --- a/packages/@tailwindcss-node/src/instrumentation.ts +++ b/packages/@tailwindcss-node/src/instrumentation.ts @@ -1,12 +1,20 @@ import { DefaultMap } from '../../tailwindcss/src/utils/default-map' import * as env from './env' +// See: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-2.html#:~:text=Symbol.dispose,-??=%20Symbol(%22Symbol.dispose +// @ts-expect-error — Ensure Symbol.dispose exists +Symbol.dispose ??= Symbol('Symbol.dispose') +// @ts-expect-error — Ensure Symbol.asyncDispose exists +Symbol.asyncDispose ??= Symbol('Symbol.asyncDispose') + export class Instrumentation implements Disposable { #hits = new DefaultMap(() => ({ value: 0 })) #timers = new DefaultMap(() => ({ value: 0n })) #timerStack: { id: string; label: string; namespace: string; value: bigint }[] = [] - constructor(private defaultFlush = (message: string) => process.stderr.write(`${message}\n`)) {} + constructor( + private defaultFlush = (message: string) => void process.stderr.write(`${message}\n`), + ) {} hit(label: string) { this.#hits.get(label).value++