@yangyongtao/gaea 1.1.30 → 1.1.31
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/CHANGELOG.md +7 -0
- package/package.json +1 -1
- package/src/vite-plugin.js +62 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.1.31] - 2026-09-09
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- Vite 插件 `transformIndexHtml` 自动给外部跨域 `<script src="http(s)://...">` 补 `crossorigin="anonymous"`:解决跨域隔离(COEP: require-corp)下第三方脚本因缺少 CORP 响应头被拦截(`NotSameOriginAfterDefaultedToSameOriginByCoep`)并阻塞页面加载的问题(如 `live.dcyun.com` 的 DcVideo.js 视频库)
|
|
7
|
+
- 注入前置脚本 hook `Node.prototype.appendChild/insertBefore`:第三方脚本内部 `document.createElement('script')` 动态加载的跨域子脚本自动补 `crossorigin`(DcVideo.js 内部的 jquery / DCHls / EasyWasmPlayer / ezuikit 等均可正常加载)
|
|
8
|
+
- 新增 `gaeaVitePlugin({ skipExternalScripts: [...] })` 配置:构建期移除匹配的外部脚本(字符串子串或正则),用于跳过跨域隔离下无法正常工作且当前未使用的第三方脚本
|
|
9
|
+
|
|
3
10
|
## [1.1.30] - 2026-09-09
|
|
4
11
|
|
|
5
12
|
### Added
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yangyongtao/gaea",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.31",
|
|
4
4
|
"description": "Gaea 3D visualization component library - Vue 3 components based on Godot WASM engine. Includes WMTS layer loading, camera view control, Vite plugin auto-injection, etc.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.cjs",
|
package/src/vite-plugin.js
CHANGED
|
@@ -55,7 +55,40 @@ const COEP_HEADERS = {
|
|
|
55
55
|
'Cross-Origin-Embedder-Policy': 'require-corp',
|
|
56
56
|
};
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
/**
|
|
59
|
+
* 给外部跨域 <script src="http(s)://..."> 自动补 crossorigin="anonymous"。
|
|
60
|
+
*
|
|
61
|
+
* 背景:Gaea 引擎要求跨域隔离(COEP: require-corp)。在 COEP 下,普通 no-cors
|
|
62
|
+
* 跨域脚本因缺少 Cross-Origin-Resource-Policy 响应头会被浏览器拦截(
|
|
63
|
+
* NotSameOriginAfterDefaultedToSameOriginByCoep),且同步脚本会挂起阻塞页面加载。
|
|
64
|
+
* 补上 crossorigin 后改为 CORS 模式加载,只要服务器返回 Access-Control-Allow-Origin
|
|
65
|
+
* 即可通过 COEP 检查。
|
|
66
|
+
*/
|
|
67
|
+
function addCrossOriginToExternalScripts(html) {
|
|
68
|
+
return html.replace(/<script\b([^>]*?)>/g, (match, attrs) => {
|
|
69
|
+
if (!/\bsrc="https?:\/\//.test(attrs)) return match;
|
|
70
|
+
if (/\bcrossorigin(=|[\s>])/i.test(attrs)) return match;
|
|
71
|
+
return match.replace(/^<script/, '<script crossorigin="anonymous"');
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* 移除 HTML 中匹配的外部 <script src="http(s)://..."> 标签。
|
|
77
|
+
* 用于跳过某些在跨域隔离(COEP)下无法正常工作、且当前项目并未使用的第三方脚本
|
|
78
|
+
* (如第三方视频播放库),避免它们拖慢首屏、产生无意义报错。
|
|
79
|
+
* @param {string} html
|
|
80
|
+
* @param {Array<string|RegExp>} rules 匹配规则:字符串按子串匹配 src,正则直接 test
|
|
81
|
+
*/
|
|
82
|
+
function skipExternalScriptTags(html, rules) {
|
|
83
|
+
if (!rules?.length) return html;
|
|
84
|
+
return html.replace(/<script\b([^>]*?src="(https?:\/\/[^"]+)"[^>]*)>[\s\S]*?<\/script>/g, (match, attrs, src) => {
|
|
85
|
+
const hit = rules.some((rule) => (rule instanceof RegExp ? rule.test(src) : String(src).includes(rule)));
|
|
86
|
+
return hit ? '' : match;
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export default function gaeaVitePlugin(options = {}) {
|
|
91
|
+
const skipScripts = options.skipExternalScripts || [];
|
|
59
92
|
let resolvedOutDir = '';
|
|
60
93
|
|
|
61
94
|
return {
|
|
@@ -166,6 +199,12 @@ export default function gaeaVitePlugin() {
|
|
|
166
199
|
},
|
|
167
200
|
|
|
168
201
|
transformIndexHtml(html) {
|
|
202
|
+
// 跳过配置中匹配的外部脚本(如项目未使用的第三方视频库)
|
|
203
|
+
html = skipExternalScriptTags(html, skipScripts);
|
|
204
|
+
|
|
205
|
+
// 外部跨域脚本自动补 crossorigin(绕过 COEP 拦截,避免阻塞页面)
|
|
206
|
+
html = addCrossOriginToExternalScripts(html);
|
|
207
|
+
|
|
169
208
|
// 自动注入 Gaea.js(消费者无需在 HTML 中手动写 <script src="/Gaea.js">)
|
|
170
209
|
if (!html.includes('/Gaea.js')) {
|
|
171
210
|
html = html.replace(
|
|
@@ -174,10 +213,31 @@ export default function gaeaVitePlugin() {
|
|
|
174
213
|
);
|
|
175
214
|
}
|
|
176
215
|
|
|
177
|
-
// 跨域隔离检测
|
|
216
|
+
// 跨域隔离检测 + 动态跨域脚本自动补 crossorigin(必须在 body 脚本执行前注入到 head)
|
|
178
217
|
html = html.replace(
|
|
179
218
|
'</head>',
|
|
180
219
|
`<script>
|
|
220
|
+
// 动态创建的跨域 <script> 自动补 crossorigin="anonymous":
|
|
221
|
+
// 跨域隔离(COEP)下,第三方脚本内部 document.createElement('script') 动态加载的子脚本
|
|
222
|
+
// 若不带 crossorigin 会被拦截(NotSameOriginAfterDefaultedToSameOriginByCoep)并阻塞页面。
|
|
223
|
+
(function () {
|
|
224
|
+
if (!window.crossOriginIsolated) return;
|
|
225
|
+
function fix(el) {
|
|
226
|
+
if (el && el.tagName === 'SCRIPT' && el.src && !el.crossOrigin) {
|
|
227
|
+
try {
|
|
228
|
+
if (new URL(el.src, location.href).origin !== location.origin) {
|
|
229
|
+
el.crossOrigin = 'anonymous';
|
|
230
|
+
}
|
|
231
|
+
} catch (e) {}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
var oa = Node.prototype.appendChild;
|
|
235
|
+
var oi = Node.prototype.insertBefore;
|
|
236
|
+
Node.prototype.appendChild = function (el) { fix(el); return oa.call(this, el); };
|
|
237
|
+
Node.prototype.insertBefore = function (el, ref) { fix(el); return oi.call(this, el, ref); };
|
|
238
|
+
})();
|
|
239
|
+
</script>
|
|
240
|
+
<script>
|
|
181
241
|
if (!window.crossOriginIsolated) {
|
|
182
242
|
if (!location.search.includes('gaea_isolated=1')) {
|
|
183
243
|
location.replace(location.href.split('?')[0] + '?gaea_isolated=1');
|