From 543177d3093ec6453257cc739129248c44a51950 Mon Sep 17 00:00:00 2001 From: Tiffany Trinh Date: Tue, 27 Oct 2026 13:55:58 -0400 Subject: [PATCH 1/2] chore: run the repo on Node 24 Volta's pin sets the Node version for local development and for every CI job (setup-node reads it). Node 20 reached end of life on 2026-04-30; the publish job already uses Node 24. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/publish.yaml | 2 +- package.json | 2 +- packages/tests/src/_jest/nockInterceptors.test.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index db79fd775..ec4a0c040 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -30,7 +30,7 @@ jobs: fetch-depth: 0 # Full history needed for yarn version to find ancestor with master/main - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: - node-version: "24" + node-version-file: "package.json" registry-url: "https://registry.npmjs.org" - name: Validate and set channel diff --git a/package.json b/package.json index f4dc48aa6..52b74a7cd 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "packages/published/*" ], "volta": { - "node": "20.19.4", + "node": "24.14.1", "yarn": "1.22.19" }, "scripts": { diff --git a/packages/tests/src/_jest/nockInterceptors.test.ts b/packages/tests/src/_jest/nockInterceptors.test.ts index c9d73e3ff..8de35d580 100644 --- a/packages/tests/src/_jest/nockInterceptors.test.ts +++ b/packages/tests/src/_jest/nockInterceptors.test.ts @@ -65,7 +65,7 @@ const runInLeakDir = (leakDir: string, fixtureGlobals: string, setupFilesAfterEn }; // Node 22 handles the same leak without touching the interceptors, so neither case can tell -// anything apart there. They run before Node 22, which covers the Node 20 the repo pins. +// anything apart there. They only run on a Node older than 22. const nodeMajorVersion = process.versions.node.split('.')[0]; const describeBeforeNode22 = Number(nodeMajorVersion) < 22 ? describe : describe.skip; const INTERCEPTOR_WARNING = /JEST-01.*accessed on \[\w*Interceptor\]/; From f55653d91dc6542f04898cc605fc749d4a83a547 Mon Sep 17 00:00:00 2001 From: Tiffany Trinh Date: Tue, 27 Oct 2026 16:18:46 -0400 Subject: [PATCH 2/2] feat(vite-plugin): warn that Vite below 6.4 is deprecated Every plugin now warns at startup on an older Vite, and on a Vite above 8.x, while the peer range stays `>= 5.x <= 8.x` so no install breaks. A test ties the upper bound to the peer range in package.json. Co-Authored-By: Claude Opus 5.5 --- packages/factory/package.json | 2 + .../factory/src/helpers/vite-version.test.ts | 48 +++++++++++++++ packages/factory/src/helpers/vite-version.ts | 29 +++++++++ packages/factory/src/index.test.ts | 60 +++++++++++++++++++ packages/factory/src/index.ts | 7 +++ .../published/esbuild-plugin/package.json | 1 + packages/published/rollup-plugin/package.json | 1 + packages/published/rspack-plugin/package.json | 1 + packages/published/vite-plugin/package.json | 1 + .../published/webpack-plugin/package.json | 1 + yarn.lock | 25 +++++--- 11 files changed, 167 insertions(+), 9 deletions(-) create mode 100644 packages/factory/src/helpers/vite-version.test.ts create mode 100644 packages/factory/src/helpers/vite-version.ts diff --git a/packages/factory/package.json b/packages/factory/package.json index 0870e0930..3d27ca453 100644 --- a/packages/factory/package.json +++ b/packages/factory/package.json @@ -35,9 +35,11 @@ "@dd/output-plugin": "workspace:*", "@dd/rum-plugin": "workspace:*", "chalk": "2.3.1", + "semver": "7.7.2", "unplugin": "2.3.11" }, "devDependencies": { + "@types/semver": "7.5.8", "typescript": "5.4.3" } } diff --git a/packages/factory/src/helpers/vite-version.test.ts b/packages/factory/src/helpers/vite-version.test.ts new file mode 100644 index 000000000..e0ab82d5c --- /dev/null +++ b/packages/factory/src/helpers/vite-version.test.ts @@ -0,0 +1,48 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the MIT License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2019-Present Datadog, Inc. + +import vitePluginPackage from '../../../published/vite-plugin/package.json'; + +import { getUnsupportedViteWarning, MAX_VITE_MAJOR, MIN_VITE_VERSION } from './vite-version'; + +const floor = MIN_VITE_VERSION.split('.').slice(0, 2).join('.'); +const deprecated = (version: string) => + `Vite ${version} is deprecated in Datadog's Vite plugin: please upgrade to Vite ${floor} or later.`; +const untested = (version: string) => + `Datadog's Vite plugin is tested up to Vite ${MAX_VITE_MAJOR}.x (found ${version}).`; + +describe('getUnsupportedViteWarning', () => { + const cases: { version: unknown; expected: string | undefined }[] = [ + { version: '4.5.3', expected: deprecated('4.5.3') }, + { version: '5.4.21', expected: deprecated('5.4.21') }, + { version: '6.0.0', expected: deprecated('6.0.0') }, + { version: '6.3.9', expected: deprecated('6.3.9') }, + { version: '6.4.0-beta.1', expected: deprecated('6.4.0-beta.1') }, + { version: MIN_VITE_VERSION, expected: undefined }, + { version: '6.4.3', expected: undefined }, + { version: '6.10.0', expected: undefined }, + { version: '7.0.0-beta.1', expected: undefined }, + { version: '8.3.4', expected: undefined }, + { version: '9.0.0', expected: untested('9.0.0') }, + { version: '9.0.0-beta.1', expected: untested('9.0.0-beta.1') }, + { version: '10.1.0', expected: untested('10.1.0') }, + { version: 'v5.4.21', expected: deprecated('v5.4.21') }, + { version: '6.3', expected: undefined }, + { version: '', expected: undefined }, + { version: 'not-a-version', expected: undefined }, + { version: undefined, expected: undefined }, + { version: 5, expected: undefined }, + ]; + + test.each(cases)('Should return the expected warning for $version', ({ version, expected }) => { + const warning = getUnsupportedViteWarning(version); + expect(warning).toBe(expected); + }); + + // Versions below the floor stay in the peer range while deprecated. + test('Should share its upper bound with the peer range the Vite plugin declares', () => { + const upperBound = new RegExp(`<= ?${MAX_VITE_MAJOR}\\.x$`); + expect(vitePluginPackage.peerDependencies.vite).toMatch(upperBound); + }); +}); diff --git a/packages/factory/src/helpers/vite-version.ts b/packages/factory/src/helpers/vite-version.ts new file mode 100644 index 000000000..e2ff65cdf --- /dev/null +++ b/packages/factory/src/helpers/vite-version.ts @@ -0,0 +1,29 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the MIT License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2019-Present Datadog, Inc. + +import semver from 'semver'; + +// The oldest line Vite still patches: https://vite.dev/releases#supported-versions +export const MIN_VITE_VERSION = '6.4.0'; +export const MAX_VITE_MAJOR = 8; + +const MIN_VITE_LINE = `${semver.major(MIN_VITE_VERSION)}.${semver.minor(MIN_VITE_VERSION)}`; + +// An unreadable version is left alone: the warning is advice, not a gate. +export const getUnsupportedViteWarning = (version: unknown): string | undefined => { + const parsed = typeof version === 'string' ? semver.parse(version) : null; + if (!parsed) { + return undefined; + } + + if (semver.lt(parsed, MIN_VITE_VERSION)) { + return `Vite ${version} is deprecated in Datadog's Vite plugin: please upgrade to Vite ${MIN_VITE_LINE} or later.`; + } + + if (parsed.major > MAX_VITE_MAJOR) { + return `Datadog's Vite plugin is tested up to Vite ${MAX_VITE_MAJOR}.x (found ${version}).`; + } + + return undefined; +}; diff --git a/packages/factory/src/index.test.ts b/packages/factory/src/index.test.ts index 601a3f5f4..de77c65d9 100644 --- a/packages/factory/src/index.test.ts +++ b/packages/factory/src/index.test.ts @@ -4,6 +4,7 @@ import type { PluginOptions, Options } from '@dd/core/types'; import { PLUGIN_NAME as ERROR_TRACKING_PLUGIN_NAME } from '@dd/error-tracking-plugin'; +import { getUnsupportedViteWarning } from '@dd/factory/helpers/vite-version'; import { buildPluginFactory } from '@dd/factory'; const invokeFactory = (opts: Options): PluginOptions[] => { @@ -93,4 +94,63 @@ describe('Factory', () => { expect(hasPlugin(plugins, 'output')).toBe(true); }); }); + + describe('Vite version', () => { + let warn: jest.SpyInstance; + + beforeEach(() => { + warn = jest.spyOn(console, 'warn').mockImplementation(() => {}); + }); + + afterEach(() => { + warn.mockRestore(); + }); + + const cases: { + description: string; + framework: 'vite' | 'esbuild'; + version: string; + warns: boolean; + }[] = [ + { description: 'Vite 5', framework: 'vite', version: '5.4.21', warns: true }, + { description: 'Vite 6.3', framework: 'vite', version: '6.3.5', warns: true }, + { description: 'Vite 6.4', framework: 'vite', version: '6.4.3', warns: false }, + { description: 'Vite 8', framework: 'vite', version: '8.3.4', warns: false }, + { description: 'Vite 9', framework: 'vite', version: '9.0.0', warns: true }, + { + description: 'another bundler with a low version', + framework: 'esbuild', + version: '0.25.8', + warns: false, + }, + ]; + + test.each(cases)( + 'Should warn about an unsupported Vite only when it is one: $description', + ({ framework, version, warns }) => { + const factory = buildPluginFactory({ bundler: { version }, version: '1.0.0' }); + factory.raw({ logLevel: 'warn' }, { framework }); + const warnings = warn.mock.calls.map(([message]) => String(message)); + const viteWarnings = warnings.filter((message) => + message.includes("Datadog's Vite plugin"), + ); + const expected = getUnsupportedViteWarning(version); + const matching = viteWarnings.filter( + (message) => expected !== undefined && message.endsWith(expected), + ); + const count = warns ? 1 : 0; + expect(viteWarnings).toHaveLength(count); + expect(matching).toHaveLength(count); + }, + ); + + test('Should not print the warning when logs are off', () => { + const factory = buildPluginFactory({ + bundler: { version: '5.4.21' }, + version: '1.0.0', + }); + factory.raw({ logLevel: 'none' }, { framework: 'vite' }); + expect(warn).not.toHaveBeenCalled(); + }); + }); }); diff --git a/packages/factory/src/index.ts b/packages/factory/src/index.ts index 775800e2b..bd6d12c9c 100644 --- a/packages/factory/src/index.ts +++ b/packages/factory/src/index.ts @@ -31,6 +31,7 @@ import chalk from 'chalk'; import { validateOptions } from './validate'; import { getContext } from './helpers/context'; +import { getUnsupportedViteWarning } from './helpers/vite-version'; import { wrapGetPlugins } from './helpers/wrapPlugins'; import { ALL_ENVS, HOST_NAME } from '@dd/core/constants'; import { notifyOnEnvOverrides } from '@dd/core/helpers/env'; @@ -136,6 +137,12 @@ export const buildPluginFactory = ({ const log = context.getLogger('factory'); const timeInit = log.time('Plugins initialization', { start: pluginStart }); + const viteWarning = + bundlerName === 'vite' ? getUnsupportedViteWarning(bundlerVersion) : undefined; + if (viteWarning) { + log.warn(viteWarning); + } + context.pluginNames.push(HOST_NAME); const pluginsToAdd: [name: string, GetPlugins | GetCustomPlugins | GetInternalPlugins][] = diff --git a/packages/published/esbuild-plugin/package.json b/packages/published/esbuild-plugin/package.json index 407a0e0d9..ce4212a88 100644 --- a/packages/published/esbuild-plugin/package.json +++ b/packages/published/esbuild-plugin/package.json @@ -64,6 +64,7 @@ "p-queue": "6.6.2", "picomatch": "4.0.7", "pretty-bytes": "5.6.0", + "semver": "7.7.2", "simple-git": "4.0.2", "unplugin": "2.3.11" }, diff --git a/packages/published/rollup-plugin/package.json b/packages/published/rollup-plugin/package.json index 33983df1d..a43d5304b 100644 --- a/packages/published/rollup-plugin/package.json +++ b/packages/published/rollup-plugin/package.json @@ -67,6 +67,7 @@ "p-queue": "6.6.2", "picomatch": "4.0.7", "pretty-bytes": "5.6.0", + "semver": "7.7.2", "simple-git": "4.0.2", "unplugin": "2.3.11" }, diff --git a/packages/published/rspack-plugin/package.json b/packages/published/rspack-plugin/package.json index 057196f49..69b4f5440 100644 --- a/packages/published/rspack-plugin/package.json +++ b/packages/published/rspack-plugin/package.json @@ -64,6 +64,7 @@ "p-queue": "6.6.2", "picomatch": "4.0.7", "pretty-bytes": "5.6.0", + "semver": "7.7.2", "simple-git": "4.0.2", "unplugin": "2.3.11" }, diff --git a/packages/published/vite-plugin/package.json b/packages/published/vite-plugin/package.json index d8beaf083..296e013fd 100644 --- a/packages/published/vite-plugin/package.json +++ b/packages/published/vite-plugin/package.json @@ -64,6 +64,7 @@ "p-queue": "6.6.2", "picomatch": "4.0.7", "pretty-bytes": "5.6.0", + "semver": "7.7.2", "simple-git": "4.0.2", "unplugin": "2.3.11" }, diff --git a/packages/published/webpack-plugin/package.json b/packages/published/webpack-plugin/package.json index 8d329dc91..426b4cf1d 100644 --- a/packages/published/webpack-plugin/package.json +++ b/packages/published/webpack-plugin/package.json @@ -64,6 +64,7 @@ "p-queue": "6.6.2", "picomatch": "4.0.7", "pretty-bytes": "5.6.0", + "semver": "7.7.2", "simple-git": "4.0.2", "unplugin": "2.3.11" }, diff --git a/yarn.lock b/yarn.lock index 5a81e9e8c..13cefe523 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1713,6 +1713,7 @@ __metadata: pretty-bytes: "npm:5.6.0" rollup: "npm:4.60.4" rollup-plugin-esbuild: "npm:6.1.1" + semver: "npm:7.7.2" simple-git: "npm:4.0.2" typescript: "npm:5.4.3" unplugin: "npm:2.3.11" @@ -1772,6 +1773,7 @@ __metadata: pretty-bytes: "npm:5.6.0" rollup: "npm:4.60.4" rollup-plugin-esbuild: "npm:6.1.1" + semver: "npm:7.7.2" simple-git: "npm:4.0.2" typescript: "npm:5.4.3" unplugin: "npm:2.3.11" @@ -1824,6 +1826,7 @@ __metadata: pretty-bytes: "npm:5.6.0" rollup: "npm:4.60.4" rollup-plugin-esbuild: "npm:6.1.1" + semver: "npm:7.7.2" simple-git: "npm:4.0.2" typescript: "npm:5.4.3" unplugin: "npm:2.3.11" @@ -1879,6 +1882,7 @@ __metadata: pretty-bytes: "npm:5.6.0" rollup: "npm:4.60.4" rollup-plugin-esbuild: "npm:6.1.1" + semver: "npm:7.7.2" simple-git: "npm:4.0.2" typescript: "npm:5.4.3" unplugin: "npm:2.3.11" @@ -1931,6 +1935,7 @@ __metadata: pretty-bytes: "npm:5.6.0" rollup: "npm:4.60.4" rollup-plugin-esbuild: "npm:6.1.1" + semver: "npm:7.7.2" simple-git: "npm:4.0.2" typescript: "npm:5.4.3" unplugin: "npm:2.3.11" @@ -2028,7 +2033,9 @@ __metadata: "@dd/metrics-plugin": "workspace:*" "@dd/output-plugin": "workspace:*" "@dd/rum-plugin": "workspace:*" + "@types/semver": "npm:7.5.8" chalk: "npm:2.3.1" + semver: "npm:7.7.2" typescript: "npm:5.4.3" unplugin: "npm:2.3.11" languageName: unknown @@ -4262,7 +4269,7 @@ __metadata: languageName: node linkType: hard -"@types/semver@npm:^7.5.0": +"@types/semver@npm:7.5.8, @types/semver@npm:^7.5.0": version: 7.5.8 resolution: "@types/semver@npm:7.5.8" checksum: 10/3496808818ddb36deabfe4974fd343a78101fa242c4690044ccdc3b95dcf8785b494f5d628f2f47f38a702f8db9c53c67f47d7818f2be1b79f2efb09692e1178 @@ -10224,21 +10231,21 @@ __metadata: languageName: node linkType: hard -"semver@npm:^6.0.0, semver@npm:^6.3.1": - version: 6.3.1 - resolution: "semver@npm:6.3.1" +"semver@npm:7.7.2, semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.5.4, semver@npm:^7.6.0, semver@npm:^7.7.2": + version: 7.7.2 + resolution: "semver@npm:7.7.2" bin: semver: bin/semver.js - checksum: 10/1ef3a85bd02a760c6ef76a45b8c1ce18226de40831e02a00bad78485390b98b6ccaa31046245fc63bba4a47a6a592b6c7eedc65cc47126e60489f9cc1ce3ed7e + checksum: 10/7a24cffcaa13f53c09ce55e05efe25cd41328730b2308678624f8b9f5fc3093fc4d189f47950f0b811ff8f3c3039c24a2c36717ba7961615c682045bf03e1dda languageName: node linkType: hard -"semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.5.4, semver@npm:^7.6.0, semver@npm:^7.7.2": - version: 7.7.2 - resolution: "semver@npm:7.7.2" +"semver@npm:^6.0.0, semver@npm:^6.3.1": + version: 6.3.1 + resolution: "semver@npm:6.3.1" bin: semver: bin/semver.js - checksum: 10/7a24cffcaa13f53c09ce55e05efe25cd41328730b2308678624f8b9f5fc3093fc4d189f47950f0b811ff8f3c3039c24a2c36717ba7961615c682045bf03e1dda + checksum: 10/1ef3a85bd02a760c6ef76a45b8c1ce18226de40831e02a00bad78485390b98b6ccaa31046245fc63bba4a47a6a592b6c7eedc65cc47126e60489f9cc1ce3ed7e languageName: node linkType: hard