From e21c1a60102765b15e303c3312b43d96c1623c52 Mon Sep 17 00:00:00 2001 From: Jack Hsu Date: Tue, 29 Apr 2025 09:57:16 -0400 Subject: [PATCH] feat(react): replace deprecated babel classProperties.loose option in .babelrc files (#30912) This PR updates all `.babelrc` file that still uses the deprecated `classProperties.loose` (deprecated since v18). The top-level `loose` option does the same thing -- previously the two options handled different cases because `@babel/preset-env` did not include class properties. --- docs/generated/manifests/nx-api.json | 10 ++++ docs/generated/packages-metadata.json | 10 ++++ .../update-21-0-0-update-babel-loose.json | 14 +++++ packages/react/migrations.json | 6 +++ .../update-21-0-0/update-babel-loose.md | 48 +++++++++++++++++ .../update-21-0-0/update-babel-loose.spec.ts | 53 +++++++++++++++++++ .../update-21-0-0/update-babel-loose.ts | 31 +++++++++++ 7 files changed, 172 insertions(+) create mode 100644 docs/generated/packages/react/migrations/update-21-0-0-update-babel-loose.json create mode 100644 packages/react/src/migrations/update-21-0-0/update-babel-loose.md create mode 100644 packages/react/src/migrations/update-21-0-0/update-babel-loose.spec.ts create mode 100644 packages/react/src/migrations/update-21-0-0/update-babel-loose.ts diff --git a/docs/generated/manifests/nx-api.json b/docs/generated/manifests/nx-api.json index 216b7bc569..c3bf364ba9 100644 --- a/docs/generated/manifests/nx-api.json +++ b/docs/generated/manifests/nx-api.json @@ -3805,6 +3805,16 @@ } }, "migrations": { + "/nx-api/react/migrations/update-21-0-0-update-babel-loose": { + "description": "Replaces `classProperties.loose` option with `loose`.", + "file": "generated/packages/react/migrations/update-21-0-0-update-babel-loose.json", + "hidden": false, + "name": "update-21-0-0-update-babel-loose", + "version": "21.0.0-beta.11", + "originalFilePath": "/packages/react", + "path": "/nx-api/react/migrations/update-21-0-0-update-babel-loose", + "type": "migration" + }, "/nx-api/react/migrations/add-mf-env-var-to-target-defaults": { "description": "Add NX_MF_DEV_REMOTES to inputs for task hashing when '@nx/webpack:webpack' or '@nx/rspack:rspack' is used for Module Federation.", "file": "generated/packages/react/migrations/add-mf-env-var-to-target-defaults.json", diff --git a/docs/generated/packages-metadata.json b/docs/generated/packages-metadata.json index 96eca84a29..654eb1ff43 100644 --- a/docs/generated/packages-metadata.json +++ b/docs/generated/packages-metadata.json @@ -3778,6 +3778,16 @@ } ], "migrations": [ + { + "description": "Replaces `classProperties.loose` option with `loose`.", + "file": "generated/packages/react/migrations/update-21-0-0-update-babel-loose.json", + "hidden": false, + "name": "update-21-0-0-update-babel-loose", + "version": "21.0.0-beta.11", + "originalFilePath": "/packages/react", + "path": "react/migrations/update-21-0-0-update-babel-loose", + "type": "migration" + }, { "description": "Add NX_MF_DEV_REMOTES to inputs for task hashing when '@nx/webpack:webpack' or '@nx/rspack:rspack' is used for Module Federation.", "file": "generated/packages/react/migrations/add-mf-env-var-to-target-defaults.json", diff --git a/docs/generated/packages/react/migrations/update-21-0-0-update-babel-loose.json b/docs/generated/packages/react/migrations/update-21-0-0-update-babel-loose.json new file mode 100644 index 0000000000..e5b8ee8e0a --- /dev/null +++ b/docs/generated/packages/react/migrations/update-21-0-0-update-babel-loose.json @@ -0,0 +1,14 @@ +{ + "name": "update-21-0-0-update-babel-loose", + "cli": "nx", + "version": "21.0.0-beta.11", + "description": "Replaces `classProperties.loose` option with `loose`.", + "factory": "./src/migrations/update-21-0-0/update-babel-loose", + "implementation": "/packages/react/src/migrations/update-21-0-0/update-babel-loose.ts", + "aliases": [], + "hidden": false, + "path": "/packages/react", + "schema": null, + "type": "migration", + "examplesFile": "#### Replace `classProperties.loose` option in `.babelrc`\n\nThe `classProperties.loose` option is replaced by `loose` in `.babelrc` files.\n\n#### Sample Code Changes\n\n{% tabs %}\n{% tab label=\"Before\" %}\n\n```json {% fileName=\".babelrc\" %}\n{\n \"presets\": [\n [\n \"@nx/react/babel\",\n {\n \"runtime\": \"automatic\",\n \"classProperties\": {\n \"loose\": true\n },\n \"useBuiltIns\": \"usage\"\n }\n ]\n ],\n \"plugins\": []\n}\n```\n\n{% /tab %}\n{% tab label=\"After\" %}\n\n```json {% highlightLines=[7] fileName=\".babelrc\" %}\n{\n \"presets\": [\n [\n \"@nx/react/babel\",\n {\n \"runtime\": \"automatic\",\n \"loose\": true,\n \"useBuiltIns\": \"usage\"\n }\n ]\n ],\n \"plugins\": []\n}\n```\n\n{% /tab %}\n{% /tabs %}\n" +} diff --git a/packages/react/migrations.json b/packages/react/migrations.json index 4203f3cd71..37308c0f28 100644 --- a/packages/react/migrations.json +++ b/packages/react/migrations.json @@ -41,6 +41,12 @@ "version": "20.4.0-beta.0", "description": "Add NX_MF_DEV_REMOTES to inputs for task hashing when '@nx/webpack:webpack' or '@nx/rspack:rspack' is used for Module Federation.", "factory": "./src/migrations/update-18-0-0/add-mf-env-var-to-target-defaults" + }, + "update-21-0-0-update-babel-loose": { + "cli": "nx", + "version": "21.0.0-beta.11", + "description": "Replaces `classProperties.loose` option with `loose`.", + "factory": "./src/migrations/update-21-0-0/update-babel-loose" } }, "packageJsonUpdates": { diff --git a/packages/react/src/migrations/update-21-0-0/update-babel-loose.md b/packages/react/src/migrations/update-21-0-0/update-babel-loose.md new file mode 100644 index 0000000000..68ded95001 --- /dev/null +++ b/packages/react/src/migrations/update-21-0-0/update-babel-loose.md @@ -0,0 +1,48 @@ +#### Replace `classProperties.loose` option in `.babelrc` + +The `classProperties.loose` option is replaced by `loose` in `.babelrc` files. + +#### Sample Code Changes + +{% tabs %} +{% tab label="Before" %} + +```json {% fileName=".babelrc" %} +{ + "presets": [ + [ + "@nx/react/babel", + { + "runtime": "automatic", + "classProperties": { + "loose": true + }, + "useBuiltIns": "usage" + } + ] + ], + "plugins": [] +} +``` + +{% /tab %} +{% tab label="After" %} + +```json {% highlightLines=[7] fileName=".babelrc" %} +{ + "presets": [ + [ + "@nx/react/babel", + { + "runtime": "automatic", + "loose": true, + "useBuiltIns": "usage" + } + ] + ], + "plugins": [] +} +``` + +{% /tab %} +{% /tabs %} diff --git a/packages/react/src/migrations/update-21-0-0/update-babel-loose.spec.ts b/packages/react/src/migrations/update-21-0-0/update-babel-loose.spec.ts new file mode 100644 index 0000000000..8fcb60826d --- /dev/null +++ b/packages/react/src/migrations/update-21-0-0/update-babel-loose.spec.ts @@ -0,0 +1,53 @@ +import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; +import { Tree } from '@nx/devkit'; +import updateBabelLoose from './update-babel-loose'; + +describe('update-babel-loose migration', () => { + let tree: Tree; + + beforeEach(() => { + tree = createTreeWithEmptyWorkspace(); + }); + + it('should update classProperties.loose to loose in .babelrc', async () => { + const filePath = '.babelrc'; + tree.write( + filePath, + JSON.stringify({ + presets: [ + [ + '@nx/react/babel', + { + runtime: 'automatic', + classProperties: { + loose: true, + }, + useBuiltIns: 'usage', + }, + ], + ], + plugins: [], + }) + ); + + await updateBabelLoose(tree); + + const content = tree.read(filePath, 'utf-8'); + const updatedConfig = JSON.parse(content); + expect(updatedConfig.presets[0][1]).toEqual({ + runtime: 'automatic', + loose: true, + useBuiltIns: 'usage', + }); + }); + + it('should skip invalid JSON files', async () => { + const filePath = '.babelrc'; + tree.write(filePath, 'invalid json content'); + + await updateBabelLoose(tree); + + const content = tree.read(filePath, 'utf-8'); + expect(content).toBe('invalid json content'); + }); +}); diff --git a/packages/react/src/migrations/update-21-0-0/update-babel-loose.ts b/packages/react/src/migrations/update-21-0-0/update-babel-loose.ts new file mode 100644 index 0000000000..5ae9f952ec --- /dev/null +++ b/packages/react/src/migrations/update-21-0-0/update-babel-loose.ts @@ -0,0 +1,31 @@ +import { + formatFiles, + type Tree, + updateJson, + visitNotIgnoredFiles, +} from '@nx/devkit'; + +export default async function updateBabelLoose(tree: Tree) { + visitNotIgnoredFiles(tree, '', (path) => { + if (!path.endsWith('.babelrc')) return; + try { + updateJson(tree, path, (babelConfig) => { + if (!Array.isArray(babelConfig.presets)) return; + const ourPreset = babelConfig.presets.find( + (p) => Array.isArray(p) && p[0] === '@nx/react/babel' + ); + if (!ourPreset || !ourPreset[1]) return; + const options = ourPreset[1]; + if (options['classProperties']?.loose !== undefined) { + options.loose = options['classProperties'].loose; + delete options['classProperties']; + } + return babelConfig; + }); + } catch { + // Skip if JSON does not parse for whatever reason + return; + } + }); + await formatFiles(tree); +}