Skip to content

Commit

Permalink
Add support for legacy decorators through tsconfig/jsconfig (#31376)
Browse files Browse the repository at this point in the history
  • Loading branch information
timneutkens authored Nov 13, 2021
1 parent ae1cee5 commit e0531e3
Show file tree
Hide file tree
Showing 9 changed files with 128 additions and 42 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ packages/next-codemod/**/*.d.ts
packages/next-env/**/*.d.ts
packages/create-next-app/templates/**
test/integration/eslint/**
test/development/basic/legacy-decorators/**/*
test-timings.json
packages/next/build/swc/tests/**
bench/nested-deps/pages/**
Expand Down
17 changes: 8 additions & 9 deletions packages/next/build/jest/jest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { loadEnvConfig } from '@next/env'
import { resolve, join } from 'path'
import loadConfig from '../../server/config'
import { PHASE_TEST } from '../../shared/lib/constants'
// import loadJsConfig from '../load-jsconfig'
import loadJsConfig from '../load-jsconfig'
import * as Log from '../output/log'

async function getConfig(dir: string) {
Expand Down Expand Up @@ -51,7 +51,7 @@ export default function nextJest(options: { dir?: string } = {}) {
// Will be called and awaited by Jest
return async () => {
let nextConfig
let paths
let jsConfig
let resolvedBaseUrl
let isEsmProject = false
if (options.dir) {
Expand All @@ -62,9 +62,9 @@ export default function nextJest(options: { dir?: string } = {}) {
nextConfig = await getConfig(resolvedDir)
loadEnvConfig(resolvedDir, false, Log)
// TODO: revisit when bug in SWC is fixed that strips `.css`
// const result = await loadJsConfig(resolvedDir, nextConfig)
// paths = result?.jsConfig?.compilerOptions?.paths
// resolvedBaseUrl = result.resolvedBaseUrl
const result = await loadJsConfig(resolvedDir, nextConfig)
jsConfig = result.jsConfig
resolvedBaseUrl = result.resolvedBaseUrl
}
// Ensure provided async config is supported
const resolvedJestConfig =
Expand Down Expand Up @@ -107,10 +107,9 @@ export default function nextJest(options: { dir?: string } = {}) {
'^.+\\.(js|jsx|ts|tsx)$': [
require.resolve('../swc/jest-transformer'),
{
styledComponents:
nextConfig && nextConfig.experimental.styledComponents,
paths,
resolvedBaseUrl: resolvedBaseUrl,
nextConfig,
jsConfig,
resolvedBaseUrl,
isEsmProject,
},
],
Expand Down
6 changes: 3 additions & 3 deletions packages/next/build/swc/jest-transformer.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ module.exports = {
isServer:
jestConfig.testEnvironment && jestConfig.testEnvironment === 'node',
filename,
styledComponents: inputOptions.styledComponents,
paths: inputOptions.paths,
baseUrl: inputOptions.resolvedBaseUrl,
nextConfig: inputOptions.nextConfig,
jsConfig: inputOptions.jsConfig,
resolvedBaseUrl: inputOptions.resolvedBaseUrl,
esm:
isSupportEsm &&
isEsm(Boolean(inputOptions.isEsmProject), filename, jestConfig),
Expand Down
46 changes: 27 additions & 19 deletions packages/next/build/swc/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,36 @@ function getBaseSWCOptions({
development,
hasReactRefresh,
globalWindow,
styledComponents,
paths,
baseUrl,
importSource,
nextConfig,
resolvedBaseUrl,
jsConfig,
}) {
const isTSFile = filename.endsWith('.ts')
const isTypeScript = isTSFile || filename.endsWith('.tsx')

const paths = jsConfig?.compilerOptions?.paths
const enableDecorators = Boolean(
jsConfig?.compilerOptions?.experimentalDecorators
)
return {
jsc: {
...(baseUrl && paths
...(resolvedBaseUrl && paths
? {
baseUrl,
baseUrl: resolvedBaseUrl,
paths,
}
: {}),
parser: {
syntax: isTypeScript ? 'typescript' : 'ecmascript',
dynamicImport: true,
decorators: enableDecorators,
// Exclude regular TypeScript files from React transformation to prevent e.g. generic parameters and angle-bracket type assertion from being interpreted as JSX tags.
[isTypeScript ? 'tsx' : 'jsx']: isTSFile ? false : true,
},

transform: {
legacyDecorator: enableDecorators,
react: {
importSource: importSource || 'react',
importSource: jsConfig?.compilerOptions?.jsxImportSource || 'react',
runtime: 'automatic',
pragma: 'React.createElement',
pragmaFrag: 'React.Fragment',
Expand All @@ -57,7 +61,7 @@ function getBaseSWCOptions({
},
},
},
styledComponents: styledComponents
styledComponents: nextConfig?.experimental?.styledComponents
? {
displayName: Boolean(development),
}
Expand All @@ -69,18 +73,19 @@ export function getJestSWCOptions({
isServer,
filename,
esm,
styledComponents,
paths,
baseUrl,
nextConfig,
jsConfig,
// This is not passed yet as "paths" resolving needs a test first
// resolvedBaseUrl,
}) {
let baseOptions = getBaseSWCOptions({
filename,
development: false,
hasReactRefresh: false,
globalWindow: !isServer,
styledComponents,
paths,
baseUrl,
nextConfig,
jsConfig,
// resolvedBaseUrl,
})

const isNextDist = nextDistPath.test(filename)
Expand Down Expand Up @@ -108,16 +113,19 @@ export function getLoaderSWCOptions({
pagesDir,
isPageFile,
hasReactRefresh,
styledComponents,
importSource,
nextConfig,
jsConfig,
// This is not passed yet as "paths" resolving is handled by webpack currently.
// resolvedBaseUrl,
}) {
let baseOptions = getBaseSWCOptions({
filename,
development,
globalWindow: !isServer,
hasReactRefresh,
styledComponents,
importSource,
nextConfig,
jsConfig,
// resolvedBaseUrl,
})

const isNextDist = nextDistPath.test(filename)
Expand Down
4 changes: 2 additions & 2 deletions packages/next/build/webpack-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -441,8 +441,8 @@ export default async function getBaseWebpackConfig(
isServer: isMiddleware || isServer,
pagesDir,
hasReactRefresh: !isMiddleware && hasReactRefresh,
styledComponents: config.experimental.styledComponents,
importSource: jsConfig?.compilerOptions?.jsxImportSource,
nextConfig: config,
jsConfig,
},
}
: {
Expand Down
13 changes: 4 additions & 9 deletions packages/next/build/webpack/loaders/next-swc-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,8 @@ async function loaderTransform(parentTrace, source, inputSourceMap) {

let loaderOptions = this.getOptions() || {}

const {
isServer,
pagesDir,
hasReactRefresh,
styledComponents,
importSource,
} = loaderOptions
const { isServer, pagesDir, hasReactRefresh, nextConfig, jsConfig } =
loaderOptions
const isPageFile = filename.startsWith(pagesDir)

const swcOptions = getLoaderSWCOptions({
Expand All @@ -51,8 +46,8 @@ async function loaderTransform(parentTrace, source, inputSourceMap) {
isPageFile,
development: this.mode === 'development',
hasReactRefresh,
styledComponents,
importSource,
nextConfig,
jsConfig,
})

const programmaticOptions = {
Expand Down
43 changes: 43 additions & 0 deletions test/development/basic/legacy-decorators.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { join } from 'path'
import webdriver from 'next-webdriver'
import { createNext, FileRef } from 'e2e-utils'
import { NextInstance } from 'test/lib/next-modes/base'
import { check } from 'next-test-utils'

describe('Legacy decorators SWC option', () => {
let next: NextInstance

beforeAll(async () => {
next = await createNext({
files: {
'jsconfig.json': new FileRef(
join(__dirname, 'legacy-decorators/jsconfig.json')
),
pages: new FileRef(join(__dirname, 'legacy-decorators/pages')),
},
dependencies: {
mobx: '6.3.7',
'mobx-react': '7.2.1',
},
})
})
afterAll(() => next.destroy())

it('should compile with legacy decorators enabled', async () => {
let browser
try {
browser = await webdriver(next.appPort, '/')
const text = await browser.elementByCss('#count').text()
expect(text).toBe('Current number: 0')
await browser.elementByCss('#increase').click()
await check(
() => browser.elementByCss('#count').text(),
/Current number: 1/
)
} finally {
if (browser) {
await browser.close()
}
}
})
})
5 changes: 5 additions & 0 deletions test/development/basic/legacy-decorators/jsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"compilerOptions": {
"experimentalDecorators": true
}
}
35 changes: 35 additions & 0 deletions test/development/basic/legacy-decorators/pages/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react'
import { makeAutoObservable } from 'mobx'
import { observer } from 'mobx-react'

class Counter {
count = 0

constructor() {
makeAutoObservable(this)
}

increase() {
this.count += 1
}
}

const myCounter = new Counter()

@observer
class CounterView extends React.Component {
render() {
return (
<>
<span id="count">Current number: {this.props.counter.count}</span>
<button id="increase" onClick={() => this.props.counter.increase()}>
Increase
</button>
</>
)
}
}

export default function Home() {
return <CounterView counter={myCounter} />
}

0 comments on commit e0531e3

Please sign in to comment.