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(
|
||||
`apps/${appName}/pages/index.tsx`,
|
||||
`
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
export const Index = () => {
|
||||
const [greeting, setGreeting] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
fetch('/external-api/hello')
|
||||
.then(r => r.text())
|
||||
.then(setGreeting);
|
||||
}, []);
|
||||
|
||||
return <>
|
||||
<h1>{greeting}</h1>
|
||||
<h2>{process.env.NX_CUSTOM_VAR}</h2>
|
||||
</>;
|
||||
export const Index = ({ greeting }: any) => {
|
||||
return (
|
||||
<p>{process.env.NX_CUSTOM_VAR}</p>
|
||||
);
|
||||
};
|
||||
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<any> {
|
||||
function getData(port: number, path = ''): Promise<any> {
|
||||
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) => {
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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' });
|
||||
|
||||
@ -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,
|
||||
{
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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,13 +274,17 @@
|
||||
"version": "5.3.5",
|
||||
"alwaysAddToPackageJson": false
|
||||
},
|
||||
"styled-jsx": {
|
||||
"version": "5.0.1",
|
||||
"alwaysAddToPackageJson": false
|
||||
},
|
||||
"eslint-plugin-react": {
|
||||
"version": "7.29.4",
|
||||
"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 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';
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user