in packages/babel-plugin-transform-loadable-component/src/index.js [68:184]
JSXElement(p) {
let hasReferencedComponentProp = false
let hasAsyncProp = false
let hasLoadingProp = false
let loadable = false
const removeImports = []
const COMPONENT = Symbol('__COMPONENT__')
const ASYNC = Symbol('__ASYNC__')
const LOADING = Symbol('__LOADING__')
const attrs = p.get('openingElement').get('attributes')
attrs.forEach((attrPath) => {
// 如果不是一般的 attr (譬如 JSXSpreadAttribute), 则直接跳过检查
if (!attrPath.isJSXAttribute()) {
return
}
const { name, value, type } = getJSXAttr(attrPath)
// 检查是否匹配 props.component: ReferencedIdentifier
if (
name === 'component' &&
type === 'expression' &&
value.isReferencedIdentifier() &&
this.defaultImportsMap.has(value.node.name)
) {
hasReferencedComponentProp = true
// eslint-disable-next-line no-param-reassign
attrPath[COMPONENT] = true
}
// 检查是否匹配 props.__async: true
if (name === '__async') {
hasAsyncProp = true
// eslint-disable-next-line no-param-reassign
attrPath[ASYNC] = true
if (value === true) {
loadable = true
} else if (type === 'expression' && value.isBooleanLiteral()) {
loadable = value.node.value
}
}
if (name === '__loading' && type === 'expression') {
hasLoadingProp = true
// eslint-disable-next-line no-param-reassign
attrPath[LOADING] = true
}
})
if (hasReferencedComponentProp || hasAsyncProp || hasLoadingProp) {
let newAttrs = attrs
const existingReactLoadableIdentifier = this.reactLoadableImport.get(
'identifier'
)
const loadingAttrPath = newAttrs.filter(
attrPath => attrPath[LOADING]
)[0]
if (loadable && hasReferencedComponentProp) {
newAttrs = newAttrs.map((attrPath) => {
if (!attrPath[COMPONENT]) {
return attrPath
}
const { value: originComponentValue } = getJSXAttr(attrPath)
const {
source,
path: importDeclarationPath,
} = this.defaultImportsMap.get(
originComponentValue.node.name
)
this.matchedJSXSet.add(p)
removeImports.push(importDeclarationPath)
return {
node: types.JSXAttribute(
types.JSXIdentifier('component'),
types.JSXExpressionContainer(
createCalleeCallExpression(
// eslint-disable-next-line max-len
existingReactLoadableIdentifier || defaultReactLoadableSpecifier,
[
createObjectExpression({
loader: types.arrowFunctionExpression(
[],
createCalleeCallExpression('import', [
types.stringLiteral(source),
])
),
loading: loadingAttrPath ?
loadingAttrPath.get('value').get('expression').node :
undefined,
}),
]
)
)
),
}
})
}
// eslint-disable-next-line no-param-reassign
p.node.openingElement.attributes = newAttrs
.filter(attrPath => (!attrPath[ASYNC] && !attrPath[LOADING]))
.map(attrPath => attrPath.node)
}
removeImports.forEach((importPath) => {
importPath && importPath.remove()
})
},