feat(expo): add to project package.json for install command (#26500)

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes https://github.com/nrwl/nx/issues/22393
This commit is contained in:
Emily Xiong 2024-06-18 21:09:04 -04:00 committed by GitHub
parent fe30d02109
commit 5646b38c99
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 87 additions and 37 deletions

View File

@ -146,12 +146,26 @@ describe('@nx/expo (legacy)', () => {
it('should install', async () => { it('should install', async () => {
// run install command // run install command
const installResults = await runCLIAsync( let installResults = await runCLIAsync(
`install ${appName} --no-interactive` `install ${appName} --no-interactive`
); );
expect(installResults.combinedOutput).toContain( expect(installResults.combinedOutput).toContain(
'Successfully ran target install' 'Successfully ran target install'
); );
installResults = await runCLIAsync(
`install ${appName} --packages=@react-native-async-storage/async-storage,react-native-image-picker --no-interactive`
);
expect(installResults.combinedOutput).toContain(
'Successfully ran target install'
);
const packageJson = readJson(join('apps', appName, 'package.json'));
expect(packageJson).toMatchObject({
dependencies: {
'@react-native-async-storage/async-storage': '*',
'react-native-image-picker': '*',
},
});
}); });
it('should start', async () => { it('should start', async () => {

View File

@ -112,6 +112,30 @@ describe('@nx/expo', () => {
); );
}); });
it('should install', async () => {
// run install command
let installResults = await runCLIAsync(
`install ${appName} --no-interactive`
);
expect(installResults.combinedOutput).toContain(
'Successfully ran target install'
);
installResults = await runCLIAsync(
`install ${appName} --packages=@react-native-async-storage/async-storage,react-native-image-picker --no-interactive`
);
expect(installResults.combinedOutput).toContain(
'Successfully ran target install'
);
const packageJson = readJson(join(appName, 'package.json'));
expect(packageJson).toMatchObject({
dependencies: {
'@react-native-async-storage/async-storage': '*',
'react-native-image-picker': '*',
},
});
});
it('should run e2e for cypress', async () => { it('should run e2e for cypress', async () => {
if (runE2ETests()) { if (runE2ETests()) {
const results = runCLI(`e2e ${appName}-e2e`); const results = runCLI(`e2e ${appName}-e2e`);

View File

@ -123,8 +123,7 @@ function buildExpoTargets(
outputs: [getOutputs(projectRoot, 'dist')], outputs: [getOutputs(projectRoot, 'dist')],
}, },
[options.installTargetName]: { [options.installTargetName]: {
command: `expo install`, executor: '@nx/expo:install',
options: { cwd: workspaceRoot }, // install at workspace root
}, },
[options.prebuildTargetName]: { [options.prebuildTargetName]: {
executor: `@nx/expo:prebuild`, executor: `@nx/expo:prebuild`,

View File

@ -1,7 +1,13 @@
import { ExecutorContext, names } from '@nx/devkit'; import { ExecutorContext, names } from '@nx/devkit';
import { readJsonFile } from 'nx/src/utils/fileutils';
import { ChildProcess, fork } from 'child_process'; import { ChildProcess, fork } from 'child_process';
import { ExpoInstallOptions } from './schema'; import { ExpoInstallOptions } from './schema';
import { join } from 'path';
import {
displayNewlyAddedDepsMessage,
syncDeps,
} from '../sync-deps/sync-deps.impl';
export interface ExpoInstallOutput { export interface ExpoInstallOutput {
success: boolean; success: boolean;
@ -13,12 +19,8 @@ export default async function* installExecutor(
options: ExpoInstallOptions, options: ExpoInstallOptions,
context: ExecutorContext context: ExecutorContext
): AsyncGenerator<ExpoInstallOutput> { ): AsyncGenerator<ExpoInstallOutput> {
const projectRoot =
context.projectsConfigurations.projects[context.projectName].root;
try { try {
await installAsync(context.root, options); await installAndUpdatePackageJson(context, options);
yield { yield {
success: true, success: true,
}; };
@ -29,6 +31,40 @@ export default async function* installExecutor(
} }
} }
export async function installAndUpdatePackageJson(
context: ExecutorContext,
options: ExpoInstallOptions
) {
await installAsync(context.root, options);
const projectRoot =
context.projectsConfigurations.projects[context.projectName].root;
const workspacePackageJsonPath = join(context.root, 'package.json');
const projectPackageJsonPath = join(
context.root,
projectRoot,
'package.json'
);
const workspacePackageJson = readJsonFile(workspacePackageJsonPath);
const projectPackageJson = readJsonFile(projectPackageJsonPath);
const packages =
typeof options.packages === 'string'
? options.packages.split(',')
: options.packages;
displayNewlyAddedDepsMessage(
context.projectName,
await syncDeps(
context.projectName,
projectPackageJson,
projectPackageJsonPath,
workspacePackageJson,
context.projectGraph,
packages
)
);
}
export function installAsync( export function installAsync(
workspaceRoot: string, workspaceRoot: string,
options: ExpoInstallOptions options: ExpoInstallOptions

View File

@ -1,13 +1,9 @@
import { ExecutorContext, names, readJsonFile } from '@nx/devkit'; import { ExecutorContext, names } from '@nx/devkit';
import { join, resolve as pathResolve } from 'path'; import { resolve as pathResolve } from 'path';
import { ChildProcess, fork } from 'child_process'; import { ChildProcess, fork } from 'child_process';
import { resolveEas } from '../../utils/resolve-eas'; import { resolveEas } from '../../utils/resolve-eas';
import { import { installAndUpdatePackageJson } from '../install/install.impl';
displayNewlyAddedDepsMessage,
syncDeps,
} from '../sync-deps/sync-deps.impl';
import { installAsync } from '../install/install.impl';
import { ExpoEasUpdateOptions } from './schema'; import { ExpoEasUpdateOptions } from './schema';
@ -23,30 +19,11 @@ export default async function* buildExecutor(
): AsyncGenerator<ReactNativeUpdateOutput> { ): AsyncGenerator<ReactNativeUpdateOutput> {
const projectRoot = const projectRoot =
context.projectsConfigurations.projects[context.projectName].root; context.projectsConfigurations.projects[context.projectName].root;
const workspacePackageJsonPath = join(context.root, 'package.json');
const projectPackageJsonPath = join(
context.root,
projectRoot,
'package.json'
);
const workspacePackageJson = readJsonFile(workspacePackageJsonPath);
const projectPackageJson = readJsonFile(projectPackageJsonPath);
await installAsync(context.root, { packages: ['expo-updates'] });
displayNewlyAddedDepsMessage(
context.projectName,
await syncDeps(
context.projectName,
projectPackageJson,
projectPackageJsonPath,
workspacePackageJson,
context.projectGraph,
['expo-updates']
)
);
try { try {
await installAndUpdatePackageJson(context, {
packages: ['expo-updates'],
});
await runCliUpdate(context.root, projectRoot, options); await runCliUpdate(context.root, projectRoot, options);
yield { success: true }; yield { success: true };
} finally { } finally {