Skip to content

Commit

Permalink
Fix SWC loader ignore for the server layer when Babel is used (#40939)
Browse files Browse the repository at this point in the history
Specific logic to handle the file transpilation on the server layer is
implemented in SWC (#40603). When Babel is enabled, that SWC transform
is ignored at the moment. In this PR we add an additional SWC pass after
Babel to handle that.

## Bug

- [ ] Related issues linked using `fixes #number`
- [x] Integration tests added
- [ ] Errors have a helpful link attached, see `contributing.md`

## Feature

- [ ] Implements an existing feature request or RFC. Make sure the
feature request has been accepted for implementation before opening a
PR.
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [ ] Errors have a helpful link attached, see `contributing.md`

## Documentation / Examples

- [ ] Make sure the linting passes by running `pnpm lint`
- [ ] The "examples guidelines" are followed from [our contributing
doc](https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
  • Loading branch information
shuding and kodiakhq[bot] committed Sep 27, 2022
1 parent a92a3b6 commit da8d299
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 44 deletions.
98 changes: 54 additions & 44 deletions packages/next/build/webpack-config.ts
Expand Up @@ -628,52 +628,59 @@ export default async function getBaseWebpackConfig(
loggedIgnoredCompilerOptions = true
}

const getBabelOrSwcLoader = () => {
if (useSWCLoader && config?.experimental?.swcTraceProfiling) {
const getBabelLoader = () => {
return {
loader: require.resolve('./babel/loader/index'),
options: {
configFile: babelConfigFile,
isServer: isNodeServer || isEdgeServer,
distDir,
pagesDir,
cwd: dir,
development: dev,
hasReactRefresh: dev && isClient,
hasJsxRuntime: true,
},
}
}

let swcTraceProfilingInitialized = false
const getSwcLoader = (extraOptions?: any) => {
if (
config?.experimental?.swcTraceProfiling &&
!swcTraceProfilingInitialized
) {
// This will init subscribers once only in a single process lifecycle,
// even though it can be called multiple times.
// Subscriber need to be initialized _before_ any actual swc's call (transform, etcs)
// to collect correct trace spans when they are called.
swcTraceProfilingInitialized = true
require('./swc')?.initCustomTraceSubscriber?.(
path.join(distDir, `swc-trace-profile-${Date.now()}.json`)
)
}

return useSWCLoader
? {
loader: 'next-swc-loader',
options: {
isServer: isNodeServer || isEdgeServer,
rootDir: dir,
pagesDir,
hasReactRefresh: dev && isClient,
fileReading: config.experimental.swcFileReading,
nextConfig: config,
jsConfig,
supportedBrowsers: config.experimental.browsersListForSwc
? supportedBrowsers
: undefined,
swcCacheDir: path.join(
dir,
config?.distDir ?? '.next',
'cache',
'swc'
),
},
}
: {
loader: require.resolve('./babel/loader/index'),
options: {
configFile: babelConfigFile,
isServer: isNodeServer || isEdgeServer,
distDir,
pagesDir,
cwd: dir,
development: dev,
hasReactRefresh: dev && isClient,
hasJsxRuntime: true,
},
}
return {
loader: 'next-swc-loader',
options: {
isServer: isNodeServer || isEdgeServer,
rootDir: dir,
pagesDir,
hasReactRefresh: dev && isClient,
fileReading: config.experimental.swcFileReading,
nextConfig: config,
jsConfig,
supportedBrowsers: config.experimental.browsersListForSwc
? supportedBrowsers
: undefined,
swcCacheDir: path.join(dir, config?.distDir ?? '.next', 'cache', 'swc'),
...extraOptions,
},
}
}

const getBabelOrSwcLoader = () => {
return useSWCLoader ? getSwcLoader() : getBabelLoader()
}

const defaultLoaders = {
Expand Down Expand Up @@ -1613,13 +1620,16 @@ export default async function getBaseWebpackConfig(
{
test: codeCondition.test,
issuerLayer: WEBPACK_LAYERS.server,
use: {
...defaultLoaders.babel,
options: {
...defaultLoaders.babel.options,
isServerLayer: true,
},
},
use: useSWCLoader
? getSwcLoader({ isServerLayer: true })
: // When using Babel, we will have to add the SWC loader
// as an additional pass to handle RSC correctly.
// This will cause some performance overhead but
// acceptable as Babel will not be recommended.
[
getSwcLoader({ isServerLayer: true }),
getBabelLoader(),
],
},
]
: []),
Expand Down
35 changes: 35 additions & 0 deletions test/e2e/app-dir/with-babel.test.ts
@@ -0,0 +1,35 @@
import { createNext, FileRef } from 'e2e-utils'
import { NextInstance } from 'test/lib/next-modes/base'
import { renderViaHTTP } from 'next-test-utils'
import path from 'path'
import cheerio from 'cheerio'

describe('with babel', () => {
if ((global as any).isNextDeploy) {
it('should skip next deploy for now', () => {})
return
}

if (process.env.NEXT_TEST_REACT_VERSION === '^17') {
it('should skip for react v17', () => {})
return
}
let next: NextInstance

beforeAll(async () => {
next = await createNext({
files: new FileRef(path.join(__dirname, 'with-babel')),
dependencies: {
react: 'experimental',
'react-dom': 'experimental',
},
})
})
afterAll(() => next.destroy())

it('should support babel in app dir', async () => {
const html = await renderViaHTTP(next.url, '/')
const $ = cheerio.load(html)
expect($('h1').text()).toBe('hello')
})
})
10 changes: 10 additions & 0 deletions test/e2e/app-dir/with-babel/app/layout.js
@@ -0,0 +1,10 @@
export default function Root({ children }) {
return (
<html>
<head>
<title>hello</title>
</head>
<body>{children}</body>
</html>
)
}
8 changes: 8 additions & 0 deletions test/e2e/app-dir/with-babel/app/page.js
@@ -0,0 +1,8 @@
'client'

import { useState } from 'react'

export default function Page() {
const state = useState('hello')[0]
return <h1>{state}</h1>
}
3 changes: 3 additions & 0 deletions test/e2e/app-dir/with-babel/babel.config.js
@@ -0,0 +1,3 @@
module.exports = {
presets: ['next/babel'],
}
5 changes: 5 additions & 0 deletions test/e2e/app-dir/with-babel/next.config.js
@@ -0,0 +1,5 @@
module.exports = {
experimental: {
appDir: true,
},
}

0 comments on commit da8d299

Please sign in to comment.