@startupjs/babel-plugin-startupjs 0.61.0 → 0.61.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +136 -37
- package/package.json +2 -2
package/index.js
CHANGED
|
@@ -1,59 +1,158 @@
|
|
|
1
1
|
const { readFileSync } = require('fs')
|
|
2
2
|
const { join } = require('path')
|
|
3
3
|
|
|
4
|
-
const MAGIC_MODULE_NAME = '
|
|
4
|
+
const MAGIC_MODULE_NAME = 'startupjs-ui'
|
|
5
5
|
|
|
6
|
-
module.exports = function ({ template, types: t }) {
|
|
6
|
+
module.exports = function ({ template, types: t }, { asyncImports = false } = {}) {
|
|
7
7
|
const buildImport = template('import %%name%% from %%source%%')
|
|
8
8
|
const buildExport = template('export { default as %%name%% } from %%source%%')
|
|
9
|
+
// when asyncImports is enabled, we replace imports with dynamic imports:
|
|
10
|
+
// import { Button, Card } from 'startupjs-ui'
|
|
11
|
+
// -->
|
|
12
|
+
// const [Button, Card] = await Promise.all([
|
|
13
|
+
// import('startupjs-ui/Button').then(m => m.default),
|
|
14
|
+
// import('startupjs-ui/Card').then(m => m.default)
|
|
15
|
+
// ])
|
|
16
|
+
// Note that this currently does not work in Expo because React Native
|
|
17
|
+
// does not support top-level await yet.
|
|
18
|
+
const buildAsyncImport = source => {
|
|
19
|
+
const importCall = t.callExpression(t.import(), [t.stringLiteral(source)])
|
|
20
|
+
return t.callExpression(
|
|
21
|
+
t.memberExpression(importCall, t.identifier('then')),
|
|
22
|
+
[t.arrowFunctionExpression(
|
|
23
|
+
[t.identifier('m')],
|
|
24
|
+
t.memberExpression(t.identifier('m'), t.identifier('default'))
|
|
25
|
+
)]
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
const buildPromiseAll = (names, imports) => t.variableDeclaration('const', [
|
|
29
|
+
t.variableDeclarator(
|
|
30
|
+
t.arrayPattern(names),
|
|
31
|
+
t.awaitExpression(
|
|
32
|
+
t.callExpression(
|
|
33
|
+
t.memberExpression(t.identifier('Promise'), t.identifier('all')),
|
|
34
|
+
[t.arrayExpression(imports)]
|
|
35
|
+
)
|
|
36
|
+
)
|
|
37
|
+
)
|
|
38
|
+
])
|
|
9
39
|
|
|
10
40
|
return {
|
|
11
41
|
name: 'Unwrap imports for tree shaking.',
|
|
12
42
|
visitor: {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
43
|
+
Program ($this) {
|
|
44
|
+
let executed = false
|
|
45
|
+
const asyncImportNames = []
|
|
46
|
+
const asyncImportExpressions = []
|
|
47
|
+
const asyncExportSpecifiers = []
|
|
48
|
+
$this.traverse({
|
|
49
|
+
ImportDeclaration ($path) {
|
|
50
|
+
if ($path.get('source').node.value !== MAGIC_MODULE_NAME) return
|
|
51
|
+
let transformed = false // needed to prevent infinite loops
|
|
52
|
+
const theImports = []
|
|
53
|
+
$path.get('specifiers').forEach($specifier => {
|
|
54
|
+
// pluck out into a separate import
|
|
55
|
+
if ($specifier.isImportSpecifier()) {
|
|
56
|
+
transformed = true
|
|
57
|
+
const originalName = $specifier.get('imported').node.name
|
|
58
|
+
if (!checkNamedExportExists(originalName)) {
|
|
59
|
+
throw $specifier.buildCodeFrameError(
|
|
60
|
+
`Named export "${originalName}" does not exist in "${MAGIC_MODULE_NAME}" "exports" field in package.json`
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
const importedName = $specifier.get('local').node.name
|
|
64
|
+
if (asyncImports) {
|
|
65
|
+
asyncImportNames.push(t.identifier(importedName))
|
|
66
|
+
asyncImportExpressions.push(buildAsyncImport(`${MAGIC_MODULE_NAME}/${originalName}`))
|
|
67
|
+
} else {
|
|
68
|
+
theImports.push(buildImport({
|
|
69
|
+
name: importedName,
|
|
70
|
+
source: `${MAGIC_MODULE_NAME}/${originalName}`
|
|
71
|
+
}))
|
|
72
|
+
}
|
|
73
|
+
return
|
|
74
|
+
}
|
|
75
|
+
// pass as is
|
|
76
|
+
theImports.push(t.importDeclaration([$specifier.node], t.stringLiteral(MAGIC_MODULE_NAME)))
|
|
77
|
+
})
|
|
78
|
+
if (!transformed) return
|
|
79
|
+
if (asyncImports) {
|
|
80
|
+
if (theImports.length > 0) {
|
|
81
|
+
$path.replaceWithMultiple(theImports)
|
|
82
|
+
} else {
|
|
83
|
+
$path.remove()
|
|
84
|
+
}
|
|
85
|
+
} else {
|
|
86
|
+
$path.replaceWithMultiple(theImports)
|
|
87
|
+
}
|
|
88
|
+
executed = true
|
|
89
|
+
},
|
|
90
|
+
ExportNamedDeclaration ($path) {
|
|
91
|
+
if ($path.get('source')?.node?.value !== MAGIC_MODULE_NAME) return
|
|
92
|
+
const specifiers = $path.get('specifiers')
|
|
93
|
+
if (asyncImports) {
|
|
94
|
+
specifiers.forEach($specifier => {
|
|
95
|
+
const originalName = $specifier.get('local').node.name
|
|
96
|
+
if (!checkNamedExportExists(originalName)) {
|
|
97
|
+
throw $specifier.buildCodeFrameError(
|
|
98
|
+
`Named export "${originalName}" does not exist in "${MAGIC_MODULE_NAME}" "exports" field in package.json`
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
const exportedName = $specifier.get('exported').node.name
|
|
102
|
+
const localId = t.identifier(exportedName)
|
|
103
|
+
asyncImportNames.push(localId)
|
|
104
|
+
asyncImportExpressions.push(buildAsyncImport(`${MAGIC_MODULE_NAME}/${originalName}`))
|
|
105
|
+
asyncExportSpecifiers.push(t.exportSpecifier(localId, t.identifier(exportedName)))
|
|
106
|
+
})
|
|
107
|
+
if (specifiers.length > 0) {
|
|
108
|
+
$path.remove()
|
|
109
|
+
executed = true
|
|
110
|
+
}
|
|
111
|
+
return
|
|
112
|
+
}
|
|
113
|
+
const theExports = specifiers.map($specifier => {
|
|
114
|
+
const originalName = $specifier.get('local').node.name
|
|
22
115
|
if (!checkNamedExportExists(originalName)) {
|
|
23
116
|
throw $specifier.buildCodeFrameError(
|
|
24
117
|
`Named export "${originalName}" does not exist in "${MAGIC_MODULE_NAME}" "exports" field in package.json`
|
|
25
118
|
)
|
|
26
119
|
}
|
|
27
|
-
const
|
|
28
|
-
return
|
|
29
|
-
name:
|
|
120
|
+
const exportedName = $specifier.get('exported').node.name
|
|
121
|
+
return buildExport({
|
|
122
|
+
name: exportedName,
|
|
30
123
|
source: `${MAGIC_MODULE_NAME}/${originalName}`
|
|
31
124
|
})
|
|
32
|
-
}
|
|
33
|
-
// pass as is
|
|
34
|
-
return t.importDeclaration([$specifier.node], t.stringLiteral(MAGIC_MODULE_NAME))
|
|
35
|
-
})
|
|
36
|
-
if (!transformed) return
|
|
37
|
-
$this.replaceWithMultiple(theImports)
|
|
38
|
-
},
|
|
39
|
-
ExportNamedDeclaration ($this) {
|
|
40
|
-
if ($this.get('source').node.value !== MAGIC_MODULE_NAME) return
|
|
41
|
-
const theExports = $this.get('specifiers')
|
|
42
|
-
.map($specifier => {
|
|
43
|
-
const originalName = $specifier.get('local').node.name
|
|
44
|
-
if (!checkNamedExportExists(originalName)) {
|
|
45
|
-
throw $specifier.buildCodeFrameError(
|
|
46
|
-
`Named export "${originalName}" does not exist in "${MAGIC_MODULE_NAME}" "exports" field in package.json`
|
|
47
|
-
)
|
|
48
|
-
}
|
|
49
|
-
const exportedName = $specifier.get('exported').node.name
|
|
50
|
-
return buildExport({
|
|
51
|
-
name: exportedName,
|
|
52
|
-
source: `${MAGIC_MODULE_NAME}/${originalName}`
|
|
53
125
|
})
|
|
126
|
+
$path.replaceWithMultiple(theExports)
|
|
127
|
+
executed = true
|
|
128
|
+
}
|
|
129
|
+
})
|
|
130
|
+
if (asyncImports && asyncImportNames.length > 0) {
|
|
131
|
+
const promiseAll = buildPromiseAll(asyncImportNames, asyncImportExpressions)
|
|
132
|
+
const bodyPaths = $this.get('body')
|
|
133
|
+
let lastImportPath
|
|
134
|
+
bodyPaths.forEach($path => {
|
|
135
|
+
if ($path.isImportDeclaration()) lastImportPath = $path
|
|
54
136
|
})
|
|
55
|
-
|
|
56
|
-
|
|
137
|
+
let promiseAllPath
|
|
138
|
+
if (lastImportPath) {
|
|
139
|
+
promiseAllPath = lastImportPath.insertAfter(promiseAll)[0]
|
|
140
|
+
} else {
|
|
141
|
+
$this.unshiftContainer('body', promiseAll)
|
|
142
|
+
promiseAllPath = $this.get('body.0')
|
|
143
|
+
}
|
|
144
|
+
if (asyncExportSpecifiers.length > 0) {
|
|
145
|
+
const exportDeclaration = t.exportNamedDeclaration(null, asyncExportSpecifiers)
|
|
146
|
+
if (promiseAllPath) {
|
|
147
|
+
promiseAllPath.insertAfter(exportDeclaration)
|
|
148
|
+
} else {
|
|
149
|
+
$this.pushContainer('body', exportDeclaration)
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
executed = true
|
|
153
|
+
}
|
|
154
|
+
// re-crawl to update scope bindings
|
|
155
|
+
if (executed) $this.scope.crawl()
|
|
57
156
|
}
|
|
58
157
|
}
|
|
59
158
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@startupjs/babel-plugin-startupjs",
|
|
3
|
-
"version": "0.61.
|
|
3
|
+
"version": "0.61.3",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -31,5 +31,5 @@
|
|
|
31
31
|
"babel-plugin-tester": "^9.1.0",
|
|
32
32
|
"jest": "^29.2.1"
|
|
33
33
|
},
|
|
34
|
-
"gitHead": "
|
|
34
|
+
"gitHead": "4d14704ebbbcddd4de51dc8b1f5432f1f855b544"
|
|
35
35
|
}
|