diff --git a/e2e/next/src/next.test.ts b/e2e/next/src/next.test.ts
index 6d95facbebd42..f7f2bdf58aadd 100644
--- a/e2e/next/src/next.test.ts
+++ b/e2e/next/src/next.test.ts
@@ -161,21 +161,12 @@ describe('Next.js Applications', () => {
updateFile(
`apps/${appName}/pages/index.tsx`,
`
- import React, { useEffect, useState } from 'react';
-
- export const Index = () => {
- const [greeting, setGreeting] = useState('');
-
- useEffect(() => {
- fetch('/external-api/hello')
- .then(r => r.text())
- .then(setGreeting);
- }, []);
-
- return <>
-
{greeting}
- {process.env.NX_CUSTOM_VAR}
- >;
+ import React from 'react';
+
+ export const Index = ({ greeting }: any) => {
+ return (
+ {process.env.NX_CUSTOM_VAR}
+ );
};
export default Index;
`
@@ -185,7 +176,7 @@ describe('Next.js Applications', () => {
`apps/${appName}/pages/api/hello.js`,
`
export default (_req, res) => {
- res.status(200).send('Welcome to ${appName}');
+ res.status(200).send('Welcome');
};
`
);
@@ -198,9 +189,10 @@ describe('Next.js Applications', () => {
}
);
- const data = await getData(port);
- expect(data).toContain(`Welcome to ${appName}`);
- expect(data).toContain(`test value from a file`);
+ const apiData = await getData(port, '/external-api/hello');
+ const pageData = await getData(port, '/');
+ expect(apiData).toContain(`Welcome`);
+ expect(pageData).toContain(`test value from a file`);
try {
await promisifiedTreeKill(p.pid, 'SIGKILL');
@@ -356,7 +348,7 @@ describe('Next.js Applications', () => {
);
const data = await getData(port);
- expect(data).toContain(`Welcome to ${appName}`);
+ expect(data).toContain(`Welcome`);
try {
await promisifiedTreeKill(p.pid, 'SIGKILL');
@@ -419,9 +411,9 @@ describe('Next.js Applications', () => {
}, 300000);
});
-function getData(port: number): Promise {
+function getData(port: number, path = ''): Promise {
return new Promise((resolve) => {
- http.get(`http://localhost:${port}`, (res) => {
+ http.get(`http://localhost:${port}${path}`, (res) => {
expect(res.statusCode).toEqual(200);
let data = '';
res.on('data', (chunk) => {
diff --git a/packages/next/migrations.json b/packages/next/migrations.json
index dfeaea3b84de2..51beb49861e94 100644
--- a/packages/next/migrations.json
+++ b/packages/next/migrations.json
@@ -220,6 +220,23 @@
"alwaysAddToPackageJson": false
}
}
+ },
+ "13.10.0": {
+ "version": "13.10.0-beta.1",
+ "packages": {
+ "next": {
+ "version": "12.1.2",
+ "alwaysAddToPackageJson": false
+ },
+ "eslint-config-next": {
+ "version": "12.1.2",
+ "alwaysAddToPackageJson": false
+ },
+ "sass": {
+ "version": "1.49.9",
+ "alwaysAddToPackageJson": false
+ }
+ }
}
}
}
diff --git a/packages/next/src/utils/versions.ts b/packages/next/src/utils/versions.ts
index 17ce54ebe6f3d..ddc0126ad4e34 100644
--- a/packages/next/src/utils/versions.ts
+++ b/packages/next/src/utils/versions.ts
@@ -1,7 +1,7 @@
export const nxVersion = '*';
-export const nextVersion = '12.1.0';
-export const eslintConfigNextVersion = '12.1.1-canary.3';
+export const nextVersion = '12.1.2';
+export const eslintConfigNextVersion = '12.1.2';
export const sassVersion = '1.43.2';
export const lessLoader = '10.2.0';
export const stylusLoader = '6.2.0';
diff --git a/packages/react-native/migrations.json b/packages/react-native/migrations.json
index 053e63657d7e9..e765a3b0b2b77 100644
--- a/packages/react-native/migrations.json
+++ b/packages/react-native/migrations.json
@@ -440,6 +440,35 @@
"alwaysAddToPackageJson": false
}
}
+ },
+ "13.10.0": {
+ "version": "13.10.0-beta.1",
+ "packages": {
+ "react-native": {
+ "version": "0.67.4",
+ "alwaysAddToPackageJson": false
+ },
+ "metro": {
+ "version": "0.70.0",
+ "alwaysAddToPackageJson": false
+ },
+ "@types/react": {
+ "version": "17.0.43",
+ "alwaysAddToPackageJson": false
+ },
+ "metro-react-native-babel-preset": {
+ "version": "0.70.0",
+ "alwaysAddToPackageJson": false
+ },
+ "@testing-library/react-native": {
+ "version": "9.1.0",
+ "alwaysAddToPackageJson": false
+ },
+ "@babel/runtime": {
+ "version": "7.17.8",
+ "alwaysAddToPackageJson": false
+ }
+ }
}
}
}
diff --git a/packages/react-native/src/generators/init/init.spec.ts b/packages/react-native/src/generators/init/init.spec.ts
index 1bdbc6e63b1cd..e8917d8fa6369 100644
--- a/packages/react-native/src/generators/init/init.spec.ts
+++ b/packages/react-native/src/generators/init/init.spec.ts
@@ -1,3 +1,4 @@
+import { logger } from '@nrwl/devkit';
import { Tree, readJson, updateJson } from '@nrwl/devkit';
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
import { reactNativeInitGenerator } from './init';
@@ -34,6 +35,31 @@ describe('init', () => {
expect(content).toMatch(/# Nested node_modules/);
});
+ it.each`
+ version
+ ${'18.0.0'}
+ ${'~18.0.0'}
+ ${'^18.0.0'}
+ `(
+ 'should warn if React v18 is already installed in workspace',
+ async ({ version }) => {
+ const spy = jest.spyOn(logger, 'warn');
+ spy.mockImplementation(() => {});
+ updateJson(tree, 'package.json', (json) => {
+ json.dependencies = {
+ react: version,
+ };
+ return json;
+ });
+
+ await reactNativeInitGenerator(tree, { e2eTestRunner: 'none' });
+
+ expect(spy).toHaveBeenCalledWith(expect.stringContaining('incompatible'));
+
+ spy.mockRestore();
+ }
+ );
+
describe('defaultCollection', () => {
it('should be set if none was set before', async () => {
await reactNativeInitGenerator(tree, { e2eTestRunner: 'none' });
diff --git a/packages/react-native/src/generators/init/init.ts b/packages/react-native/src/generators/init/init.ts
index f3764cc8493b7..b45ab12534c25 100644
--- a/packages/react-native/src/generators/init/init.ts
+++ b/packages/react-native/src/generators/init/init.ts
@@ -4,6 +4,8 @@ import {
convertNxGenerator,
detectPackageManager,
formatFiles,
+ logger,
+ readJson,
removeDependenciesFromPackageJson,
Tree,
} from '@nrwl/devkit';
@@ -11,10 +13,7 @@ import { Schema } from './schema';
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
import { jestInitGenerator } from '@nrwl/jest';
import { detoxInitGenerator } from '@nrwl/detox';
-import {
- reactVersion,
- typesReactVersion,
-} from '@nrwl/react/src/utils/versions';
+import { typesReactVersion } from '@nrwl/react/src/utils/versions';
import {
babelRuntimeVersion,
@@ -31,6 +30,7 @@ import {
reactNativeSvgVersion,
reactNativeVersion,
reactTestRendererVersion,
+ reactVersion,
testingLibraryJestNativeVersion,
testingLibraryReactNativeVersion,
typesReactNativeVersion,
@@ -65,6 +65,13 @@ export async function reactNativeInitGenerator(host: Tree, schema: Schema) {
export function updateDependencies(host: Tree) {
const isPnpm = detectPackageManager(host.root) === 'pnpm';
+ const { dependencies = {} } = readJson(host, 'package.json');
+ // TODO(jack): Remove this once React Native 0.68.0 is out.
+ if (dependencies['react']?.match(/[\^~]?18/)) {
+ logger.warn(
+ `React version ${dependencies['react']} is incompatible with React Native version ${reactNativeVersion}. Nx will downgrade the version to ${reactVersion}.`
+ );
+ }
return addDependenciesToPackageJson(
host,
{
diff --git a/packages/react-native/src/utils/versions.ts b/packages/react-native/src/utils/versions.ts
index 8f2b4b913635b..d9cc73d4a9bb2 100644
--- a/packages/react-native/src/utils/versions.ts
+++ b/packages/react-native/src/utils/versions.ts
@@ -1,9 +1,14 @@
export const nxVersion = '*';
-export const reactNativeVersion = '0.67.3';
+export const reactNativeVersion = '0.67.4';
export const typesReactNativeVersion = '0.67.3';
-export const metroVersion = '0.69.1';
+export const metroVersion = '0.70.0';
+
+// TODO(jack): Remove this once react-native 0.68.0 is released.
+// v18 is only supported on the New Architecture
+// See: https://reactnative.dev/blog/2022/03/15/an-update-on-the-new-architecture-rollout
+export const reactVersion = '17.0.2';
export const reactNativeCommunityCli = '7.0.1';
export const reactNativeCommunityCliIos = '7.0.1';
@@ -12,9 +17,9 @@ export const reactNativeCommunityCliAndroid = '7.0.1';
export const reactNativeConfigVersion = '1.4.5';
export const reactNativeAsyncStorageAsyncStorageVersion = '1.16.3';
-export const metroReactNativeBabelPresetVersion = '0.69.1';
+export const metroReactNativeBabelPresetVersion = '0.70.0';
-export const testingLibraryReactNativeVersion = '9.0.0';
+export const testingLibraryReactNativeVersion = '9.1.0';
export const testingLibraryJestNativeVersion = '4.0.4';
export const jestReactNativeVersion = '18.0.0';
@@ -24,4 +29,4 @@ export const reactTestRendererVersion = '17.0.2';
export const reactNativeSvgTransformerVersion = '1.0.0';
export const reactNativeSvgVersion = '12.3.0';
-export const babelRuntimeVersion = '7.17.7';
+export const babelRuntimeVersion = '7.17.8';
diff --git a/packages/react/migrations.json b/packages/react/migrations.json
index fd325e02154eb..3378935fc04d2 100644
--- a/packages/react/migrations.json
+++ b/packages/react/migrations.json
@@ -29,6 +29,12 @@
"version": "13.0.0-beta.0",
"description": "Migrate Storybook to use webpack 5",
"factory": "./src/migrations/update-13-0-0/migrate-storybook-to-webpack-5"
+ },
+ "update-react-18-13.10.0": {
+ "cli": "nx",
+ "version": "13.10.0-beta.0",
+ "description": "Update to React 18",
+ "factory": "./src/migrations/update-13-10-0/update-13-10-0"
}
},
"packageJsonUpdates": {
@@ -268,12 +274,16 @@
"version": "5.3.5",
"alwaysAddToPackageJson": false
},
+ "eslint-plugin-react": {
+ "version": "7.29.4",
+ "alwaysAddToPackageJson": false
+ },
"styled-jsx": {
- "version": "5.0.1",
+ "version": "5.0.2",
"alwaysAddToPackageJson": false
},
- "eslint-plugin-react": {
- "version": "7.29.4",
+ "eslint-plugin-react-hooks": {
+ "version": "4.4.0",
"alwaysAddToPackageJson": false
}
}
diff --git a/packages/react/src/migrations/update-13-10-0/update-13-10-0.spec.ts b/packages/react/src/migrations/update-13-10-0/update-13-10-0.spec.ts
new file mode 100644
index 0000000000000..39862a215b18e
--- /dev/null
+++ b/packages/react/src/migrations/update-13-10-0/update-13-10-0.spec.ts
@@ -0,0 +1,50 @@
+import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
+import { writeJson, readJson, Tree } from '@nrwl/devkit';
+import migrate from './update-13-10-0';
+
+describe('Update tsconfig for React apps', () => {
+ let tree: Tree;
+
+ beforeEach(() => {
+ tree = createTreeWithEmptyWorkspace();
+ });
+
+ it('should update to React 18 if React Native is not installed', async () => {
+ writeJson(tree, 'package.json', {
+ dependencies: {
+ react: '17.0.2',
+ },
+ });
+
+ const installTask = await migrate(tree);
+ expect(installTask).toBeDefined();
+ });
+
+ it('should update to React 18 if React Native 0.68.0-rc.4 is installed', async () => {
+ writeJson(tree, 'package.json', {
+ dependencies: {
+ react: '17.0.2',
+ 'react-native': '0.68.0-rc.4',
+ },
+ });
+
+ await migrate(tree);
+
+ const installTask = await migrate(tree);
+ expect(installTask).toBeDefined();
+ });
+
+ it('should skip update to React 18 if React Native 0.67.0 is installed', async () => {
+ writeJson(tree, 'package.json', {
+ dependencies: {
+ react: '17.0.2',
+ 'react-native': '0.67.0',
+ },
+ });
+
+ await migrate(tree);
+
+ const installTask = await migrate(tree);
+ expect(installTask).not.toBeDefined();
+ });
+});
diff --git a/packages/react/src/migrations/update-13-10-0/update-13-10-0.ts b/packages/react/src/migrations/update-13-10-0/update-13-10-0.ts
new file mode 100644
index 0000000000000..8da7193550ac0
--- /dev/null
+++ b/packages/react/src/migrations/update-13-10-0/update-13-10-0.ts
@@ -0,0 +1,34 @@
+import {
+ addDependenciesToPackageJson,
+ readJson,
+ logger,
+ Tree,
+} from '@nrwl/devkit';
+
+// Putting this here because React Native 0.67 is incompatible with React 18.
+// Waiting for 0.68 to come out with support for React 18.
+// TODO(jack): For Nx 14 let's add another migration for React 18 in migrations.json because by then React Native 0.68.0 should be released.
+export async function updateToReact18(host: Tree) {
+ const { dependencies } = readJson(host, 'package.json');
+ if (
+ dependencies['react-native'] &&
+ !dependencies['react-native'].match(/[\^~]?0.68/)
+ ) {
+ logger.info(
+ `React Native ${dependencies['react-native']} is incompatible with React 18. Skipping update until React Native 0.68.0 is released.`
+ );
+ } else {
+ return addDependenciesToPackageJson(
+ host,
+ {
+ react: '18.0.0',
+ 'react-dom': '18.0.0',
+ 'react-is': '18.0.0',
+ 'react-test-renderer': '18.0.0',
+ },
+ {}
+ );
+ }
+}
+
+export default updateToReact18;
diff --git a/packages/react/src/utils/versions.ts b/packages/react/src/utils/versions.ts
index c7538d59aece6..099a99e8b54ed 100755
--- a/packages/react/src/utils/versions.ts
+++ b/packages/react/src/utils/versions.ts
@@ -1,8 +1,8 @@
export const nxVersion = '*';
-export const reactVersion = '17.0.2';
-export const reactDomVersion = '17.0.2';
-export const reactIsVersion = '17.0.2';
+export const reactVersion = '18.0.0';
+export const reactDomVersion = '18.0.0';
+export const reactIsVersion = '18.0.0';
export const typesReactVersion = '17.0.43';
export const typesReactDomVersion = '17.0.14';
export const typesReactIsVersion = '17.0.3';
@@ -14,7 +14,7 @@ export const emotionStyledVersion = '11.8.1';
export const emotionReactVersion = '11.8.2';
export const emotionBabelPlugin = '11.7.2';
-export const styledJsxVersion = '5.0.1';
+export const styledJsxVersion = '5.0.2';
export const reactRouterDomVersion = '5.3.0';
export const typesReactRouterDomVersion = '5.3.3';
@@ -24,11 +24,11 @@ export const testingLibraryReactHooksVersion = '7.0.2';
export const reduxjsToolkitVersion = '1.8.0';
export const reactReduxVersion = '7.2.6';
-export const reactTestRendererVersion = '17.0.2';
+export const reactTestRendererVersion = '18.0.0';
export const eslintPluginImportVersion = '2.25.4';
export const eslintPluginJsxA11yVersion = '6.5.1';
export const eslintPluginReactVersion = '7.29.4';
-export const eslintPluginReactHooksVersion = '4.3.0';
+export const eslintPluginReactHooksVersion = '4.4.0';
export const babelPluginStyledComponentsVersion = '1.10.7';