-
Notifications
You must be signed in to change notification settings - Fork 2
/
babel.ts
103 lines (91 loc) · 3.39 KB
/
babel.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// https://babeljs.io/docs/en/babel-types
// https://doc.esdoc.org/github.com/mason-lang/esast/class/src/ast.js~Property.html
// https://astexplorer.net/
import nodePath from 'node:path'
export default ({types: t, /*template*/}, {shortenPath, absPath}: {
shortenPath?: string
absPath?: boolean
} = {}) => {
return ({
visitor: {
ImportDeclaration(path) {
const source = path.node.source.value
if (source !== '@react-loadable/revised') return
const defaultSpecifier = path.get('specifiers').find(specifier => specifier.isImportDefaultSpecifier())
if (!defaultSpecifier) return
const bindingName = defaultSpecifier.node.local.name
const binding = path.scope.getBinding(bindingName)
refPath:
for (const refPath of binding.referencePaths) {
const callExpression = refPath.parentPath
if (!callExpression.isCallExpression()) continue
const args = callExpression.get('arguments')
if (args.length !== 1) throw new Error('react-loadable: must provide exactly 1 argument to loadable()')
const options = args[0]
if (!options.isObjectExpression()) continue
let loader
for (const property of options.get('properties')) {
if (property.type !== 'SpreadProperty') {
const key = property.get('key')
if (key.node.name === 'webpack') continue refPath
else if (key.node.name === 'loader') loader = property
}
}
if (!loader) throw new Error('react-loadable: at least loader or webpack properties must be statically provided to the option that is passed to loadable()')
const loaderValue = loader.get('value')
const dynamicImports = []
const body = loader.isFunction()
? loader.get('body')
: loaderValue.isArrowFunctionExpression() && loaderValue.get('body')
if (!body) throw new Error('react-loadable: loader must be function shorthand expression or arrow function expression')
body.traverse({
Import(path) {
dynamicImports.push(path.parentPath)
}
})
if (!dynamicImports.length) continue
loader.insertAfter(
t.objectProperty(
t.identifier('webpack'),
t.arrowFunctionExpression(
[],
t.arrayExpression(
dynamicImports.map(dynamicImport => t.callExpression(
t.memberExpression(
t.identifier('require'),
t.identifier('resolveWeak'),
),
[dynamicImport.get('arguments')[0].node],
))
)
)
)
)
const dir = nodePath.dirname(this.file.opts.filename)
const rootDir = this.file.opts.root
loader.insertAfter(
t.objectProperty(
t.identifier('modules'),
t.arrayExpression(
dynamicImports.map(dynamicImport => {
const node = dynamicImport.get('arguments')[0].node
if (absPath && node.type === 'StringLiteral') {
const {value} = node
if (typeof value === 'string') {
const resolvedPath = absPath && value.startsWith('./') ? nodePath.resolve(dir, value) : value
const afterShortenPath = typeof shortenPath === 'string' && resolvedPath.startsWith(rootDir)
? `${shortenPath}${resolvedPath.slice(rootDir.length)}`
: resolvedPath
return t.stringLiteral(afterShortenPath)
}
}
return node
})
)
)
)
}
}
}
})
}