Skip to content

Commit

Permalink
Auto enable React's new JSX transform on 17.x (#16603)
Browse files Browse the repository at this point in the history
  • Loading branch information
Timer authored Sep 1, 2020
1 parent 6f60a22 commit f921b4f
Show file tree
Hide file tree
Showing 17 changed files with 306 additions and 675 deletions.
6 changes: 4 additions & 2 deletions .github/workflows/build_test_deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@ jobs:
steps:
- run: exit 0

testWebpack5:
name: webpack 5 (Basic, Production, Acceptance)
testFutureDependencies:
name: React 17 + webpack 5 (Basic, Production, Acceptance)
runs-on: ubuntu-latest
env:
NEXT_TELEMETRY_DISABLED: 1
Expand All @@ -108,6 +108,8 @@ jobs:
- uses: actions/checkout@v2
- run: git fetch --depth=1 origin +refs/tags/*:refs/tags/*
- run: cat package.json | jq '.resolutions.webpack = "^5.0.0-beta.22"' > package.json.tmp && mv package.json.tmp package.json
- run: cat package.json | jq '.resolutions.react = "^17.0.0-rc.1"' > package.json.tmp && mv package.json.tmp package.json
- run: cat package.json | jq '.resolutions."react-dom" = "^17.0.0-rc.1"' > package.json.tmp && mv package.json.tmp package.json
- run: yarn install --check-files
- run: node run-tests.js test/integration/production/test/index.test.js
- run: node run-tests.js test/integration/basic/test/index.test.js
Expand Down
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@
},
"pre-commit": "lint-staged",
"devDependencies": {
"@babel/plugin-proposal-object-rest-spread": "7.9.6",
"@babel/preset-flow": "7.9.0",
"@babel/preset-react": "7.9.4",
"@babel/plugin-proposal-object-rest-spread": "7.11.0",
"@babel/preset-flow": "7.10.4",
"@babel/preset-react": "7.10.4",
"@fullhuman/postcss-purgecss": "1.3.0",
"@mdx-js/loader": "0.18.0",
"@types/cheerio": "0.22.16",
Expand All @@ -53,7 +53,7 @@
"@zeit/next-sass": "1.0.2-canary.2",
"@zeit/next-typescript": "1.1.2-canary.0",
"abort-controller": "3.0.0",
"amphtml-validator": "1.0.30",
"amphtml-validator": "1.0.33",
"async-sema": "3.0.1",
"babel-core": "7.0.0-bridge.0",
"babel-eslint": "10.0.3",
Expand Down
17 changes: 8 additions & 9 deletions packages/next/build/babel/preset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ module.exports = (
const supportsESM = api.caller(supportsStaticESM)
const isServer = api.caller((caller: any) => !!caller && caller.isServer)
const isModern = api.caller((caller: any) => !!caller && caller.isModern)
const hasJsxRuntime = Boolean(
api.caller((caller: any) => !!caller && caller.hasJsxRuntime)
)

const isLaxModern =
isModern ||
Expand Down Expand Up @@ -113,7 +116,7 @@ module.exports = (
// This adds @babel/plugin-transform-react-jsx-source and
// @babel/plugin-transform-react-jsx-self automatically in development
development: isDevelopment || isTest,
pragma: '__jsx',
...(hasJsxRuntime ? { runtime: 'automatic' } : { pragma: '__jsx' }),
...options['preset-react'],
},
],
Expand All @@ -123,7 +126,7 @@ module.exports = (
],
],
plugins: [
[
!hasJsxRuntime && [
require('./plugins/jsx-pragma'),
{
// This produces the following injected import for modules containing JSX:
Expand Down Expand Up @@ -181,14 +184,10 @@ module.exports = (
require('@babel/plugin-proposal-optional-chaining'),
require('@babel/plugin-proposal-nullish-coalescing-operator'),
isServer && require('@babel/plugin-syntax-bigint'),
[require('@babel/plugin-proposal-numeric-separator').default, false],
// Always compile numeric separator because the resulting number is
// smaller.
require('@babel/plugin-proposal-numeric-separator'),
require('@babel/plugin-proposal-export-namespace-from'),
].filter(Boolean),
overrides: [
{
test: /\.tsx?$/,
plugins: [require('@babel/plugin-proposal-numeric-separator').default],
},
],
}
}
14 changes: 12 additions & 2 deletions packages/next/build/webpack-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import ReactRefreshWebpackPlugin from '@next/react-refresh-utils/ReactRefreshWeb
import crypto from 'crypto'
import { readFileSync } from 'fs'
import chalk from 'next/dist/compiled/chalk'
import semver from 'next/dist/compiled/semver'
import TerserPlugin from 'next/dist/compiled/terser-webpack-plugin'
import path from 'path'
import webpack from 'webpack'
Expand All @@ -14,6 +15,8 @@ import {
PAGES_DIR_ALIAS,
} from '../lib/constants'
import { fileExists } from '../lib/file-exists'
import { getPackageVersion } from '../lib/get-package-version'
import { Rewrite } from '../lib/load-custom-routes'
import { resolveRequest } from '../lib/resolve-request'
import { getTypeScriptConfiguration } from '../lib/typescript/getTypeScriptConfiguration'
import {
Expand Down Expand Up @@ -54,7 +57,7 @@ import WebpackConformancePlugin, {
ReactSyncScriptsConformanceCheck,
} from './webpack/plugins/webpack-conformance-plugin'
import { WellKnownErrorsPlugin } from './webpack/plugins/wellknown-errors-plugin'
import { Rewrite } from '../lib/load-custom-routes'

type ExcludesFalse = <T>(x: T | false) => x is T

const isWebpack5 = parseInt(webpack.version!) === 5
Expand Down Expand Up @@ -226,7 +229,13 @@ export default async function getBaseWebpackConfig(
}
}

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

const distDir = path.join(dir, config.distDir)
const defaultLoaders = {
Expand All @@ -243,6 +252,7 @@ export default async function getBaseWebpackConfig(
hasModern: !!config.experimental.modern,
development: dev,
hasReactRefresh,
hasJsxRuntime,
},
},
// Backwards compat
Expand Down
9 changes: 7 additions & 2 deletions packages/next/build/webpack/loaders/next-babel-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import hash from 'next/dist/compiled/string-hash'
import { basename, join } from 'path'
import * as Log from '../../output/log'

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

const getModernOptions = (babelOptions = {}) => {
Expand Down Expand Up @@ -61,6 +61,7 @@ module.exports = babelLoader.custom((babel) => {
babelPresetPlugins: opts.babelPresetPlugins,
development: opts.development,
hasReactRefresh: opts.hasReactRefresh,
hasJsxRuntime: opts.hasJsxRuntime,
}
const filename = join(opts.cwd, 'noop.js')
const loader = Object.assign(
Expand All @@ -76,6 +77,7 @@ module.exports = babelLoader.custom((babel) => {
'-new-polyfills' +
(opts.development ? '-development' : '-production') +
(opts.hasReactRefresh ? '-react-refresh' : '') +
(opts.hasJsxRuntime ? '-jsx-runtime' : '') +
JSON.stringify(
babel.loadPartialConfig({
filename,
Expand All @@ -99,6 +101,7 @@ module.exports = babelLoader.custom((babel) => {
delete loader.babelPresetPlugins
delete loader.development
delete loader.hasReactRefresh
delete loader.hasJsxRuntime
return { loader, custom }
},
config(
Expand All @@ -113,6 +116,7 @@ module.exports = babelLoader.custom((babel) => {
babelPresetPlugins,
development,
hasReactRefresh,
hasJsxRuntime,
},
}
) {
Expand All @@ -136,6 +140,7 @@ module.exports = babelLoader.custom((babel) => {
options.caller.isServer = isServer
options.caller.isModern = isModern
options.caller.isDev = development
options.caller.hasJsxRuntime = hasJsxRuntime

const emitWarning = this.emitWarning.bind(this)
Object.defineProperty(options.caller, 'onWarning', {
Expand Down
2 changes: 1 addition & 1 deletion packages/next/compiled/amphtml-validator/index.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/next/compiled/comment-json/index.js

Large diffs are not rendered by default.

32 changes: 16 additions & 16 deletions packages/next/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,24 +59,24 @@
},
"dependencies": {
"@ampproject/toolbox-optimizer": "2.6.0",
"@babel/code-frame": "7.8.3",
"@babel/code-frame": "7.10.4",
"@babel/core": "7.7.7",
"@babel/plugin-proposal-class-properties": "7.8.3",
"@babel/plugin-proposal-class-properties": "7.10.4",
"@babel/plugin-proposal-export-namespace-from": "7.10.4",
"@babel/plugin-proposal-nullish-coalescing-operator": "7.8.3",
"@babel/plugin-proposal-numeric-separator": "7.8.3",
"@babel/plugin-proposal-object-rest-spread": "7.9.6",
"@babel/plugin-proposal-optional-chaining": "7.9.0",
"@babel/plugin-proposal-nullish-coalescing-operator": "7.10.4",
"@babel/plugin-proposal-numeric-separator": "7.10.4",
"@babel/plugin-proposal-object-rest-spread": "7.11.0",
"@babel/plugin-proposal-optional-chaining": "7.11.0",
"@babel/plugin-syntax-bigint": "7.8.3",
"@babel/plugin-syntax-dynamic-import": "7.8.3",
"@babel/plugin-transform-modules-commonjs": "7.9.6",
"@babel/plugin-transform-runtime": "7.9.6",
"@babel/preset-env": "7.9.6",
"@babel/preset-modules": "0.1.3",
"@babel/preset-react": "7.9.4",
"@babel/preset-typescript": "7.9.0",
"@babel/runtime": "7.9.6",
"@babel/types": "7.9.6",
"@babel/plugin-transform-modules-commonjs": "7.10.4",
"@babel/plugin-transform-runtime": "7.11.5",
"@babel/preset-env": "7.11.5",
"@babel/preset-modules": "0.1.4",
"@babel/preset-react": "7.10.4",
"@babel/preset-typescript": "7.10.4",
"@babel/runtime": "7.11.2",
"@babel/types": "7.11.5",
"@next/react-dev-overlay": "9.5.3-canary.25",
"@next/react-refresh-utils": "9.5.3-canary.25",
"ast-types": "0.13.2",
Expand Down Expand Up @@ -160,7 +160,7 @@
"@types/text-table": "0.2.1",
"@types/webpack-sources": "0.1.5",
"@zeit/ncc": "0.22.0",
"amphtml-validator": "1.0.31",
"amphtml-validator": "1.0.33",
"arg": "4.1.0",
"async-retry": "1.2.3",
"async-sema": "3.0.0",
Expand All @@ -169,7 +169,7 @@
"cache-loader": "4.1.0",
"chalk": "2.4.2",
"ci-info": "watson/ci-info#f43f6a1cefff47fb361c88cf4b943fdbcaafe540",
"comment-json": "3.0.2",
"comment-json": "3.0.3",
"compression": "1.7.4",
"conf": "5.0.0",
"content-type": "1.0.4",
Expand Down
2 changes: 1 addition & 1 deletion packages/react-dev-overlay/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"build": "tsc -d -w -p tsconfig.json"
},
"dependencies": {
"@babel/code-frame": "7.8.3",
"@babel/code-frame": "7.10.4",
"ally.js": "1.4.1",
"anser": "1.4.9",
"chalk": "4.0.0",
Expand Down
2 changes: 2 additions & 0 deletions test/acceptance/ReactRefreshLogBox.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ test('render error not shown right after syntax error', async () => {
await session.patch(
'index.js',
`
import * as React from 'react';
class ClassDefault extends React.Component {
render() {
return <h1>Default Export</h1>;
Expand Down Expand Up @@ -576,6 +577,7 @@ test('boundaries', async () => {
'index.js',
`
import FunctionDefault from './FunctionDefault.js'
import * as React from 'react'
class ErrorBoundary extends React.Component {
constructor() {
super()
Expand Down
3 changes: 3 additions & 0 deletions test/acceptance/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ export async function sandbox(
})
const browser = await webdriver(appPort, '/')

// Slow down tests a bit to ensure application is ready:
await new Promise((resolve) => setTimeout(resolve, 750))

return [
{
sandboxDirectory,
Expand Down
8 changes: 4 additions & 4 deletions test/integration/basic/test/dynamic.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,17 @@ export default (context, render) => {
it('should render dynamic import components', async () => {
const $ = await get$('/dynamic/ssr')
// Make sure the client side knows it has to wait for the bundle
expect($('body').html()).toContain(
'"dynamicIds":["./components/hello1.js"]'
expect(JSON.parse($('#__NEXT_DATA__').html()).dynamicIds).toContain(
'./components/hello1.js'
)
expect($('body').text()).toMatch(/Hello World 1/)
})

it('should render dynamic import components using a function as first parameter', async () => {
const $ = await get$('/dynamic/function')
// Make sure the client side knows it has to wait for the bundle
expect($('body').html()).toContain(
'"dynamicIds":["./components/hello1.js"]'
expect(JSON.parse($('#__NEXT_DATA__').html()).dynamicIds).toContain(
'./components/hello1.js'
)
expect($('body').text()).toMatch(/Hello World 1/)
})
Expand Down
19 changes: 3 additions & 16 deletions test/integration/basic/test/error-recovery.js
Original file line number Diff line number Diff line change
Expand Up @@ -253,22 +253,9 @@ export default (context, renderViaHTTP) => {
'__WEBPACK_DEFAULT_EXPORT__',
'Unknown'
)
).toMatchInlineSnapshot(`
" 1 of 1 unhandled error
Server Error
Error: Objects are not valid as a React child (found: /search/). If you meant to render a collection of children, use an array instead.
in Unknown
in App
in Unknown
in Context.Provider
in Context.Provider
in Context.Provider
in Context.Provider
in AppContainer
This error happened while generating the page. Any console logs will be displayed in the terminal window."
`)
).toMatch(
'Objects are not valid as a React child (found: /search/). If you meant to render a collection of children, use an array instead.'
)

aboutPage.restore()

Expand Down
File renamed without changes.
22 changes: 22 additions & 0 deletions test/integration/numeric-sep/test/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/* eslint-env jest */

import { nextBuild } from 'next-test-utils'
import { join } from 'path'

jest.setTimeout(1000 * 60 * 2)

const appDir = join(__dirname, '../')

describe('Numeric Separator Support', () => {
it('should successfully build for a JavaScript file', async () => {
const { code, stdout, stderr } = await nextBuild(appDir, [], {
stdout: true,
stderr: true,
})

expect(code).toBe(0)

expect(stdout).toContain('Compiled successfully')
expect(stderr).not.toContain('Failed to compile')
})
})

This file was deleted.

Loading

0 comments on commit f921b4f

Please sign in to comment.