mp-weixin-back 0.0.7 → 0.0.8

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
@@ -7,6 +7,7 @@ const kolorist = require('kolorist');
7
7
  const generate = require('@babel/generator');
8
8
  const compilerSfc = require('@vue/compiler-sfc');
9
9
  const astKit = require('ast-kit');
10
+ const MagicString = require('magic-string');
10
11
 
11
12
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
12
13
 
@@ -14,6 +15,7 @@ const path__default = /*#__PURE__*/_interopDefaultCompat(path);
14
15
  const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
15
16
  const JSON5__default = /*#__PURE__*/_interopDefaultCompat(JSON5);
16
17
  const generate__default = /*#__PURE__*/_interopDefaultCompat(generate);
18
+ const MagicString__default = /*#__PURE__*/_interopDefaultCompat(MagicString);
17
19
 
18
20
  const virtualFileId = "mp-weixin-back-helper";
19
21
 
@@ -30,52 +32,55 @@ async function parseSFC(code) {
30
32
  }
31
33
  }
32
34
  async function transformVueFile(code, id) {
33
- if (code.includes("<page-container")) {
34
- return code;
35
- }
36
- if (!code.includes("<template")) {
35
+ const sfc = await parseSFC(code);
36
+ if (!sfc.template?.content) {
37
37
  return code;
38
38
  }
39
- const componentStr = '<page-container :show="__MP_BACK_SHOW_PAGE_CONTAINER__" :overlay="false" @beforeleave="onBeforeLeave" :z-index="1" :duration="false"></page-container>';
40
- const sfc = await parseSFC(code);
41
- const setupCode = sfc.scriptSetup?.loc.source;
42
- const setupAst = astKit.babelParse(setupCode || "", sfc.scriptSetup?.lang);
43
- let pageBackConfig = this.config;
44
- let hasPageBack = false, hasImportRef = false, pageBackFnName = "onPageBack", callbackCode = ``;
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 = ``;
45
+ const codeMs = new MagicString__default(code);
46
+ const setupCode = sfc.scriptSetup?.loc.source || "";
47
+ const setupAst = astKit.babelParse(setupCode, sfc.scriptSetup?.lang);
45
48
  if (setupAst) {
46
49
  astKit.walkAST(setupAst, {
47
50
  enter(node) {
48
- if (node.type == "ImportDeclaration" && node.source.value.includes(virtualFileId)) {
49
- const importSpecifier = node.specifiers[0];
50
- hasPageBack = true;
51
- pageBackFnName = importSpecifier.local.name;
52
- }
53
- if (node.type == "ImportDeclaration" && node.source.value === "vue") {
54
- const importSpecifiers = node.specifiers;
55
- for (let i = 0; i < importSpecifiers.length; i++) {
56
- const element = importSpecifiers[i];
57
- if (element.local.name == "ref") {
58
- hasImportRef = true;
59
- break;
60
- }
51
+ if (node.type === "ImportDeclaration") {
52
+ if (node.source.value.includes(virtualFileId)) {
53
+ const importSpecifier = node.specifiers[0];
54
+ hasPageBack = true;
55
+ pageBackFnName = importSpecifier.local.name;
56
+ }
57
+ if (node.source.value === "vue") {
58
+ node.specifiers.some((specifier) => {
59
+ if (specifier.local.name === "ref") {
60
+ hasImportRef = true;
61
+ return true;
62
+ }
63
+ return false;
64
+ });
61
65
  }
62
66
  }
63
- if (node.type == "ExpressionStatement" && node.expression.type == "CallExpression" && node.expression.callee.loc?.identifierName == pageBackFnName) {
67
+ if (node.type === "ExpressionStatement" && node.expression.type === "CallExpression" && node.expression.callee.loc?.identifierName === pageBackFnName) {
64
68
  const callback = node.expression.arguments[0];
65
69
  const backArguments = node.expression.arguments[1];
66
- if (backArguments && backArguments.type == "ObjectExpression") {
70
+ if (backArguments?.type === "ObjectExpression") {
67
71
  const config = new Function(
68
72
  // @ts-ignore
69
73
  `return (${(generate__default.default ? generate__default.default : generate__default)(backArguments).code});`
70
74
  )();
71
- pageBackConfig = { ...pageBackConfig, ...config };
75
+ Object.assign(pageBackConfig, config);
72
76
  }
73
77
  if (callback && (callback.type === "ArrowFunctionExpression" || callback.type === "FunctionExpression")) {
74
78
  const body = callback.body;
75
79
  if (body.type === "BlockStatement") {
76
- body.body.forEach((statement) => {
77
- callbackCode += (generate__default.default ? generate__default.default : generate__default)(statement).code;
78
- });
80
+ callbackCode += body.body.map(
81
+ // @ts-ignore
82
+ (statement) => (generate__default.default ? generate__default.default : generate__default)(statement).code
83
+ ).join("");
79
84
  }
80
85
  }
81
86
  }
@@ -85,23 +90,25 @@ async function transformVueFile(code, id) {
85
90
  if (!hasPageBack)
86
91
  return;
87
92
  this.log.devLog(`\u9875\u9762${this.getPageById(id)}\u6CE8\u5165mp-weixin-back`);
93
+ if (code.includes("<page-container")) {
94
+ this.log.devLog(`${this.getPageById(id)}\u9875\u9762\u5DF2\u6709page-container\u7EC4\u4EF6\uFF0C\u6CE8\u5165\u5931\u8D25`);
95
+ return code;
96
+ }
88
97
  if (!pageBackConfig.preventDefault) {
89
98
  callbackCode += `uni.navigateBack({ delta: 1 });`;
90
99
  }
91
100
  const configBack = (() => {
92
- if (!pageBackConfig.onPageBack)
101
+ const onPageBack = pageBackConfig.onPageBack;
102
+ if (!onPageBack)
93
103
  return "";
94
- if (typeof pageBackConfig.onPageBack !== "function") {
104
+ if (typeof onPageBack !== "function") {
95
105
  throw new Error("`onPageBack` must be a function");
96
106
  }
97
- const params = JSON.stringify({
98
- page: this.getPageById(id)
99
- });
100
- const hasFunction = pageBackConfig.onPageBack.toString().includes("function");
101
- if (isArrowFunction(pageBackConfig.onPageBack) || hasFunction) {
102
- return `(${pageBackConfig.onPageBack})(${params});`;
107
+ const params = JSON.stringify({ page: this.getPageById(id) });
108
+ if (isArrowFunction(onPageBack) || onPageBack.toString().includes("function")) {
109
+ return `(${onPageBack})(${params});`;
103
110
  }
104
- return `(function ${pageBackConfig.onPageBack})()`;
111
+ return `(function ${onPageBack})()`;
105
112
  })();
106
113
  const beforeLeaveStr = `
107
114
  ${!hasImportRef ? "import { ref } from 'vue'" : ""}
@@ -111,33 +118,34 @@ async function transformVueFile(code, id) {
111
118
  console.log("__MP_BACK_FREQUENCY__", __MP_BACK_FREQUENCY__, ${pageBackConfig.frequency})
112
119
  if (__MP_BACK_FREQUENCY__ < ${pageBackConfig.frequency}) {
113
120
  __MP_BACK_SHOW_PAGE_CONTAINER__.value = false
114
- setTimeout(() => {
115
- __MP_BACK_SHOW_PAGE_CONTAINER__.value = true
116
- }, 0);
121
+ setTimeout(() => __MP_BACK_SHOW_PAGE_CONTAINER__.value = true, 0);
117
122
  __MP_BACK_FREQUENCY__++
118
123
  }
119
- // \u8FD0\u884C\u914D\u7F6E\u7684\u533F\u540D\u51FD\u6570
120
124
  ${configBack}
121
125
  ${callbackCode}
122
126
  };
123
127
  `;
124
- const result = code.replace(
125
- /(<template.*?>)([\s\S]*?)(<\/template>)([\s\S]*?)(<script\s+(?:lang="ts"\s+)?setup.*?>|$)/,
126
- (match, templateStart, templateContent, templateEnd, middleContent, scriptSetup) => {
127
- const hasScriptSetup = Boolean(scriptSetup);
128
- const scriptStartTag = hasScriptSetup ? scriptSetup : "<script setup>";
129
- const scriptEndTag = hasScriptSetup ? "" : "<\/script>";
130
- const injectedTemplate = `${templateStart}${templateContent}
131
- ${componentStr}
132
- ${templateEnd}`;
133
- const injectedScript = `
134
- ${middleContent}${scriptStartTag}
135
- ${beforeLeaveStr}
136
- ${scriptEndTag}`;
137
- return injectedTemplate + injectedScript;
138
- }
139
- );
140
- return result;
128
+ const { template, script, scriptSetup } = sfc;
129
+ const tempOffsets = {
130
+ start: template.loc.start.offset,
131
+ end: template.loc.end.offset,
132
+ content: template.content
133
+ };
134
+ const templateMagicString = new MagicString__default(tempOffsets.content);
135
+ templateMagicString.append(componentStr);
136
+ codeMs.overwrite(tempOffsets.start, tempOffsets.end, templateMagicString.toString());
137
+ const scriptSfc = script || scriptSetup;
138
+ if (!scriptSfc)
139
+ return;
140
+ const scriptOffsets = {
141
+ start: scriptSfc.loc.start.offset,
142
+ end: scriptSfc.loc.end.offset,
143
+ content: scriptSfc.content || ""
144
+ };
145
+ const scriptMagicString = new MagicString__default(scriptOffsets.content);
146
+ scriptMagicString.prepend(beforeLeaveStr);
147
+ codeMs.overwrite(scriptOffsets.start, scriptOffsets.end, scriptMagicString.toString());
148
+ return codeMs.toString();
141
149
  }
142
150
 
143
151
  var __defProp = Object.defineProperty;
package/dist/index.mjs CHANGED
@@ -5,6 +5,7 @@ import { white, red, green } from 'kolorist';
5
5
  import generate from '@babel/generator';
6
6
  import { parse } from '@vue/compiler-sfc';
7
7
  import { babelParse, walkAST } from 'ast-kit';
8
+ import MagicString from 'magic-string';
8
9
 
9
10
  const virtualFileId = "mp-weixin-back-helper";
10
11
 
@@ -21,52 +22,55 @@ async function parseSFC(code) {
21
22
  }
22
23
  }
23
24
  async function transformVueFile(code, id) {
24
- if (code.includes("<page-container")) {
25
- return code;
26
- }
27
- if (!code.includes("<template")) {
25
+ const sfc = await parseSFC(code);
26
+ if (!sfc.template?.content) {
28
27
  return code;
29
28
  }
30
- const componentStr = '<page-container :show="__MP_BACK_SHOW_PAGE_CONTAINER__" :overlay="false" @beforeleave="onBeforeLeave" :z-index="1" :duration="false"></page-container>';
31
- const sfc = await parseSFC(code);
32
- const setupCode = sfc.scriptSetup?.loc.source;
33
- const setupAst = babelParse(setupCode || "", sfc.scriptSetup?.lang);
34
- let pageBackConfig = this.config;
35
- let hasPageBack = false, hasImportRef = false, pageBackFnName = "onPageBack", callbackCode = ``;
29
+ const componentStr = ' <page-container :show="__MP_BACK_SHOW_PAGE_CONTAINER__" :overlay="false" @beforeleave="onBeforeLeave" :z-index="1" :duration="false"></page-container>\n';
30
+ let pageBackConfig = { ...this.config };
31
+ let hasPageBack = false;
32
+ let hasImportRef = false;
33
+ let pageBackFnName = "onPageBack";
34
+ let callbackCode = ``;
35
+ const codeMs = new MagicString(code);
36
+ const setupCode = sfc.scriptSetup?.loc.source || "";
37
+ const setupAst = babelParse(setupCode, sfc.scriptSetup?.lang);
36
38
  if (setupAst) {
37
39
  walkAST(setupAst, {
38
40
  enter(node) {
39
- if (node.type == "ImportDeclaration" && node.source.value.includes(virtualFileId)) {
40
- const importSpecifier = node.specifiers[0];
41
- hasPageBack = true;
42
- pageBackFnName = importSpecifier.local.name;
43
- }
44
- if (node.type == "ImportDeclaration" && node.source.value === "vue") {
45
- const importSpecifiers = node.specifiers;
46
- for (let i = 0; i < importSpecifiers.length; i++) {
47
- const element = importSpecifiers[i];
48
- if (element.local.name == "ref") {
49
- hasImportRef = true;
50
- break;
51
- }
41
+ if (node.type === "ImportDeclaration") {
42
+ if (node.source.value.includes(virtualFileId)) {
43
+ const importSpecifier = node.specifiers[0];
44
+ hasPageBack = true;
45
+ pageBackFnName = importSpecifier.local.name;
46
+ }
47
+ if (node.source.value === "vue") {
48
+ node.specifiers.some((specifier) => {
49
+ if (specifier.local.name === "ref") {
50
+ hasImportRef = true;
51
+ return true;
52
+ }
53
+ return false;
54
+ });
52
55
  }
53
56
  }
54
- 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 === pageBackFnName) {
55
58
  const callback = node.expression.arguments[0];
56
59
  const backArguments = node.expression.arguments[1];
57
- if (backArguments && backArguments.type == "ObjectExpression") {
60
+ if (backArguments?.type === "ObjectExpression") {
58
61
  const config = new Function(
59
62
  // @ts-ignore
60
63
  `return (${(generate.default ? generate.default : generate)(backArguments).code});`
61
64
  )();
62
- pageBackConfig = { ...pageBackConfig, ...config };
65
+ Object.assign(pageBackConfig, config);
63
66
  }
64
67
  if (callback && (callback.type === "ArrowFunctionExpression" || callback.type === "FunctionExpression")) {
65
68
  const body = callback.body;
66
69
  if (body.type === "BlockStatement") {
67
- body.body.forEach((statement) => {
68
- callbackCode += (generate.default ? generate.default : generate)(statement).code;
69
- });
70
+ callbackCode += body.body.map(
71
+ // @ts-ignore
72
+ (statement) => (generate.default ? generate.default : generate)(statement).code
73
+ ).join("");
70
74
  }
71
75
  }
72
76
  }
@@ -76,23 +80,25 @@ async function transformVueFile(code, id) {
76
80
  if (!hasPageBack)
77
81
  return;
78
82
  this.log.devLog(`\u9875\u9762${this.getPageById(id)}\u6CE8\u5165mp-weixin-back`);
83
+ if (code.includes("<page-container")) {
84
+ this.log.devLog(`${this.getPageById(id)}\u9875\u9762\u5DF2\u6709page-container\u7EC4\u4EF6\uFF0C\u6CE8\u5165\u5931\u8D25`);
85
+ return code;
86
+ }
79
87
  if (!pageBackConfig.preventDefault) {
80
88
  callbackCode += `uni.navigateBack({ delta: 1 });`;
81
89
  }
82
90
  const configBack = (() => {
83
- if (!pageBackConfig.onPageBack)
91
+ const onPageBack = pageBackConfig.onPageBack;
92
+ if (!onPageBack)
84
93
  return "";
85
- if (typeof pageBackConfig.onPageBack !== "function") {
94
+ if (typeof onPageBack !== "function") {
86
95
  throw new Error("`onPageBack` must be a function");
87
96
  }
88
- const params = JSON.stringify({
89
- page: this.getPageById(id)
90
- });
91
- const hasFunction = pageBackConfig.onPageBack.toString().includes("function");
92
- if (isArrowFunction(pageBackConfig.onPageBack) || hasFunction) {
93
- return `(${pageBackConfig.onPageBack})(${params});`;
97
+ const params = JSON.stringify({ page: this.getPageById(id) });
98
+ if (isArrowFunction(onPageBack) || onPageBack.toString().includes("function")) {
99
+ return `(${onPageBack})(${params});`;
94
100
  }
95
- return `(function ${pageBackConfig.onPageBack})()`;
101
+ return `(function ${onPageBack})()`;
96
102
  })();
97
103
  const beforeLeaveStr = `
98
104
  ${!hasImportRef ? "import { ref } from 'vue'" : ""}
@@ -102,33 +108,34 @@ async function transformVueFile(code, id) {
102
108
  console.log("__MP_BACK_FREQUENCY__", __MP_BACK_FREQUENCY__, ${pageBackConfig.frequency})
103
109
  if (__MP_BACK_FREQUENCY__ < ${pageBackConfig.frequency}) {
104
110
  __MP_BACK_SHOW_PAGE_CONTAINER__.value = false
105
- setTimeout(() => {
106
- __MP_BACK_SHOW_PAGE_CONTAINER__.value = true
107
- }, 0);
111
+ setTimeout(() => __MP_BACK_SHOW_PAGE_CONTAINER__.value = true, 0);
108
112
  __MP_BACK_FREQUENCY__++
109
113
  }
110
- // \u8FD0\u884C\u914D\u7F6E\u7684\u533F\u540D\u51FD\u6570
111
114
  ${configBack}
112
115
  ${callbackCode}
113
116
  };
114
117
  `;
115
- const result = code.replace(
116
- /(<template.*?>)([\s\S]*?)(<\/template>)([\s\S]*?)(<script\s+(?:lang="ts"\s+)?setup.*?>|$)/,
117
- (match, templateStart, templateContent, templateEnd, middleContent, scriptSetup) => {
118
- const hasScriptSetup = Boolean(scriptSetup);
119
- const scriptStartTag = hasScriptSetup ? scriptSetup : "<script setup>";
120
- const scriptEndTag = hasScriptSetup ? "" : "<\/script>";
121
- const injectedTemplate = `${templateStart}${templateContent}
122
- ${componentStr}
123
- ${templateEnd}`;
124
- const injectedScript = `
125
- ${middleContent}${scriptStartTag}
126
- ${beforeLeaveStr}
127
- ${scriptEndTag}`;
128
- return injectedTemplate + injectedScript;
129
- }
130
- );
131
- return result;
118
+ const { template, script, scriptSetup } = sfc;
119
+ const tempOffsets = {
120
+ start: template.loc.start.offset,
121
+ end: template.loc.end.offset,
122
+ content: template.content
123
+ };
124
+ const templateMagicString = new MagicString(tempOffsets.content);
125
+ templateMagicString.append(componentStr);
126
+ codeMs.overwrite(tempOffsets.start, tempOffsets.end, templateMagicString.toString());
127
+ const scriptSfc = script || scriptSetup;
128
+ if (!scriptSfc)
129
+ return;
130
+ const scriptOffsets = {
131
+ start: scriptSfc.loc.start.offset,
132
+ end: scriptSfc.loc.end.offset,
133
+ content: scriptSfc.content || ""
134
+ };
135
+ const scriptMagicString = new MagicString(scriptOffsets.content);
136
+ scriptMagicString.prepend(beforeLeaveStr);
137
+ codeMs.overwrite(scriptOffsets.start, scriptOffsets.end, scriptMagicString.toString());
138
+ return codeMs.toString();
132
139
  }
133
140
 
134
141
  var __defProp = Object.defineProperty;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mp-weixin-back",
3
3
  "type": "module",
4
- "version": "0.0.7",
4
+ "version": "0.0.8",
5
5
  "description": "监听微信小程序的手势返回和页面默认导航栏的返回",
6
6
  "main": "dist/index.cjs",
7
7
  "module": "dist/index.mjs",
@@ -41,14 +41,13 @@
41
41
  "@babel/generator": "^7.26.2",
42
42
  "@babel/parser": "^7.26.2",
43
43
  "@babel/traverse": "^7.25.9",
44
- "@types/babel__generator": "^7.6.8",
45
- "@types/node": "^22.9.3",
46
44
  "@vitejs/plugin-vue": "^5.2.0",
47
45
  "@vue/test-utils": "^2.4.6",
48
46
  "ast-kit": "^1.3.1",
49
47
  "happy-dom": "^15.11.6",
50
48
  "json5": "^2.2.3",
51
49
  "kolorist": "^1.8.0",
50
+ "magic-string": "^0.30.13",
52
51
  "typescript": "^5.7.2",
53
52
  "vitest": "^2.1.5"
54
53
  },
@@ -60,6 +59,8 @@
60
59
  "*": "prettier --write"
61
60
  },
62
61
  "devDependencies": {
62
+ "@types/babel__generator": "^7.6.8",
63
+ "@types/node": "^22.9.3",
63
64
  "unbuild": "^2.0.0",
64
65
  "vue": "^3.5.13"
65
66
  }
package/utils/index.ts CHANGED
@@ -2,6 +2,7 @@ import generate from '@babel/generator'
2
2
  import { parse } from '@vue/compiler-sfc'
3
3
  import { babelParse, walkAST } from 'ast-kit'
4
4
  import { pageContext } from '../src/context'
5
+ import MagicString from 'magic-string'
5
6
  import { virtualFileId } from './constant'
6
7
  import type { SFCDescriptor } from '@vue/compiler-sfc'
7
8
  import type { Node } from '@babel/types'
@@ -20,62 +21,58 @@ async function parseSFC(code: string): Promise<SFCDescriptor> {
20
21
  }
21
22
 
22
23
  export async function transformVueFile(this: pageContext, code: string, id: string) {
23
- // 检查代码中是否已经包含page-container组件
24
- if (code.includes('<page-container')) {
25
- return code
26
- }
27
-
28
- // 检查是否包含template标签
29
- if (!code.includes('<template')) {
24
+ const sfc = await parseSFC(code)
25
+ if (!sfc.template?.content) {
30
26
  return code
31
27
  }
32
28
 
33
29
  const componentStr =
34
- '<page-container :show="__MP_BACK_SHOW_PAGE_CONTAINER__" :overlay="false" @beforeleave="onBeforeLeave" :z-index="1" :duration="false"></page-container>'
30
+ ' <page-container :show="__MP_BACK_SHOW_PAGE_CONTAINER__" :overlay="false" @beforeleave="onBeforeLeave" :z-index="1" :duration="false"></page-container>\n'
35
31
 
36
- const sfc = await parseSFC(code)
37
- const setupCode = sfc.scriptSetup?.loc.source
38
- const setupAst = babelParse(setupCode || '', sfc.scriptSetup?.lang)
39
- let pageBackConfig = this.config
40
- let hasPageBack = false,
41
- hasImportRef = false,
42
- pageBackFnName = 'onPageBack',
43
- callbackCode = ``
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)
44
41
 
45
42
  if (setupAst) {
46
43
  walkAST<Node>(setupAst, {
47
44
  enter(node) {
48
- if (node.type == 'ImportDeclaration' && node.source.value.includes(virtualFileId)) {
49
- const importSpecifier = node.specifiers[0]
50
- hasPageBack = true
51
- pageBackFnName = importSpecifier.local.name
52
- }
53
-
54
- if (node.type == 'ImportDeclaration' && node.source.value === 'vue') {
55
- const importSpecifiers = node.specifiers
56
- for (let i = 0; i < importSpecifiers.length; i++) {
57
- const element = importSpecifiers[i]
58
- if (element.local.name == 'ref') {
59
- hasImportRef = true
60
- break
61
- }
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
+ })
62
59
  }
63
60
  }
64
61
 
65
62
  if (
66
- node.type == 'ExpressionStatement' &&
67
- node.expression.type == 'CallExpression' &&
68
- node.expression.callee.loc?.identifierName == pageBackFnName
63
+ node.type === 'ExpressionStatement' &&
64
+ node.expression.type === 'CallExpression' &&
65
+ node.expression.callee.loc?.identifierName === pageBackFnName
69
66
  ) {
70
- const callback = node.expression.arguments[0] // 获取第一个参数
67
+ const callback = node.expression.arguments[0]
71
68
  const backArguments = node.expression.arguments[1]
72
- // 第二个参数为object才有效,覆盖插件传入的配置
73
- if (backArguments && backArguments.type == 'ObjectExpression') {
69
+
70
+ if (backArguments?.type === 'ObjectExpression') {
74
71
  const config = new Function(
75
72
  // @ts-ignore
76
73
  `return (${(generate.default ? generate.default : generate)(backArguments).code});`
77
74
  )()
78
- pageBackConfig = { ...pageBackConfig, ...config }
75
+ Object.assign(pageBackConfig, config)
79
76
  }
80
77
 
81
78
  if (
@@ -84,11 +81,12 @@ export async function transformVueFile(this: pageContext, code: string, id: stri
84
81
  ) {
85
82
  const body = callback.body
86
83
  if (body.type === 'BlockStatement') {
87
- // 遍历 BlockStatement 的内容
88
- body.body.forEach((statement) => {
89
- // @ts-ignore
90
- callbackCode += (generate.default ? generate.default : generate)(statement).code // 将 AST 节点生成代码
91
- })
84
+ callbackCode += body.body
85
+ .map(
86
+ // @ts-ignore
87
+ (statement) => (generate.default ? generate.default : generate)(statement).code
88
+ )
89
+ .join('')
92
90
  }
93
91
  }
94
92
  }
@@ -100,29 +98,29 @@ export async function transformVueFile(this: pageContext, code: string, id: stri
100
98
 
101
99
  this.log.devLog(`页面${this.getPageById(id)}注入mp-weixin-back`)
102
100
 
103
- // 不阻止默认行为就返回到上一层
101
+ if (code.includes('<page-container')) {
102
+ this.log.devLog(`${this.getPageById(id)}页面已有page-container组件,注入失败`)
103
+ return code
104
+ }
105
+
104
106
  if (!pageBackConfig.preventDefault) {
105
107
  callbackCode += `uni.navigateBack({ delta: 1 });`
106
108
  }
107
109
 
108
- // 处理统一的返回方法
109
110
  const configBack = (() => {
110
- if (!pageBackConfig.onPageBack) return ''
111
- if (typeof pageBackConfig.onPageBack !== 'function') {
111
+ const onPageBack = pageBackConfig.onPageBack
112
+ if (!onPageBack) return ''
113
+ if (typeof onPageBack !== 'function') {
112
114
  throw new Error('`onPageBack` must be a function')
113
115
  }
114
116
 
115
- const params = JSON.stringify({
116
- page: this.getPageById(id),
117
- })
118
-
119
- const hasFunction = pageBackConfig.onPageBack.toString().includes('function')
117
+ const params = JSON.stringify({ page: this.getPageById(id) })
120
118
 
121
- if (isArrowFunction(pageBackConfig.onPageBack) || hasFunction) {
122
- return `(${pageBackConfig.onPageBack})(${params});`
119
+ if (isArrowFunction(onPageBack) || onPageBack.toString().includes('function')) {
120
+ return `(${onPageBack})(${params});`
123
121
  }
124
122
 
125
- return `(function ${pageBackConfig.onPageBack})()`
123
+ return `(function ${onPageBack})()`
126
124
  })()
127
125
 
128
126
  const beforeLeaveStr = `
@@ -133,33 +131,37 @@ export async function transformVueFile(this: pageContext, code: string, id: stri
133
131
  console.log("__MP_BACK_FREQUENCY__", __MP_BACK_FREQUENCY__, ${pageBackConfig.frequency})
134
132
  if (__MP_BACK_FREQUENCY__ < ${pageBackConfig.frequency}) {
135
133
  __MP_BACK_SHOW_PAGE_CONTAINER__.value = false
136
- setTimeout(() => {
137
- __MP_BACK_SHOW_PAGE_CONTAINER__.value = true
138
- }, 0);
134
+ setTimeout(() => __MP_BACK_SHOW_PAGE_CONTAINER__.value = true, 0);
139
135
  __MP_BACK_FREQUENCY__++
140
136
  }
141
- // 运行配置的匿名函数
142
137
  ${configBack}
143
138
  ${callbackCode}
144
139
  };
145
140
  `
146
141
 
147
- // template标签后插入page-container组件和script setup声明
148
- const result = code.replace(
149
- /(<template.*?>)([\s\S]*?)(<\/template>)([\s\S]*?)(<script\s+(?:lang="ts"\s+)?setup.*?>|$)/,
150
- (match, templateStart, templateContent, templateEnd, middleContent, scriptSetup) => {
151
- // 处理script setup标签
152
- const hasScriptSetup = Boolean(scriptSetup)
153
- const scriptStartTag = hasScriptSetup ? scriptSetup : '<script setup>'
154
- const scriptEndTag = hasScriptSetup ? '' : '</script>'
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
+ }
155
148
 
156
- // 构建注入的内容
157
- const injectedTemplate = `${templateStart}${templateContent}\n ${componentStr}\n${templateEnd}`
158
- const injectedScript = `\n${middleContent}${scriptStartTag}\n${beforeLeaveStr}\n${scriptEndTag}`
149
+ const templateMagicString = new MagicString(tempOffsets.content)
150
+ templateMagicString.append(componentStr)
151
+ codeMs.overwrite(tempOffsets.start, tempOffsets.end, templateMagicString.toString())
159
152
 
160
- return injectedTemplate + injectedScript
161
- }
162
- )
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 || '',
160
+ }
161
+
162
+ const scriptMagicString = new MagicString(scriptOffsets.content)
163
+ scriptMagicString.prepend(beforeLeaveStr)
164
+ codeMs.overwrite(scriptOffsets.start, scriptOffsets.end, scriptMagicString.toString())
163
165
 
164
- return result
166
+ return codeMs.toString()
165
167
  }