Skip to content

Commit

Permalink
feat: allow loading config page from subdomain after sw registration (#…
Browse files Browse the repository at this point in the history
…96)

* refactor: remove unused helia andu se verified fetch

* chore: remove empty line

* fix: load config iframe using a hash fragment

fixes #88

* fix: load default config initially

* chore: fix linting errors

* chore: remove unused deps

* chore: re-add needed @helia/ipns dependency

* fix: set verifiedFetch when sw is activated

* chore: remove lib/heliaFetch and cleanup sw.ts

* feat: allow loading config page from subdomain after sw registration

* chore: remove unnecessary redirect

---------

Co-authored-by: Daniel N <2color@users.noreply.github.com>
  • Loading branch information
SgtPooki and 2color authored Mar 12, 2024
1 parent 0c81f2a commit 1201b22
Show file tree
Hide file tree
Showing 8 changed files with 40 additions and 17 deletions.
1 change: 0 additions & 1 deletion public/_redirects
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
/config /#/config 302
/* /?helia-sw=/:splat 302
10 changes: 8 additions & 2 deletions src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,19 @@ import RedirectPage from './redirectPage.tsx'

function App (): JSX.Element {
const { isConfigExpanded, setConfigExpanded } = useContext(ConfigContext)
const isRequestToViewConfigPage = isConfigPage(window.location.hash)
const isSubdomainRender = isPathOrSubdomainRequest(window.location)

if (isRequestToViewConfigPage) {
if (isSubdomainRender) {
return <RedirectPage />
}

if (isConfigPage()) {
setConfigExpanded(true)
return <Config />
}

if (isPathOrSubdomainRequest(window.location)) {
if (isSubdomainRender) {
return (<RedirectPage />)
}

Expand Down
1 change: 0 additions & 1 deletion src/components/config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ export default (): JSX.Element | null => {
return
}
// we get the iframe origin from a query parameter called 'origin', if this is loaded in an iframe
// TODO: why we need this origin here? where is targetOrigin used?
const targetOrigin = decodeURIComponent(window.location.hash.split('@origin=')[1])
const config = await getConfig()
trace('config-page: postMessage config to origin ', config, origin)
Expand Down
2 changes: 1 addition & 1 deletion src/context/config-context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const ConfigContext = createContext({

export const ConfigProvider = ({ children, expanded = isLoadedInIframe }: { children: JSX.Element[] | JSX.Element, expanded?: boolean }): JSX.Element => {
const [isConfigExpanded, setConfigExpanded] = useState(expanded)
const isExplicitlyLoadedConfigPage = isConfigPage()
const isExplicitlyLoadedConfigPage = isConfigPage(window.location.hash)

const setConfigExpandedWrapped = (value: boolean): void => {
if (isLoadedInIframe || isExplicitlyLoadedConfigPage) {
Expand Down
2 changes: 1 addition & 1 deletion src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const root = ReactDOMClient.createRoot(container)
root.render(
<React.StrictMode>
<ServiceWorkerProvider>
<ConfigProvider expanded={isConfigPage()}>
<ConfigProvider expanded={isConfigPage(window.location.hash)}>
<App />
</ConfigProvider>
</ServiceWorkerProvider>
Expand Down
7 changes: 3 additions & 4 deletions src/lib/is-config-page.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
export function isConfigPage (): boolean {
const isConfigPathname = window.location.pathname === '/config'
const isConfigHashPath = window.location.hash.startsWith('#/config') // needed for _redirects and IPFS hosted sw gateways
return isConfigPathname || isConfigHashPath
export function isConfigPage (hash: string): boolean {
const isConfigHashPath = hash.startsWith('#/ipfs-sw-config') // needed for _redirects and IPFS hosted sw gateways
return isConfigHashPath
}
14 changes: 10 additions & 4 deletions src/redirectPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import { ServiceWorkerContext } from './context/service-worker-context.tsx'
import { HeliaServiceWorkerCommsChannel } from './lib/channel.ts'
import { setConfig, type ConfigDb } from './lib/config-db.ts'
import { getSubdomainParts } from './lib/get-subdomain-parts'
import { isConfigPage } from './lib/is-config-page'
import { error, trace } from './lib/logger.ts'

const ConfigIframe = (): JSX.Element => {
const { parentDomain } = getSubdomainParts(window.location.href)

const portString = window.location.port === '' ? '' : `:${window.location.port}`
const iframeSrc = `${window.location.protocol}//${parentDomain}${portString}#/config@origin=${encodeURIComponent(window.location.origin)}`
const iframeSrc = `${window.location.protocol}//${parentDomain}${portString}#/ipfs-sw-config@origin=${encodeURIComponent(window.location.origin)}`

return (
<iframe id="redirect-config-iframe" src={iframeSrc} style={{ width: '100vw', height: '100vh', border: 'none' }} />
Expand Down Expand Up @@ -55,19 +56,24 @@ export default function RedirectPage (): JSX.Element {
}
}, [])

let reloadUrl = window.location.href
if (isConfigPage(window.location.hash)) {
reloadUrl = window.location.href.replace('#/ipfs-sw-config', '')
}

const displayString = useMemo(() => {
if (!isServiceWorkerRegistered) {
return 'Registering Helia service worker...'
}
if (isAutoReloadEnabled) {
if (isAutoReloadEnabled && !isConfigPage(window.location.hash)) {
return 'Redirecting you because Auto Reload is enabled.'
}

return 'Please save your changes to the config to apply them. You can then refresh the page to load your content.'
}, [isAutoReloadEnabled, isServiceWorkerRegistered])

useEffect(() => {
if (isAutoReloadEnabled && isServiceWorkerRegistered) {
if (isAutoReloadEnabled && isServiceWorkerRegistered && !isConfigPage(window.location.hash)) {
window.location.reload()
}
}, [isAutoReloadEnabled, isServiceWorkerRegistered])
Expand All @@ -76,7 +82,7 @@ export default function RedirectPage (): JSX.Element {
<div className="redirect-page">
<div className="pa4-l mw7 mv5 center pa4">
<h3 className="">{displayString}</h3>
<ServiceWorkerReadyButton id="load-content" label='Load content' waitingLabel='Waiting for service worker registration...' onClick={() => { window.location.reload() }} />
<ServiceWorkerReadyButton id="load-content" label='Load content' waitingLabel='Waiting for service worker registration...' onClick={() => { window.location.href = reloadUrl }} />
</div>
<ConfigIframe />
</div>
Expand Down
20 changes: 17 additions & 3 deletions src/sw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { HeliaServiceWorkerCommsChannel, type ChannelMessage } from './lib/chann
import { getConfig } from './lib/config-db.ts'
import { contentTypeParser } from './lib/content-type-parser.ts'
import { getSubdomainParts } from './lib/get-subdomain-parts.ts'
import { isConfigPage } from './lib/is-config-page.ts'
import { error, log, trace } from './lib/logger.ts'
import { findOriginIsolationRedirect } from './lib/path-or-subdomain.ts'

Expand Down Expand Up @@ -52,11 +53,11 @@ const updateVerifiedFetch = async (): Promise<void> => {
self.addEventListener('install', (event) => {
// 👇 When a new version of the SW is installed, activate immediately
void self.skipWaiting()
// ensure verifiedFetch is ready for use
event.waitUntil(updateVerifiedFetch())
})

self.addEventListener('activate', (event) => {
// ensure verifiedFetch is ready for use
event.waitUntil(updateVerifiedFetch())
/**
* 👇 Claim all clients immediately. This handles the case when subdomain is
* loaded for the first time, and config is updated and then a pre-fetch is
Expand Down Expand Up @@ -85,7 +86,11 @@ self.addEventListener('fetch', (event) => {
const urlString = request.url
const url = new URL(urlString)

if (!isValidRequestForSW(event)) {
if (isConfigPageRequest(url) || isSwAssetRequest(event)) {
// get the assets from the server
trace('helia-sw: config page or js asset request, ignoring ', urlString)
return
} else if (!isValidRequestForSW(event)) {
trace('helia-sw: not a valid request for helia-sw, ignoring ', urlString)
return
} else {
Expand Down Expand Up @@ -134,6 +139,10 @@ function isSubdomainRequest (event: FetchEvent): boolean {
return id != null && protocol != null
}

function isConfigPageRequest (url: URL): boolean {
return isConfigPage(url.hash)
}

function isValidRequestForSW (event: FetchEvent): boolean {
return isSubdomainRequest(event) || isRootRequestForContent(event)
}
Expand Down Expand Up @@ -163,6 +172,11 @@ function getVerifiedFetchUrl ({ protocol, id, path }: GetVerifiedFetchUrlOptions
return `${namespaceString}://${pathRootString}/${contentPath}`
}

function isSwAssetRequest (event: FetchEvent): boolean {
const isActualSwAsset = /^.+\/(?:ipfs-sw-).+\.js$/.test(event.request.url)
return isActualSwAsset
}

async function fetchHandler ({ path, request }: FetchHandlerArg): Promise<Response> {
/**
* > Any global variables you set will be lost if the service worker shuts down.
Expand Down

0 comments on commit 1201b22

Please sign in to comment.