1- import { declare } from ' @babel/helper-plugin-utils'
1+ import { declare } from " @babel/helper-plugin-utils" ;
22import syntaxDynamicImport from '@babel/plugin-syntax-dynamic-import'
33import chunkNameProperty from './properties/chunkName'
44import isReadyProperty from './properties/isReady'
@@ -20,194 +20,164 @@ const properties = [
2020
2121const LOADABLE_COMMENT = '#__LOADABLE__'
2222
23- /**
24- * The options for the plugin
25- * @typedef {Object } LoadabelBabelPluginOptions
26- * @property {string } [defaultImportSpecifier] - The default import specifier, defaults to `loadable`
27- * @property {boolean } [moduleFederation] - Whether to use module federation
28- */
29-
30- /**
31- * The options for the plugin
32- * @typedef {Object } PropertyFactoryOptions
33- * @property {import('@babel/core').NodePath<import('@babel/types').CallExpression> } callPath
34- * @property {import('@babel/core').NodePath<import('@babel/types').FunctionExpression | import('@babel/types').ArrowFunctionExpression | import('@babel/types').ObjectMethod> } funcPath
35- * @property {import('@babel/core').NodePath<import('@babel/types').ObjectExpression> } path
36- */
37-
38- /**
39- * The factory for a property
40- * @typedef {Function } PropertyFactory
41- * @param {PropertyFactoryOptions } options
42- * @returns {import('@babel/types').ObjectMethod }
43- */
44-
45- const loadablePlugin = declare (
46- /**
47- *
48- * @param {import('@babel/helper-plugin-utils').BabelAPI } api
49- * @param {LoadabelBabelPluginOptions } babelOptions
50- * @returns {import('@babel/core').PluginObj }
51- */
52- ( api , babelOptions ) => {
53- const { defaultImportSpecifier = 'loadable' } = babelOptions
54-
55- const { types : t } = api
56-
57- function collectImportCallPaths ( startPath ) {
58- const imports = [ ]
59- startPath . traverse ( {
60- Import ( importPath ) {
61- imports . push ( importPath . parentPath )
62- } ,
63- } )
64- return imports
65- }
23+ const loadablePlugin = declare ( ( api , babelOptions ) => {
24+ const { defaultImportSpecifier = 'loadable' } = babelOptions
6625
67- const propertyFactories = properties . map ( init => init ( api , babelOptions ) )
26+ const { types : t } = api
6827
69- function isValidIdentifier (
70- path ,
71- loadableImportSpecifier ,
72- lazyImportSpecifier ,
28+ function collectImportCallPaths ( startPath ) {
29+ const imports = [ ]
30+ startPath . traverse ( {
31+ Import ( importPath ) {
32+ imports . push ( importPath . parentPath )
33+ } ,
34+ } )
35+ return imports
36+ }
37+
38+ const propertyFactories = properties . map ( init => init ( api , babelOptions ) )
39+
40+ function isValidIdentifier (
41+ path ,
42+ loadableImportSpecifier ,
43+ lazyImportSpecifier ,
44+ ) {
45+ // `loadable()`
46+ if (
47+ loadableImportSpecifier &&
48+ path . get ( 'callee' ) . isIdentifier ( { name : loadableImportSpecifier } )
7349 ) {
74- // `loadable()`
75- if (
76- loadableImportSpecifier &&
77- path . get ( 'callee' ) . isIdentifier ( { name : loadableImportSpecifier } )
78- ) {
79- return true
80- }
81-
82- // `lazy()`
83- if (
84- lazyImportSpecifier &&
85- path . get ( 'callee' ) . isIdentifier ( { name : lazyImportSpecifier } )
86- ) {
87- return true
88- }
89-
90- // `loadable.lib()`
91- return (
92- loadableImportSpecifier &&
93- path . get ( 'callee' ) . isMemberExpression ( ) &&
94- path
95- . get ( 'callee.object' )
96- . isIdentifier ( { name : loadableImportSpecifier } ) &&
97- path . get ( 'callee.property' ) . isIdentifier ( { name : 'lib' } )
98- )
50+ return true
9951 }
10052
101- function hasLoadableComment ( path ) {
102- const comments = path . get ( 'leadingComments' )
103- const comment = comments . find (
104- ( { node } ) =>
105- node && node . value && String ( node . value ) . includes ( LOADABLE_COMMENT ) ,
106- )
107- if ( ! comment ) return false
108- comment . remove ( )
53+ // `lazy()`
54+ if (
55+ lazyImportSpecifier &&
56+ path . get ( 'callee' ) . isIdentifier ( { name : lazyImportSpecifier } )
57+ ) {
10958 return true
11059 }
11160
112- function getFuncPath ( path ) {
113- const funcPath = path . isCallExpression ( ) ? path . get ( 'arguments.0' ) : path
114- if (
115- ! funcPath . isFunctionExpression ( ) &&
116- ! funcPath . isArrowFunctionExpression ( ) &&
117- ! funcPath . isObjectMethod ( )
118- ) {
119- return null
120- }
121- return funcPath
61+ // `loadable.lib()`
62+ return (
63+ loadableImportSpecifier &&
64+ path . get ( 'callee' ) . isMemberExpression ( ) &&
65+ path
66+ . get ( 'callee.object' )
67+ . isIdentifier ( { name : loadableImportSpecifier } ) &&
68+ path . get ( 'callee.property' ) . isIdentifier ( { name : 'lib' } )
69+ )
70+ }
71+
72+ function hasLoadableComment ( path ) {
73+ const comments = path . get ( 'leadingComments' )
74+ const comment = comments . find (
75+ ( { node } ) =>
76+ node && node . value && String ( node . value ) . includes ( LOADABLE_COMMENT ) ,
77+ )
78+ if ( ! comment ) return false
79+ comment . remove ( )
80+ return true
81+ }
82+
83+ function getFuncPath ( path ) {
84+ const funcPath = path . isCallExpression ( ) ? path . get ( 'arguments.0' ) : path
85+ if (
86+ ! funcPath . isFunctionExpression ( ) &&
87+ ! funcPath . isArrowFunctionExpression ( ) &&
88+ ! funcPath . isObjectMethod ( )
89+ ) {
90+ return null
12291 }
92+ return funcPath
93+ }
12394
124- function transformImport ( path ) {
125- const callPaths = collectImportCallPaths ( path )
95+ function transformImport ( path ) {
96+ const callPaths = collectImportCallPaths ( path )
12697
127- // Ignore loadable function that does not have any "import" call
128- if ( callPaths . length === 0 ) return
98+ // Ignore loadable function that does not have any "import" call
99+ if ( callPaths . length === 0 ) return
129100
130- // Multiple imports call is not supported
131- if ( callPaths . length > 1 ) {
132- throw new Error (
133- 'loadable: multiple import calls inside `loadable()` function are not supported.' ,
134- )
135- }
101+ // Multiple imports call is not supported
102+ if ( callPaths . length > 1 ) {
103+ throw new Error (
104+ 'loadable: multiple import calls inside `loadable()` function are not supported.' ,
105+ )
106+ }
136107
137- const [ callPath ] = callPaths
108+ const [ callPath ] = callPaths
138109
139- const funcPath = getFuncPath ( path )
140- if ( ! funcPath ) return
110+ const funcPath = getFuncPath ( path )
111+ if ( ! funcPath ) return
141112
142- funcPath . node . params = funcPath . node . params || [ ]
113+ funcPath . node . params = funcPath . node . params || [ ]
143114
144- const object = t . objectExpression (
145- propertyFactories . map ( getProperty =>
146- getProperty ( { path, callPath, funcPath } ) ,
147- ) ,
148- )
115+ const object = t . objectExpression (
116+ propertyFactories . map ( getProperty =>
117+ getProperty ( { path, callPath, funcPath } ) ,
118+ ) ,
119+ )
149120
150- if ( funcPath . isObjectMethod ( ) ) {
151- funcPath . replaceWith (
152- t . objectProperty ( funcPath . node . key , object , funcPath . node . computed ) ,
153- )
154- } else {
155- funcPath . replaceWith ( object )
156- }
121+ if ( funcPath . isObjectMethod ( ) ) {
122+ funcPath . replaceWith (
123+ t . objectProperty ( funcPath . node . key , object , funcPath . node . computed ) ,
124+ )
125+ } else {
126+ funcPath . replaceWith ( object )
157127 }
158-
159- return {
160- inherits : syntaxDynamicImport ,
161- visitor : {
162- Program : {
163- enter ( programPath ) {
164- let loadableImportSpecifier = defaultImportSpecifier
165- let lazyImportSpecifier = false
166-
167- programPath . traverse ( {
168- ImportDefaultSpecifier ( path ) {
169- if ( ! loadableImportSpecifier ) {
170- const { parent } = path
171- const { local } = path . node
172- loadableImportSpecifier =
173- parent . source . value == '@loadable/component' &&
174- local &&
175- local . name
176- }
177- } ,
178- ImportSpecifier ( path ) {
179- if ( ! lazyImportSpecifier ) {
180- const { parent } = path
181- const { imported , local } = path . node
182- lazyImportSpecifier =
183- parent . source . value == '@loadable/component' &&
184- imported &&
185- imported . name == 'lazy' &&
186- local &&
187- local . name
188- }
189- } ,
190- CallExpression ( path ) {
191- if (
192- ! isValidIdentifier (
193- path ,
194- loadableImportSpecifier ,
195- lazyImportSpecifier ,
196- )
128+ }
129+
130+ return {
131+ inherits : syntaxDynamicImport ,
132+ visitor : {
133+ Program : {
134+ enter ( programPath ) {
135+ let loadableImportSpecifier = defaultImportSpecifier
136+ let lazyImportSpecifier = false
137+
138+ programPath . traverse ( {
139+ ImportDefaultSpecifier ( path ) {
140+ if ( ! loadableImportSpecifier ) {
141+ const { parent } = path
142+ const { local } = path . node
143+ loadableImportSpecifier =
144+ parent . source . value == '@loadable/component' &&
145+ local &&
146+ local . name
147+ }
148+ } ,
149+ ImportSpecifier ( path ) {
150+ if ( ! lazyImportSpecifier ) {
151+ const { parent } = path
152+ const { imported , local } = path . node
153+ lazyImportSpecifier =
154+ parent . source . value == '@loadable/component' &&
155+ imported &&
156+ imported . name == 'lazy' &&
157+ local &&
158+ local . name
159+ }
160+ } ,
161+ CallExpression ( path ) {
162+ if (
163+ ! isValidIdentifier (
164+ path ,
165+ loadableImportSpecifier ,
166+ lazyImportSpecifier ,
197167 )
198- return
199- transformImport ( path )
200- } ,
201- 'ArrowFunctionExpression|FunctionExpression|ObjectMethod' : path => {
202- if ( ! hasLoadableComment ( path ) ) return
203- transformImport ( path )
204- } ,
205- } )
206- } ,
168+ )
169+ return
170+ transformImport ( path )
171+ } ,
172+ 'ArrowFunctionExpression|FunctionExpression|ObjectMethod' : path => {
173+ if ( ! hasLoadableComment ( path ) ) return
174+ transformImport ( path )
175+ } ,
176+ } )
207177 } ,
208178 } ,
209- }
210- } ,
211- )
179+ } ,
180+ }
181+ } )
212182
213183export default loadablePlugin
0 commit comments