@galacean/effects-plugin-dom-content 2.9.1 → 2.9.3
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.mjs
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.3
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import * as EFFECTS from '@galacean/effects';
|
|
@@ -609,28 +609,39 @@ function _renderDOMToImage() {
|
|
|
609
609
|
"data:application/x-font"
|
|
610
610
|
];
|
|
611
611
|
/**
|
|
612
|
-
*
|
|
613
|
-
*
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
612
|
+
* 解码 HTML 实体(数字和常用命名实体),不做其他变换。
|
|
613
|
+
* 用于把从 HTML 字面字符串提取出的 URL 还原为 fetch 时浏览器实际会发起的 URL。
|
|
614
|
+
*
|
|
615
|
+
* 必须做这一步,否则 `<img src="...?a=1&b=2">` 提取到的字面 `&` 会被直接
|
|
616
|
+
* 拼进 XHR 请求,CDN 收到 `?a=1&b=2` 视作 query 参数名 `amp;b`,普遍返回 404。
|
|
617
|
+
*/ function decodeHtmlEntities(value) {
|
|
618
|
+
return value.replace(/&#x([0-9a-fA-F]+);?/g, function(_, hex) {
|
|
618
619
|
return String.fromCharCode(parseInt(hex, 16));
|
|
619
|
-
})
|
|
620
|
-
normalized = normalized.replace(/&#(\d+);?/g, function(_, dec) {
|
|
620
|
+
}).replace(/&#(\d+);?/g, function(_, dec) {
|
|
621
621
|
return String.fromCharCode(parseInt(dec, 10));
|
|
622
|
-
})
|
|
623
|
-
normalized = normalized.replace(/&(amp|lt|gt|quot|apos);/gi, function(match, name) {
|
|
622
|
+
}).replace(/&([a-zA-Z]+);/gi, function(match, name) {
|
|
624
623
|
var map = {
|
|
625
624
|
amp: "&",
|
|
626
625
|
lt: "<",
|
|
627
626
|
gt: ">",
|
|
628
627
|
quot: '"',
|
|
629
|
-
apos: "'"
|
|
628
|
+
apos: "'",
|
|
629
|
+
// 安全相关:协议分隔符和空白字符,防止绕过 isDangerousUrl 检查
|
|
630
|
+
colon: ":",
|
|
631
|
+
semi: ";",
|
|
632
|
+
tab: " ",
|
|
633
|
+
newline: "\n",
|
|
634
|
+
nbsp: "\xa0"
|
|
630
635
|
};
|
|
631
636
|
var _map_name_toLowerCase;
|
|
632
637
|
return (_map_name_toLowerCase = map[name.toLowerCase()]) != null ? _map_name_toLowerCase : match;
|
|
633
638
|
});
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* 规范化 URL 属性值:解码 HTML 实体和百分号编码,
|
|
642
|
+
* 移除控制字符和空白,转小写后检查是否包含危险协议
|
|
643
|
+
*/ function normalizeUrlAttr(value) {
|
|
644
|
+
var normalized = decodeHtmlEntities(value);
|
|
634
645
|
// 解码百分号编码
|
|
635
646
|
try {
|
|
636
647
|
normalized = decodeURIComponent(normalized);
|
|
@@ -943,15 +954,20 @@ function _inlineImageSources() {
|
|
|
943
954
|
4,
|
|
944
955
|
promisePool(urls.map(function(url) {
|
|
945
956
|
return /*#__PURE__*/ _async_to_generator(function() {
|
|
946
|
-
var _, _tmp, e;
|
|
957
|
+
var fetchUrl, _, _tmp, e;
|
|
947
958
|
return __generator(this, function(_state) {
|
|
948
959
|
switch(_state.label){
|
|
949
960
|
case 0:
|
|
961
|
+
// fetch 前必须解码 HTML 实体,否则 URL 含 & 等会被字面拼进请求,
|
|
962
|
+
// 导致 CDN 返回 404;Map key 仍用原始字符串,replaceUrls 才能精准匹配 HTML 原文。
|
|
963
|
+
fetchUrl = decodeHtmlEntities(url);
|
|
964
|
+
_state.label = 1;
|
|
965
|
+
case 1:
|
|
950
966
|
_state.trys.push([
|
|
951
|
-
|
|
952
|
-
|
|
967
|
+
1,
|
|
968
|
+
3,
|
|
953
969
|
,
|
|
954
|
-
|
|
970
|
+
4
|
|
955
971
|
]);
|
|
956
972
|
_ = urlToBase64.set;
|
|
957
973
|
_tmp = [
|
|
@@ -959,24 +975,24 @@ function _inlineImageSources() {
|
|
|
959
975
|
];
|
|
960
976
|
return [
|
|
961
977
|
4,
|
|
962
|
-
fetchAsBase64(
|
|
978
|
+
fetchAsBase64(fetchUrl)
|
|
963
979
|
];
|
|
964
|
-
case
|
|
980
|
+
case 2:
|
|
965
981
|
_.apply(urlToBase64, _tmp.concat([
|
|
966
982
|
_state.sent()
|
|
967
983
|
]));
|
|
968
984
|
return [
|
|
969
985
|
3,
|
|
970
|
-
|
|
986
|
+
4
|
|
971
987
|
];
|
|
972
|
-
case
|
|
988
|
+
case 3:
|
|
973
989
|
e = _state.sent();
|
|
974
|
-
logger.warn('inlineImageSources: Failed to fetch "' +
|
|
990
|
+
logger.warn('inlineImageSources: Failed to fetch "' + fetchUrl + '". ' + FETCH_FAIL_HINT, e);
|
|
975
991
|
return [
|
|
976
992
|
3,
|
|
977
|
-
|
|
993
|
+
4
|
|
978
994
|
];
|
|
979
|
-
case
|
|
995
|
+
case 4:
|
|
980
996
|
return [
|
|
981
997
|
2
|
|
982
998
|
];
|
|
@@ -1036,15 +1052,18 @@ function _inlineFontSources() {
|
|
|
1036
1052
|
4,
|
|
1037
1053
|
promisePool(urls.map(function(url) {
|
|
1038
1054
|
return /*#__PURE__*/ _async_to_generator(function() {
|
|
1039
|
-
var _, _tmp, e;
|
|
1055
|
+
var fetchUrl, _, _tmp, e;
|
|
1040
1056
|
return __generator(this, function(_state) {
|
|
1041
1057
|
switch(_state.label){
|
|
1042
1058
|
case 0:
|
|
1059
|
+
fetchUrl = decodeHtmlEntities(url);
|
|
1060
|
+
_state.label = 1;
|
|
1061
|
+
case 1:
|
|
1043
1062
|
_state.trys.push([
|
|
1044
|
-
|
|
1045
|
-
|
|
1063
|
+
1,
|
|
1064
|
+
3,
|
|
1046
1065
|
,
|
|
1047
|
-
|
|
1066
|
+
4
|
|
1048
1067
|
]);
|
|
1049
1068
|
_ = urlToBase64.set;
|
|
1050
1069
|
_tmp = [
|
|
@@ -1052,24 +1071,24 @@ function _inlineFontSources() {
|
|
|
1052
1071
|
];
|
|
1053
1072
|
return [
|
|
1054
1073
|
4,
|
|
1055
|
-
fetchAsBase64(
|
|
1074
|
+
fetchAsBase64(fetchUrl)
|
|
1056
1075
|
];
|
|
1057
|
-
case
|
|
1076
|
+
case 2:
|
|
1058
1077
|
_.apply(urlToBase64, _tmp.concat([
|
|
1059
1078
|
_state.sent()
|
|
1060
1079
|
]));
|
|
1061
1080
|
return [
|
|
1062
1081
|
3,
|
|
1063
|
-
|
|
1082
|
+
4
|
|
1064
1083
|
];
|
|
1065
|
-
case
|
|
1084
|
+
case 3:
|
|
1066
1085
|
e = _state.sent();
|
|
1067
|
-
logger.warn('inlineFontSources: Failed to fetch font "' +
|
|
1086
|
+
logger.warn('inlineFontSources: Failed to fetch font "' + fetchUrl + '". ' + FETCH_FAIL_HINT, e);
|
|
1068
1087
|
return [
|
|
1069
1088
|
3,
|
|
1070
|
-
|
|
1089
|
+
4
|
|
1071
1090
|
];
|
|
1072
|
-
case
|
|
1091
|
+
case 4:
|
|
1073
1092
|
return [
|
|
1074
1093
|
2
|
|
1075
1094
|
];
|
|
@@ -1250,10 +1269,14 @@ function _inlineFontSources() {
|
|
|
1250
1269
|
if (targetAttrs.includes(lowerName)) {
|
|
1251
1270
|
var base64 = urlToBase64.get(value);
|
|
1252
1271
|
if (base64) {
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1272
|
+
if (quote === null) {
|
|
1273
|
+
// 原属性无引号时必须补引号:base64 含 ;,/=+ 等字符,无引号会被 HTML parser
|
|
1274
|
+
// 在首个 ; 或空白处截断 src 值,导致图片加载失败。
|
|
1275
|
+
out += section.slice(nameStart, valueStart) + '"' + base64 + '"';
|
|
1276
|
+
} else {
|
|
1277
|
+
// 有引号时 section.slice(nameStart, valueStart) 已包含开引号,只需追加闭合引号。
|
|
1278
|
+
out += section.slice(nameStart, valueStart) + base64 + quote;
|
|
1279
|
+
}
|
|
1257
1280
|
i = attrEnd;
|
|
1258
1281
|
continue;
|
|
1259
1282
|
}
|
|
@@ -1300,6 +1323,7 @@ function _inlineFontSources() {
|
|
|
1300
1323
|
var MAX_FETCH_CONCURRENCY = 6; // 最大并发获取数
|
|
1301
1324
|
var MAX_RESOURCE_BYTES = 10 * 1024 * 1024; // 单个资源最大 10MB
|
|
1302
1325
|
var MAX_URLS = 100; // 单次内联处理的最大 URL 数量
|
|
1326
|
+
/** 内联资源 fetch 失败时附加的排查 hint,覆盖业务最常踩的三种原因 */ var FETCH_FAIL_HINT = "可能原因: (1) 资源服务器未开启 CORS(需 Access-Control-Allow-Origin 响应头); " + "(2) URL 不可访问 (404 / 403); (3) 网络异常。";
|
|
1303
1327
|
function promisePool(tasks, concurrency) {
|
|
1304
1328
|
return _promisePool.apply(this, arguments);
|
|
1305
1329
|
}
|
|
@@ -1693,7 +1717,7 @@ DomContentComponent = __decorate([
|
|
|
1693
1717
|
effectsClass(DATA_TYPE)
|
|
1694
1718
|
], DomContentComponent);
|
|
1695
1719
|
|
|
1696
|
-
var version = "2.9.
|
|
1720
|
+
var version = "2.9.3";
|
|
1697
1721
|
registerPlugin("dom-content", DomContentLoader);
|
|
1698
1722
|
logger.info("Plugin dom-content version: " + version + ".");
|
|
1699
1723
|
if (version !== EFFECTS.version) {
|