开启自带的js minify之后实机调试出现 Uncaught TypeError: n is not a function 一类的报错。
通过调试工具查看 usr/app-service.js 之后发现似乎是minify的过程中将函数inline再加上重命名导致函数参数和外部函数发生混淆,怀疑是微信使用的老版本uglify-js的bug。(详情见最后面)
如果可能的话尽量不考虑修改js规避问题的解决方案,因为我js是从Kotlin编译出来的,要修改编译出来的js很麻烦。
自己做了一些简单实验,没有成功用简单代码片段来复现问题。
自己安装最新版uglify-js后手动minify出来是没有问题的,所以最佳解决方法应该是自定义minify过程,但在文档和社区没找到相关的资料。只知道有预编译shell指令之类的,但我不想让脚本修改项目中原始文件,否则在开发环境调试会很麻烦。最好的情况是脚本只影响实机调试和打包上传的代码,不影响开发工具内原始代码(就像自带的minify一样),但是不知道怎么实现。
项目仓库:https://github.com/shBLOCK/SolarUtils(因为是Kotlin项目所以结构很奇怪,微信开发者工具项目在wechat文件夹中。其中wechat/miniprogram/index/src中的代码是根目录中的gradle项目编译生成的。如果需要详细构建测试流程的话回复一下。)
原始代码(完整原始代码:https://gist.github.com/shBLOCK/5cad5d1ea2e2701f103d52100061e888):
function layout(_this__u8e3s4, layout) {
_this__u8e3s4.o5t(layout);
return _this__u8e3s4;
}
......
function addPanelSurface(_this__u8e3s4, colors, sizes, name, backgroundColor, layout, block) {
colors = colors === _kotlin_kotlin_stdlib_mjs__WEBPACK_IMPORTED_MODULE_0__.VOID7hggqo3abtya ? Companion_getInstance_44().p5l() : colors;
sizes = sizes === _kotlin_kotlin_stdlib_mjs__WEBPACK_IMPORTED_MODULE_0__.VOID7hggqo3abtya ? Companion_getInstance_48().h5q_1 : sizes;
name = name === _kotlin_kotlin_stdlib_mjs__WEBPACK_IMPORTED_MODULE_0__.VOID7hggqo3abtya ? 'Panel' : name;
var tmp;
if (backgroundColor === _kotlin_kotlin_stdlib_mjs__WEBPACK_IMPORTED_MODULE_0__.VOID7hggqo3abtya) {
tmp = addPanelSurface$lambda(colors);
} else {
tmp = backgroundColor;
}
backgroundColor = tmp;
layout = layout === _kotlin_kotlin_stdlib_mjs__WEBPACK_IMPORTED_MODULE_0__.VOID7hggqo3abtya ? ColumnLayout_instance : layout;
var panelSurface = PanelSurface(colors, sizes, name, backgroundColor, layout, block);
_this__u8e3s4.j5q(panelSurface);
return panelSurface;
}
function PanelSurface(colors, sizes, name, backgroundColor, layout, block) {
colors = colors === _kotlin_kotlin_stdlib_mjs__WEBPACK_IMPORTED_MODULE_0__.VOID7hggqo3abtya ? Companion_getInstance_44().p5l() : colors;
sizes = sizes === _kotlin_kotlin_stdlib_mjs__WEBPACK_IMPORTED_MODULE_0__.VOID7hggqo3abtya ? Companion_getInstance_48().h5q_1 : sizes;
name = name === _kotlin_kotlin_stdlib_mjs__WEBPACK_IMPORTED_MODULE_0__.VOID7hggqo3abtya ? 'Panel' : name;
var tmp;
if (backgroundColor === _kotlin_kotlin_stdlib_mjs__WEBPACK_IMPORTED_MODULE_0__.VOID7hggqo3abtya) {
tmp = PanelSurface$lambda;
} else {
tmp = backgroundColor;
}
backgroundColor = tmp;
layout = layout === _kotlin_kotlin_stdlib_mjs__WEBPACK_IMPORTED_MODULE_0__.VOID7hggqo3abtya ? ColumnLayout_instance : layout;
var panelSurface = UiSurface.k5q(colors, sizes, name);
var tmp_0 = panelSurface;
tmp_0.w5p_1 = PanelSurface$lambda_0(backgroundColor, layout, name, block);
return panelSurface;
}
function Panel(_this__u8e3s4, backgroundColor_0, layout_0, scopeName, block) {
backgroundColor_0 = backgroundColor_0 === _kotlin_kotlin_stdlib_mjs__WEBPACK_IMPORTED_MODULE_0__.VOID7hggqo3abtya ? _this__u8e3s4.e5g().w5l_1 : backgroundColor_0;
layout_0 = layout_0 === _kotlin_kotlin_stdlib_mjs__WEBPACK_IMPORTED_MODULE_0__.VOID7hggqo3abtya ? ColumnLayout_instance : layout_0;
scopeName = scopeName === _kotlin_kotlin_stdlib_mjs__WEBPACK_IMPORTED_MODULE_0__.VOID7hggqo3abtya ? null : scopeName;
// Inline function 'de.fabmax.kool.modules.ui2.Box' call
var box = _this__u8e3s4.x5e().a5g(scopeName, (0,_kotlin_kotlin_stdlib_mjs__WEBPACK_IMPORTED_MODULE_0__.getKClass1s3j9wy1cofik)(BoxNode), Companion_getInstance_42().p5d_1);
size(box.g5e(), FitContent_instance, FitContent_instance);
// Inline function 'de.fabmax.kool.modules.ui2.Panel.<anonymous>' call
backgroundColor(layout(box.g5e(), layout_0), backgroundColor_0);
block(box);
}
minify后的代码片段(IDE pretty-print后的minify代码):
var _ = function (t, i, r, e, n, s) {
var a;
t = t === Ks.VOID7hggqo3abtya ? hO().p5l() : t, i = i === Ks.VOID7hggqo3abtya ? pO().h5q_1 : i, r = r === Ks.VOID7hggqo3abtya ? "Panel" : r, a = e === Ks.VOID7hggqo3abtya ? bO : e, e = a, n = n === Ks.VOID7hggqo3abtya ? Di : n;
var h = ud.k5q(t, i, r);
return h.w5p_1 = function (t, i, r, e) {
return s => (function (t, i, r, e, s) {
i = i === Ks.VOID7hggqo3abtya ? t.e5g().w5l_1 : i, r = r === Ks.VOID7hggqo3abtya ? Di : r, e = e === Ks.VOID7hggqo3abtya ? null : e;
var a = t.x5e().a5g(e, (0, Ks.getKClass1s3j9wy1cofik)(hf), nO().p5d_1);
RO(a.g5e(), Fi, Fi), function (t, i) {
t.q5t(null != i ? new td(i) : null)
}(n(a.g5e(), r), i), s(a)
}(s, t(s), i, r, e), Ks.Unit_instance14hm69wy3kr8u)
}(e, n, r, s), h
}(i, r, e, n, s, a);ke
可以通过 g5e() 函数来帮助对应两段代码。可以发现原代码中倒数第三行中对layout的调用变成了对变量n(原名layout)的调用。
开发者工具:最新(1.06.2412050 win32-x64)
这个地方可以让我们有运行一个脚本的能力。
比如node install terser之后,运行以下脚本node precompile.js。
// precompile.js 任意喜欢的压缩工具 const { minify } = require("terser"); await minify( ...........
看了一下原项目,可以让压缩后文件名为index.min.js 。index.js里面require的地方改成 index.min.js 。kotlin gen出来的依然保持 index.js。
这样可以实现自定义压缩,但是开发者工具里运行时也用的是压缩的代码。然后开发者工具里对sourcemap的支持似乎不是很好,导致调试会很难受。不过后来发现其实可以用conditional compilation解决。或者只在需要真机调试和上传的时候手动运行一下压缩。
总之其实不算特别严重的问题,就是麻烦点。但可以考虑官方更新一下uglifyjs?(没有向后兼容问题的话)