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,138 +20,194 @@ const properties = [
2020
2121const LOADABLE_COMMENT = '#__LOADABLE__'
2222
23- const loadablePlugin = declare ( ( api , { defaultImportSpecifier = 'loadable' } ) => {
24- const { types : t } = api
25-
26- function collectImportCallPaths ( startPath ) {
27- const imports = [ ]
28- startPath . traverse ( {
29- Import ( importPath ) {
30- imports . push ( importPath . parentPath )
31- } ,
32- } )
33- return imports
34- }
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+ }
3566
36- const propertyFactories = properties . map ( init => init ( api ) )
67+ const propertyFactories = properties . map ( init => init ( api , babelOptions ) )
3768
38- function isValidIdentifier ( path , loadableImportSpecifier , lazyImportSpecifier ) {
39- // `loadable()`
40- if ( loadableImportSpecifier && path . get ( 'callee' ) . isIdentifier ( { name : loadableImportSpecifier } ) ) {
41- return true
69+ function isValidIdentifier (
70+ path ,
71+ loadableImportSpecifier ,
72+ lazyImportSpecifier ,
73+ ) {
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+ )
4299 }
43100
44- // `lazy()`
45- if ( lazyImportSpecifier && path . get ( 'callee' ) . isIdentifier ( { name : lazyImportSpecifier } ) ) {
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 ( )
46109 return true
47110 }
48111
49- // `loadable.lib()`
50- return (
51- loadableImportSpecifier &&
52- path . get ( 'callee' ) . isMemberExpression ( ) &&
53- path . get ( 'callee.object' ) . isIdentifier ( { name : loadableImportSpecifier } ) &&
54- path . get ( 'callee.property' ) . isIdentifier ( { name : 'lib' } )
55- )
56- }
57-
58- function hasLoadableComment ( path ) {
59- const comments = path . get ( 'leadingComments' )
60- const comment = comments . find (
61- ( { node } ) =>
62- node && node . value && String ( node . value ) . includes ( LOADABLE_COMMENT ) ,
63- )
64- if ( ! comment ) return false
65- comment . remove ( )
66- return true
67- }
68-
69- function getFuncPath ( path ) {
70- const funcPath = path . isCallExpression ( ) ? path . get ( 'arguments.0' ) : path
71- if (
72- ! funcPath . isFunctionExpression ( ) &&
73- ! funcPath . isArrowFunctionExpression ( ) &&
74- ! funcPath . isObjectMethod ( )
75- ) {
76- return null
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
77122 }
78- return funcPath
79- }
80-
81- function transformImport ( path ) {
82- const callPaths = collectImportCallPaths ( path )
83123
84- // Ignore loadable function that does not have any "import" call
85- if ( callPaths . length === 0 ) return
124+ function transformImport ( path ) {
125+ const callPaths = collectImportCallPaths ( path )
86126
87- // Multiple imports call is not supported
88- if ( callPaths . length > 1 ) {
89- throw new Error (
90- 'loadable: multiple import calls inside `loadable()` function are not supported.' ,
91- )
92- }
127+ // Ignore loadable function that does not have any "import" call
128+ if ( callPaths . length === 0 ) return
93129
94- const [ callPath ] = callPaths
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+ }
95136
96- const funcPath = getFuncPath ( path )
97- if ( ! funcPath ) return
137+ const [ callPath ] = callPaths
98138
99- funcPath . node . params = funcPath . node . params || [ ]
139+ const funcPath = getFuncPath ( path )
140+ if ( ! funcPath ) return
100141
101- const object = t . objectExpression (
102- propertyFactories . map ( getProperty =>
103- getProperty ( { path, callPath, funcPath } ) ,
104- ) ,
105- )
142+ funcPath . node . params = funcPath . node . params || [ ]
106143
107- if ( funcPath . isObjectMethod ( ) ) {
108- funcPath . replaceWith (
109- t . objectProperty ( funcPath . node . key , object , funcPath . node . computed ) ,
144+ const object = t . objectExpression (
145+ propertyFactories . map ( getProperty =>
146+ getProperty ( { path, callPath, funcPath } ) ,
147+ ) ,
110148 )
111- } else {
112- funcPath . replaceWith ( object )
149+
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+ }
113157 }
114- }
115-
116-
117- return {
118- inherits : syntaxDynamicImport ,
119- visitor : {
120- Program : {
121- enter ( programPath ) {
122- let loadableImportSpecifier = defaultImportSpecifier
123- let lazyImportSpecifier = false
124-
125- programPath . traverse ( {
126- ImportDefaultSpecifier ( path ) {
127- if ( ! loadableImportSpecifier ) {
128- const { parent } = path
129- const { local } = path . node
130- loadableImportSpecifier = parent . source . value == '@loadable/component' &&
131- local && local . name
132- }
133- } ,
134- ImportSpecifier ( path ) {
135- if ( ! lazyImportSpecifier ) {
136- const { parent } = path
137- const { imported, local } = path . node
138- lazyImportSpecifier = parent . source . value == '@loadable/component' &&
139- imported && imported . name == 'lazy' && local && local . name
140- }
141- } ,
142- CallExpression ( path ) {
143- if ( ! isValidIdentifier ( path , loadableImportSpecifier , lazyImportSpecifier ) ) return
144- transformImport ( path )
145- } ,
146- 'ArrowFunctionExpression|FunctionExpression|ObjectMethod' : path => {
147- if ( ! hasLoadableComment ( path ) ) return
148- transformImport ( path )
149- } ,
150- } )
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+ )
197+ )
198+ return
199+ transformImport ( path )
200+ } ,
201+ 'ArrowFunctionExpression|FunctionExpression|ObjectMethod' : path => {
202+ if ( ! hasLoadableComment ( path ) ) return
203+ transformImport ( path )
204+ } ,
205+ } )
206+ } ,
151207 } ,
152208 } ,
153- } ,
154- }
155- } )
209+ }
210+ } ,
211+ )
156212
157213export default loadablePlugin
0 commit comments