mp-weixin-back 0.0.8 → 0.0.10
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/dist/index.cjs +247 -57
- package/dist/index.mjs +247 -57
- package/package.json +2 -2
- package/src/context.ts +6 -5
- package/test/data/index-default.vue +17 -0
- package/test/data/{index.vue → index-setup.vue} +1 -0
- package/test/generate.spec.ts +20 -3
- package/utils/index.ts +15 -156
- package/utils/walker.ts +389 -0
package/utils/index.ts
CHANGED
|
@@ -1,167 +1,26 @@
|
|
|
1
|
-
import generate from '@babel/generator'
|
|
2
1
|
import { parse } from '@vue/compiler-sfc'
|
|
3
|
-
import { babelParse, walkAST } from 'ast-kit'
|
|
4
2
|
import { pageContext } from '../src/context'
|
|
5
|
-
import
|
|
6
|
-
import { virtualFileId } from './constant'
|
|
3
|
+
import { vueWalker } from './walker'
|
|
7
4
|
import type { SFCDescriptor } from '@vue/compiler-sfc'
|
|
8
|
-
import type { Node } from '@babel/types'
|
|
9
|
-
|
|
10
|
-
function isArrowFunction(func: Function) {
|
|
11
|
-
if (typeof func !== 'function') return false
|
|
12
|
-
return !func.hasOwnProperty('prototype') && func.toString().includes('=>')
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
async function parseSFC(code: string): Promise<SFCDescriptor> {
|
|
16
|
-
try {
|
|
17
|
-
return parse(code).descriptor
|
|
18
|
-
} catch (error) {
|
|
19
|
-
throw new Error(`解析vue文件失败,请检查文件是否正确`)
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
5
|
|
|
23
6
|
export async function transformVueFile(this: pageContext, code: string, id: string) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const componentStr =
|
|
30
|
-
' <page-container :show="__MP_BACK_SHOW_PAGE_CONTAINER__" :overlay="false" @beforeleave="onBeforeLeave" :z-index="1" :duration="false"></page-container>\n'
|
|
31
|
-
|
|
32
|
-
let pageBackConfig = { ...this.config }
|
|
33
|
-
let hasPageBack = false
|
|
34
|
-
let hasImportRef = false
|
|
35
|
-
let pageBackFnName = 'onPageBack'
|
|
36
|
-
let callbackCode = ``
|
|
37
|
-
|
|
38
|
-
const codeMs = new MagicString(code)
|
|
39
|
-
const setupCode = sfc.scriptSetup?.loc.source || ''
|
|
40
|
-
const setupAst = babelParse(setupCode, sfc.scriptSetup?.lang)
|
|
41
|
-
|
|
42
|
-
if (setupAst) {
|
|
43
|
-
walkAST<Node>(setupAst, {
|
|
44
|
-
enter(node) {
|
|
45
|
-
if (node.type === 'ImportDeclaration') {
|
|
46
|
-
if (node.source.value.includes(virtualFileId)) {
|
|
47
|
-
const importSpecifier = node.specifiers[0]
|
|
48
|
-
hasPageBack = true
|
|
49
|
-
pageBackFnName = importSpecifier.local.name
|
|
50
|
-
}
|
|
51
|
-
if (node.source.value === 'vue') {
|
|
52
|
-
node.specifiers.some((specifier) => {
|
|
53
|
-
if (specifier.local.name === 'ref') {
|
|
54
|
-
hasImportRef = true
|
|
55
|
-
return true
|
|
56
|
-
}
|
|
57
|
-
return false
|
|
58
|
-
})
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (
|
|
63
|
-
node.type === 'ExpressionStatement' &&
|
|
64
|
-
node.expression.type === 'CallExpression' &&
|
|
65
|
-
node.expression.callee.loc?.identifierName === pageBackFnName
|
|
66
|
-
) {
|
|
67
|
-
const callback = node.expression.arguments[0]
|
|
68
|
-
const backArguments = node.expression.arguments[1]
|
|
69
|
-
|
|
70
|
-
if (backArguments?.type === 'ObjectExpression') {
|
|
71
|
-
const config = new Function(
|
|
72
|
-
// @ts-ignore
|
|
73
|
-
`return (${(generate.default ? generate.default : generate)(backArguments).code});`
|
|
74
|
-
)()
|
|
75
|
-
Object.assign(pageBackConfig, config)
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (
|
|
79
|
-
callback &&
|
|
80
|
-
(callback.type === 'ArrowFunctionExpression' || callback.type === 'FunctionExpression')
|
|
81
|
-
) {
|
|
82
|
-
const body = callback.body
|
|
83
|
-
if (body.type === 'BlockStatement') {
|
|
84
|
-
callbackCode += body.body
|
|
85
|
-
.map(
|
|
86
|
-
// @ts-ignore
|
|
87
|
-
(statement) => (generate.default ? generate.default : generate)(statement).code
|
|
88
|
-
)
|
|
89
|
-
.join('')
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
},
|
|
94
|
-
})
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
if (!hasPageBack) return
|
|
98
|
-
|
|
99
|
-
this.log.devLog(`页面${this.getPageById(id)}注入mp-weixin-back`)
|
|
100
|
-
|
|
101
|
-
if (code.includes('<page-container')) {
|
|
102
|
-
this.log.devLog(`${this.getPageById(id)}页面已有page-container组件,注入失败`)
|
|
103
|
-
return code
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
if (!pageBackConfig.preventDefault) {
|
|
107
|
-
callbackCode += `uni.navigateBack({ delta: 1 });`
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const configBack = (() => {
|
|
111
|
-
const onPageBack = pageBackConfig.onPageBack
|
|
112
|
-
if (!onPageBack) return ''
|
|
113
|
-
if (typeof onPageBack !== 'function') {
|
|
114
|
-
throw new Error('`onPageBack` must be a function')
|
|
7
|
+
try {
|
|
8
|
+
const sfc = parse(code).descriptor
|
|
9
|
+
const { template, script, scriptSetup } = sfc
|
|
10
|
+
if (!template?.content) {
|
|
11
|
+
return code
|
|
115
12
|
}
|
|
116
13
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
if (isArrowFunction(onPageBack) || onPageBack.toString().includes('function')) {
|
|
120
|
-
return `(${onPageBack})(${params});`
|
|
14
|
+
if (!script?.content && !scriptSetup?.content) {
|
|
15
|
+
return code
|
|
121
16
|
}
|
|
122
17
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
const onBeforeLeave = () => {
|
|
131
|
-
console.log("__MP_BACK_FREQUENCY__", __MP_BACK_FREQUENCY__, ${pageBackConfig.frequency})
|
|
132
|
-
if (__MP_BACK_FREQUENCY__ < ${pageBackConfig.frequency}) {
|
|
133
|
-
__MP_BACK_SHOW_PAGE_CONTAINER__.value = false
|
|
134
|
-
setTimeout(() => __MP_BACK_SHOW_PAGE_CONTAINER__.value = true, 0);
|
|
135
|
-
__MP_BACK_FREQUENCY__++
|
|
136
|
-
}
|
|
137
|
-
${configBack}
|
|
138
|
-
${callbackCode}
|
|
139
|
-
};
|
|
140
|
-
`
|
|
141
|
-
|
|
142
|
-
const { template, script, scriptSetup } = sfc
|
|
143
|
-
const tempOffsets = {
|
|
144
|
-
start: template.loc.start.offset,
|
|
145
|
-
end: template.loc.end.offset,
|
|
146
|
-
content: template.content,
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
const templateMagicString = new MagicString(tempOffsets.content)
|
|
150
|
-
templateMagicString.append(componentStr)
|
|
151
|
-
codeMs.overwrite(tempOffsets.start, tempOffsets.end, templateMagicString.toString())
|
|
152
|
-
|
|
153
|
-
const scriptSfc = script || scriptSetup
|
|
154
|
-
if (!scriptSfc) return
|
|
155
|
-
|
|
156
|
-
const scriptOffsets = {
|
|
157
|
-
start: scriptSfc.loc.start.offset,
|
|
158
|
-
end: scriptSfc.loc.end.offset,
|
|
159
|
-
content: scriptSfc.content || '',
|
|
18
|
+
// 判断页面是否为组合式写法
|
|
19
|
+
const walker = scriptSetup ? 'compositionWalk' : 'optionsWalk'
|
|
20
|
+
return vueWalker[walker](this, code, sfc, id)
|
|
21
|
+
} catch (error) {
|
|
22
|
+
this.log.error('解析vue文件失败,请检查文件是否正确')
|
|
23
|
+
this.log.debugLog(String(error))
|
|
24
|
+
return code
|
|
160
25
|
}
|
|
161
|
-
|
|
162
|
-
const scriptMagicString = new MagicString(scriptOffsets.content)
|
|
163
|
-
scriptMagicString.prepend(beforeLeaveStr)
|
|
164
|
-
codeMs.overwrite(scriptOffsets.start, scriptOffsets.end, scriptMagicString.toString())
|
|
165
|
-
|
|
166
|
-
return codeMs.toString()
|
|
167
26
|
}
|
package/utils/walker.ts
ADDED
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
import generate from '@babel/generator'
|
|
2
|
+
import MagicString from 'magic-string'
|
|
3
|
+
import { babelParse, walkAST } from 'ast-kit'
|
|
4
|
+
import { pageContext } from '../src/context'
|
|
5
|
+
import { virtualFileId } from './constant'
|
|
6
|
+
import type {
|
|
7
|
+
BlockStatement,
|
|
8
|
+
FunctionExpression,
|
|
9
|
+
Node,
|
|
10
|
+
ObjectExpression,
|
|
11
|
+
ObjectMethod,
|
|
12
|
+
ObjectProperty,
|
|
13
|
+
} from '@babel/types'
|
|
14
|
+
|
|
15
|
+
const pageContainerComp =
|
|
16
|
+
' <page-container :show="__MP_BACK_SHOW_PAGE_CONTAINER__" :overlay="false" @beforeleave="onBeforeLeave" :z-index="1" :duration="false"></page-container>\n'
|
|
17
|
+
|
|
18
|
+
function isArrowFunction(func: Function) {
|
|
19
|
+
if (typeof func !== 'function') return false
|
|
20
|
+
return !func.hasOwnProperty('prototype') && func.toString().includes('=>')
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function compositionWalk(context: pageContext, code: string, sfc: any, id: string) {
|
|
24
|
+
const codeMs = new MagicString(code)
|
|
25
|
+
const setupAst = babelParse(sfc.scriptSetup!.loc.source, sfc.scriptSetup!.lang)
|
|
26
|
+
|
|
27
|
+
let pageInfo = {
|
|
28
|
+
hasPageBack: false,
|
|
29
|
+
pageBackFnName: 'onPageBack',
|
|
30
|
+
hasImportRef: false,
|
|
31
|
+
backConfig: { ...context.config },
|
|
32
|
+
callbackCode: '',
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (setupAst) {
|
|
36
|
+
walkAST<Node>(setupAst, {
|
|
37
|
+
enter(node) {
|
|
38
|
+
if (node.type === 'ImportDeclaration') {
|
|
39
|
+
if (node.source.value.includes(virtualFileId)) {
|
|
40
|
+
const importSpecifier = node.specifiers[0]
|
|
41
|
+
pageInfo.hasPageBack = true
|
|
42
|
+
pageInfo.pageBackFnName = importSpecifier.local.name
|
|
43
|
+
}
|
|
44
|
+
if (node.source.value === 'vue') {
|
|
45
|
+
node.specifiers.some((specifier) => {
|
|
46
|
+
if (specifier.local.name === 'ref') {
|
|
47
|
+
pageInfo.hasImportRef = true
|
|
48
|
+
return true
|
|
49
|
+
}
|
|
50
|
+
return false
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (
|
|
56
|
+
node.type === 'ExpressionStatement' &&
|
|
57
|
+
node.expression.type === 'CallExpression' &&
|
|
58
|
+
node.expression.callee.loc?.identifierName === pageInfo.pageBackFnName
|
|
59
|
+
) {
|
|
60
|
+
const callback = node.expression.arguments[0]
|
|
61
|
+
const backArguments = node.expression.arguments[1]
|
|
62
|
+
|
|
63
|
+
if (backArguments?.type === 'ObjectExpression') {
|
|
64
|
+
const config = new Function(
|
|
65
|
+
// @ts-ignore
|
|
66
|
+
`return (${(generate.default ? generate.default : generate)(backArguments).code});`
|
|
67
|
+
)()
|
|
68
|
+
Object.assign(pageInfo.backConfig, config)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (
|
|
72
|
+
callback &&
|
|
73
|
+
(callback.type === 'ArrowFunctionExpression' || callback.type === 'FunctionExpression')
|
|
74
|
+
) {
|
|
75
|
+
const body = callback.body
|
|
76
|
+
if (body.type === 'BlockStatement') {
|
|
77
|
+
pageInfo.callbackCode += body.body
|
|
78
|
+
.map(
|
|
79
|
+
// @ts-ignore
|
|
80
|
+
(statement) => (generate.default ? generate.default : generate)(statement).code
|
|
81
|
+
)
|
|
82
|
+
.join('')
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
})
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// 没有引入mp-weixin-back-helper
|
|
91
|
+
if (!pageInfo.hasPageBack) return code
|
|
92
|
+
|
|
93
|
+
if (code.includes('<page-container')) {
|
|
94
|
+
context.log.debugLog(`${context.getPageById(id)}页面已有page-container组件,注入失败`)
|
|
95
|
+
return code
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (!pageInfo.backConfig.preventDefault) {
|
|
99
|
+
pageInfo.callbackCode += 'uni.navigateBack({ delta: 1 });'
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const importRefFromVue = !pageInfo.hasImportRef ? `import { ref } from 'vue'` : ''
|
|
103
|
+
const stateFrequency = 'let __MP_BACK_FREQUENCY__ = 1;'
|
|
104
|
+
const statePageContainerVar = 'const __MP_BACK_SHOW_PAGE_CONTAINER__ = ref(true);'
|
|
105
|
+
// 获取传入插件的统一方法
|
|
106
|
+
const configBack = (() => {
|
|
107
|
+
const onPageBack = pageInfo.backConfig.onPageBack
|
|
108
|
+
if (!onPageBack) return ''
|
|
109
|
+
if (typeof onPageBack !== 'function') {
|
|
110
|
+
throw new Error('`onPageBack` must be a function')
|
|
111
|
+
}
|
|
112
|
+
const params = JSON.stringify({ page: context.getPageById(id) })
|
|
113
|
+
if (isArrowFunction(onPageBack) || onPageBack.toString().includes('function')) {
|
|
114
|
+
return `(${onPageBack})(${params});`
|
|
115
|
+
}
|
|
116
|
+
return `(function ${onPageBack})()`
|
|
117
|
+
})()
|
|
118
|
+
const stateBeforeLeave = `
|
|
119
|
+
const onBeforeLeave = () => {
|
|
120
|
+
if (__MP_BACK_FREQUENCY__ < ${pageInfo.backConfig.frequency}) {
|
|
121
|
+
__MP_BACK_SHOW_PAGE_CONTAINER__.value = false
|
|
122
|
+
setTimeout(() => __MP_BACK_SHOW_PAGE_CONTAINER__.value = true, 0);
|
|
123
|
+
__MP_BACK_FREQUENCY__++
|
|
124
|
+
}
|
|
125
|
+
${configBack}
|
|
126
|
+
${pageInfo.callbackCode}
|
|
127
|
+
};
|
|
128
|
+
`
|
|
129
|
+
const { template, scriptSetup } = sfc
|
|
130
|
+
|
|
131
|
+
// template标签中插入page-container组件
|
|
132
|
+
const tempOffsets = {
|
|
133
|
+
start: template.loc.start.offset,
|
|
134
|
+
end: template.loc.end.offset,
|
|
135
|
+
content: template.content,
|
|
136
|
+
}
|
|
137
|
+
const templateMagicString = new MagicString(tempOffsets.content)
|
|
138
|
+
templateMagicString.append(pageContainerComp)
|
|
139
|
+
codeMs.overwrite(tempOffsets.start, tempOffsets.end, templateMagicString.toString())
|
|
140
|
+
|
|
141
|
+
// script标签中插入声明的变量和方法
|
|
142
|
+
const scriptOffsets = {
|
|
143
|
+
start: scriptSetup.loc.start.offset,
|
|
144
|
+
end: scriptSetup.loc.end.offset,
|
|
145
|
+
content: scriptSetup.content || '',
|
|
146
|
+
}
|
|
147
|
+
const scriptMagicString = new MagicString(scriptOffsets.content)
|
|
148
|
+
scriptMagicString.prepend(
|
|
149
|
+
` ${importRefFromVue}
|
|
150
|
+
${stateFrequency}
|
|
151
|
+
${statePageContainerVar}
|
|
152
|
+
${stateBeforeLeave} `
|
|
153
|
+
)
|
|
154
|
+
codeMs.overwrite(scriptOffsets.start, scriptOffsets.end, scriptMagicString.toString())
|
|
155
|
+
|
|
156
|
+
return codeMs.toString()
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function optionsWalk(context: pageContext, code: string, sfc: any, id: string) {
|
|
160
|
+
const codeMs = new MagicString(code)
|
|
161
|
+
const ast = babelParse(sfc.script.loc.source, sfc.script.lang)
|
|
162
|
+
|
|
163
|
+
let pageInfo = {
|
|
164
|
+
hasPageBack: false,
|
|
165
|
+
pageBackFnName: 'onPageBack',
|
|
166
|
+
backConfig: { ...context.config },
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
let exportDefaultNode: ObjectExpression | null = null
|
|
170
|
+
let dataMethodNode: BlockStatement | null = null
|
|
171
|
+
let methodsNode: ObjectExpression | null = null
|
|
172
|
+
let onPageBackNodeMethod: ObjectMethod | null = null
|
|
173
|
+
let onPageBackNodeProperty: ObjectProperty | null = null
|
|
174
|
+
|
|
175
|
+
if (ast) {
|
|
176
|
+
walkAST<Node>(ast, {
|
|
177
|
+
enter(node) {
|
|
178
|
+
// todo需要判断使用默认选项式还是使用了setup
|
|
179
|
+
if (
|
|
180
|
+
node.type === 'ExportDefaultDeclaration' &&
|
|
181
|
+
node.declaration.type === 'ObjectExpression'
|
|
182
|
+
) {
|
|
183
|
+
exportDefaultNode = node.declaration
|
|
184
|
+
const properties = node.declaration.properties
|
|
185
|
+
|
|
186
|
+
for (let i = 0; i < properties.length; i++) {
|
|
187
|
+
const element = properties[i]
|
|
188
|
+
// export default 的 data()
|
|
189
|
+
if (
|
|
190
|
+
element.type === 'ObjectMethod' &&
|
|
191
|
+
element.key.type === 'Identifier' &&
|
|
192
|
+
element.key.name === 'data' &&
|
|
193
|
+
element.body.type === 'BlockStatement'
|
|
194
|
+
) {
|
|
195
|
+
dataMethodNode = element.body
|
|
196
|
+
}
|
|
197
|
+
// export default 的 methods
|
|
198
|
+
if (
|
|
199
|
+
element.type === 'ObjectProperty' &&
|
|
200
|
+
element.key.type === 'Identifier' &&
|
|
201
|
+
element.key.name === 'methods'
|
|
202
|
+
) {
|
|
203
|
+
methodsNode = element.value as ObjectExpression
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// 获取export default 的 onPackBack
|
|
207
|
+
const blockStatementCondition =
|
|
208
|
+
element.type === 'ObjectMethod' &&
|
|
209
|
+
element.key.type === 'Identifier' &&
|
|
210
|
+
element.key.name === pageInfo.pageBackFnName &&
|
|
211
|
+
element.body.type === 'BlockStatement'
|
|
212
|
+
|
|
213
|
+
const functionExpressionCondition =
|
|
214
|
+
element.type === 'ObjectProperty' &&
|
|
215
|
+
element.key.type === 'Identifier' &&
|
|
216
|
+
element.key.name === pageInfo.pageBackFnName &&
|
|
217
|
+
element.value.type === 'FunctionExpression'
|
|
218
|
+
|
|
219
|
+
if (blockStatementCondition) {
|
|
220
|
+
pageInfo.hasPageBack = true
|
|
221
|
+
onPageBackNodeMethod = element
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (functionExpressionCondition) {
|
|
225
|
+
pageInfo.hasPageBack = true
|
|
226
|
+
onPageBackNodeProperty = element
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
},
|
|
231
|
+
})
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (!pageInfo.hasPageBack) return
|
|
235
|
+
|
|
236
|
+
const newDataProperty = [
|
|
237
|
+
{
|
|
238
|
+
type: 'ObjectProperty',
|
|
239
|
+
key: { type: 'Identifier', name: '__MP_BACK_SHOW_PAGE_CONTAINER__' },
|
|
240
|
+
value: { type: 'BooleanLiteral', value: true },
|
|
241
|
+
computed: false,
|
|
242
|
+
shorthand: false,
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
type: 'ObjectProperty',
|
|
246
|
+
key: { type: 'Identifier', name: '__MP_BACK_FREQUENCY__' },
|
|
247
|
+
value: { type: 'NumericLiteral', value: 1 },
|
|
248
|
+
computed: false,
|
|
249
|
+
shorthand: false,
|
|
250
|
+
},
|
|
251
|
+
] as ObjectProperty[]
|
|
252
|
+
if (dataMethodNode) {
|
|
253
|
+
const returnStatement = (dataMethodNode as BlockStatement).body.find(
|
|
254
|
+
(node) => node.type === 'ReturnStatement'
|
|
255
|
+
)
|
|
256
|
+
if (
|
|
257
|
+
returnStatement &&
|
|
258
|
+
returnStatement.argument &&
|
|
259
|
+
returnStatement.argument.type === 'ObjectExpression'
|
|
260
|
+
) {
|
|
261
|
+
// 添加新的属性
|
|
262
|
+
returnStatement.argument.properties.push(...newDataProperty)
|
|
263
|
+
}
|
|
264
|
+
} else if (exportDefaultNode) {
|
|
265
|
+
const addData: ObjectMethod = {
|
|
266
|
+
type: 'ObjectMethod',
|
|
267
|
+
key: { type: 'Identifier', name: 'data' },
|
|
268
|
+
kind: 'method',
|
|
269
|
+
params: [],
|
|
270
|
+
async: false,
|
|
271
|
+
generator: false,
|
|
272
|
+
computed: false,
|
|
273
|
+
body: {
|
|
274
|
+
type: 'BlockStatement',
|
|
275
|
+
directives: [],
|
|
276
|
+
body: [
|
|
277
|
+
{
|
|
278
|
+
type: 'ReturnStatement',
|
|
279
|
+
argument: {
|
|
280
|
+
type: 'ObjectExpression',
|
|
281
|
+
properties: newDataProperty,
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
],
|
|
285
|
+
},
|
|
286
|
+
}
|
|
287
|
+
; (exportDefaultNode as ObjectExpression).properties.push(addData)
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// 获取传入插件的统一方法
|
|
291
|
+
const configBack = (() => {
|
|
292
|
+
const onPageBack = pageInfo.backConfig.onPageBack
|
|
293
|
+
if (!onPageBack) return ''
|
|
294
|
+
if (typeof onPageBack !== 'function') {
|
|
295
|
+
throw new Error('`onPageBack` must be a function')
|
|
296
|
+
}
|
|
297
|
+
const params = JSON.stringify({ page: context.getPageById(id) })
|
|
298
|
+
if (isArrowFunction(onPageBack) || onPageBack.toString().includes('function')) {
|
|
299
|
+
return `(${onPageBack})(${params});`
|
|
300
|
+
}
|
|
301
|
+
return `(function ${onPageBack})()`
|
|
302
|
+
})()
|
|
303
|
+
|
|
304
|
+
const stateBeforeLeave = `
|
|
305
|
+
function onBeforeLeave() {
|
|
306
|
+
if (this.__MP_BACK_FREQUENCY__ < ${pageInfo.backConfig.frequency}) {
|
|
307
|
+
this.__MP_BACK_SHOW_PAGE_CONTAINER__ = false
|
|
308
|
+
setTimeout(() => { this.__MP_BACK_SHOW_PAGE_CONTAINER__ = true }, 0);
|
|
309
|
+
this.__MP_BACK_FREQUENCY__++
|
|
310
|
+
}
|
|
311
|
+
${configBack}
|
|
312
|
+
${!pageInfo.backConfig.preventDefault ? 'uni.navigateBack({ delta: 1 });' : ''}
|
|
313
|
+
};
|
|
314
|
+
`
|
|
315
|
+
const stateBeforeLeaveAst = babelParse(stateBeforeLeave)
|
|
316
|
+
const stateBeforeLeaveNode = stateBeforeLeaveAst.body.find(
|
|
317
|
+
(node) => node.type === 'FunctionDeclaration'
|
|
318
|
+
)
|
|
319
|
+
const newMethodsProperty = {
|
|
320
|
+
type: 'ObjectMethod',
|
|
321
|
+
key: {
|
|
322
|
+
type: 'Identifier',
|
|
323
|
+
name: 'onBeforeLeave',
|
|
324
|
+
},
|
|
325
|
+
kind: 'method',
|
|
326
|
+
generator: false,
|
|
327
|
+
async: false,
|
|
328
|
+
params: [],
|
|
329
|
+
computed: false,
|
|
330
|
+
body: {
|
|
331
|
+
type: 'BlockStatement',
|
|
332
|
+
directives: [],
|
|
333
|
+
body: [
|
|
334
|
+
...(onPageBackNodeMethod ? (onPageBackNodeMethod as ObjectMethod)!.body.body : []),
|
|
335
|
+
...(onPageBackNodeProperty
|
|
336
|
+
? ((onPageBackNodeProperty as ObjectProperty)!.value as FunctionExpression).body.body
|
|
337
|
+
: []),
|
|
338
|
+
...stateBeforeLeaveNode!.body.body,
|
|
339
|
+
],
|
|
340
|
+
},
|
|
341
|
+
} as ObjectMethod
|
|
342
|
+
if (methodsNode) {
|
|
343
|
+
; (methodsNode as ObjectExpression).properties.push(newMethodsProperty)
|
|
344
|
+
} else if (exportDefaultNode) {
|
|
345
|
+
const addMethods: ObjectProperty = {
|
|
346
|
+
type: 'ObjectProperty',
|
|
347
|
+
computed: false,
|
|
348
|
+
shorthand: false,
|
|
349
|
+
key: {
|
|
350
|
+
type: 'Identifier',
|
|
351
|
+
name: 'methods',
|
|
352
|
+
},
|
|
353
|
+
value: {
|
|
354
|
+
type: 'ObjectExpression',
|
|
355
|
+
properties: [newMethodsProperty],
|
|
356
|
+
},
|
|
357
|
+
}
|
|
358
|
+
; (exportDefaultNode as ObjectExpression).properties.push(addMethods)
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
const { template, script } = sfc
|
|
362
|
+
|
|
363
|
+
// template标签中插入page-container组件
|
|
364
|
+
const tempOffsets = {
|
|
365
|
+
start: template.loc.start.offset,
|
|
366
|
+
end: template.loc.end.offset,
|
|
367
|
+
content: template.content,
|
|
368
|
+
}
|
|
369
|
+
const templateMagicString = new MagicString(tempOffsets.content)
|
|
370
|
+
templateMagicString.append(pageContainerComp)
|
|
371
|
+
codeMs.overwrite(tempOffsets.start, tempOffsets.end, templateMagicString.toString())
|
|
372
|
+
|
|
373
|
+
// script标签中插入声明的变量和方法
|
|
374
|
+
const scriptOffsets = {
|
|
375
|
+
start: script.loc.start.offset,
|
|
376
|
+
end: script.loc.end.offset,
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// @ts-ignore
|
|
380
|
+
const newScriptContent = (generate.default ? generate.default : generate)(ast).code
|
|
381
|
+
codeMs.overwrite(scriptOffsets.start, scriptOffsets.end, newScriptContent)
|
|
382
|
+
|
|
383
|
+
return codeMs.toString()
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
export const vueWalker = {
|
|
387
|
+
compositionWalk,
|
|
388
|
+
optionsWalk,
|
|
389
|
+
}
|