@galacean/effects-plugin-dom-content 2.9.1-beta.0 → 2.9.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/index.js +63 -39
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +2 -2
- package/dist/index.min.js.map +1 -1
- package/dist/index.mjs +63 -39
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Description: Galacean Effects plugin for rendering HTML/CSS DOM content as texture
|
|
4
4
|
* Author: Ant Group CO., Ltd.
|
|
5
5
|
* Contributors: 陈茉
|
|
6
|
-
* Version: v2.9.
|
|
6
|
+
* Version: v2.9.2
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
'use strict';
|
|
@@ -632,28 +632,39 @@ function _renderDOMToImage() {
|
|
|
632
632
|
"data:application/x-font"
|
|
633
633
|
];
|
|
634
634
|
/**
|
|
635
|
-
*
|
|
636
|
-
*
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
635
|
+
* 解码 HTML 实体(数字和常用命名实体),不做其他变换。
|
|
636
|
+
* 用于把从 HTML 字面字符串提取出的 URL 还原为 fetch 时浏览器实际会发起的 URL。
|
|
637
|
+
*
|
|
638
|
+
* 必须做这一步,否则 `<img src="...?a=1&b=2">` 提取到的字面 `&` 会被直接
|
|
639
|
+
* 拼进 XHR 请求,CDN 收到 `?a=1&b=2` 视作 query 参数名 `amp;b`,普遍返回 404。
|
|
640
|
+
*/ function decodeHtmlEntities(value) {
|
|
641
|
+
return value.replace(/&#x([0-9a-fA-F]+);?/g, function(_, hex) {
|
|
641
642
|
return String.fromCharCode(parseInt(hex, 16));
|
|
642
|
-
})
|
|
643
|
-
normalized = normalized.replace(/&#(\d+);?/g, function(_, dec) {
|
|
643
|
+
}).replace(/&#(\d+);?/g, function(_, dec) {
|
|
644
644
|
return String.fromCharCode(parseInt(dec, 10));
|
|
645
|
-
})
|
|
646
|
-
normalized = normalized.replace(/&(amp|lt|gt|quot|apos);/gi, function(match, name) {
|
|
645
|
+
}).replace(/&([a-zA-Z]+);/gi, function(match, name) {
|
|
647
646
|
var map = {
|
|
648
647
|
amp: "&",
|
|
649
648
|
lt: "<",
|
|
650
649
|
gt: ">",
|
|
651
650
|
quot: '"',
|
|
652
|
-
apos: "'"
|
|
651
|
+
apos: "'",
|
|
652
|
+
// 安全相关:协议分隔符和空白字符,防止绕过 isDangerousUrl 检查
|
|
653
|
+
colon: ":",
|
|
654
|
+
semi: ";",
|
|
655
|
+
tab: " ",
|
|
656
|
+
newline: "\n",
|
|
657
|
+
nbsp: "\xa0"
|
|
653
658
|
};
|
|
654
659
|
var _map_name_toLowerCase;
|
|
655
660
|
return (_map_name_toLowerCase = map[name.toLowerCase()]) != null ? _map_name_toLowerCase : match;
|
|
656
661
|
});
|
|
662
|
+
}
|
|
663
|
+
/**
|
|
664
|
+
* 规范化 URL 属性值:解码 HTML 实体和百分号编码,
|
|
665
|
+
* 移除控制字符和空白,转小写后检查是否包含危险协议
|
|
666
|
+
*/ function normalizeUrlAttr(value) {
|
|
667
|
+
var normalized = decodeHtmlEntities(value);
|
|
657
668
|
// 解码百分号编码
|
|
658
669
|
try {
|
|
659
670
|
normalized = decodeURIComponent(normalized);
|
|
@@ -966,15 +977,20 @@ function _inlineImageSources() {
|
|
|
966
977
|
4,
|
|
967
978
|
promisePool(urls.map(function(url) {
|
|
968
979
|
return /*#__PURE__*/ _async_to_generator(function() {
|
|
969
|
-
var _, _tmp, e;
|
|
980
|
+
var fetchUrl, _, _tmp, e;
|
|
970
981
|
return __generator(this, function(_state) {
|
|
971
982
|
switch(_state.label){
|
|
972
983
|
case 0:
|
|
984
|
+
// fetch 前必须解码 HTML 实体,否则 URL 含 & 等会被字面拼进请求,
|
|
985
|
+
// 导致 CDN 返回 404;Map key 仍用原始字符串,replaceUrls 才能精准匹配 HTML 原文。
|
|
986
|
+
fetchUrl = decodeHtmlEntities(url);
|
|
987
|
+
_state.label = 1;
|
|
988
|
+
case 1:
|
|
973
989
|
_state.trys.push([
|
|
974
|
-
|
|
975
|
-
|
|
990
|
+
1,
|
|
991
|
+
3,
|
|
976
992
|
,
|
|
977
|
-
|
|
993
|
+
4
|
|
978
994
|
]);
|
|
979
995
|
_ = urlToBase64.set;
|
|
980
996
|
_tmp = [
|
|
@@ -982,24 +998,24 @@ function _inlineImageSources() {
|
|
|
982
998
|
];
|
|
983
999
|
return [
|
|
984
1000
|
4,
|
|
985
|
-
fetchAsBase64(
|
|
1001
|
+
fetchAsBase64(fetchUrl)
|
|
986
1002
|
];
|
|
987
|
-
case
|
|
1003
|
+
case 2:
|
|
988
1004
|
_.apply(urlToBase64, _tmp.concat([
|
|
989
1005
|
_state.sent()
|
|
990
1006
|
]));
|
|
991
1007
|
return [
|
|
992
1008
|
3,
|
|
993
|
-
|
|
1009
|
+
4
|
|
994
1010
|
];
|
|
995
|
-
case
|
|
1011
|
+
case 3:
|
|
996
1012
|
e = _state.sent();
|
|
997
|
-
EFFECTS.logger.warn('inlineImageSources: Failed to fetch "' +
|
|
1013
|
+
EFFECTS.logger.warn('inlineImageSources: Failed to fetch "' + fetchUrl + '". ' + FETCH_FAIL_HINT, e);
|
|
998
1014
|
return [
|
|
999
1015
|
3,
|
|
1000
|
-
|
|
1016
|
+
4
|
|
1001
1017
|
];
|
|
1002
|
-
case
|
|
1018
|
+
case 4:
|
|
1003
1019
|
return [
|
|
1004
1020
|
2
|
|
1005
1021
|
];
|
|
@@ -1059,15 +1075,18 @@ function _inlineFontSources() {
|
|
|
1059
1075
|
4,
|
|
1060
1076
|
promisePool(urls.map(function(url) {
|
|
1061
1077
|
return /*#__PURE__*/ _async_to_generator(function() {
|
|
1062
|
-
var _, _tmp, e;
|
|
1078
|
+
var fetchUrl, _, _tmp, e;
|
|
1063
1079
|
return __generator(this, function(_state) {
|
|
1064
1080
|
switch(_state.label){
|
|
1065
1081
|
case 0:
|
|
1082
|
+
fetchUrl = decodeHtmlEntities(url);
|
|
1083
|
+
_state.label = 1;
|
|
1084
|
+
case 1:
|
|
1066
1085
|
_state.trys.push([
|
|
1067
|
-
|
|
1068
|
-
|
|
1086
|
+
1,
|
|
1087
|
+
3,
|
|
1069
1088
|
,
|
|
1070
|
-
|
|
1089
|
+
4
|
|
1071
1090
|
]);
|
|
1072
1091
|
_ = urlToBase64.set;
|
|
1073
1092
|
_tmp = [
|
|
@@ -1075,24 +1094,24 @@ function _inlineFontSources() {
|
|
|
1075
1094
|
];
|
|
1076
1095
|
return [
|
|
1077
1096
|
4,
|
|
1078
|
-
fetchAsBase64(
|
|
1097
|
+
fetchAsBase64(fetchUrl)
|
|
1079
1098
|
];
|
|
1080
|
-
case
|
|
1099
|
+
case 2:
|
|
1081
1100
|
_.apply(urlToBase64, _tmp.concat([
|
|
1082
1101
|
_state.sent()
|
|
1083
1102
|
]));
|
|
1084
1103
|
return [
|
|
1085
1104
|
3,
|
|
1086
|
-
|
|
1105
|
+
4
|
|
1087
1106
|
];
|
|
1088
|
-
case
|
|
1107
|
+
case 3:
|
|
1089
1108
|
e = _state.sent();
|
|
1090
|
-
EFFECTS.logger.warn('inlineFontSources: Failed to fetch font "' +
|
|
1109
|
+
EFFECTS.logger.warn('inlineFontSources: Failed to fetch font "' + fetchUrl + '". ' + FETCH_FAIL_HINT, e);
|
|
1091
1110
|
return [
|
|
1092
1111
|
3,
|
|
1093
|
-
|
|
1112
|
+
4
|
|
1094
1113
|
];
|
|
1095
|
-
case
|
|
1114
|
+
case 4:
|
|
1096
1115
|
return [
|
|
1097
1116
|
2
|
|
1098
1117
|
];
|
|
@@ -1273,10 +1292,14 @@ function _inlineFontSources() {
|
|
|
1273
1292
|
if (targetAttrs.includes(lowerName)) {
|
|
1274
1293
|
var base64 = urlToBase64.get(value);
|
|
1275
1294
|
if (base64) {
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1295
|
+
if (quote === null) {
|
|
1296
|
+
// 原属性无引号时必须补引号:base64 含 ;,/=+ 等字符,无引号会被 HTML parser
|
|
1297
|
+
// 在首个 ; 或空白处截断 src 值,导致图片加载失败。
|
|
1298
|
+
out += section.slice(nameStart, valueStart) + '"' + base64 + '"';
|
|
1299
|
+
} else {
|
|
1300
|
+
// 有引号时 section.slice(nameStart, valueStart) 已包含开引号,只需追加闭合引号。
|
|
1301
|
+
out += section.slice(nameStart, valueStart) + base64 + quote;
|
|
1302
|
+
}
|
|
1280
1303
|
i = attrEnd;
|
|
1281
1304
|
continue;
|
|
1282
1305
|
}
|
|
@@ -1323,6 +1346,7 @@ function _inlineFontSources() {
|
|
|
1323
1346
|
var MAX_FETCH_CONCURRENCY = 6; // 最大并发获取数
|
|
1324
1347
|
var MAX_RESOURCE_BYTES = 10 * 1024 * 1024; // 单个资源最大 10MB
|
|
1325
1348
|
var MAX_URLS = 100; // 单次内联处理的最大 URL 数量
|
|
1349
|
+
/** 内联资源 fetch 失败时附加的排查 hint,覆盖业务最常踩的三种原因 */ var FETCH_FAIL_HINT = "可能原因: (1) 资源服务器未开启 CORS(需 Access-Control-Allow-Origin 响应头); " + "(2) URL 不可访问 (404 / 403); (3) 网络异常。";
|
|
1326
1350
|
function promisePool(tasks, concurrency) {
|
|
1327
1351
|
return _promisePool.apply(this, arguments);
|
|
1328
1352
|
}
|
|
@@ -1716,7 +1740,7 @@ exports.DomContentComponent = __decorate([
|
|
|
1716
1740
|
EFFECTS.effectsClass(DATA_TYPE)
|
|
1717
1741
|
], exports.DomContentComponent);
|
|
1718
1742
|
|
|
1719
|
-
var version = "2.9.
|
|
1743
|
+
var version = "2.9.2";
|
|
1720
1744
|
EFFECTS.registerPlugin("dom-content", DomContentLoader);
|
|
1721
1745
|
EFFECTS.logger.info("Plugin dom-content version: " + version + ".");
|
|
1722
1746
|
if (version !== EFFECTS__namespace.version) {
|