feat(react): update to react 18 (#9613)
This commit is contained in:
parent
1bc2298b19
commit
b02beb551b
@ -161,21 +161,12 @@ describe('Next.js Applications', () => {
|
|||||||
updateFile(
|
updateFile(
|
||||||
`apps/${appName}/pages/index.tsx`,
|
`apps/${appName}/pages/index.tsx`,
|
||||||
`
|
`
|
||||||
import React, { useEffect, useState } from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
export const Index = () => {
|
export const Index = ({ greeting }: any) => {
|
||||||
const [greeting, setGreeting] = useState('');
|
return (
|
||||||
|
<p>{process.env.NX_CUSTOM_VAR}</p>
|
||||||
useEffect(() => {
|
);
|
||||||
fetch('/external-api/hello')
|
|
||||||
.then(r => r.text())
|
|
||||||
.then(setGreeting);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return <>
|
|
||||||
<h1>{greeting}</h1>
|
|
||||||
<h2>{process.env.NX_CUSTOM_VAR}</h2>
|
|
||||||
</>;
|
|
||||||
};
|
};
|
||||||
export default Index;
|
export default Index;
|
||||||
`
|
`
|
||||||
@ -185,7 +176,7 @@ describe('Next.js Applications', () => {
|
|||||||
`apps/${appName}/pages/api/hello.js`,
|
`apps/${appName}/pages/api/hello.js`,
|
||||||
`
|
`
|
||||||
export default (_req, res) => {
|
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);
|
const apiData = await getData(port, '/external-api/hello');
|
||||||
expect(data).toContain(`Welcome to ${appName}`);
|
const pageData = await getData(port, '/');
|
||||||
expect(data).toContain(`test value from a file`);
|
expect(apiData).toContain(`Welcome`);
|
||||||
|
expect(pageData).toContain(`test value from a file`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await promisifiedTreeKill(p.pid, 'SIGKILL');
|
await promisifiedTreeKill(p.pid, 'SIGKILL');
|
||||||
@ -356,7 +348,7 @@ describe('Next.js Applications', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const data = await getData(port);
|
const data = await getData(port);
|
||||||
expect(data).toContain(`Welcome to ${appName}`);
|
expect(data).toContain(`Welcome`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await promisifiedTreeKill(p.pid, 'SIGKILL');
|
await promisifiedTreeKill(p.pid, 'SIGKILL');
|
||||||
@ -419,9 +411,9 @@ describe('Next.js Applications', () => {
|
|||||||
}, 300000);
|
}, 300000);
|
||||||
});
|
});
|
||||||
|
|
||||||
function getData(port: number): Promise<any> {
|
function getData(port: number, path = ''): Promise<any> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
http.get(`http://localhost:${port}`, (res) => {
|
http.get(`http://localhost:${port}${path}`, (res) => {
|
||||||
expect(res.statusCode).toEqual(200);
|
expect(res.statusCode).toEqual(200);
|
||||||
let data = '';
|
let data = '';
|
||||||
res.on('data', (chunk) => {
|
res.on('data', (chunk) => {
|
||||||
|
|||||||
@ -220,6 +220,23 @@
|
|||||||
"alwaysAddToPackageJson": false
|
"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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
export const nxVersion = '*';
|
export const nxVersion = '*';
|
||||||
|
|
||||||
export const nextVersion = '12.1.0';
|
export const nextVersion = '12.1.2';
|
||||||
export const eslintConfigNextVersion = '12.1.1-canary.3';
|
export const eslintConfigNextVersion = '12.1.2';
|
||||||
export const sassVersion = '1.43.2';
|
export const sassVersion = '1.43.2';
|
||||||
export const lessLoader = '10.2.0';
|
export const lessLoader = '10.2.0';
|
||||||
export const stylusLoader = '6.2.0';
|
export const stylusLoader = '6.2.0';
|
||||||
|
|||||||
@ -440,6 +440,35 @@
|
|||||||
"alwaysAddToPackageJson": false
|
"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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { logger } from '@nrwl/devkit';
|
||||||
import { Tree, readJson, updateJson } from '@nrwl/devkit';
|
import { Tree, readJson, updateJson } from '@nrwl/devkit';
|
||||||
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
||||||
import { reactNativeInitGenerator } from './init';
|
import { reactNativeInitGenerator } from './init';
|
||||||
@ -34,6 +35,31 @@ describe('init', () => {
|
|||||||
expect(content).toMatch(/# Nested node_modules/);
|
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', () => {
|
describe('defaultCollection', () => {
|
||||||
it('should be set if none was set before', async () => {
|
it('should be set if none was set before', async () => {
|
||||||
await reactNativeInitGenerator(tree, { e2eTestRunner: 'none' });
|
await reactNativeInitGenerator(tree, { e2eTestRunner: 'none' });
|
||||||
|
|||||||
@ -4,6 +4,8 @@ import {
|
|||||||
convertNxGenerator,
|
convertNxGenerator,
|
||||||
detectPackageManager,
|
detectPackageManager,
|
||||||
formatFiles,
|
formatFiles,
|
||||||
|
logger,
|
||||||
|
readJson,
|
||||||
removeDependenciesFromPackageJson,
|
removeDependenciesFromPackageJson,
|
||||||
Tree,
|
Tree,
|
||||||
} from '@nrwl/devkit';
|
} from '@nrwl/devkit';
|
||||||
@ -11,10 +13,7 @@ import { Schema } from './schema';
|
|||||||
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
|
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
|
||||||
import { jestInitGenerator } from '@nrwl/jest';
|
import { jestInitGenerator } from '@nrwl/jest';
|
||||||
import { detoxInitGenerator } from '@nrwl/detox';
|
import { detoxInitGenerator } from '@nrwl/detox';
|
||||||
import {
|
import { typesReactVersion } from '@nrwl/react/src/utils/versions';
|
||||||
reactVersion,
|
|
||||||
typesReactVersion,
|
|
||||||
} from '@nrwl/react/src/utils/versions';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
babelRuntimeVersion,
|
babelRuntimeVersion,
|
||||||
@ -31,6 +30,7 @@ import {
|
|||||||
reactNativeSvgVersion,
|
reactNativeSvgVersion,
|
||||||
reactNativeVersion,
|
reactNativeVersion,
|
||||||
reactTestRendererVersion,
|
reactTestRendererVersion,
|
||||||
|
reactVersion,
|
||||||
testingLibraryJestNativeVersion,
|
testingLibraryJestNativeVersion,
|
||||||
testingLibraryReactNativeVersion,
|
testingLibraryReactNativeVersion,
|
||||||
typesReactNativeVersion,
|
typesReactNativeVersion,
|
||||||
@ -65,6 +65,13 @@ export async function reactNativeInitGenerator(host: Tree, schema: Schema) {
|
|||||||
|
|
||||||
export function updateDependencies(host: Tree) {
|
export function updateDependencies(host: Tree) {
|
||||||
const isPnpm = detectPackageManager(host.root) === 'pnpm';
|
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(
|
return addDependenciesToPackageJson(
|
||||||
host,
|
host,
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,9 +1,14 @@
|
|||||||
export const nxVersion = '*';
|
export const nxVersion = '*';
|
||||||
|
|
||||||
export const reactNativeVersion = '0.67.3';
|
export const reactNativeVersion = '0.67.4';
|
||||||
export const typesReactNativeVersion = '0.67.3';
|
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 reactNativeCommunityCli = '7.0.1';
|
||||||
export const reactNativeCommunityCliIos = '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 reactNativeConfigVersion = '1.4.5';
|
||||||
export const reactNativeAsyncStorageAsyncStorageVersion = '1.16.3';
|
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 testingLibraryJestNativeVersion = '4.0.4';
|
||||||
|
|
||||||
export const jestReactNativeVersion = '18.0.0';
|
export const jestReactNativeVersion = '18.0.0';
|
||||||
@ -24,4 +29,4 @@ export const reactTestRendererVersion = '17.0.2';
|
|||||||
export const reactNativeSvgTransformerVersion = '1.0.0';
|
export const reactNativeSvgTransformerVersion = '1.0.0';
|
||||||
export const reactNativeSvgVersion = '12.3.0';
|
export const reactNativeSvgVersion = '12.3.0';
|
||||||
|
|
||||||
export const babelRuntimeVersion = '7.17.7';
|
export const babelRuntimeVersion = '7.17.8';
|
||||||
|
|||||||
@ -29,6 +29,12 @@
|
|||||||
"version": "13.0.0-beta.0",
|
"version": "13.0.0-beta.0",
|
||||||
"description": "Migrate Storybook to use webpack 5",
|
"description": "Migrate Storybook to use webpack 5",
|
||||||
"factory": "./src/migrations/update-13-0-0/migrate-storybook-to-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": {
|
"packageJsonUpdates": {
|
||||||
@ -268,13 +274,17 @@
|
|||||||
"version": "5.3.5",
|
"version": "5.3.5",
|
||||||
"alwaysAddToPackageJson": false
|
"alwaysAddToPackageJson": false
|
||||||
},
|
},
|
||||||
"styled-jsx": {
|
|
||||||
"version": "5.0.1",
|
|
||||||
"alwaysAddToPackageJson": false
|
|
||||||
},
|
|
||||||
"eslint-plugin-react": {
|
"eslint-plugin-react": {
|
||||||
"version": "7.29.4",
|
"version": "7.29.4",
|
||||||
"alwaysAddToPackageJson": false
|
"alwaysAddToPackageJson": false
|
||||||
|
},
|
||||||
|
"styled-jsx": {
|
||||||
|
"version": "5.0.2",
|
||||||
|
"alwaysAddToPackageJson": false
|
||||||
|
},
|
||||||
|
"eslint-plugin-react-hooks": {
|
||||||
|
"version": "4.4.0",
|
||||||
|
"alwaysAddToPackageJson": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -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;
|
||||||
@ -1,8 +1,8 @@
|
|||||||
export const nxVersion = '*';
|
export const nxVersion = '*';
|
||||||
|
|
||||||
export const reactVersion = '17.0.2';
|
export const reactVersion = '18.0.0';
|
||||||
export const reactDomVersion = '17.0.2';
|
export const reactDomVersion = '18.0.0';
|
||||||
export const reactIsVersion = '17.0.2';
|
export const reactIsVersion = '18.0.0';
|
||||||
export const typesReactVersion = '17.0.43';
|
export const typesReactVersion = '17.0.43';
|
||||||
export const typesReactDomVersion = '17.0.14';
|
export const typesReactDomVersion = '17.0.14';
|
||||||
export const typesReactIsVersion = '17.0.3';
|
export const typesReactIsVersion = '17.0.3';
|
||||||
@ -14,7 +14,7 @@ export const emotionStyledVersion = '11.8.1';
|
|||||||
export const emotionReactVersion = '11.8.2';
|
export const emotionReactVersion = '11.8.2';
|
||||||
export const emotionBabelPlugin = '11.7.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 reactRouterDomVersion = '5.3.0';
|
||||||
export const typesReactRouterDomVersion = '5.3.3';
|
export const typesReactRouterDomVersion = '5.3.3';
|
||||||
@ -24,11 +24,11 @@ export const testingLibraryReactHooksVersion = '7.0.2';
|
|||||||
|
|
||||||
export const reduxjsToolkitVersion = '1.8.0';
|
export const reduxjsToolkitVersion = '1.8.0';
|
||||||
export const reactReduxVersion = '7.2.6';
|
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 eslintPluginImportVersion = '2.25.4';
|
||||||
export const eslintPluginJsxA11yVersion = '6.5.1';
|
export const eslintPluginJsxA11yVersion = '6.5.1';
|
||||||
export const eslintPluginReactVersion = '7.29.4';
|
export const eslintPluginReactVersion = '7.29.4';
|
||||||
export const eslintPluginReactHooksVersion = '4.3.0';
|
export const eslintPluginReactHooksVersion = '4.4.0';
|
||||||
|
|
||||||
export const babelPluginStyledComponentsVersion = '1.10.7';
|
export const babelPluginStyledComponentsVersion = '1.10.7';
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user