From 70b20895fddb55a07f0b0458d6c1fff1ed5d8955 Mon Sep 17 00:00:00 2001 From: tomoam <29677552+tomoam@users.noreply.github.com> Date: Wed, 10 May 2023 21:33:44 +0900 Subject: [PATCH 1/3] chore: safari support --- src/lib/client/adapters/webcontainer/index.js | 9 +++++++-- src/routes/tutorial/[slug]/Loading.svelte | 7 ++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/lib/client/adapters/webcontainer/index.js b/src/lib/client/adapters/webcontainer/index.js index f3e2f4cb1..bfd7e64d0 100644 --- a/src/lib/client/adapters/webcontainer/index.js +++ b/src/lib/client/adapters/webcontainer/index.js @@ -16,6 +16,11 @@ const converter = new AnsiToHtml({ /** @type {import('@webcontainer/api').WebContainer} Web container singleton */ let vm; +function webcontainer_is_supported() { + // @ts-ignore + return 'function' === typeof Atomics.waitAsync; +} + /** * @param {import('svelte/store').Writable} base * @param {import('svelte/store').Writable} error @@ -25,8 +30,8 @@ let vm; * @returns {Promise} */ export async function create(base, error, progress, logs, warnings) { - if (/safari/i.test(navigator.userAgent) && !/chrome/i.test(navigator.userAgent)) { - throw new Error('WebContainers are not supported by Safari'); + if (/safari/i.test(navigator.userAgent) && !/chrome/i.test(navigator.userAgent) && !webcontainer_is_supported()) { + throw new Error('WebContainers are not supported by Safari 16.3 or earlier'); } progress.set({ value: 0, text: 'loading files' }); diff --git a/src/routes/tutorial/[slug]/Loading.svelte b/src/routes/tutorial/[slug]/Loading.svelte index cddea05a3..02ee032a3 100644 --- a/src/routes/tutorial/[slug]/Loading.svelte +++ b/src/routes/tutorial/[slug]/Loading.svelte @@ -10,11 +10,16 @@ /** @type {string} */ export let status; + + function webcontainer_is_supported() { + // @ts-ignore + return 'function' === typeof Atomics.waitAsync; + }
{#if error} - {#if /safari/i.test(navigator.userAgent) && !/chrome/i.test(navigator.userAgent)} + {#if /safari/i.test(navigator.userAgent) && !/chrome/i.test(navigator.userAgent) && !webcontainer_is_supported()}

This app requires modern web platform features. Please use a browser other than Safari.

{:else} {error.message} From 1d16a0011931ec5886bff5c487cc8e8b726efe2c Mon Sep 17 00:00:00 2001 From: tomoam <29677552+tomoam@users.noreply.github.com> Date: Thu, 11 May 2023 18:22:25 +0900 Subject: [PATCH 2/3] Revert "chore: safari support" This reverts commit 70b20895fddb55a07f0b0458d6c1fff1ed5d8955. --- src/lib/client/adapters/webcontainer/index.js | 9 ++------- src/routes/tutorial/[slug]/Loading.svelte | 7 +------ 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/src/lib/client/adapters/webcontainer/index.js b/src/lib/client/adapters/webcontainer/index.js index bfd7e64d0..f3e2f4cb1 100644 --- a/src/lib/client/adapters/webcontainer/index.js +++ b/src/lib/client/adapters/webcontainer/index.js @@ -16,11 +16,6 @@ const converter = new AnsiToHtml({ /** @type {import('@webcontainer/api').WebContainer} Web container singleton */ let vm; -function webcontainer_is_supported() { - // @ts-ignore - return 'function' === typeof Atomics.waitAsync; -} - /** * @param {import('svelte/store').Writable} base * @param {import('svelte/store').Writable} error @@ -30,8 +25,8 @@ function webcontainer_is_supported() { * @returns {Promise} */ export async function create(base, error, progress, logs, warnings) { - if (/safari/i.test(navigator.userAgent) && !/chrome/i.test(navigator.userAgent) && !webcontainer_is_supported()) { - throw new Error('WebContainers are not supported by Safari 16.3 or earlier'); + if (/safari/i.test(navigator.userAgent) && !/chrome/i.test(navigator.userAgent)) { + throw new Error('WebContainers are not supported by Safari'); } progress.set({ value: 0, text: 'loading files' }); diff --git a/src/routes/tutorial/[slug]/Loading.svelte b/src/routes/tutorial/[slug]/Loading.svelte index 02ee032a3..cddea05a3 100644 --- a/src/routes/tutorial/[slug]/Loading.svelte +++ b/src/routes/tutorial/[slug]/Loading.svelte @@ -10,16 +10,11 @@ /** @type {string} */ export let status; - - function webcontainer_is_supported() { - // @ts-ignore - return 'function' === typeof Atomics.waitAsync; - }
{#if error} - {#if /safari/i.test(navigator.userAgent) && !/chrome/i.test(navigator.userAgent) && !webcontainer_is_supported()} + {#if /safari/i.test(navigator.userAgent) && !/chrome/i.test(navigator.userAgent)}

This app requires modern web platform features. Please use a browser other than Safari.

{:else} {error.message} From bb8c059f155119532895d99d74b8cf0e938a6d11 Mon Sep 17 00:00:00 2001 From: tomoam <29677552+tomoam@users.noreply.github.com> Date: Thu, 11 May 2023 18:30:33 +0900 Subject: [PATCH 3/3] chore: safari support --- src/lib/client/adapters/webcontainer/index.js | 5 ++-- src/lib/client/adapters/webcontainer/utils.js | 30 +++++++++++++++++++ src/routes/tutorial/[slug]/Loading.svelte | 4 ++- 3 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 src/lib/client/adapters/webcontainer/utils.js diff --git a/src/lib/client/adapters/webcontainer/index.js b/src/lib/client/adapters/webcontainer/index.js index eb204ca26..3b98cd5ca 100644 --- a/src/lib/client/adapters/webcontainer/index.js +++ b/src/lib/client/adapters/webcontainer/index.js @@ -4,6 +4,7 @@ import AnsiToHtml from 'ansi-to-html'; import * as yootils from 'yootils'; import { escape_html, get_depth } from '../../../utils.js'; import { ready } from '../common/index.js'; +import { isWebContainerSupported } from './utils.js'; /** * @typedef {import("../../../../routes/tutorial/[slug]/state.js").CompilerWarning} CompilerWarning @@ -25,8 +26,8 @@ let vm; * @returns {Promise} */ export async function create(base, error, progress, logs, warnings) { - if (/safari/i.test(navigator.userAgent) && !/chrome/i.test(navigator.userAgent)) { - throw new Error('WebContainers are not supported by Safari'); + if (!isWebContainerSupported()) { + throw new Error('WebContainers are not supported by Safari 16.3 or earlier'); } progress.set({ value: 0, text: 'loading files' }); diff --git a/src/lib/client/adapters/webcontainer/utils.js b/src/lib/client/adapters/webcontainer/utils.js new file mode 100644 index 000000000..1d6c6a569 --- /dev/null +++ b/src/lib/client/adapters/webcontainer/utils.js @@ -0,0 +1,30 @@ +/** + * Checks if WebContainer is supported on the current browser. + * This function is borrowed from [stackblitz/webcontainer-docs](https://github.com/stackblitz/webcontainer-docs/blob/369dd58b2749b085ed7642f22108a9bcbcd68fc4/docs/.vitepress/theme/components/Examples/WCEmbed/utils.ts#L4-L29) + */ +export function isWebContainerSupported() { + const hasSharedArrayBuffer = 'SharedArrayBuffer' in window; + const looksLikeChrome = navigator.userAgent.toLowerCase().includes('chrome'); + const looksLikeFirefox = navigator.userAgent.includes('Firefox'); + const looksLikeSafari = navigator.userAgent.includes('Safari'); + + if (hasSharedArrayBuffer && (looksLikeChrome || looksLikeFirefox)) { + return true; + } + + if (hasSharedArrayBuffer && looksLikeSafari) { + // we only support Safari 16.4 and up so we check for the version here + const match = navigator.userAgent.match(/Version\/(\d+)\.(\d+) (?:Mobile\/.*?)?Safari/); + const majorVersion = match ? Number(match?.[1]) : 0; + const minorVersion = match ? Number(match?.[2]) : 0; + + return majorVersion > 16 || (majorVersion === 16 && minorVersion >= 4); + } + + // Allow overriding the support check with localStorage.webcontainer_any_ua = 1 + try { + return Boolean(localStorage.getItem('webcontainer_any_ua')); + } catch { + return false; + } +} diff --git a/src/routes/tutorial/[slug]/Loading.svelte b/src/routes/tutorial/[slug]/Loading.svelte index cddea05a3..7563a6514 100644 --- a/src/routes/tutorial/[slug]/Loading.svelte +++ b/src/routes/tutorial/[slug]/Loading.svelte @@ -1,4 +1,6 @@