mp-weixin-back 0.0.2 → 0.0.4
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/build.config.ts +12 -0
- package/dist/index.cjs +231 -0
- package/dist/index.d.cts +27 -0
- package/dist/index.mjs +147 -72291
- package/package.json +22 -8
- package/src/context.ts +2 -1
- package/dist/index.js +0 -72376
- package/tsup.config.ts +0 -15
package/build.config.ts
ADDED
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const JSON5 = require('json5');
|
|
6
|
+
const generate = require('@babel/generator');
|
|
7
|
+
const compilerSfc = require('@vue/compiler-sfc');
|
|
8
|
+
const astKit = require('ast-kit');
|
|
9
|
+
|
|
10
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
11
|
+
|
|
12
|
+
const path__default = /*#__PURE__*/_interopDefaultCompat(path);
|
|
13
|
+
const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
|
|
14
|
+
const JSON5__default = /*#__PURE__*/_interopDefaultCompat(JSON5);
|
|
15
|
+
const generate__default = /*#__PURE__*/_interopDefaultCompat(generate);
|
|
16
|
+
|
|
17
|
+
const virtualFileId = "mp-weixin-back-helper";
|
|
18
|
+
|
|
19
|
+
function isArrowFunction(func) {
|
|
20
|
+
if (typeof func !== "function")
|
|
21
|
+
return false;
|
|
22
|
+
return !func.hasOwnProperty("prototype") && func.toString().includes("=>");
|
|
23
|
+
}
|
|
24
|
+
async function parseSFC(code) {
|
|
25
|
+
try {
|
|
26
|
+
return compilerSfc.parse(code).descriptor;
|
|
27
|
+
} catch (error) {
|
|
28
|
+
throw new Error(`\u89E3\u6790vue\u6587\u4EF6\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u6587\u4EF6\u662F\u5426\u6B63\u786E`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
async function transformVueFile(code, id) {
|
|
32
|
+
if (code.includes("<page-container")) {
|
|
33
|
+
return code;
|
|
34
|
+
}
|
|
35
|
+
if (!code.includes("<template")) {
|
|
36
|
+
return code;
|
|
37
|
+
}
|
|
38
|
+
const componentStr = '<page-container :show="__MP_BACK_SHOW_PAGE_CONTAINER__" :overlay="false" @beforeleave="onBeforeLeave" :z-index="1" :duration="false"></page-container>';
|
|
39
|
+
const sfc = await parseSFC(code);
|
|
40
|
+
const setupCode = sfc.scriptSetup?.loc.source;
|
|
41
|
+
const setupAst = astKit.babelParse(setupCode || "", sfc.scriptSetup?.lang);
|
|
42
|
+
let pageBackConfig = this.config;
|
|
43
|
+
let hasPageBack = false, hasImportRef = false, pageBackFnName = "onPageBack", callbackCode = ``;
|
|
44
|
+
if (setupAst) {
|
|
45
|
+
astKit.walkAST(setupAst, {
|
|
46
|
+
enter(node) {
|
|
47
|
+
if (node.type == "ImportDeclaration" && node.source.value.includes(virtualFileId)) {
|
|
48
|
+
const importSpecifier = node.specifiers[0];
|
|
49
|
+
hasPageBack = true;
|
|
50
|
+
pageBackFnName = importSpecifier.local.name;
|
|
51
|
+
}
|
|
52
|
+
if (node.type == "ImportDeclaration" && node.source.value === "vue") {
|
|
53
|
+
const importSpecifiers = node.specifiers;
|
|
54
|
+
for (let i = 0; i < importSpecifiers.length; i++) {
|
|
55
|
+
const element = importSpecifiers[i];
|
|
56
|
+
if (element.local.name == "ref") {
|
|
57
|
+
hasImportRef = true;
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (node.type == "ExpressionStatement" && node.expression.type == "CallExpression" && node.expression.callee.loc?.identifierName == pageBackFnName) {
|
|
63
|
+
const callback = node.expression.arguments[0];
|
|
64
|
+
const backArguments = node.expression.arguments[1];
|
|
65
|
+
if (backArguments && backArguments.type == "ObjectExpression") {
|
|
66
|
+
const config = new Function(`return (${generate__default(backArguments).code});`)();
|
|
67
|
+
pageBackConfig = { ...pageBackConfig, ...config };
|
|
68
|
+
}
|
|
69
|
+
if (callback && (callback.type === "ArrowFunctionExpression" || callback.type === "FunctionExpression")) {
|
|
70
|
+
const body = callback.body;
|
|
71
|
+
if (body.type === "BlockStatement") {
|
|
72
|
+
body.body.forEach((statement) => {
|
|
73
|
+
callbackCode += generate__default(statement).code;
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
if (!hasPageBack)
|
|
82
|
+
return;
|
|
83
|
+
if (!pageBackConfig.preventDefault) {
|
|
84
|
+
callbackCode += `uni.navigateBack({ delta: 1 });`;
|
|
85
|
+
}
|
|
86
|
+
const configBack = (() => {
|
|
87
|
+
if (!pageBackConfig.onPageBack)
|
|
88
|
+
return "";
|
|
89
|
+
if (typeof pageBackConfig.onPageBack !== "function") {
|
|
90
|
+
throw new Error("`onPageBack` must be a function");
|
|
91
|
+
}
|
|
92
|
+
const params = JSON.stringify({
|
|
93
|
+
page: this.getPageById(id)
|
|
94
|
+
});
|
|
95
|
+
const hasFunction = pageBackConfig.onPageBack.toString().includes("function");
|
|
96
|
+
if (isArrowFunction(pageBackConfig.onPageBack) || hasFunction) {
|
|
97
|
+
return `(${pageBackConfig.onPageBack})(${params});`;
|
|
98
|
+
}
|
|
99
|
+
return `(function ${pageBackConfig.onPageBack})()`;
|
|
100
|
+
})();
|
|
101
|
+
const beforeLeaveStr = `
|
|
102
|
+
${!hasImportRef ? "import { ref } from 'vue'" : ""}
|
|
103
|
+
let __MP_BACK_FREQUENCY__ = 1
|
|
104
|
+
const __MP_BACK_SHOW_PAGE_CONTAINER__ = ref(true);
|
|
105
|
+
const onBeforeLeave = () => {
|
|
106
|
+
console.log("__MP_BACK_FREQUENCY__", __MP_BACK_FREQUENCY__, ${pageBackConfig.frequency})
|
|
107
|
+
if (__MP_BACK_FREQUENCY__ < ${pageBackConfig.frequency}) {
|
|
108
|
+
__MP_BACK_SHOW_PAGE_CONTAINER__.value = false
|
|
109
|
+
setTimeout(() => {
|
|
110
|
+
__MP_BACK_SHOW_PAGE_CONTAINER__.value = true
|
|
111
|
+
}, 0);
|
|
112
|
+
__MP_BACK_FREQUENCY__++
|
|
113
|
+
}
|
|
114
|
+
// \u8FD0\u884C\u914D\u7F6E\u7684\u533F\u540D\u51FD\u6570
|
|
115
|
+
${configBack}
|
|
116
|
+
${callbackCode}
|
|
117
|
+
};
|
|
118
|
+
`;
|
|
119
|
+
const result = code.replace(
|
|
120
|
+
/(<template.*?>)([\s\S]*?)(<\/template>)([\s\S]*?)(<script\s+(?:lang="ts"\s+)?setup.*?>|$)/,
|
|
121
|
+
(match, templateStart, templateContent, templateEnd, middleContent, scriptSetup) => {
|
|
122
|
+
const hasScriptSetup = Boolean(scriptSetup);
|
|
123
|
+
const scriptStartTag = hasScriptSetup ? scriptSetup : "<script setup>";
|
|
124
|
+
const scriptEndTag = hasScriptSetup ? "" : "<\/script>";
|
|
125
|
+
const injectedTemplate = `${templateStart}${templateContent}
|
|
126
|
+
${componentStr}
|
|
127
|
+
${templateEnd}`;
|
|
128
|
+
const injectedScript = `
|
|
129
|
+
${middleContent}${scriptStartTag}
|
|
130
|
+
${beforeLeaveStr}
|
|
131
|
+
${scriptEndTag}`;
|
|
132
|
+
return injectedTemplate + injectedScript;
|
|
133
|
+
}
|
|
134
|
+
);
|
|
135
|
+
return result;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
var __defProp = Object.defineProperty;
|
|
139
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
140
|
+
var __publicField = (obj, key, value) => {
|
|
141
|
+
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
142
|
+
return value;
|
|
143
|
+
};
|
|
144
|
+
class pageContext {
|
|
145
|
+
constructor(config) {
|
|
146
|
+
__publicField(this, "config");
|
|
147
|
+
__publicField(this, "pages", []);
|
|
148
|
+
this.config = config;
|
|
149
|
+
}
|
|
150
|
+
getPagesJsonPath() {
|
|
151
|
+
const pagesJsonPath = path__default.join(this.config.root, "src/pages.json");
|
|
152
|
+
return pagesJsonPath;
|
|
153
|
+
}
|
|
154
|
+
// 获取页面配置详情
|
|
155
|
+
async getPagesJsonInfo() {
|
|
156
|
+
const hasPagesJson = fs__default.existsSync(this.getPagesJsonPath());
|
|
157
|
+
if (!hasPagesJson)
|
|
158
|
+
return;
|
|
159
|
+
try {
|
|
160
|
+
const content = await fs__default.promises.readFile(this.getPagesJsonPath(), "utf-8");
|
|
161
|
+
const pagesContent = JSON5__default.parse(content);
|
|
162
|
+
const { pages, subpackages } = pagesContent;
|
|
163
|
+
if (pages) {
|
|
164
|
+
const mainPages = pages.reduce((acc, current) => {
|
|
165
|
+
acc.push(current.path);
|
|
166
|
+
return acc;
|
|
167
|
+
}, []);
|
|
168
|
+
this.pages.push(...mainPages);
|
|
169
|
+
}
|
|
170
|
+
if (subpackages) {
|
|
171
|
+
const root = subpackages.root;
|
|
172
|
+
const subPages = subpackages.pages.reduce((acc, current) => {
|
|
173
|
+
acc.push(`${root}/${current.path}`.replace("//", "/"));
|
|
174
|
+
return acc;
|
|
175
|
+
}, []);
|
|
176
|
+
this.pages.push(...subPages);
|
|
177
|
+
}
|
|
178
|
+
} catch (error) {
|
|
179
|
+
throw new Error("\u8BF7\u6B63\u786E\u914D\u7F6E\u9879\u76EE\u7684pages.json\u6587\u4EF6");
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
// 获取指定id的page
|
|
183
|
+
getPageById(id) {
|
|
184
|
+
const path2 = (id.split("src/")[1] || "").replace(".vue", "");
|
|
185
|
+
return this.pages.find((i) => i === path2) || null;
|
|
186
|
+
}
|
|
187
|
+
async transform(code, id) {
|
|
188
|
+
const result = await transformVueFile.call(this, code, id);
|
|
189
|
+
return result;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function MpBackPlugin(userOptions = {}) {
|
|
194
|
+
let context;
|
|
195
|
+
const defaultOptions = {
|
|
196
|
+
preventDefault: false,
|
|
197
|
+
frequency: 1
|
|
198
|
+
};
|
|
199
|
+
const options = { ...defaultOptions, ...userOptions };
|
|
200
|
+
return {
|
|
201
|
+
name: "vite-plugin-mp-weixin-back",
|
|
202
|
+
enforce: "pre",
|
|
203
|
+
configResolved(config) {
|
|
204
|
+
context = new pageContext({ ...options, mode: config.mode, root: config.root });
|
|
205
|
+
},
|
|
206
|
+
buildStart() {
|
|
207
|
+
context.getPagesJsonInfo();
|
|
208
|
+
},
|
|
209
|
+
resolveId(id) {
|
|
210
|
+
if (id === virtualFileId) {
|
|
211
|
+
return virtualFileId;
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
load(id) {
|
|
215
|
+
if (id.includes("node_modules")) {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
if (id === virtualFileId) {
|
|
219
|
+
return `export default function onPageBack() {}`;
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
async transform(code, id) {
|
|
223
|
+
if (id.includes("node_modules") || !id.includes(".vue")) {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
return context.transform(code, id);
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
module.exports = MpBackPlugin;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Plugin } from 'vite';
|
|
2
|
+
|
|
3
|
+
type UserOptions = Partial<Config>;
|
|
4
|
+
type Config = {
|
|
5
|
+
/**
|
|
6
|
+
* 是否阻止默认的回退事件,默认为 false
|
|
7
|
+
*/
|
|
8
|
+
preventDefault: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* 阻止次数,默认是 `1`
|
|
11
|
+
*/
|
|
12
|
+
frequency: number;
|
|
13
|
+
/**
|
|
14
|
+
* 页面回退时触发
|
|
15
|
+
*/
|
|
16
|
+
onPageBack?: (params: BackParams) => void;
|
|
17
|
+
};
|
|
18
|
+
type BackParams = {
|
|
19
|
+
/**
|
|
20
|
+
* 当前页面路径
|
|
21
|
+
*/
|
|
22
|
+
page: string;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
declare function MpBackPlugin(userOptions?: UserOptions): Plugin;
|
|
26
|
+
|
|
27
|
+
export { MpBackPlugin as default };
|