@nx/expo 23.2.0-beta.6 → 23.2.0-beta.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1,4 @@
1
- export declare function getResolveRequest(extensions: string[], exportsConditionNames?: string[], mainFields?: string[]): (_context: any, realModuleName: string, platform: string | null) => any;
1
+ export declare function getResolveRequest(extensions: string[], exportsConditionNames?: string[], mainFields?: string[], anchor?: {
2
+ appRoot?: string;
3
+ usesExpoMetro: boolean;
4
+ }): (_context: any, realModuleName: string, platform: string | null) => any;
@@ -9,29 +9,28 @@ const enhanced_resolve_1 = require("enhanced-resolve");
9
9
  const path_1 = require("path");
10
10
  const fs = tslib_1.__importStar(require("fs"));
11
11
  const devkit_1 = require("@nx/devkit");
12
- // Cache for metro-resolver module
13
- let metroResolver = null;
14
- /**
15
- * Lazily require the Metro resolver.
16
- *
17
- * Expo SDK 55+ ships Metro through `@expo/metro`, so the resolver must come
18
- * from the same Metro instance Expo uses. Older SDKs (53/54) use the standalone
19
- * `metro-resolver` package. We prefer `@expo/metro` and fall back to the
20
- * standalone package to stay compatible with both.
21
- */
22
- function getMetroResolver() {
12
+ const metroResolverCache = new Map();
13
+ // The resolver must come from the same Metro instance Expo uses: `@expo/metro`
14
+ // on SDK 55+, standalone `metro-resolver` on 53/54. Resolve from the app root
15
+ // so each app gets its own SDK's copy.
16
+ function getMetroResolver(appRoot, usesExpoMetro) {
17
+ const cacheKey = `${appRoot ?? ''}|${usesExpoMetro}`;
18
+ let metroResolver = metroResolverCache.get(cacheKey);
23
19
  if (!metroResolver) {
24
- try {
25
- metroResolver = require('@expo/metro/metro-resolver');
26
- }
27
- catch {
20
+ const candidates = usesExpoMetro
21
+ ? ['@expo/metro/metro-resolver', 'metro-resolver']
22
+ : ['metro-resolver', '@expo/metro/metro-resolver'];
23
+ for (const candidate of candidates) {
28
24
  try {
29
- metroResolver = require('metro-resolver');
30
- }
31
- catch (error) {
32
- throw new Error('Unable to load Metro resolver. Install `@expo/metro` (Expo SDK 55+) or `metro-resolver` (>= 0.82.0).');
25
+ metroResolver = require(require.resolve(candidate, appRoot ? { paths: [appRoot] } : undefined));
26
+ break;
33
27
  }
28
+ catch { }
29
+ }
30
+ if (!metroResolver) {
31
+ throw new Error('Unable to load Metro resolver. Install `@expo/metro` (Expo SDK 55+) or `metro-resolver` (>= 0.82.0).');
34
32
  }
33
+ metroResolverCache.set(cacheKey, metroResolver);
35
34
  }
36
35
  return metroResolver;
37
36
  }
@@ -41,13 +40,17 @@ function getMetroResolver() {
41
40
  * This resolve function requires projectRoot to be set to
42
41
  * workspace root in order modules and assets to be registered and watched.
43
42
  */
44
- function getResolveRequest(extensions, exportsConditionNames = [], mainFields = []) {
43
+ function getResolveRequest(extensions, exportsConditionNames = [], mainFields = [],
44
+ // which app is being bundled; default keeps the process-wide preference
45
+ anchor = {
46
+ usesExpoMetro: true,
47
+ }) {
45
48
  return function (_context, realModuleName, platform) {
46
49
  const debug = process.env.NX_REACT_NATIVE_DEBUG === 'true';
47
50
  const { resolveRequest, ...context } = _context;
48
51
  const resolvedPath = resolveRequestFromContext(resolveRequest, _context, realModuleName, platform, debug) ??
49
- defaultMetroResolver(context, realModuleName, platform, debug) ??
50
- tsconfigPathsResolver(context, extensions, realModuleName, platform, debug) ??
52
+ defaultMetroResolver(context, realModuleName, platform, debug, anchor) ??
53
+ tsconfigPathsResolver(context, extensions, realModuleName, platform, debug, anchor) ??
51
54
  pnpmResolver(extensions, context, realModuleName, debug, exportsConditionNames, mainFields);
52
55
  if (resolvedPath) {
53
56
  return resolvedPath;
@@ -71,9 +74,9 @@ function resolveRequestFromContext(resolveRequest, context, realModuleName, plat
71
74
  * This function try to resolve path using metro's default resolver
72
75
  * @returns path if resolved, else undefined
73
76
  */
74
- function defaultMetroResolver(context, realModuleName, platform, debug) {
77
+ function defaultMetroResolver(context, realModuleName, platform, debug, anchor) {
75
78
  try {
76
- const resolver = getMetroResolver();
79
+ const resolver = getMetroResolver(anchor.appRoot, anchor.usesExpoMetro);
77
80
  return resolver.resolve(context, realModuleName, platform);
78
81
  }
79
82
  catch {
@@ -109,11 +112,11 @@ function pnpmResolver(extensions, context, realModuleName, debug, exportsConditi
109
112
  * This function try to resolve files that are specified in tsconfig's paths
110
113
  * @returns path if resolved, else undefined
111
114
  */
112
- function tsconfigPathsResolver(context, extensions, realModuleName, platform, debug) {
115
+ function tsconfigPathsResolver(context, extensions, realModuleName, platform, debug, anchor) {
113
116
  try {
114
117
  const tsConfigPathMatcher = getMatcher(debug);
115
118
  const match = tsConfigPathMatcher(realModuleName, undefined, undefined, extensions.map((ext) => `.${ext}`));
116
- const resolver = getMetroResolver();
119
+ const resolver = getMetroResolver(anchor.appRoot, anchor.usesExpoMetro);
117
120
  return resolver.resolve(context, match, platform);
118
121
  }
119
122
  catch {
@@ -1,3 +1,4 @@
1
+ export declare function appUsesExpoMetro(appRoot: string | undefined): boolean;
1
2
  type MetroConfig = any;
2
3
  interface WithNxOptions {
3
4
  /**
@@ -1,36 +1,66 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.appUsesExpoMetro = appUsesExpoMetro;
3
4
  exports.withNxMetro = withNxMetro;
4
5
  const devkit_1 = require("@nx/devkit");
5
6
  const node_fs_1 = require("node:fs");
6
7
  const path_1 = require("path");
7
- // Cache for metro-config module
8
- let metroConfig = null;
9
- /**
10
- * Lazily require the Metro config helpers.
11
- *
12
- * Expo SDK 55+ ships Metro through the `@expo/metro` package family, so the
13
- * `mergeConfig` used here must come from the same Metro instance that
14
- * `@expo/metro-config`'s `getDefaultConfig` is built against. Older SDKs
15
- * (53/54) use the standalone `metro-config` package. We prefer `@expo/metro`
16
- * and fall back to the standalone package to stay compatible with both.
17
- */
18
- function getMetroConfig() {
8
+ const metroConfigCache = new Map();
9
+ // `mergeConfig` must come from the same Metro instance as the app's
10
+ // `getDefaultConfig`: `@expo/metro` on SDK 55+, standalone `metro-config` on
11
+ // 53/54. Resolve from the app root so each app gets its own SDK's copy.
12
+ function getMetroConfig(appRoot, usesExpoMetro) {
13
+ const cacheKey = `${appRoot ?? ''}|${usesExpoMetro}`;
14
+ let metroConfig = metroConfigCache.get(cacheKey);
19
15
  if (!metroConfig) {
20
- try {
21
- metroConfig = require('@expo/metro/metro-config');
22
- }
23
- catch {
16
+ const candidates = usesExpoMetro
17
+ ? ['@expo/metro/metro-config', 'metro-config']
18
+ : ['metro-config', '@expo/metro/metro-config'];
19
+ for (const candidate of candidates) {
24
20
  try {
25
- metroConfig = require('metro-config');
26
- }
27
- catch (error) {
28
- throw new Error('Unable to load Metro config. Install `@expo/metro` (Expo SDK 55+) or `metro-config` (>= 0.82.0).');
21
+ metroConfig = require(require.resolve(candidate, appRoot ? { paths: [appRoot] } : undefined));
22
+ break;
29
23
  }
24
+ catch { }
30
25
  }
26
+ if (!metroConfig) {
27
+ throw new Error('Unable to load Metro config. Install `@expo/metro` (Expo SDK 55+) or `metro-config` (>= 0.82.0).');
28
+ }
29
+ metroConfigCache.set(cacheKey, metroConfig);
31
30
  }
32
31
  return metroConfig;
33
32
  }
33
+ // SDK 55+ ships Metro through `@expo/metro`. Resolve `expo` from the app's
34
+ // own root: probing from this plugin's location reads whichever copy is
35
+ // hoisted, which can belong to a sibling app on a different SDK.
36
+ function appUsesExpoMetro(appRoot) {
37
+ try {
38
+ const expoPkgPath = require.resolve('expo/package.json', appRoot ? { paths: [appRoot] } : undefined);
39
+ return parseInt(require(expoPkgPath).version, 10) >= 55;
40
+ }
41
+ catch {
42
+ // expo not resolvable; probe `@expo/metro` process-wide (no root entry
43
+ // point, so resolve a known subpath)
44
+ try {
45
+ require.resolve('@expo/metro/metro-config');
46
+ return true;
47
+ }
48
+ catch {
49
+ return false;
50
+ }
51
+ }
52
+ }
53
+ function appOwnsExpo(appNodeModules) {
54
+ const appExpo = (0, path_1.join)(appNodeModules, 'expo');
55
+ if (!(0, node_fs_1.existsSync)(appExpo))
56
+ return false;
57
+ const hoistedExpo = (0, path_1.join)(devkit_1.workspaceRoot, 'node_modules', 'expo');
58
+ // no hoisted copy: the app-local one is the only expo, and Expo's HMR
59
+ // rewrite resolves strictly from `projectRoot`, so anchor at the app
60
+ if (!(0, node_fs_1.existsSync)(hoistedExpo))
61
+ return true;
62
+ return (0, node_fs_1.realpathSync)(appExpo) !== (0, node_fs_1.realpathSync)(hoistedExpo);
63
+ }
34
64
  const metro_resolver_1 = require("./metro-resolver");
35
65
  function withNxMetro(userConfig, opts = {}) {
36
66
  const extensions = ['', 'ts', 'tsx', 'js', 'jsx', 'json'];
@@ -46,30 +76,30 @@ function withNxMetro(userConfig, opts = {}) {
46
76
  watchFolders = watchFolders.concat(opts.watchFolders);
47
77
  }
48
78
  watchFolders = [...new Set(watchFolders)].filter((folder) => (0, node_fs_1.existsSync)(folder));
49
- // Expo SDK 55+ ships Metro via `@expo/metro` and resolves the project's
50
- // Babel config relative to `projectRoot`. Forcing `projectRoot` to the
51
- // workspace root breaks that lookup, because the app's `.babelrc.js` lives in
52
- // the project directory, not the workspace root (Metro's babel transformer
53
- // does `path.resolve(projectRoot, '.babelrc.js')`). So only override
54
- // `projectRoot` for older SDKs (53/54). Workspace libraries remain resolvable
55
- // via `watchFolders`, `nodeModulesPaths`, and the custom `resolveRequest`.
56
- // `@expo/metro` has no root entry point (only subpath exports), so resolve a
57
- // known subpath to detect it `require.resolve('@expo/metro')` would throw
58
- // ERR_PACKAGE_PATH_NOT_EXPORTED even when the package is installed.
59
- let usesExpoMetro = false;
60
- try {
61
- require.resolve('@expo/metro/metro-config');
62
- usesExpoMetro = true;
63
- }
64
- catch { }
79
+ // `getDefaultConfig(__dirname)` set this to the app directory
80
+ const appRoot = userConfig.projectRoot;
81
+ const usesExpoMetro = appUsesExpoMetro(appRoot);
82
+ const appNodeModules = appRoot ? (0, path_1.join)(appRoot, 'node_modules') : null;
83
+ const hasAppNodeModules = !!appNodeModules && (0, node_fs_1.existsSync)(appNodeModules);
84
+ // an app pinning its own `expo` must stay anchored at the app, or the
85
+ // bundle picks up the hoisted copy alongside its own. Compare real paths:
86
+ // `ensureNodeModulesSymlink` links the whole app node_modules to the
87
+ // workspace's, which is not an app-owned copy.
88
+ const ownsExpo = hasAppNodeModules && appOwnsExpo(appNodeModules);
89
+ // SDK 55+ resolves Babel config and the HMR client relative to
90
+ // `projectRoot`; SDK 53/54 apps relying on hoisted Expo need the workspace
91
+ // root so `originModulePath` stays workspace-relative for the Nx resolver.
65
92
  const nxConfig = {
66
- ...(usesExpoMetro ? {} : { projectRoot: devkit_1.workspaceRoot }),
93
+ ...(usesExpoMetro || ownsExpo ? {} : { projectRoot: devkit_1.workspaceRoot }),
67
94
  resolver: {
68
- resolveRequest: (0, metro_resolver_1.getResolveRequest)(extensions, opts.exportsConditionNames, opts.mainFields),
69
- nodeModulesPaths: [(0, path_1.join)(devkit_1.workspaceRoot, 'node_modules')],
95
+ resolveRequest: (0, metro_resolver_1.getResolveRequest)(extensions, opts.exportsConditionNames, opts.mainFields, { appRoot, usesExpoMetro }),
96
+ nodeModulesPaths: [
97
+ ...(hasAppNodeModules ? [appNodeModules] : []),
98
+ (0, path_1.join)(devkit_1.workspaceRoot, 'node_modules'),
99
+ ],
70
100
  },
71
101
  watchFolders,
72
102
  };
73
- const { mergeConfig } = getMetroConfig();
103
+ const { mergeConfig } = getMetroConfig(appRoot, usesExpoMetro);
74
104
  return mergeConfig(userConfig, nxConfig);
75
105
  }
@@ -60,27 +60,52 @@ function serveAsync(workspaceRoot, projectRoot, options) {
60
60
  env: process.env,
61
61
  stdio: ['inherit', 'pipe', 'pipe', 'ipc'],
62
62
  });
63
+ let settled = false;
64
+ const settleResolve = (cp) => {
65
+ if (settled)
66
+ return;
67
+ settled = true;
68
+ resolve(cp);
69
+ };
70
+ const settleReject = (err) => {
71
+ if (settled)
72
+ return;
73
+ settled = true;
74
+ reject(err);
75
+ };
76
+ // Expo bundles on first request, so waiting on a bundle log line deadlocks
77
+ // against a consumer that only requests once we report ready (@nx/cypress).
78
+ // /status answers packager-status:running once Metro's bundler is ready.
79
+ void (async () => {
80
+ while (!settled) {
81
+ if ((await (0, is_packager_running_1.isPackagerRunning)(options.port)) === 'running') {
82
+ settleResolve(childProcess);
83
+ return;
84
+ }
85
+ await new Promise((r) => setTimeout(r, 500));
86
+ }
87
+ })();
63
88
  childProcess.stdout.on('data', (data) => {
64
89
  process.stdout.write(data);
65
90
  if (data.toString().includes('Bundling complete') ||
66
91
  data.toString().includes('Bundled')) {
67
- resolve(childProcess);
92
+ settleResolve(childProcess);
68
93
  }
69
94
  });
70
95
  childProcess.stderr.on('data', (data) => {
71
96
  process.stderr.write(data);
72
97
  });
73
98
  childProcess.on('error', (err) => {
74
- reject(err);
99
+ settleReject(err);
75
100
  });
76
101
  childProcess.on('exit', (code, signal) => {
77
102
  if (code === null)
78
103
  code = (0, internal_1.signalToCode)(signal);
79
104
  if (code === 0) {
80
- resolve(childProcess);
105
+ settleResolve(childProcess);
81
106
  }
82
107
  else {
83
- reject(code);
108
+ settleReject(code);
84
109
  }
85
110
  });
86
111
  });
@@ -1,6 +1,8 @@
1
1
  import { Tree } from '@nx/devkit';
2
2
  import { Schema } from '../schema';
3
+ import type { LinterType } from '@nx/js';
3
4
  export interface NormalizedSchema extends Omit<Schema, 'name' | 'useTsSolution'> {
5
+ linter: LinterType;
4
6
  className: string;
5
7
  simpleName: string;
6
8
  projectName: string;
@@ -27,6 +27,10 @@ async function normalizeOptions(host, options) {
27
27
  const e2eProjectRoot = rootProject ? 'e2e' : `${appProjectRoot}-e2e`;
28
28
  return {
29
29
  ...options,
30
+ // Resolved after the spread: `undefined` is falsy, so the ESLint arm in
31
+ // add-linting would still run while the `=== 'eslint'` tsconfig excludes
32
+ // below are skipped.
33
+ linter: await (0, internal_2.normalizeLinterOption)(host, options.linter),
30
34
  unitTestRunner: options.unitTestRunner || 'jest',
31
35
  e2eTestRunner: options.e2eTestRunner || 'none',
32
36
  simpleName: projectNames.projectSimpleName,
@@ -1,4 +1,4 @@
1
- import type { Linter, LinterType } from '@nx/eslint';
1
+ import type { LinterType } from '@nx/js';
2
2
 
3
3
  export interface Schema {
4
4
  directory: string;
@@ -10,7 +10,7 @@ export interface Schema {
10
10
  unitTestRunner: 'jest' | 'none'; // default is jest
11
11
  classComponent?: boolean;
12
12
  js: boolean; // default is false
13
- linter: Linter | LinterType; // default is eslint
13
+ linter?: LinterType;
14
14
  enableTypedLinting?: boolean; // default is false
15
15
  /**
16
16
  * @deprecated Use `enableTypedLinting` instead. This option will be removed in Nx v24.
@@ -41,11 +41,9 @@
41
41
  "x-priority": "internal"
42
42
  },
43
43
  "linter": {
44
- "description": "The tool to use for running lint checks.",
44
+ "description": "The tool to use for running lint checks. Defaults to the linter the workspace already uses.",
45
45
  "type": "string",
46
- "enum": ["eslint", "none"],
47
- "default": "none",
48
- "x-prompt": "Which linter would you like to use?",
46
+ "enum": ["eslint", "oxlint", "none"],
49
47
  "x-priority": "important"
50
48
  },
51
49
  "unitTestRunner": {
@@ -1,6 +1,8 @@
1
1
  import { Tree } from '@nx/devkit';
2
2
  import { Schema } from '../schema';
3
+ import type { LinterType } from '@nx/js';
3
4
  export interface NormalizedSchema extends Omit<Schema, 'name'> {
5
+ linter: LinterType;
4
6
  fileName: string;
5
7
  projectName: string;
6
8
  projectRoot: string;
@@ -23,6 +23,10 @@ async function normalizeOptions(host, options) {
23
23
  const useProjectJson = options.useProjectJson ?? !isUsingTsSolutionConfig;
24
24
  const normalized = {
25
25
  ...options,
26
+ // Resolved in the literal so the type guarantees it: `undefined` is falsy,
27
+ // so the ESLint arm would still run while the `=== 'eslint'` tsconfig
28
+ // excludes below are skipped.
29
+ linter: await (0, internal_2.normalizeLinterOption)(host, options.linter),
26
30
  fileName: projectName,
27
31
  routePath: `/${projectNames.projectSimpleName}`,
28
32
  projectName: isUsingTsSolutionConfig && !options.name ? importPath : projectName,
@@ -1,4 +1,4 @@
1
- import type { Linter, LinterType } from '@nx/eslint';
1
+ import type { LinterType } from '@nx/js';
2
2
 
3
3
  /**
4
4
  * Same as the @nx/react library schema, except it removes keys: style, component, routing, appProject
@@ -10,7 +10,7 @@ export interface Schema {
10
10
  skipFormat: boolean; // default is false
11
11
  tags?: string;
12
12
  unitTestRunner: 'jest' | 'none';
13
- linter: Linter | LinterType; // default is eslint
13
+ linter?: LinterType;
14
14
  publishable?: boolean;
15
15
  buildable?: boolean;
16
16
  importPath?: string;
@@ -26,11 +26,9 @@
26
26
  "x-priority": "important"
27
27
  },
28
28
  "linter": {
29
- "description": "The tool to use for running lint checks.",
29
+ "description": "The tool to use for running lint checks. Defaults to the linter the workspace already uses.",
30
30
  "type": "string",
31
- "enum": ["eslint", "none"],
32
- "default": "none",
33
- "x-prompt": "Which linter would you like to use?",
31
+ "enum": ["eslint", "oxlint", "none"],
34
32
  "x-priority": "important"
35
33
  },
36
34
  "unitTestRunner": {
@@ -1,7 +1,7 @@
1
- import { Linter, LinterType } from '@nx/eslint';
1
+ import { LinterType } from '@nx/js';
2
2
  import { GeneratorCallback, Tree } from '@nx/devkit';
3
3
  interface NormalizedSchema {
4
- linter?: Linter | LinterType;
4
+ linter?: LinterType;
5
5
  projectName: string;
6
6
  projectRoot: string;
7
7
  enableTypedLinting?: boolean;
@@ -10,6 +10,7 @@ interface NormalizedSchema {
10
10
  */
11
11
  setParserOptionsProject?: boolean;
12
12
  tsConfigPaths: string[];
13
+ unitTestRunner?: string;
13
14
  skipPackageJson?: boolean;
14
15
  addPlugin?: boolean;
15
16
  buildable?: boolean;
@@ -1,26 +1,28 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.addLinting = addLinting;
4
- const eslint_1 = require("@nx/eslint");
5
4
  const devkit_1 = require("@nx/devkit");
6
5
  const react_1 = require("@nx/react");
7
6
  const internal_1 = require("@nx/eslint/internal");
7
+ const internal_2 = require("@nx/js/internal");
8
8
  async function addLinting(host, options) {
9
- if (options.linter === 'none') {
10
- return () => { };
11
- }
12
9
  const tasks = [];
13
- const lintTask = await (0, eslint_1.lintProjectGenerator)(host, {
10
+ tasks.push(await (0, internal_2.addLintingToProject)(host, {
11
+ oxlintPlugins: ['react', 'react-perf'],
14
12
  linter: options.linter,
15
13
  project: options.projectName,
16
14
  tsConfigPaths: options.tsConfigPaths,
17
- skipFormat: true,
15
+ unitTestRunner: options.unitTestRunner,
18
16
  skipPackageJson: options.skipPackageJson,
19
17
  enableTypedLinting: (0, internal_1.isTypedLintingEnabled)(options),
20
18
  addPlugin: options.addPlugin,
21
19
  addPackageJsonDependencyChecks: options.buildable,
22
- });
23
- tasks.push(lintTask);
20
+ }));
21
+ // Everything below configures ESLint — predefined configs, `extends`, ignore
22
+ // entries — which have no equivalent in other linters.
23
+ if (options.linter && options.linter !== 'eslint') {
24
+ return (0, devkit_1.runTasksInSerial)(...tasks);
25
+ }
24
26
  // Add ignored dependencies and files to dependency-checks rule
25
27
  if ((0, internal_1.isEslintConfigSupported)(host)) {
26
28
  (0, internal_1.updateOverrideInLintConfig)(host, options.projectRoot, (override) => Boolean(override.rules?.['@nx/dependency-checks']), (override) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/expo",
3
- "version": "23.2.0-beta.6",
3
+ "version": "23.2.0-beta.8",
4
4
  "private": false,
5
5
  "description": "The Expo Plugin for Nx contains executors and generators for managing and developing an expo application within your workspace. For example, you can directly build for different target platforms as well as generate projects and publish your code.",
6
6
  "keywords": [
@@ -61,18 +61,18 @@
61
61
  "semver": "^7.6.3",
62
62
  "tsconfig-paths": "^4.1.2",
63
63
  "tslib": "^2.3.0",
64
- "@nx/devkit": "23.2.0-beta.6",
65
- "@nx/eslint": "23.2.0-beta.6",
66
- "@nx/js": "23.2.0-beta.6",
67
- "@nx/react": "23.2.0-beta.6"
64
+ "@nx/devkit": "23.2.0-beta.8",
65
+ "@nx/eslint": "23.2.0-beta.8",
66
+ "@nx/js": "23.2.0-beta.8",
67
+ "@nx/react": "23.2.0-beta.8"
68
68
  },
69
69
  "peerDependencies": {
70
70
  "expo": ">=53.0.0",
71
71
  "@expo/metro": ">= 55.0.0",
72
72
  "metro-config": ">= 0.82.0",
73
73
  "metro-resolver": ">= 0.82.0",
74
- "@nx/cypress": "23.2.0-beta.6",
75
- "@nx/playwright": "23.2.0-beta.6"
74
+ "@nx/cypress": "23.2.0-beta.8",
75
+ "@nx/playwright": "23.2.0-beta.8"
76
76
  },
77
77
  "peerDependenciesMeta": {
78
78
  "@nx/cypress": {
@@ -95,11 +95,11 @@
95
95
  }
96
96
  },
97
97
  "devDependencies": {
98
- "nx": "23.2.0-beta.6"
98
+ "nx": "23.2.0-beta.8"
99
99
  },
100
100
  "optionalDependencies": {
101
- "@nx/detox": "23.2.0-beta.6",
102
- "@nx/rollup": "23.2.0-beta.6"
101
+ "@nx/detox": "23.2.0-beta.8",
102
+ "@nx/rollup": "23.2.0-beta.8"
103
103
  },
104
104
  "executors": "./executors.json",
105
105
  "ng-update": {