Skip to content

Commit f921b4f

Browse files
authoredSep 1, 2020
Auto enable React's new JSX transform on 17.x (#16603)
1 parent 6f60a22 commit f921b4f

File tree

17 files changed

+306
-675
lines changed

17 files changed

+306
-675
lines changed
 

‎.github/workflows/build_test_deploy.yml

+4-2
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,8 @@ jobs:
9696
steps:
9797
- run: exit 0
9898

99-
testWebpack5:
100-
name: webpack 5 (Basic, Production, Acceptance)
99+
testFutureDependencies:
100+
name: React 17 + webpack 5 (Basic, Production, Acceptance)
101101
runs-on: ubuntu-latest
102102
env:
103103
NEXT_TELEMETRY_DISABLED: 1
@@ -108,6 +108,8 @@ jobs:
108108
- uses: actions/checkout@v2
109109
- run: git fetch --depth=1 origin +refs/tags/*:refs/tags/*
110110
- run: cat package.json | jq '.resolutions.webpack = "^5.0.0-beta.22"' > package.json.tmp && mv package.json.tmp package.json
111+
- run: cat package.json | jq '.resolutions.react = "^17.0.0-rc.1"' > package.json.tmp && mv package.json.tmp package.json
112+
- run: cat package.json | jq '.resolutions."react-dom" = "^17.0.0-rc.1"' > package.json.tmp && mv package.json.tmp package.json
111113
- run: yarn install --check-files
112114
- run: node run-tests.js test/integration/production/test/index.test.js
113115
- run: node run-tests.js test/integration/basic/test/index.test.js

‎package.json

+4-4
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@
3737
},
3838
"pre-commit": "lint-staged",
3939
"devDependencies": {
40-
"@babel/plugin-proposal-object-rest-spread": "7.9.6",
41-
"@babel/preset-flow": "7.9.0",
42-
"@babel/preset-react": "7.9.4",
40+
"@babel/plugin-proposal-object-rest-spread": "7.11.0",
41+
"@babel/preset-flow": "7.10.4",
42+
"@babel/preset-react": "7.10.4",
4343
"@fullhuman/postcss-purgecss": "1.3.0",
4444
"@mdx-js/loader": "0.18.0",
4545
"@types/cheerio": "0.22.16",
@@ -53,7 +53,7 @@
5353
"@zeit/next-sass": "1.0.2-canary.2",
5454
"@zeit/next-typescript": "1.1.2-canary.0",
5555
"abort-controller": "3.0.0",
56-
"amphtml-validator": "1.0.30",
56+
"amphtml-validator": "1.0.33",
5757
"async-sema": "3.0.1",
5858
"babel-core": "7.0.0-bridge.0",
5959
"babel-eslint": "10.0.3",

‎packages/next/build/babel/preset.ts

+8-9
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ module.exports = (
6565
const supportsESM = api.caller(supportsStaticESM)
6666
const isServer = api.caller((caller: any) => !!caller && caller.isServer)
6767
const isModern = api.caller((caller: any) => !!caller && caller.isModern)
68+
const hasJsxRuntime = Boolean(
69+
api.caller((caller: any) => !!caller && caller.hasJsxRuntime)
70+
)
6871

6972
const isLaxModern =
7073
isModern ||
@@ -113,7 +116,7 @@ module.exports = (
113116
// This adds @babel/plugin-transform-react-jsx-source and
114117
// @babel/plugin-transform-react-jsx-self automatically in development
115118
development: isDevelopment || isTest,
116-
pragma: '__jsx',
119+
...(hasJsxRuntime ? { runtime: 'automatic' } : { pragma: '__jsx' }),
117120
...options['preset-react'],
118121
},
119122
],
@@ -123,7 +126,7 @@ module.exports = (
123126
],
124127
],
125128
plugins: [
126-
[
129+
!hasJsxRuntime && [
127130
require('./plugins/jsx-pragma'),
128131
{
129132
// This produces the following injected import for modules containing JSX:
@@ -181,14 +184,10 @@ module.exports = (
181184
require('@babel/plugin-proposal-optional-chaining'),
182185
require('@babel/plugin-proposal-nullish-coalescing-operator'),
183186
isServer && require('@babel/plugin-syntax-bigint'),
184-
[require('@babel/plugin-proposal-numeric-separator').default, false],
187+
// Always compile numeric separator because the resulting number is
188+
// smaller.
189+
require('@babel/plugin-proposal-numeric-separator'),
185190
require('@babel/plugin-proposal-export-namespace-from'),
186191
].filter(Boolean),
187-
overrides: [
188-
{
189-
test: /\.tsx?$/,
190-
plugins: [require('@babel/plugin-proposal-numeric-separator').default],
191-
},
192-
],
193192
}
194193
}

‎packages/next/build/webpack-config.ts

+12-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import ReactRefreshWebpackPlugin from '@next/react-refresh-utils/ReactRefreshWeb
33
import crypto from 'crypto'
44
import { readFileSync } from 'fs'
55
import chalk from 'next/dist/compiled/chalk'
6+
import semver from 'next/dist/compiled/semver'
67
import TerserPlugin from 'next/dist/compiled/terser-webpack-plugin'
78
import path from 'path'
89
import webpack from 'webpack'
@@ -14,6 +15,8 @@ import {
1415
PAGES_DIR_ALIAS,
1516
} from '../lib/constants'
1617
import { fileExists } from '../lib/file-exists'
18+
import { getPackageVersion } from '../lib/get-package-version'
19+
import { Rewrite } from '../lib/load-custom-routes'
1720
import { resolveRequest } from '../lib/resolve-request'
1821
import { getTypeScriptConfiguration } from '../lib/typescript/getTypeScriptConfiguration'
1922
import {
@@ -54,7 +57,7 @@ import WebpackConformancePlugin, {
5457
ReactSyncScriptsConformanceCheck,
5558
} from './webpack/plugins/webpack-conformance-plugin'
5659
import { WellKnownErrorsPlugin } from './webpack/plugins/wellknown-errors-plugin'
57-
import { Rewrite } from '../lib/load-custom-routes'
60+
5861
type ExcludesFalse = <T>(x: T | false) => x is T
5962

6063
const isWebpack5 = parseInt(webpack.version!) === 5
@@ -226,7 +229,13 @@ export default async function getBaseWebpackConfig(
226229
}
227230
}
228231

229-
const hasReactRefresh = dev && !isServer
232+
const reactVersion = await getPackageVersion({ cwd: dir, name: 'react' })
233+
const hasReactRefresh: boolean = dev && !isServer
234+
const hasJsxRuntime: boolean =
235+
Boolean(reactVersion) &&
236+
// 17.0.0-rc.0 had a breaking change not compatible with Next.js, but was
237+
// fixed in rc.1.
238+
semver.gte(reactVersion!, '17.0.0-rc.1')
230239

231240
const distDir = path.join(dir, config.distDir)
232241
const defaultLoaders = {
@@ -243,6 +252,7 @@ export default async function getBaseWebpackConfig(
243252
hasModern: !!config.experimental.modern,
244253
development: dev,
245254
hasReactRefresh,
255+
hasJsxRuntime,
246256
},
247257
},
248258
// Backwards compat

‎packages/next/build/webpack/loaders/next-babel-loader.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import hash from 'next/dist/compiled/string-hash'
33
import { basename, join } from 'path'
44
import * as Log from '../../output/log'
55

6-
// increment 'm' to invalidate cache
6+
// increment 'n' to invalidate cache
77
// eslint-disable-next-line no-useless-concat
8-
const cacheKey = 'babel-cache-' + 'm' + '-'
8+
const cacheKey = 'babel-cache-' + 'n' + '-'
99
const nextBabelPreset = require('../../babel/preset')
1010

1111
const getModernOptions = (babelOptions = {}) => {
@@ -61,6 +61,7 @@ module.exports = babelLoader.custom((babel) => {
6161
babelPresetPlugins: opts.babelPresetPlugins,
6262
development: opts.development,
6363
hasReactRefresh: opts.hasReactRefresh,
64+
hasJsxRuntime: opts.hasJsxRuntime,
6465
}
6566
const filename = join(opts.cwd, 'noop.js')
6667
const loader = Object.assign(
@@ -76,6 +77,7 @@ module.exports = babelLoader.custom((babel) => {
7677
'-new-polyfills' +
7778
(opts.development ? '-development' : '-production') +
7879
(opts.hasReactRefresh ? '-react-refresh' : '') +
80+
(opts.hasJsxRuntime ? '-jsx-runtime' : '') +
7981
JSON.stringify(
8082
babel.loadPartialConfig({
8183
filename,
@@ -99,6 +101,7 @@ module.exports = babelLoader.custom((babel) => {
99101
delete loader.babelPresetPlugins
100102
delete loader.development
101103
delete loader.hasReactRefresh
104+
delete loader.hasJsxRuntime
102105
return { loader, custom }
103106
},
104107
config(
@@ -113,6 +116,7 @@ module.exports = babelLoader.custom((babel) => {
113116
babelPresetPlugins,
114117
development,
115118
hasReactRefresh,
119+
hasJsxRuntime,
116120
},
117121
}
118122
) {
@@ -136,6 +140,7 @@ module.exports = babelLoader.custom((babel) => {
136140
options.caller.isServer = isServer
137141
options.caller.isModern = isModern
138142
options.caller.isDev = development
143+
options.caller.hasJsxRuntime = hasJsxRuntime
139144

140145
const emitWarning = this.emitWarning.bind(this)
141146
Object.defineProperty(options.caller, 'onWarning', {

‎packages/next/compiled/amphtml-validator/index.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎packages/next/compiled/comment-json/index.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎packages/next/package.json

+16-16
Original file line numberDiff line numberDiff line change
@@ -59,24 +59,24 @@
5959
},
6060
"dependencies": {
6161
"@ampproject/toolbox-optimizer": "2.6.0",
62-
"@babel/code-frame": "7.8.3",
62+
"@babel/code-frame": "7.10.4",
6363
"@babel/core": "7.7.7",
64-
"@babel/plugin-proposal-class-properties": "7.8.3",
64+
"@babel/plugin-proposal-class-properties": "7.10.4",
6565
"@babel/plugin-proposal-export-namespace-from": "7.10.4",
66-
"@babel/plugin-proposal-nullish-coalescing-operator": "7.8.3",
67-
"@babel/plugin-proposal-numeric-separator": "7.8.3",
68-
"@babel/plugin-proposal-object-rest-spread": "7.9.6",
69-
"@babel/plugin-proposal-optional-chaining": "7.9.0",
66+
"@babel/plugin-proposal-nullish-coalescing-operator": "7.10.4",
67+
"@babel/plugin-proposal-numeric-separator": "7.10.4",
68+
"@babel/plugin-proposal-object-rest-spread": "7.11.0",
69+
"@babel/plugin-proposal-optional-chaining": "7.11.0",
7070
"@babel/plugin-syntax-bigint": "7.8.3",
7171
"@babel/plugin-syntax-dynamic-import": "7.8.3",
72-
"@babel/plugin-transform-modules-commonjs": "7.9.6",
73-
"@babel/plugin-transform-runtime": "7.9.6",
74-
"@babel/preset-env": "7.9.6",
75-
"@babel/preset-modules": "0.1.3",
76-
"@babel/preset-react": "7.9.4",
77-
"@babel/preset-typescript": "7.9.0",
78-
"@babel/runtime": "7.9.6",
79-
"@babel/types": "7.9.6",
72+
"@babel/plugin-transform-modules-commonjs": "7.10.4",
73+
"@babel/plugin-transform-runtime": "7.11.5",
74+
"@babel/preset-env": "7.11.5",
75+
"@babel/preset-modules": "0.1.4",
76+
"@babel/preset-react": "7.10.4",
77+
"@babel/preset-typescript": "7.10.4",
78+
"@babel/runtime": "7.11.2",
79+
"@babel/types": "7.11.5",
8080
"@next/react-dev-overlay": "9.5.3-canary.25",
8181
"@next/react-refresh-utils": "9.5.3-canary.25",
8282
"ast-types": "0.13.2",
@@ -160,7 +160,7 @@
160160
"@types/text-table": "0.2.1",
161161
"@types/webpack-sources": "0.1.5",
162162
"@zeit/ncc": "0.22.0",
163-
"amphtml-validator": "1.0.31",
163+
"amphtml-validator": "1.0.33",
164164
"arg": "4.1.0",
165165
"async-retry": "1.2.3",
166166
"async-sema": "3.0.0",
@@ -169,7 +169,7 @@
169169
"cache-loader": "4.1.0",
170170
"chalk": "2.4.2",
171171
"ci-info": "watson/ci-info#f43f6a1cefff47fb361c88cf4b943fdbcaafe540",
172-
"comment-json": "3.0.2",
172+
"comment-json": "3.0.3",
173173
"compression": "1.7.4",
174174
"conf": "5.0.0",
175175
"content-type": "1.0.4",

‎packages/react-dev-overlay/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"build": "tsc -d -w -p tsconfig.json"
1717
},
1818
"dependencies": {
19-
"@babel/code-frame": "7.8.3",
19+
"@babel/code-frame": "7.10.4",
2020
"ally.js": "1.4.1",
2121
"anser": "1.4.9",
2222
"chalk": "4.0.0",

‎test/acceptance/ReactRefreshLogBox.test.js

+2
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ test('render error not shown right after syntax error', async () => {
238238
await session.patch(
239239
'index.js',
240240
`
241+
import * as React from 'react';
241242
class ClassDefault extends React.Component {
242243
render() {
243244
return <h1>Default Export</h1>;
@@ -576,6 +577,7 @@ test('boundaries', async () => {
576577
'index.js',
577578
`
578579
import FunctionDefault from './FunctionDefault.js'
580+
import * as React from 'react'
579581
class ErrorBoundary extends React.Component {
580582
constructor() {
581583
super()

‎test/acceptance/helpers.js

+3
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ export async function sandbox(
3838
})
3939
const browser = await webdriver(appPort, '/')
4040

41+
// Slow down tests a bit to ensure application is ready:
42+
await new Promise((resolve) => setTimeout(resolve, 750))
43+
4144
return [
4245
{
4346
sandboxDirectory,

‎test/integration/basic/test/dynamic.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,17 @@ export default (context, render) => {
1313
it('should render dynamic import components', async () => {
1414
const $ = await get$('/dynamic/ssr')
1515
// Make sure the client side knows it has to wait for the bundle
16-
expect($('body').html()).toContain(
17-
'"dynamicIds":["./components/hello1.js"]'
16+
expect(JSON.parse($('#__NEXT_DATA__').html()).dynamicIds).toContain(
17+
'./components/hello1.js'
1818
)
1919
expect($('body').text()).toMatch(/Hello World 1/)
2020
})
2121

2222
it('should render dynamic import components using a function as first parameter', async () => {
2323
const $ = await get$('/dynamic/function')
2424
// Make sure the client side knows it has to wait for the bundle
25-
expect($('body').html()).toContain(
26-
'"dynamicIds":["./components/hello1.js"]'
25+
expect(JSON.parse($('#__NEXT_DATA__').html()).dynamicIds).toContain(
26+
'./components/hello1.js'
2727
)
2828
expect($('body').text()).toMatch(/Hello World 1/)
2929
})

‎test/integration/basic/test/error-recovery.js

+3-16
Original file line numberDiff line numberDiff line change
@@ -253,22 +253,9 @@ export default (context, renderViaHTTP) => {
253253
'__WEBPACK_DEFAULT_EXPORT__',
254254
'Unknown'
255255
)
256-
).toMatchInlineSnapshot(`
257-
" 1 of 1 unhandled error
258-
Server Error
259-
260-
Error: Objects are not valid as a React child (found: /search/). If you meant to render a collection of children, use an array instead.
261-
in Unknown
262-
in App
263-
in Unknown
264-
in Context.Provider
265-
in Context.Provider
266-
in Context.Provider
267-
in Context.Provider
268-
in AppContainer
269-
270-
This error happened while generating the page. Any console logs will be displayed in the terminal window."
271-
`)
256+
).toMatch(
257+
'Objects are not valid as a React child (found: /search/). If you meant to render a collection of children, use an array instead.'
258+
)
272259

273260
aboutPage.restore()
274261

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/* eslint-env jest */
2+
3+
import { nextBuild } from 'next-test-utils'
4+
import { join } from 'path'
5+
6+
jest.setTimeout(1000 * 60 * 2)
7+
8+
const appDir = join(__dirname, '../')
9+
10+
describe('Numeric Separator Support', () => {
11+
it('should successfully build for a JavaScript file', async () => {
12+
const { code, stdout, stderr } = await nextBuild(appDir, [], {
13+
stdout: true,
14+
stderr: true,
15+
})
16+
17+
expect(code).toBe(0)
18+
19+
expect(stdout).toContain('Compiled successfully')
20+
expect(stderr).not.toContain('Failed to compile')
21+
})
22+
})

‎test/integration/typescript-numeric-sep-exclusive/test/index.test.js

-22
This file was deleted.

0 commit comments

Comments
 (0)
Please sign in to comment.