diff --git a/index.html b/index.html index bd539cb..618cce0 100644 --- a/index.html +++ b/index.html @@ -8,11 +8,7 @@ - + {{#if process.env.NODE_ENV === 'development' }} diff --git a/public/appfont.ttf b/public/appfont.ttf new file mode 100644 index 0000000..0bd7eb0 Binary files /dev/null and b/public/appfont.ttf differ diff --git a/public/favicon.ico b/public/favicon.ico index ca9a21a..c73851a 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/src/components/banner.vue b/src/components/banner.vue index 4acd392..71c47c2 100644 --- a/src/components/banner.vue +++ b/src/components/banner.vue @@ -43,7 +43,7 @@ .info { display: flex; flex-direction: column; - width: 212px; + width: 256px; padding: 8px 12px; background: var(--color-plain-1); diff --git a/src/lib/checks.js b/src/lib/checks.js index 4ff824c..5cc2c0a 100644 --- a/src/lib/checks.js +++ b/src/lib/checks.js @@ -4,8 +4,15 @@ * @date 2023/07/18 19:11:01 */ +import { IS_SAFARI } from './env.js' + // 用canvas检测图形/图象的支持 export function checkCanvas(type) { + // macos下的safari, 调用webgpu,会崩溃 + // 所以, webgpu不能用canvas调用来判断 + if (type == 'webgpu') { + return !!navigator.gpu ^ 0 + } try { var canvas = document.createElement('canvas') var ctx = canvas.getContext(type) @@ -16,10 +23,9 @@ export function checkCanvas(type) { } } -export function checkMedia(type, isAudio = true) { +export function checkMedia(type, isAudio = 1) { let ctx = isAudio ? new Audio() : document.createElement('video') let res = ctx.canPlayType(type) - console.log(isAudio, res) if (res === 'maybe' || res === 'probably') { return 1 } diff --git a/src/lib/env.js b/src/lib/env.js index 6ebc69e..5422c2c 100644 --- a/src/lib/env.js +++ b/src/lib/env.js @@ -4,18 +4,23 @@ * @date 2023/07/18 16:16:02 */ -const UA = navigator.userAgent.toLowerCase() -const UNKNOW_MATCH = [null, 'unknow'] +const UNKNOW = 'Unknow' -const IS_CHROME = !!window.chrome -const IS_FIREFOX = !!window.sidebar +export const UA = navigator.userAgent.toLowerCase() +export const UNKNOW_MATCH = [null, UNKNOW] -const IS_LINUX = UA.includes('linux') -const IS_WIN = UA.includes('windows nt') -const IS_ANDROID = UA.includes('android') -const IS_IOS = +/* 分辨率 */ +const SCREEN = `${screen.width} x ${screen.height}` + +/* 操作系统 */ +export const IS_LINUX = UA.includes('linux') +export const IS_WIN = UA.includes('windows nt') +export const IS_MACOS = UA.includes('mac os x') + +export const IS_ANDROID = UA.includes('android') +export const IS_IOS = UA.includes('iphone') || UA.includes('ipad') || UA.includes('ipod') -const IS_MOBILE = IS_ANDROID || IS_IOS || UA.includes('mobile') +export const IS_MOBILE = IS_ANDROID || IS_IOS || UA.includes('mobile') const OS_NAME = IS_ANDROID ? 'Android' @@ -25,12 +30,18 @@ const OS_NAME = IS_ANDROID ? 'Linux' : IS_WIN ? 'Windows' - : 'MacOS' + : IS_MACOS + ? 'MacOS' + : UNKNOW const OS_VERSION = IS_ANDROID ? UA.match(/android ([\d\.]*?);/)[1] : '' -const SCREEN = `${screen.width} x ${screen.height}` +/* 浏览器 */ +export const IS_CHROME = !!window.chrome +export const IS_FIREFOX = 'MozAppearance' in document.documentElement.style +export const IS_SAFARI = (IS_MACOS || IS_IOS) && !!window.safari -const BROWSER_NAME = IS_IOS +/* 浏览器名称 */ +const BROWSER_NAME = IS_SAFARI ? 'Safari' : IS_CHROME ? 'Chrome' @@ -38,16 +49,25 @@ const BROWSER_NAME = IS_IOS ? 'Firefox' : 'Unknow' +/* 浏览器版本 */ const GENERAL_VERSION = UA.match(/version\/([\d\.]*?) /) || UNKNOW_MATCH -const CHROME_VERSION = - IS_CHROME && (UA.match(/chrome\/([\d\.]*?) /) || UNKNOW_MATCH) -const IPAD_WEBKIT_VERSION = - IS_IOS && (UA.match(/crios\/([\d\.]*?) /) || GENERAL_VERSION) +const CHROME_VERSION = UA.match(/chrome\/([\d\.]*?) /) || UNKNOW_MATCH +const IPAD_WEBKIT_VERSION = UA.match(/crios\/([\d\.]*?) /) || GENERAL_VERSION +const FIREFOX_VERSION = UA.match(/firefox\/([\d\.]*)/) || UNKNOW_MATCH const BROWSER_VERSION = IS_IOS ? IPAD_WEBKIT_VERSION[1] : IS_CHROME ? CHROME_VERSION[1] + : IS_FIREFOX + ? FIREFOX_VERSION[1] : GENERAL_VERSION[1] +// 是否支持 Import assertions +export const SUPPORT_ASSERTIONS = IS_CHROME + ? CHROME_VERSION[1].split('.').shift() > 91 + : IS_SAFARI + ? GENERAL_VERSION[1].split('.').shift() >= 15 + : false + export { OS_NAME, OS_VERSION, BROWSER_NAME, BROWSER_VERSION, SCREEN } diff --git a/src/store.js b/src/store.js index 9a0e402..dd976a2 100644 --- a/src/store.js +++ b/src/store.js @@ -12,7 +12,7 @@ const store = reactive({ { name: '音频支持', total: 0, - factor: 80, + factor: 70, scores: [ !!window.AudioContext ^ 0, checkMedia('audio/wav'), @@ -29,19 +29,17 @@ const store = reactive({ 'flac support', 'aac support', 'ogg support', - 'webm support', - 'Dolby Digital support', - 'Dolby Digital Plus support' + 'webm support' ] }, { name: '视频支持', total: 0, - factor: 80, + factor: 70, scores: [ checkMedia('video/mp4; codecs="mp4v.20.8"', 0), checkMedia('video/mp4', 0), - checkMedia('video/mp4; codecs="hev1"', 0), + checkMedia('video/mp4; codecs="hev1"', 0) * 1.1, checkMedia('video/ogg', 0), checkMedia('video/webm; codecs="vp8"', 0), checkMedia('video/webm; codecs="vp9"', 0) @@ -58,7 +56,20 @@ const store = reactive({ { name: '流媒体', total: 0, - scores: [1, 1, 0, 0], + scores: [ + 1, + !!navigator.requestMediaKeySystemAccess ^ 0, + MediaSource.isTypeSupported( + 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"' + ) + ? 1.1 + : 0, + MediaSource.isTypeSupported( + 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"' + ) + ? 1.1 + : 0 + ], factor: 100, items: [ 'Media Source extensions', @@ -67,30 +78,6 @@ const store = reactive({ 'HTTP Live Streaming / HLS' ] }, - { - name: '自定义组件', - total: 0, - factor: 80, - scores: [ - !!window.customElements ^ 0, - !!document.body.attachShadow ^ 0, - !!document.adoptedStyleSheets ^ 0 - ], - items: ['Custom elements', 'Shadow DOM', 'adoptedStyleSheets'] - }, - { - name: '图形图象支持', - total: 0, - factor: 120, - scores: [ - checkCanvas('2d'), - checkCanvas('webgl'), - checkCanvas('webgl2'), - checkCanvas('webgpu'), - !!navigator.xr ^ 0 - ], - items: ['canvas 2D', 'WebGL', 'WebGL 2', 'WebGPU', 'WebVR'] - }, { name: '网络', total: 0, @@ -107,11 +94,106 @@ const store = reactive({ 'fetch api', 'ArrayBuffer and Blob support' ] + }, + { + name: '数据流', + factor: 80, + total: 0, + scores: [ + !!window.FileSystemHandle ^ 0, + !!window.ReadableStream ^ 0, + !!window.WritableStream ^ 0 + ], + items: ['File System', 'Readable Stream', 'Writable Stream'] + }, + { + name: '自定义组件', + total: 0, + factor: 80, + scores: [ + !!window.customElements ^ 0, + !!document.body.attachShadow ^ 0, + document.adoptedStyleSheets ? 1.1 : 0 + ], + items: ['Custom elements', 'Shadow DOM', 'adoptedStyleSheets'] + }, + { + name: '图形图象支持', + total: 0, + factor: 120, + scores: [ + checkCanvas('2d'), + checkCanvas('webgl'), + checkCanvas('webgl2') * 1.1, + checkCanvas('webgpu') * 2, + navigator.xr ? 2 : 0 + ], + items: ['canvas 2D', 'WebGL', 'WebGL 2', 'WebGPU', 'WebVR'] + }, + { + name: '点对点连接', + total: 0, + factor: 40, + scores: [ + !!( + window.RTCPeerConnection || + window.webkitRTCPeerConnection || + window.mozRTCPeerConnection + ) ^ 0, + window.RTCIceTransport || + window.webkitRTCIceTransport || + window.mozRTCIceTransport + ? 2.5 + : 0, + !!navigator.getUserMedia ^ 0, + navigator.mediaDevices && navigator.mediaDevices.getDisplayMedia + ? 1.5 + : 0, + !!window.MediaRecorder ^ 0 + ], + items: [ + 'WebRTC 1.0', + 'ObjectRTC API for WebRTC', + 'Access the webcam', + 'Screen Capture', + 'Media Stream recorder' + ] + }, + { + name: 'ES6模块', + total: 0, + factor: 40, + scores: [1, env.SUPPORT_ASSERTIONS ? 2.5 : 0], + items: ['import/export', 'Import assertions'] + }, + { + name: '性能', + total: 0, + factor: 70, + scores: [!!navigator.serviceWorker ^ 0, window.WebAssembly ? 1.5 : 0], + items: ['Web Workers', 'WebAssembly'] + }, + { + name: '其他', + total: 0, + factor: 80, + scores: [ + !!navigator.bluetooth ^ 0, + navigator.clipboard ? 0.8 : 0, + navigator.usb ? 2 : 0, + !!navigator.windowControlsOverlay ^ 0 + ], + items: ['Bluetooth', 'clipboard', 'USB', 'Window Controls Overlay'] } ] }) -store.modules.forEach(it => (it.total = it.items.length)) +store.modules.forEach( + it => ( + (it.total = it.items.length), + (it.passed = it.scores.filter(n => n > 0).length) + ) +) store.scores = store.modules.map(it => it.scores.sum() * it.factor).sum() export default function (app) { diff --git a/src/views/main.vue b/src/views/main.vue index 3af6954..c32e88a 100644 --- a/src/views/main.vue +++ b/src/views/main.vue @@ -4,7 +4,7 @@ {{ it.name }} - {{ it.scores.sum() }}/{{ it.total }} + {{ it.passed }}/{{ it.total }}