Skip to content

Commit cefcef9

Browse files
committed
move to oxc and use babel for classes
1 parent 2301c95 commit cefcef9

File tree

6 files changed

+200
-89
lines changed

6 files changed

+200
-89
lines changed

packages/compiler/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
},
3030
"dependencies": {
3131
"@babel/core": "^7.26.0",
32+
"@babel/plugin-transform-class-properties": "^7.25.9",
33+
"@babel/plugin-transform-classes": "^7.25.9",
3234
"@babel/plugin-transform-destructuring": "^7.25.9",
3335
"@babel/plugin-transform-private-methods": "^7.25.9",
3436
"@babel/plugin-transform-react-jsx": "^7.25.9",
@@ -37,6 +39,7 @@
3739
"@vxrn/utils": "workspace:*",
3840
"@vxrn/vite-native-client": "workspace:*",
3941
"babel-plugin-react-compiler": "^19.0.0-beta-201e55d-20241215",
42+
"oxc-transform": "^0.48.2",
4043
"react-native-css-interop": "^0.1.22",
4144
"ts-deepmerge": "^7.0.2",
4245
"vite": "^6.1.0"

packages/compiler/src/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,5 @@ export const parsers: Record<string, ParserConfig> = {
1919
}
2020

2121
export const validParsers = new Set([...Object.keys(parsers), '.css'])
22+
23+
export const USE_OXC = false

packages/compiler/src/transformBabel.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import babel from '@babel/core'
22
import { resolvePath } from '@vxrn/utils'
33
import { relative } from 'node:path'
44
import { configuration } from './configure'
5-
import { asyncGeneratorRegex, debug } from './constants'
5+
import { asyncGeneratorRegex, debug, USE_OXC } from './constants'
66
import type { GetTransformProps, GetTransformResponse } from './types'
77

88
type Props = GetTransformProps & {
@@ -52,6 +52,11 @@ const getOptions = (props: Props, force = false): babel.TransformOptions | null
5252
plugins.push('react-native-reanimated/plugin')
5353
}
5454

55+
if (USE_OXC && /class [a-z]+ \{/i.test(props.code)) {
56+
plugins.push(`@babel/plugin-transform-class-properties`)
57+
plugins.push(`@babel/plugin-transform-classes`)
58+
}
59+
5560
if (shouldBabelReactCompiler(props)) {
5661
debug?.(`Using babel react compiler on file`)
5762
plugins.push(getBabelReactCompilerPlugin(props))

packages/compiler/src/transformSWC.ts

Lines changed: 96 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
import { extname, sep } from 'node:path'
99
import { merge } from 'ts-deepmerge'
1010
import { configuration } from './configure'
11-
import { asyncGeneratorRegex, debug, parsers, runtimePublicPath } from './constants'
11+
import { asyncGeneratorRegex, debug, parsers, runtimePublicPath, USE_OXC } from './constants'
1212
import type { Options } from './types'
1313

1414
const ignoreId = new RegExp(`node_modules\\${sep}(\\.vite|vite)\\${sep}`)
@@ -45,108 +45,116 @@ export async function transformSWC(
4545
!options.forceJSX &&
4646
!id.includes('node_modules')
4747

48-
const reactConfig = {
49-
refresh,
50-
development: !options.forceJSX && !options.production,
51-
runtime: 'automatic',
52-
importSource: 'react',
53-
...(configuration.enableNativewind && !id.includes('node_modules')
54-
? {
55-
importSource: 'nativewind',
56-
// pragma: 'createInteropElement',
57-
// pragmaFrag: '_InteropFragment',
58-
// swc doesnt actually change the import right
59-
// runtime: 'classic',
60-
}
61-
: {}),
62-
} satisfies TransformConfig['react']
63-
64-
const transformOptions = ((): SWCOptions => {
65-
if (options.environment === 'client' || options.environment === 'ssr') {
66-
return {
67-
sourceMaps: shouldSourceMap(),
68-
jsc: {
69-
target: 'es2020',
70-
parser,
71-
transform: {
72-
useDefineForClassFields: true,
73-
react: reactConfig,
74-
},
75-
},
76-
}
77-
}
78-
79-
const shouldEs5Transform =
80-
options.es5 || (!process.env.VXRN_USE_BABEL_FOR_GENERATORS && asyncGeneratorRegex.test(code))
81-
82-
const opts: SWCOptions = shouldEs5Transform
83-
? {
48+
let result: Output
49+
50+
if (USE_OXC) {
51+
const oxc = await import('oxc-transform')
52+
result = oxc.transform(id, code, {})
53+
} else {
54+
const reactConfig = {
55+
refresh,
56+
development: !options.forceJSX && !options.production,
57+
runtime: 'automatic',
58+
importSource: 'react',
59+
...(configuration.enableNativewind && !id.includes('node_modules')
60+
? {
61+
importSource: 'nativewind',
62+
// pragma: 'createInteropElement',
63+
// pragmaFrag: '_InteropFragment',
64+
// swc doesnt actually change the import right
65+
// runtime: 'classic',
66+
}
67+
: {}),
68+
} satisfies TransformConfig['react']
69+
70+
const transformOptions = ((): SWCOptions => {
71+
if (options.environment === 'client' || options.environment === 'ssr') {
72+
return {
73+
sourceMaps: shouldSourceMap(),
8474
jsc: {
75+
target: 'es2020',
8576
parser,
86-
target: 'es5',
8777
transform: {
8878
useDefineForClassFields: true,
8979
react: reactConfig,
9080
},
9181
},
9282
}
93-
: {
94-
...(!options.forceJSX && { env: SWC_ENV }),
95-
jsc: {
96-
...(options.forceJSX && { target: 'esnext' }),
97-
parser,
98-
transform: {
99-
useDefineForClassFields: true,
100-
react: reactConfig,
83+
}
84+
85+
const shouldEs5Transform =
86+
options.es5 ||
87+
(!process.env.VXRN_USE_BABEL_FOR_GENERATORS && asyncGeneratorRegex.test(code))
88+
89+
const opts: SWCOptions = shouldEs5Transform
90+
? {
91+
jsc: {
92+
parser,
93+
target: 'es5',
94+
transform: {
95+
useDefineForClassFields: true,
96+
react: reactConfig,
97+
},
10198
},
102-
},
103-
}
99+
}
100+
: {
101+
...(!options.forceJSX && { env: SWC_ENV }),
102+
jsc: {
103+
...(options.forceJSX && { target: 'esnext' }),
104+
parser,
105+
transform: {
106+
useDefineForClassFields: true,
107+
react: reactConfig,
108+
},
109+
},
110+
}
104111

105-
return {
106-
sourceMaps: shouldSourceMap(),
107-
module: {
108-
importInterop: 'none',
109-
type: 'nodenext',
110-
},
111-
...(options.mode === 'serve-cjs' && {
112+
return {
113+
sourceMaps: shouldSourceMap(),
112114
module: {
113115
importInterop: 'none',
114-
type: 'commonjs',
115-
strict: true,
116+
type: 'nodenext',
116117
},
117-
}),
118-
...opts,
119-
}
120-
})()
121-
122-
const finalOptions = merge(
123-
{
124-
filename: id,
125-
swcrc: false,
126-
configFile: false,
127-
...transformOptions,
128-
},
129-
swcOptions || {}
130-
) satisfies SWCOptions
131-
132-
const result: Output = await (async () => {
133-
try {
134-
debug?.(`transformSWC ${id} using options:\n${JSON.stringify(finalOptions, null, 2)}`)
135-
136-
return await transform(code, finalOptions)
137-
} catch (e: any) {
138-
const message: string = e.message
139-
const fileStartIndex = message.indexOf('╭─[')
140-
if (fileStartIndex !== -1) {
141-
const match = message.slice(fileStartIndex).match(/:(\d+):(\d+)]/)
142-
if (match) {
143-
e.line = match[1]
144-
e.column = match[2]
118+
...(options.mode === 'serve-cjs' && {
119+
module: {
120+
importInterop: 'none',
121+
type: 'commonjs',
122+
strict: true,
123+
},
124+
}),
125+
...opts,
126+
}
127+
})()
128+
129+
const finalOptions = merge(
130+
{
131+
filename: id,
132+
swcrc: false,
133+
configFile: false,
134+
...transformOptions,
135+
},
136+
swcOptions || {}
137+
) satisfies SWCOptions
138+
139+
result = await (async () => {
140+
try {
141+
debug?.(`transformSWC ${id} using options:\n${JSON.stringify(finalOptions, null, 2)}`)
142+
143+
return await transform(code, finalOptions)
144+
} catch (e: any) {
145+
const message: string = e.message
146+
const fileStartIndex = message.indexOf('╭─[')
147+
if (fileStartIndex !== -1) {
148+
const match = message.slice(fileStartIndex).match(/:(\d+):(\d+)]/)
149+
if (match) {
150+
e.line = match[1]
151+
e.column = match[2]
152+
}
145153
}
154+
throw e
146155
}
147-
throw e
148-
}
149-
})()
156+
})()
157+
}
150158

151159
if (configuration.enableNativeCSS) {
152160
if (result.code.includes(`createInteropElement(`)) {

packages/compiler/types/constants.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ export declare const runtimePublicPath = "/@react-refresh";
66
export declare const asyncGeneratorRegex: RegExp;
77
export declare const parsers: Record<string, ParserConfig>;
88
export declare const validParsers: Set<string>;
9+
export declare const USE_OXC = false;
910
//# sourceMappingURL=constants.d.ts.map

0 commit comments

Comments
 (0)