@@ -3,6 +3,19 @@ import { CodeInjection, containsOnlyImports, stripQueryAndHashFromPath } from '.
33import type { transformAsync as babelTransformAsync } from '@babel/core' ;
44import type componentNameAnnotatePlugin from '../babel-plugin' ;
55import type { experimentalComponentNameAnnotatePlugin } from '../babel-plugin' ;
6+ import type {
7+ ComponentAnnotationTransformMeta ,
8+ ComponentAnnotationTransformResult ,
9+ ParseAstAsync ,
10+ } from './component-annotation-oxc-ast' ;
11+
12+ type FastAnnotationHooks = {
13+ transform (
14+ code : string ,
15+ id : string ,
16+ meta ?: ComponentAnnotationTransformMeta ,
17+ ) : Promise < ComponentAnnotationTransformResult > ;
18+ } ;
619
720type BabelTransformAsync = typeof babelTransformAsync ;
821type BabelParserPlugins = NonNullable < NonNullable < Parameters < BabelTransformAsync > [ 1 ] > [ 'parserOpts' ] > [ 'plugins' ] ;
@@ -76,59 +89,86 @@ export function shouldSkipCodeInjection(code: string, facadeModuleId: string | n
7689export { globFiles } from './glob' ;
7790
7891// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
79- export function createComponentNameAnnotateHooks ( ignoredComponents : string [ ] , injectIntoHtml : boolean ) {
80- return {
81- async transform ( this : void , code : string , id : string ) {
82- // id may contain query and hash which will trip up our file extension logic below
83- const idWithoutQueryAndHash = stripQueryAndHashFromPath ( id ) ;
92+ export function createComponentNameAnnotateHooks (
93+ ignoredComponents : string [ ] ,
94+ injectIntoHtml : boolean ,
95+ getParseAstAsync ?: ( ) => Promise < ParseAstAsync | null > ,
96+ ) {
97+ let fastHooksPromise : Promise < FastAnnotationHooks > | undefined ;
8498
85- if ( idWithoutQueryAndHash . match ( / \\ n o d e _ m o d u l e s \\ | \/ n o d e _ m o d u l e s \/ / ) ) {
86- return null ;
99+ return {
100+ async transform ( this : void , code : string , id : string , meta ?: ComponentAnnotationTransformMeta ) {
101+ if ( ! fastHooksPromise ) {
102+ fastHooksPromise = import ( './component-annotation-oxc' ) . then (
103+ ( { createOxcComponentNameAnnotateHooks, getOxcParseAstAsync } ) =>
104+ createOxcComponentNameAnnotateHooks (
105+ ignoredComponents ,
106+ getParseAstAsync ?? getOxcParseAstAsync ,
107+ injectIntoHtml ,
108+ ) ,
109+ ) ;
87110 }
88111
89- // We will only apply this plugin on jsx and tsx files
90- if ( ! [ '.jsx' , '.tsx' ] . some ( ending => idWithoutQueryAndHash . endsWith ( ending ) ) ) {
91- return null ;
112+ const fastResult = await ( await fastHooksPromise ) . transform ( code , id , meta ) ;
113+ if ( fastResult !== undefined ) {
114+ return fastResult ;
92115 }
93116
94- const parserPlugins : BabelParserPlugins = [ ] ;
95- if ( idWithoutQueryAndHash . endsWith ( '.jsx' ) ) {
96- parserPlugins . push ( 'jsx' ) ;
97- } else if ( idWithoutQueryAndHash . endsWith ( '.tsx' ) ) {
98- parserPlugins . push ( 'jsx' , 'typescript' ) ;
99- }
117+ return transformWithBabel ( code , id , ignoredComponents , injectIntoHtml ) ;
118+ } ,
119+ } ;
120+ }
100121
101- const { transformAsync, componentNameAnnotatePlugin, experimentalComponentNameAnnotatePlugin } =
102- await loadBabelAnnotationRuntime ( ) ;
103- const plugin = injectIntoHtml ? experimentalComponentNameAnnotatePlugin : componentNameAnnotatePlugin ;
104-
105- try {
106- const result = await transformAsync ( code , {
107- plugins : [ [ plugin , { ignoredComponents } ] ] ,
108- filename : id ,
109- sourceFileName : idWithoutQueryAndHash ,
110- parserOpts : {
111- sourceType : 'module' ,
112- allowAwaitOutsideFunction : true ,
113- plugins : parserPlugins ,
114- } ,
115- generatorOpts : {
116- decoratorsBeforeExport : true ,
117- } ,
118- sourceMaps : true ,
119- } ) ;
122+ // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
123+ async function transformWithBabel ( code : string , id : string , ignoredComponents : string [ ] , injectIntoHtml : boolean ) {
124+ // id may contain query and hash which will trip up our file extension logic below
125+ const idWithoutQueryAndHash = stripQueryAndHashFromPath ( id ) ;
120126
121- return {
122- code : result ?. code ?? code ,
123- map : result ?. map ,
124- } ;
125- } catch ( e ) {
126- debug . error ( `Failed to apply react annotate plugin` , e ) ;
127- }
127+ if ( idWithoutQueryAndHash . match ( / \\ n o d e _ m o d u l e s \\ | \/ n o d e _ m o d u l e s \/ / ) ) {
128+ return null ;
129+ }
128130
129- return { code } ;
130- } ,
131- } ;
131+ // We will only apply this plugin on jsx and tsx files
132+ if ( ! [ '.jsx' , '.tsx' ] . some ( ending => idWithoutQueryAndHash . endsWith ( ending ) ) ) {
133+ return null ;
134+ }
135+
136+ const parserPlugins : BabelParserPlugins = [ ] ;
137+ if ( idWithoutQueryAndHash . endsWith ( '.jsx' ) ) {
138+ parserPlugins . push ( 'jsx' ) ;
139+ } else if ( idWithoutQueryAndHash . endsWith ( '.tsx' ) ) {
140+ parserPlugins . push ( 'jsx' , 'typescript' ) ;
141+ }
142+
143+ const { transformAsync, componentNameAnnotatePlugin, experimentalComponentNameAnnotatePlugin } =
144+ await loadBabelAnnotationRuntime ( ) ;
145+ const plugin = injectIntoHtml ? experimentalComponentNameAnnotatePlugin : componentNameAnnotatePlugin ;
146+
147+ try {
148+ const result = await transformAsync ( code , {
149+ plugins : [ [ plugin , { ignoredComponents } ] ] ,
150+ filename : id ,
151+ sourceFileName : idWithoutQueryAndHash ,
152+ parserOpts : {
153+ sourceType : 'module' ,
154+ allowAwaitOutsideFunction : true ,
155+ plugins : parserPlugins ,
156+ } ,
157+ generatorOpts : {
158+ decoratorsBeforeExport : true ,
159+ } ,
160+ sourceMaps : true ,
161+ } ) ;
162+
163+ return {
164+ code : result ?. code ?? code ,
165+ map : result ?. map ,
166+ } ;
167+ } catch ( e ) {
168+ debug . error ( `Failed to apply react annotate plugin` , e ) ;
169+ }
170+
171+ return { code } ;
132172}
133173
134174export function getDebugIdSnippet ( debugId : string ) : CodeInjection {
0 commit comments