Skip to content

Commit

Permalink
feat: defer iframe load (#3219)
Browse files Browse the repository at this point in the history
  • Loading branch information
tomiir authored Nov 19, 2024
1 parent 27e4ea3 commit f33aa3b
Show file tree
Hide file tree
Showing 11 changed files with 72 additions and 8 deletions.
25 changes: 25 additions & 0 deletions .changeset/brave-balloons-wait.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
'@apps/laboratory': patch
'@reown/appkit-wallet': patch
'@apps/demo': patch
'@apps/gallery': patch
'@reown/appkit-adapter-ethers': patch
'@reown/appkit-adapter-ethers5': patch
'@reown/appkit-adapter-polkadot': patch
'@reown/appkit-adapter-solana': patch
'@reown/appkit-adapter-wagmi': patch
'@reown/appkit': patch
'@reown/appkit-utils': patch
'@reown/appkit-cdn': patch
'@reown/appkit-common': patch
'@reown/appkit-core': patch
'@reown/appkit-experimental': patch
'@reown/appkit-polyfills': patch
'@reown/appkit-scaffold-ui': patch
'@reown/appkit-siwe': patch
'@reown/appkit-siwx': patch
'@reown/appkit-ui': patch
---

Update secure site url to include version 2.0.0 parameter.
Defers frame load until it's needed on email or social connection or reconnection.
3 changes: 3 additions & 0 deletions apps/laboratory/tests/email.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ emailTest.beforeAll(async ({ browser, library }) => {
}
email = new Email(mailsacApiKey)
tempEmail = await email.getEmailAddressToUse()

// Iframe should not be injected until needed
validator.expectSecureSiteFrameNotInjected()
await page.emailFlow(tempEmail, context, mailsacApiKey)

await validator.expectConnected()
Expand Down
3 changes: 3 additions & 0 deletions apps/laboratory/tests/siwe-email.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ emailSiweTest.beforeAll(async ({ browser, library }) => {
}
const email = new Email(mailsacApiKey)
const tempEmail = await email.getEmailAddressToUse()

// Iframe should not be injected until needed
validator.expectSecureSiteFrameNotInjected()
await page.emailFlow(tempEmail, context, mailsacApiKey)
await page.promptSiwe()
await page.approveSign()
Expand Down
3 changes: 3 additions & 0 deletions apps/laboratory/tests/siwe-sa.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ smartAccountSiweTest.beforeAll(async ({ browser, library }) => {
await validator.expectSwitchedNetworkOnNetworksView('Polygon')
await page.closeModal()
const tempEmail = await email.getEmailAddressToUse()

// Iframe should not be injected until needed
validator.expectSecureSiteFrameNotInjected()
await page.emailFlow(tempEmail, context, mailsacApiKey)
await page.promptSiwe()
await page.approveSign()
Expand Down
4 changes: 4 additions & 0 deletions apps/laboratory/tests/smart-account.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ smartAccountTest.beforeAll(async ({ browser, library }) => {
if (!mailsacApiKey) {
throw new Error('MAILSAC_API_KEY is not set')
}

// Iframe should not be injected until needed
validator.expectSecureSiteFrameNotInjected()

const email = new Email(mailsacApiKey)

// Switch to a SA enabled network
Expand Down
3 changes: 3 additions & 0 deletions apps/laboratory/tests/wallet-features.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ walletFeaturesTest.beforeAll(async ({ browser, browserName, library }) => {
}
const email = new Email(mailsacApiKey)
const tempEmail = await email.getEmailAddressToUse()

// Iframe should not be injected until needed
validator.expectSecureSiteFrameNotInjected()
await page.emailFlow(tempEmail, context, mailsacApiKey)

await validator.expectConnected()
Expand Down
2 changes: 1 addition & 1 deletion packages/appkit/exports/constants.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export const PACKAGE_VERSION = '1.4.1'
export const PACKAGE_VERSION = '1.5.0'
22 changes: 16 additions & 6 deletions packages/wallet/src/W3mFrame.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { SECURE_SITE_SDK, W3mFrameConstants } from './W3mFrameConstants.js'
import { SECURE_SITE_SDK, SECURE_SITE_SDK_VERSION, W3mFrameConstants } from './W3mFrameConstants.js'
import { W3mFrameSchema } from './W3mFrameSchema.js'
import { W3mFrameHelpers } from './W3mFrameHelpers.js'
import type { W3mFrameTypes } from './W3mFrameTypes.js'
Expand Down Expand Up @@ -39,26 +39,35 @@ export class W3mFrame {
if (W3mFrameHelpers.isClient) {
const iframe = document.createElement('iframe')
iframe.id = 'w3m-iframe'
iframe.src = `${SECURE_SITE_SDK}?projectId=${projectId}&chainId=${chainId}`
iframe.src = `${SECURE_SITE_SDK}?projectId=${projectId}&chainId=${chainId}&version=${SECURE_SITE_SDK_VERSION}`
iframe.name = 'w3m-secure-iframe'
iframe.style.position = 'fixed'
iframe.style.zIndex = '999999'
iframe.style.display = 'none'
iframe.style.animationDelay = '0s, 50ms'
iframe.style.borderBottomLeftRadius = `clamp(0px, var(--wui-border-radius-l), 44px)`
iframe.style.borderBottomRightRadius = `clamp(0px, var(--wui-border-radius-l), 44px)`
document.body.appendChild(iframe)
this.iframe = iframe
this.iframe.onload = () => {
this.frameLoadPromiseResolver?.resolve(undefined)
}
this.iframe.onerror = () => {
this.frameLoadPromiseResolver?.reject('Unable to load email login dependency')
}

this.events.onFrameEvent(event => {
if (event.type === '@w3m-frame/READY') {
this.frameLoadPromiseResolver?.resolve(undefined)
}
})
}
}
}

public initFrame = () => {
const isFrameInitialized = document.getElementById('w3m-iframe')
if (this.iframe && !isFrameInitialized) {
document.body.appendChild(this.iframe)
}
}

// -- Networks --------------------------------------------------------------
get networks(): Record<string, W3mFrameTypes.Network> {
const data = [
Expand Down Expand Up @@ -136,6 +145,7 @@ export class W3mFrame {
) {
return
}

const frameEvent = W3mFrameSchema.frameEvent.parse(data)
callback(frameEvent)
})
Expand Down
2 changes: 2 additions & 0 deletions packages/wallet/src/W3mFrameConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ export const SECURE_SITE_SDK =

export const DEFAULT_LOG_LEVEL = process.env['NEXT_PUBLIC_DEFAULT_LOG_LEVEL'] || 'error'

export const SECURE_SITE_SDK_VERSION = process.env['NEXT_PUBLIC_SECURE_SITE_SDK_VERSION'] || 2

export const W3mFrameConstants = {
APP_EVENT_KEY: '@w3m-app/',
FRAME_EVENT_KEY: '@w3m-frame/',
Expand Down
7 changes: 7 additions & 0 deletions packages/wallet/src/W3mFrameProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ export class W3mFrameProvider {
this.w3mLogger = new W3mFrameLogger(projectId)
this.w3mFrame = new W3mFrame(projectId, true, chainId)
this.onTimeout = onTimeout
if (this.getLoginEmailUsed()) {
this.w3mFrame.initFrame()
}
}

// -- Extended Methods ------------------------------------------------
Expand All @@ -47,6 +50,7 @@ export class W3mFrameProvider {
public async connectEmail(payload: W3mFrameTypes.Requests['AppConnectEmailRequest']) {
try {
W3mFrameHelpers.checkIfAllowedToTriggerEmail()
this.w3mFrame.initFrame()
const response = await this.appEvent<'ConnectEmail'>({
type: W3mFrameConstants.APP_CONNECT_EMAIL,
payload
Expand Down Expand Up @@ -119,6 +123,8 @@ export class W3mFrameProvider {
payload: W3mFrameTypes.Requests['AppGetSocialRedirectUriRequest']
) {
try {
this.w3mFrame.initFrame()

return this.appEvent<'GetSocialRedirectUri'>({
type: W3mFrameConstants.APP_GET_SOCIAL_REDIRECT_URI,
payload
Expand Down Expand Up @@ -283,6 +289,7 @@ export class W3mFrameProvider {

public async getFarcasterUri() {
try {
this.w3mFrame.initFrame()
const response = await this.appEvent<'GetFarcasterUri'>({
type: W3mFrameConstants.APP_GET_FARCASTER_URI
} as W3mFrameTypes.AppEvent)
Expand Down
6 changes: 5 additions & 1 deletion packages/wallet/tests/W3mFrameProvider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,11 @@ describe('W3mFrameProvider', () => {
it(
'should timeout after 30 seconds',
async () => {
const postAppEventSpy = vi.spyOn(provider['w3mFrame'].events, 'postAppEvent')
const postAppEventSpy = vi
.spyOn(provider['w3mFrame'].events, 'postAppEvent')
.mockImplementation(() => {
// Do nothing
})

const mockTimeoutSpy = vi.spyOn(provider, 'onTimeout')

Expand Down

0 comments on commit f33aa3b

Please sign in to comment.