From 341f7649cee399d6c17414a7a368c1f8ff22d2ce Mon Sep 17 00:00:00 2001 From: Emily Xiong Date: Fri, 28 Apr 2023 16:01:01 -0400 Subject: [PATCH] fix(core): preserve deps in package.json for nx init react (#16528) --- e2e/nx-init/src/nx-init-react.test.ts | 5 ++ packages/nx/src/nx-init/react/index.ts | 66 ++++++++++++++++++++++++-- 2 files changed, 67 insertions(+), 4 deletions(-) diff --git a/e2e/nx-init/src/nx-init-react.test.ts b/e2e/nx-init/src/nx-init-react.test.ts index ee27eadd48bc5..37f43ca15592f 100644 --- a/e2e/nx-init/src/nx-init-react.test.ts +++ b/e2e/nx-init/src/nx-init-react.test.ts @@ -40,6 +40,8 @@ describe('nx init (for React)', () => { expect(packageJson.devDependencies['@nx/jest']).toBeDefined(); expect(packageJson.devDependencies['@nx/vite']).toBeUndefined(); expect(packageJson.devDependencies['@nx/webpack']).toBeDefined(); + expect(packageJson.dependencies['redux']).toBeDefined(); + expect(packageJson.name).toEqual(appName); runCLI(`build ${appName}`, { env: { @@ -149,6 +151,8 @@ describe('nx init (for React)', () => { const packageJson = readJson('package.json'); expect(packageJson.devDependencies['@nx/jest']).toBeUndefined(); + expect(packageJson.dependencies['redux']).toBeDefined(); + expect(packageJson.name).toEqual(appName); const viteConfig = readFile(`vite.config.js`); expect(viteConfig).toContain('port: 4200'); // default port @@ -186,6 +190,7 @@ function createReactApp(appName: string) { 'react-dom': '^18.2.0', 'react-scripts': '5.0.1', 'web-vitals': '2.1.4', + redux: '^3.6.0', }, scripts: { start: 'react-scripts start', diff --git a/packages/nx/src/nx-init/react/index.ts b/packages/nx/src/nx-init/react/index.ts index 9d7f36f2cbef2..9751d552315cf 100644 --- a/packages/nx/src/nx-init/react/index.ts +++ b/packages/nx/src/nx-init/react/index.ts @@ -2,13 +2,14 @@ import { execSync } from 'child_process'; import { copySync, moveSync, readdirSync, removeSync } from 'fs-extra'; import { join } from 'path'; import { InitArgs } from '../../command-line/init'; -import { fileExists, readJsonFile } from '../../utils/fileutils'; +import { fileExists, readJsonFile, writeJsonFile } from '../../utils/fileutils'; import { output } from '../../utils/output'; import { detectPackageManager, getPackageManagerCommand, PackageManagerCommands, } from '../../utils/package-manager'; +import { PackageJson } from '../../utils/package-json'; import { askAboutNxCloud, printFinalMessage } from '../utils'; import { checkForCustomWebpackSetup } from './check-for-custom-webpack-setup'; import { checkForUncommittedChanges } from './check-for-uncommitted-changes'; @@ -76,7 +77,7 @@ async function normalizeOptions(options: Options): Promise { const appIsJs = !fileExists(`tsconfig.json`); const reactAppName = readNameFromPackageJson(); - const packageJson = readJsonFile('package.json'); + const packageJson = readJsonFile(join(process.cwd(), 'package.json')); const deps = { ...packageJson.dependencies, ...packageJson.devDependencies, @@ -105,6 +106,13 @@ async function normalizeOptions(options: Options): Promise { }; } +/** + * - Create a temp workspace + * - Move all files to temp workspace + * - Add bundler to temp workspace + * - Move files back to root + * - Clean up unused files + */ async function reorgnizeWorkspaceStructure(options: NormalizedOptions) { createTempWorkspace(options); @@ -162,6 +170,8 @@ async function reorgnizeWorkspaceStructure(options: NormalizedOptions) { } function createTempWorkspace(options: NormalizedOptions) { + removeSync('temp-workspace'); + execSync( `npx ${ options.npxYesFlagNeeded ? '-y' : '' @@ -187,12 +197,60 @@ function createTempWorkspace(options: NormalizedOptions) { removeSync('node_modules'); } +function copyPackageJsonDepsFromTempWorkspace() { + const repoRoot = process.cwd(); + let rootPackageJson = readJsonFile(join(repoRoot, 'package.json')); + const tempWorkspacePackageJson = readJsonFile( + join(repoRoot, 'temp-workspace', 'package.json') + ); + + rootPackageJson = overridePackageDeps( + 'dependencies', + rootPackageJson, + tempWorkspacePackageJson + ); + rootPackageJson = overridePackageDeps( + 'devDependencies', + rootPackageJson, + tempWorkspacePackageJson + ); + rootPackageJson.scripts = {}; // remove existing scripts + writeJsonFile(join(repoRoot, 'package.json'), rootPackageJson); + writeJsonFile( + join(repoRoot, 'temp-workspace', 'package.json'), + rootPackageJson + ); +} + +function overridePackageDeps( + depConfigName: 'dependencies' | 'devDependencies', + base: PackageJson, + override: PackageJson +): PackageJson { + if (!base[depConfigName]) { + base[depConfigName] = override[depConfigName]; + return base; + } + const deps = override[depConfigName]; + Object.keys(deps).forEach((dep) => { + if (base.dependencies?.[dep]) { + delete base.dependencies[dep]; + } + if (base.devDependencies?.[dep]) { + delete base.devDependencies[dep]; + } + base[depConfigName][dep] = deps[dep]; + }); + return base; +} + function moveFilesToTempWorkspace(options: NormalizedOptions) { output.log({ title: '🚚 Moving your React app in your new Nx workspace' }); + copyPackageJsonDepsFromTempWorkspace(); const requiredCraFiles = [ 'project.json', - options.isStandalone ? null : 'package.json', + 'package.json', 'src', 'public', options.appIsJs ? null : 'tsconfig.json', @@ -292,7 +350,7 @@ function cleanUpUnusedFilesAndAddConfigFiles(options: NormalizedOptions) { setupE2eProject(options.reactAppName); } else { removeSync(join('apps', `${options.reactAppName}-e2e`)); - execSync(`${options.pmc.rm} @nx/cypress eslint-plugin-cypress`); + execSync(`${options.pmc.rm} cypress @nx/cypress eslint-plugin-cypress`); } if (options.isStandalone) {