mp-weixin-back 0.0.8 → 0.0.9

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 CHANGED
@@ -4,8 +4,8 @@ const path = require('path');
4
4
  const fs = require('fs');
5
5
  const JSON5 = require('json5');
6
6
  const kolorist = require('kolorist');
7
- const generate = require('@babel/generator');
8
7
  const compilerSfc = require('@vue/compiler-sfc');
8
+ const generate = require('@babel/generator');
9
9
  const astKit = require('ast-kit');
10
10
  const MagicString = require('magic-string');
11
11
 
@@ -19,52 +19,42 @@ const MagicString__default = /*#__PURE__*/_interopDefaultCompat(MagicString);
19
19
 
20
20
  const virtualFileId = "mp-weixin-back-helper";
21
21
 
22
+ const pageContainerComp = ' <page-container :show="__MP_BACK_SHOW_PAGE_CONTAINER__" :overlay="false" @beforeleave="onBeforeLeave" :z-index="1" :duration="false"></page-container>\n';
22
23
  function isArrowFunction(func) {
23
24
  if (typeof func !== "function")
24
25
  return false;
25
26
  return !func.hasOwnProperty("prototype") && func.toString().includes("=>");
26
27
  }
27
- async function parseSFC(code) {
28
- try {
29
- return compilerSfc.parse(code).descriptor;
30
- } catch (error) {
31
- throw new Error(`\u89E3\u6790vue\u6587\u4EF6\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u6587\u4EF6\u662F\u5426\u6B63\u786E`);
32
- }
33
- }
34
- async function transformVueFile(code, id) {
35
- const sfc = await parseSFC(code);
36
- if (!sfc.template?.content) {
37
- return code;
38
- }
39
- const componentStr = ' <page-container :show="__MP_BACK_SHOW_PAGE_CONTAINER__" :overlay="false" @beforeleave="onBeforeLeave" :z-index="1" :duration="false"></page-container>\n';
40
- let pageBackConfig = { ...this.config };
41
- let hasPageBack = false;
42
- let hasImportRef = false;
43
- let pageBackFnName = "onPageBack";
44
- let callbackCode = ``;
28
+ function compositionWalk(context, code, sfc, id) {
45
29
  const codeMs = new MagicString__default(code);
46
- const setupCode = sfc.scriptSetup?.loc.source || "";
47
- const setupAst = astKit.babelParse(setupCode, sfc.scriptSetup?.lang);
30
+ const setupAst = astKit.babelParse(sfc.scriptSetup.loc.source, sfc.scriptSetup.lang);
31
+ let pageInfo = {
32
+ hasPageBack: false,
33
+ pageBackFnName: "onPageBack",
34
+ hasImportRef: false,
35
+ backConfig: { ...context.config },
36
+ callbackCode: ""
37
+ };
48
38
  if (setupAst) {
49
39
  astKit.walkAST(setupAst, {
50
40
  enter(node) {
51
41
  if (node.type === "ImportDeclaration") {
52
42
  if (node.source.value.includes(virtualFileId)) {
53
43
  const importSpecifier = node.specifiers[0];
54
- hasPageBack = true;
55
- pageBackFnName = importSpecifier.local.name;
44
+ pageInfo.hasPageBack = true;
45
+ pageInfo.pageBackFnName = importSpecifier.local.name;
56
46
  }
57
47
  if (node.source.value === "vue") {
58
48
  node.specifiers.some((specifier) => {
59
49
  if (specifier.local.name === "ref") {
60
- hasImportRef = true;
50
+ pageInfo.hasImportRef = true;
61
51
  return true;
62
52
  }
63
53
  return false;
64
54
  });
65
55
  }
66
56
  }
67
- if (node.type === "ExpressionStatement" && node.expression.type === "CallExpression" && node.expression.callee.loc?.identifierName === pageBackFnName) {
57
+ if (node.type === "ExpressionStatement" && node.expression.type === "CallExpression" && node.expression.callee.loc?.identifierName === pageInfo.pageBackFnName) {
68
58
  const callback = node.expression.arguments[0];
69
59
  const backArguments = node.expression.arguments[1];
70
60
  if (backArguments?.type === "ObjectExpression") {
@@ -72,12 +62,12 @@ async function transformVueFile(code, id) {
72
62
  // @ts-ignore
73
63
  `return (${(generate__default.default ? generate__default.default : generate__default)(backArguments).code});`
74
64
  )();
75
- Object.assign(pageBackConfig, config);
65
+ Object.assign(pageInfo.backConfig, config);
76
66
  }
77
67
  if (callback && (callback.type === "ArrowFunctionExpression" || callback.type === "FunctionExpression")) {
78
68
  const body = callback.body;
79
69
  if (body.type === "BlockStatement") {
80
- callbackCode += body.body.map(
70
+ pageInfo.callbackCode += body.body.map(
81
71
  // @ts-ignore
82
72
  (statement) => (generate__default.default ? generate__default.default : generate__default)(statement).code
83
73
  ).join("");
@@ -87,66 +77,267 @@ async function transformVueFile(code, id) {
87
77
  }
88
78
  });
89
79
  }
90
- if (!hasPageBack)
91
- return;
92
- this.log.devLog(`\u9875\u9762${this.getPageById(id)}\u6CE8\u5165mp-weixin-back`);
80
+ if (!pageInfo.hasPageBack)
81
+ return code;
93
82
  if (code.includes("<page-container")) {
94
- this.log.devLog(`${this.getPageById(id)}\u9875\u9762\u5DF2\u6709page-container\u7EC4\u4EF6\uFF0C\u6CE8\u5165\u5931\u8D25`);
83
+ context.log.debugLog(`${context.getPageById(id)}\u9875\u9762\u5DF2\u6709page-container\u7EC4\u4EF6\uFF0C\u6CE8\u5165\u5931\u8D25`);
95
84
  return code;
96
85
  }
97
- if (!pageBackConfig.preventDefault) {
98
- callbackCode += `uni.navigateBack({ delta: 1 });`;
86
+ if (!pageInfo.backConfig.preventDefault) {
87
+ pageInfo.callbackCode += "uni.navigateBack({ delta: 1 });";
99
88
  }
89
+ const importRefFromVue = !pageInfo.hasImportRef ? `import { ref } from 'vue'` : "";
90
+ const stateFrequency = "let __MP_BACK_FREQUENCY__ = 1;";
91
+ const statePageContainerVar = "const __MP_BACK_SHOW_PAGE_CONTAINER__ = ref(true);";
100
92
  const configBack = (() => {
101
- const onPageBack = pageBackConfig.onPageBack;
93
+ const onPageBack = pageInfo.backConfig.onPageBack;
102
94
  if (!onPageBack)
103
95
  return "";
104
96
  if (typeof onPageBack !== "function") {
105
97
  throw new Error("`onPageBack` must be a function");
106
98
  }
107
- const params = JSON.stringify({ page: this.getPageById(id) });
99
+ const params = JSON.stringify({ page: context.getPageById(id) });
108
100
  if (isArrowFunction(onPageBack) || onPageBack.toString().includes("function")) {
109
101
  return `(${onPageBack})(${params});`;
110
102
  }
111
103
  return `(function ${onPageBack})()`;
112
104
  })();
113
- const beforeLeaveStr = `
114
- ${!hasImportRef ? "import { ref } from 'vue'" : ""}
115
- let __MP_BACK_FREQUENCY__ = 1
116
- const __MP_BACK_SHOW_PAGE_CONTAINER__ = ref(true);
105
+ const stateBeforeLeave = `
117
106
  const onBeforeLeave = () => {
118
- console.log("__MP_BACK_FREQUENCY__", __MP_BACK_FREQUENCY__, ${pageBackConfig.frequency})
119
- if (__MP_BACK_FREQUENCY__ < ${pageBackConfig.frequency}) {
107
+ if (__MP_BACK_FREQUENCY__ < ${pageInfo.backConfig.frequency}) {
120
108
  __MP_BACK_SHOW_PAGE_CONTAINER__.value = false
121
109
  setTimeout(() => __MP_BACK_SHOW_PAGE_CONTAINER__.value = true, 0);
122
110
  __MP_BACK_FREQUENCY__++
123
111
  }
124
112
  ${configBack}
125
- ${callbackCode}
113
+ ${pageInfo.callbackCode}
126
114
  };
127
115
  `;
128
- const { template, script, scriptSetup } = sfc;
116
+ const { template, scriptSetup } = sfc;
129
117
  const tempOffsets = {
130
118
  start: template.loc.start.offset,
131
119
  end: template.loc.end.offset,
132
120
  content: template.content
133
121
  };
134
122
  const templateMagicString = new MagicString__default(tempOffsets.content);
135
- templateMagicString.append(componentStr);
123
+ templateMagicString.append(pageContainerComp);
136
124
  codeMs.overwrite(tempOffsets.start, tempOffsets.end, templateMagicString.toString());
137
- const scriptSfc = script || scriptSetup;
138
- if (!scriptSfc)
139
- return;
140
125
  const scriptOffsets = {
141
- start: scriptSfc.loc.start.offset,
142
- end: scriptSfc.loc.end.offset,
143
- content: scriptSfc.content || ""
126
+ start: scriptSetup.loc.start.offset,
127
+ end: scriptSetup.loc.end.offset,
128
+ content: scriptSetup.content || ""
144
129
  };
145
130
  const scriptMagicString = new MagicString__default(scriptOffsets.content);
146
- scriptMagicString.prepend(beforeLeaveStr);
131
+ scriptMagicString.prepend(
132
+ ` ${importRefFromVue}
133
+ ${stateFrequency}
134
+ ${statePageContainerVar}
135
+ ${stateBeforeLeave} `
136
+ );
147
137
  codeMs.overwrite(scriptOffsets.start, scriptOffsets.end, scriptMagicString.toString());
148
138
  return codeMs.toString();
149
139
  }
140
+ function optionsWalk(context, code, sfc, id) {
141
+ const codeMs = new MagicString__default(code);
142
+ const ast = astKit.babelParse(sfc.script.loc.source, sfc.script.lang);
143
+ let pageInfo = {
144
+ hasPageBack: false,
145
+ pageBackFnName: "onPageBack",
146
+ backConfig: { ...context.config }
147
+ };
148
+ let exportDefaultNode = null;
149
+ let dataMethodNode = null;
150
+ let methodsNode = null;
151
+ let onPageBackNodeMethod = null;
152
+ let onPageBackNodeProperty = null;
153
+ if (ast) {
154
+ astKit.walkAST(ast, {
155
+ enter(node) {
156
+ if (node.type === "ExportDefaultDeclaration" && node.declaration.type === "ObjectExpression") {
157
+ exportDefaultNode = node.declaration;
158
+ const properties = node.declaration.properties;
159
+ for (let i = 0; i < properties.length; i++) {
160
+ const element = properties[i];
161
+ if (element.type === "ObjectMethod" && element.key.type === "Identifier" && element.key.name === "data" && element.body.type === "BlockStatement") {
162
+ dataMethodNode = element.body;
163
+ }
164
+ if (element.type === "ObjectProperty" && element.key.type === "Identifier" && element.key.name === "methods") {
165
+ methodsNode = element.value;
166
+ }
167
+ const blockStatementCondition = element.type === "ObjectMethod" && element.key.type === "Identifier" && element.key.name === pageInfo.pageBackFnName && element.body.type === "BlockStatement";
168
+ const functionExpressionCondition = element.type === "ObjectProperty" && element.key.type === "Identifier" && element.key.name === pageInfo.pageBackFnName && element.value.type === "FunctionExpression";
169
+ if (blockStatementCondition) {
170
+ pageInfo.hasPageBack = true;
171
+ onPageBackNodeMethod = element;
172
+ }
173
+ if (functionExpressionCondition) {
174
+ pageInfo.hasPageBack = true;
175
+ onPageBackNodeProperty = element;
176
+ }
177
+ }
178
+ }
179
+ }
180
+ });
181
+ }
182
+ if (!pageInfo.hasPageBack)
183
+ return;
184
+ const newDataProperty = [
185
+ {
186
+ type: "ObjectProperty",
187
+ key: { type: "Identifier", name: "__MP_BACK_SHOW_PAGE_CONTAINER__" },
188
+ value: { type: "BooleanLiteral", value: true },
189
+ computed: false,
190
+ shorthand: false
191
+ },
192
+ {
193
+ type: "ObjectProperty",
194
+ key: { type: "Identifier", name: "__MP_BACK_FREQUENCY__" },
195
+ value: { type: "NumericLiteral", value: 1 },
196
+ computed: false,
197
+ shorthand: false
198
+ }
199
+ ];
200
+ if (dataMethodNode) {
201
+ const returnStatement = dataMethodNode.body.find(
202
+ (node) => node.type === "ReturnStatement"
203
+ );
204
+ if (returnStatement && returnStatement.argument && returnStatement.argument.type === "ObjectExpression") {
205
+ returnStatement.argument.properties.push(...newDataProperty);
206
+ }
207
+ } else if (exportDefaultNode) {
208
+ const addData = {
209
+ type: "ObjectMethod",
210
+ key: { type: "Identifier", name: "data" },
211
+ kind: "method",
212
+ params: [],
213
+ async: false,
214
+ generator: false,
215
+ computed: false,
216
+ body: {
217
+ type: "BlockStatement",
218
+ directives: [],
219
+ body: [
220
+ {
221
+ type: "ReturnStatement",
222
+ argument: {
223
+ type: "ObjectExpression",
224
+ properties: newDataProperty
225
+ }
226
+ }
227
+ ]
228
+ }
229
+ };
230
+ exportDefaultNode.properties.push(addData);
231
+ }
232
+ const configBack = (() => {
233
+ const onPageBack = pageInfo.backConfig.onPageBack;
234
+ if (!onPageBack)
235
+ return "";
236
+ if (typeof onPageBack !== "function") {
237
+ throw new Error("`onPageBack` must be a function");
238
+ }
239
+ const params = JSON.stringify({ page: context.getPageById(id) });
240
+ if (isArrowFunction(onPageBack) || onPageBack.toString().includes("function")) {
241
+ return `(${onPageBack})(${params});`;
242
+ }
243
+ return `(function ${onPageBack})()`;
244
+ })();
245
+ const stateBeforeLeave = `
246
+ function onBeforeLeave() {
247
+ if (this.__MP_BACK_FREQUENCY__ < ${pageInfo.backConfig.frequency}) {
248
+ this.__MP_BACK_SHOW_PAGE_CONTAINER__ = false
249
+ setTimeout(() => { this.__MP_BACK_SHOW_PAGE_CONTAINER__ = true }, 0);
250
+ this.__MP_BACK_FREQUENCY__++
251
+ }
252
+ ${configBack}
253
+ ${!pageInfo.backConfig.preventDefault ? "uni.navigateBack({ delta: 1 });" : ""}
254
+ };
255
+ `;
256
+ const stateBeforeLeaveAst = astKit.babelParse(stateBeforeLeave);
257
+ const stateBeforeLeaveNode = stateBeforeLeaveAst.body.find(
258
+ (node) => node.type === "FunctionDeclaration"
259
+ );
260
+ const newMethodsProperty = {
261
+ type: "ObjectMethod",
262
+ key: {
263
+ type: "Identifier",
264
+ name: "onBeforeLeave"
265
+ },
266
+ kind: "method",
267
+ generator: false,
268
+ async: false,
269
+ params: [],
270
+ computed: false,
271
+ body: {
272
+ type: "BlockStatement",
273
+ directives: [],
274
+ body: [
275
+ ...onPageBackNodeMethod ? onPageBackNodeMethod.body.body : [],
276
+ ...onPageBackNodeProperty ? onPageBackNodeProperty.value.body.body : [],
277
+ ...stateBeforeLeaveNode.body.body
278
+ ]
279
+ }
280
+ };
281
+ if (methodsNode) {
282
+ methodsNode.properties.push(newMethodsProperty);
283
+ const code2 = (generate__default.default ? generate__default.default : generate__default)(methodsNode);
284
+ console.log(code2);
285
+ } else if (exportDefaultNode) {
286
+ const addMethods = {
287
+ type: "ObjectProperty",
288
+ computed: false,
289
+ shorthand: false,
290
+ key: {
291
+ type: "Identifier",
292
+ name: "methods"
293
+ },
294
+ value: {
295
+ type: "ObjectExpression",
296
+ properties: [newMethodsProperty]
297
+ }
298
+ };
299
+ exportDefaultNode.properties.push(addMethods);
300
+ }
301
+ const { template, script } = sfc;
302
+ const tempOffsets = {
303
+ start: template.loc.start.offset,
304
+ end: template.loc.end.offset,
305
+ content: template.content
306
+ };
307
+ const templateMagicString = new MagicString__default(tempOffsets.content);
308
+ templateMagicString.append(pageContainerComp);
309
+ codeMs.overwrite(tempOffsets.start, tempOffsets.end, templateMagicString.toString());
310
+ const scriptOffsets = {
311
+ start: script.loc.start.offset,
312
+ end: script.loc.end.offset
313
+ };
314
+ const newScriptContent = (generate__default.default ? generate__default.default : generate__default)(ast).code;
315
+ codeMs.overwrite(scriptOffsets.start, scriptOffsets.end, newScriptContent);
316
+ return codeMs.toString();
317
+ }
318
+ const vueWalker = {
319
+ compositionWalk,
320
+ optionsWalk
321
+ };
322
+
323
+ async function transformVueFile(code, id) {
324
+ try {
325
+ const sfc = compilerSfc.parse(code).descriptor;
326
+ const { template, script, scriptSetup } = sfc;
327
+ if (!template?.content) {
328
+ return code;
329
+ }
330
+ if (!script?.content && !scriptSetup?.content) {
331
+ return code;
332
+ }
333
+ const walker = scriptSetup ? "compositionWalk" : "optionsWalk";
334
+ return vueWalker[walker](this, code, sfc, id);
335
+ } catch (error) {
336
+ this.log.error("\u89E3\u6790vue\u6587\u4EF6\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u6587\u4EF6\u662F\u5426\u6B63\u786E");
337
+ this.log.debugLog(String(error));
338
+ return code;
339
+ }
340
+ }
150
341
 
151
342
  var __defProp = Object.defineProperty;
152
343
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -156,18 +347,19 @@ var __publicField = (obj, key, value) => {
156
347
  };
157
348
  class pageContext {
158
349
  constructor(config) {
350
+ __publicField(this, "logPreText", "[mp-weixin-back] : ");
159
351
  __publicField(this, "config");
160
352
  __publicField(this, "pages", []);
161
353
  __publicField(this, "log", {
162
354
  info: (text) => {
163
- console.log(kolorist.white(text));
355
+ console.log(kolorist.white(this.logPreText + text));
164
356
  },
165
357
  error: (text) => {
166
- console.log(kolorist.red(text));
358
+ console.log(kolorist.red(this.logPreText + text));
167
359
  },
168
- devLog: (text) => {
360
+ debugLog: (text) => {
169
361
  if (this.config.mode === "development" && this.config.debug) {
170
- console.log(kolorist.green(text));
362
+ console.log(kolorist.green(this.logPreText + text));
171
363
  }
172
364
  }
173
365
  });
@@ -206,7 +398,7 @@ class pageContext {
206
398
  }
207
399
  } catch (error) {
208
400
  this.log.error("\u8BFB\u53D6pages.json\u6587\u4EF6\u5931\u8D25");
209
- this.log.devLog(String(error));
401
+ this.log.debugLog(String(error));
210
402
  }
211
403
  }
212
404
  // 获取指定id的page