@serveryyswys/opm 0.1.0 → 0.1.2
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/lib/build.js +19 -8
- package/dist/lib/js-requires.d.ts +9 -2
- package/dist/lib/js-requires.js +18 -1
- package/dist/lib/rewrite.js +8 -0
- package/package.json +1 -1
package/dist/lib/build.js
CHANGED
|
@@ -120,6 +120,23 @@ function buildProject(options) {
|
|
|
120
120
|
const locate = (0, typescript_1.createLocator)(projectDir, plan.outDir);
|
|
121
121
|
const env = { locate, contract, nodeOperitArchiveDir: contract_1.NODE_OPERIT_DIR };
|
|
122
122
|
const seeds = collectSeeds(manifest, errors);
|
|
123
|
+
// 入口要注入 process / Buffer 全局(沙盒没有这两个全局)。
|
|
124
|
+
// 关键是:**注入必须在可达性遍历之前登记**,把被注入引用的这两个文件
|
|
125
|
+
// 也当作种子。否则注入代码指向的 dist/process.js 不会进包,
|
|
126
|
+
// 产物一加载就 "Cannot resolve module ./node_modules/.../dist/process.js" ——
|
|
127
|
+
// 而且是每个用户代码自己没 require process 的包都这样。
|
|
128
|
+
const entryPath = typeof manifest.main === 'string' ? toPosix(manifest.main) : '';
|
|
129
|
+
let prelude = '';
|
|
130
|
+
if (entryPath !== '') {
|
|
131
|
+
const joined = toPosix(joinRelative((0, node_path_1.dirname)(entryPath), contract_1.NODE_OPERIT_DIR));
|
|
132
|
+
const relative = joined.startsWith('.') ? joined : './' + joined;
|
|
133
|
+
prelude =
|
|
134
|
+
'/* opm: Operit 沙盒没有 process / Buffer 全局,入口先挂上(见 node.operit 的 BUILTINS.json) */\n' +
|
|
135
|
+
"globalThis.process = require('" + relative + "/dist/process.js');\n" +
|
|
136
|
+
"globalThis.Buffer = require('" + relative + "/dist/buffer.js').Buffer;\n";
|
|
137
|
+
seeds.push(joined + '/dist/process.js');
|
|
138
|
+
seeds.push(joined + '/dist/buffer.js');
|
|
139
|
+
}
|
|
123
140
|
const visited = new Set();
|
|
124
141
|
const rewritten = new Map();
|
|
125
142
|
const queue = [];
|
|
@@ -152,14 +169,8 @@ function buildProject(options) {
|
|
|
152
169
|
}
|
|
153
170
|
}
|
|
154
171
|
}
|
|
155
|
-
//
|
|
156
|
-
|
|
157
|
-
if (entryPath !== '' && rewritten.has(entryPath)) {
|
|
158
|
-
const joined = toPosix(joinRelative((0, node_path_1.dirname)(entryPath), contract_1.NODE_OPERIT_DIR));
|
|
159
|
-
const relative = joined.startsWith('.') ? joined : './' + joined;
|
|
160
|
-
const prelude = '/* opm: Operit 沙盒没有 process / Buffer 全局,入口先挂上(见 node.operit 的 BUILTINS.json) */\n' +
|
|
161
|
-
"globalThis.process = require('" + relative + "/dist/process.js');\n" +
|
|
162
|
-
"globalThis.Buffer = require('" + relative + "/dist/buffer.js').Buffer;\n";
|
|
172
|
+
// 注入正文(文件已在遍历阶段按种子收好,这里只贴前置代码)
|
|
173
|
+
if (entryPath !== '' && prelude !== '' && rewritten.has(entryPath)) {
|
|
163
174
|
rewritten.set(entryPath, prelude + rewritten.get(entryPath));
|
|
164
175
|
notes.push('已向入口 ' + entryPath + ' 注入 process / Buffer 全局');
|
|
165
176
|
}
|
|
@@ -8,8 +8,15 @@
|
|
|
8
8
|
* 以及 "// require('x')" 这种情况。
|
|
9
9
|
*/
|
|
10
10
|
export interface RequireSite {
|
|
11
|
-
/** require
|
|
12
|
-
spec: string;
|
|
11
|
+
/** require 的实参(已去引号、已解转义);**动态形式为 null** */
|
|
12
|
+
spec: string | null;
|
|
13
|
+
/**
|
|
14
|
+
* 无法静态分析(变量 / 模板串 / 字符串拼接 / 三元…)。
|
|
15
|
+
*
|
|
16
|
+
* 这类 require 打包器改不了,而 Operit 运行时对裸名**静默返回 {}** ——
|
|
17
|
+
* 于是依赖在业务里神秘失效。所以必须显式报错,不能放过。
|
|
18
|
+
*/
|
|
19
|
+
dynamic: boolean;
|
|
13
20
|
/** spec 在源码里的起止下标(不含引号),替换时用 */
|
|
14
21
|
start: number;
|
|
15
22
|
end: number;
|
package/dist/lib/js-requires.js
CHANGED
|
@@ -97,12 +97,29 @@ function findRequires(source) {
|
|
|
97
97
|
cursor += 1;
|
|
98
98
|
}
|
|
99
99
|
if (cursor < length) {
|
|
100
|
-
|
|
100
|
+
// 字面量后面若还跟着运算('a' + x / 'a' ? ...),实参其实是表达式。
|
|
101
|
+
// 以前这里会把它当成 'a' 去重写 —— 截断比忽略更糟,必须区分。
|
|
102
|
+
let after = cursor + 1;
|
|
103
|
+
while (after < length && /\s/.test(source[after])) {
|
|
104
|
+
after += 1;
|
|
105
|
+
}
|
|
106
|
+
const trailing = source[after];
|
|
107
|
+
const isExpression = trailing === '+' || trailing === '?' || trailing === '|' || trailing === '&';
|
|
108
|
+
sites.push({
|
|
109
|
+
spec: isExpression ? null : value,
|
|
110
|
+
dynamic: isExpression,
|
|
111
|
+
start: start,
|
|
112
|
+
end: cursor
|
|
113
|
+
});
|
|
101
114
|
index = cursor + 1;
|
|
102
115
|
previousMeaningful = quote;
|
|
103
116
|
continue;
|
|
104
117
|
}
|
|
105
118
|
}
|
|
119
|
+
else {
|
|
120
|
+
// 实参不是字符串字面量:变量 / 模板串 / 三元 / 函数调用…全部无法静态改写
|
|
121
|
+
sites.push({ spec: null, dynamic: true, start: cursor, end: cursor });
|
|
122
|
+
}
|
|
106
123
|
}
|
|
107
124
|
}
|
|
108
125
|
}
|
package/dist/lib/rewrite.js
CHANGED
|
@@ -150,6 +150,14 @@ function rewriteModule(env, archivePath, source) {
|
|
|
150
150
|
let output = source;
|
|
151
151
|
for (let index = sites.length - 1; index >= 0; index -= 1) {
|
|
152
152
|
const site = sites[index];
|
|
153
|
+
if (site.dynamic) {
|
|
154
|
+
// 改不了就必须说,不能默认放过:运行时对裸名静默返回 {},
|
|
155
|
+
// 症状会是"某个依赖神秘失效",比构建立刻失败难查得多。
|
|
156
|
+
errors.push(archivePath + ' 里存在无法静态分析的 require(偏移 ' + site.start + ')。\n' +
|
|
157
|
+
' 打包器无法改写它,而 Operit 运行时对裸名会静默返回 {} —— 依赖会在业务里失效而不报错。\n' +
|
|
158
|
+
' 请改成字符串字面量(require(\'fs\')),或拆成多分支的字面量 require。');
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
153
161
|
const spec = site.spec;
|
|
154
162
|
if (contract_1.RUNTIME_BUILTINS.includes(spec)) {
|
|
155
163
|
diagnostics.push({ file: archivePath, spec, kind: 'untouched', target: spec });
|