Initial TrueGrowth source import
This commit is contained in:
236
apps/web/public/cdn-config.js
Normal file
236
apps/web/public/cdn-config.js
Normal file
@@ -0,0 +1,236 @@
|
||||
/**
|
||||
* CDN 智能选择器 - 在主应用加载前运行
|
||||
*
|
||||
* 功能:
|
||||
* 1. 检测可用的 CDN 源
|
||||
* 2. 选择最快的 CDN
|
||||
* 3. 将选择结果存储到 localStorage
|
||||
* 4. 供 Service Worker 使用
|
||||
*
|
||||
* 使用方式:
|
||||
* 在 index.html 的 <head> 中添加:
|
||||
* <script src="cdn-config.js"></script>
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var CDN_GLOBAL_KEY = '__OPENTU_CDN__';
|
||||
var CDN_API_GLOBAL_KEY = '__OPENTU_CDN_API__';
|
||||
var LEGACY_CDN_GLOBAL_KEY = '__AITU_CDN__';
|
||||
var LEGACY_CDN_API_GLOBAL_KEY = '__AITU_CDN_API__';
|
||||
var STORAGE_KEY = 'opentu-cdn-preference';
|
||||
var LEGACY_STORAGE_KEY = 'aitu-cdn-preference';
|
||||
|
||||
function setCDNPreference(value) {
|
||||
window[CDN_GLOBAL_KEY] = value;
|
||||
window[LEGACY_CDN_GLOBAL_KEY] = value;
|
||||
}
|
||||
|
||||
function getCDNPreference() {
|
||||
return window[CDN_GLOBAL_KEY] || window[LEGACY_CDN_GLOBAL_KEY] || null;
|
||||
}
|
||||
|
||||
function isSupportedCDNName(name) {
|
||||
for (var i = 0; i < CDN_SOURCES.length; i++) {
|
||||
if (CDN_SOURCES[i].name === name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return name === 'local';
|
||||
}
|
||||
|
||||
function setCDNApi(api) {
|
||||
window[CDN_API_GLOBAL_KEY] = api;
|
||||
window[LEGACY_CDN_API_GLOBAL_KEY] = api;
|
||||
}
|
||||
|
||||
|
||||
// 开发模式检测 - 本地开发时跳过 CDN 逻辑
|
||||
var isDevelopment = window.location.hostname === 'localhost' ||
|
||||
window.location.hostname === '127.0.0.1' ||
|
||||
window.location.hostname.endsWith('.localhost');
|
||||
|
||||
if (isDevelopment) {
|
||||
setCDNPreference({ cdn: 'local', latency: 0, timestamp: Date.now(), isDevelopment: true });
|
||||
setCDNApi({
|
||||
selectBestCDN: function() { return Promise.resolve(getCDNPreference()); },
|
||||
getCDNBaseUrl: function() { return null; },
|
||||
clearCDNCache: function() {},
|
||||
reselectCDN: function() { return Promise.resolve(getCDNPreference()); },
|
||||
sources: [],
|
||||
config: {},
|
||||
isDevelopment: true,
|
||||
});
|
||||
return; // 直接返回,不执行 CDN 检测
|
||||
}
|
||||
|
||||
// 配置
|
||||
var CONFIG = {
|
||||
packageName: 'aitu-app',
|
||||
storageKey: STORAGE_KEY,
|
||||
testTimeout: 5000, // 测试超时时间(毫秒)
|
||||
cacheExpiry: 3600000, // 缓存过期时间(1小时)
|
||||
};
|
||||
|
||||
// 运行时 CDN 候选:主 CDN 优先,备用 CDN 兜底
|
||||
var CDN_SOURCES = [
|
||||
{
|
||||
name: 'jsdelivr',
|
||||
baseUrl: 'https://cdn.jsdelivr.net/npm/' + CONFIG.packageName,
|
||||
testPath: '/version.json',
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* 测试单个 CDN 的响应时间
|
||||
*/
|
||||
function testCDN(source) {
|
||||
return new Promise(function(resolve) {
|
||||
var startTime = Date.now();
|
||||
var testUrl = source.baseUrl + source.testPath + '?t=' + startTime;
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.timeout = CONFIG.testTimeout;
|
||||
|
||||
xhr.onload = function() {
|
||||
if (xhr.status === 200) {
|
||||
var latency = Date.now() - startTime;
|
||||
resolve({ name: source.name, latency: latency, success: true });
|
||||
} else {
|
||||
resolve({ name: source.name, latency: Infinity, success: false });
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onerror = function() {
|
||||
resolve({ name: source.name, latency: Infinity, success: false });
|
||||
};
|
||||
|
||||
xhr.ontimeout = function() {
|
||||
resolve({ name: source.name, latency: Infinity, success: false });
|
||||
};
|
||||
|
||||
xhr.open('GET', testUrl, true);
|
||||
xhr.send();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择最快的 CDN
|
||||
*/
|
||||
function selectBestCDN() {
|
||||
// 检查缓存
|
||||
try {
|
||||
var cached =
|
||||
localStorage.getItem(CONFIG.storageKey) ||
|
||||
localStorage.getItem(LEGACY_STORAGE_KEY);
|
||||
if (cached) {
|
||||
var data = JSON.parse(cached);
|
||||
if (
|
||||
Date.now() - data.timestamp < CONFIG.cacheExpiry &&
|
||||
isSupportedCDNName(data.cdn)
|
||||
) {
|
||||
setCDNPreference(data);
|
||||
return Promise.resolve(data);
|
||||
}
|
||||
|
||||
if (!isSupportedCDNName(data.cdn)) {
|
||||
clearCDNCache();
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// 忽略解析错误
|
||||
}
|
||||
|
||||
// 并行测试所有 CDN
|
||||
var tests = CDN_SOURCES.map(testCDN);
|
||||
|
||||
return Promise.all(tests).then(function(results) {
|
||||
// 过滤成功的结果并按延迟排序
|
||||
var successfulResults = results
|
||||
.filter(function(r) { return r.success; })
|
||||
.sort(function(a, b) { return a.latency - b.latency; });
|
||||
|
||||
if (successfulResults.length === 0) {
|
||||
return { cdn: 'local', latency: 0, timestamp: Date.now(), allResults: results };
|
||||
}
|
||||
|
||||
var best = successfulResults[0];
|
||||
var preference = {
|
||||
cdn: best.name,
|
||||
latency: best.latency,
|
||||
timestamp: Date.now(),
|
||||
allResults: results,
|
||||
};
|
||||
|
||||
// 缓存结果
|
||||
try {
|
||||
localStorage.setItem(CONFIG.storageKey, JSON.stringify(preference));
|
||||
} catch (e) {
|
||||
// 忽略存储错误
|
||||
}
|
||||
|
||||
// 暴露到全局变量供 SW 使用
|
||||
setCDNPreference(preference);
|
||||
|
||||
return preference;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 CDN 基础 URL
|
||||
*/
|
||||
function getCDNBaseUrl(cdnName, version) {
|
||||
for (var i = 0; i < CDN_SOURCES.length; i++) {
|
||||
if (CDN_SOURCES[i].name === cdnName) {
|
||||
var baseUrl = CDN_SOURCES[i].baseUrl;
|
||||
if (version) {
|
||||
baseUrl = baseUrl.replace(CONFIG.packageName, CONFIG.packageName + '@' + version);
|
||||
}
|
||||
return baseUrl;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除 CDN 缓存(用于调试)
|
||||
*/
|
||||
function clearCDNCache() {
|
||||
try {
|
||||
localStorage.removeItem(CONFIG.storageKey);
|
||||
localStorage.removeItem(LEGACY_STORAGE_KEY);
|
||||
delete window[CDN_GLOBAL_KEY];
|
||||
delete window[LEGACY_CDN_GLOBAL_KEY];
|
||||
} catch (e) {
|
||||
// 忽略
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 强制重新选择 CDN
|
||||
*/
|
||||
function reselectCDN() {
|
||||
clearCDNCache();
|
||||
return selectBestCDN();
|
||||
}
|
||||
|
||||
// 暴露 API
|
||||
setCDNApi({
|
||||
selectBestCDN: selectBestCDN,
|
||||
getCDNBaseUrl: getCDNBaseUrl,
|
||||
clearCDNCache: clearCDNCache,
|
||||
reselectCDN: reselectCDN,
|
||||
sources: CDN_SOURCES,
|
||||
config: CONFIG,
|
||||
});
|
||||
|
||||
// 页面加载时自动选择 CDN(非阻塞)
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
selectBestCDN();
|
||||
});
|
||||
} else {
|
||||
// DOM 已加载完成
|
||||
selectBestCDN();
|
||||
}
|
||||
|
||||
})();
|
||||
Reference in New Issue
Block a user