npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@factoryfour/frame-client

v1.9.3

Published

Allows a page to communicate over `postMessage` with multiple iframes.

Downloads

116

Readme

frame-client

Allows a page to communicate over postMessage with multiple iframes.

Example

Check out /example/app and /example/frame for example usage in React.

Backwards Compatibility

This client can be used within frames that use the older FETCH_DATA protocol built into FactoryFour order & task frames:

const client = new FrameClient();
client.on('initial', data => {
    // do something with initial data
});
client.on('update', data => {
    // do something with updated data
});

// this promise won't be resolved, but the parent window will send 'initial' and 'update'
client.connectParentWindow(); 

// works as usual
client.send('REQUEST_TYPE', payload);

Usage

Parent page

const iframe = document.getElementById('my-iframe');
const client = new FrameClient();
const origin = 'http://domain-where-iframe-is-hosted.com';

// Get ready to handle messages from the frame
client.on('ok_here_is_the_sum', data => {
    console.log('The frame computed the sum: ' + data.sum);
});

// Connect to the iframe
client.connectChildIframe(iframe, origin).then(() => {
    // This will be called when the handshake is complete
    client.send('here_is_some_initial_data', {a: 3, b: 5});
});

// Make as many iframes as you want!
const iframe2 = document.getElementById('another-iframe');
const client2 = new FrameClient();
client2.connectChildIframe(iframe2, origin);

Child (inside the frame)

const client = new FrameClient();

client.on('here_is_some_initial_data', data => {
    const { a, b } = data;
    client.send('ok_here_is_the_sum', {sum: a + b});
});

client.connectParentWindow().then(() => {
    // This will also be called when the handshake is complete
    console.log('Ready to start doing some sums!');
})

Handshake Protocol

This all happens under the hood, and hopefully knowledge of this protocol is not required to use this library in an application.

1. Parent Frame

  • Parent Frame creates an iframe, and ends up with a ref to the iframe HTML element
  • Parent Frame picks a unique "channel ID" to use for this particular frame
  • Parent Frame calls the FrameManager singleton's register method
    • This adds the FrameClient to the global list of FrameClients
    • This can happen before or after the frame is loaded
  • Parent Frame sends CHANNEL_ID just in case the frame is already loaded

2. Child Frame

  • The iframe loads. Its contents must be using this same repo! If not, none of this will work
  • The iframe knows its parent window (window.parent) but does not yet know its channel ID
  • The iframe sends a postMessage to window.parent with type=REQUEST_CHANNEL_IDS

3. Parent Frame

  • FrameManager is always listening for REQUEST_CHANNEL_IDS.
  • When it hears this, it sends type=CHANNEL_ID with the particular channel ID for EACH frame to ALL frames
    • We don't know the source of the REQUEST_CHANNEL_IDS message, so other frames will unexpectedly get notified of their CHANNEL_ID even though they didn't ask for it
      • Technically, we could deduce the source of the message by comparing it to all the contentWindow references we have stored. But this is brittle because if any of the iframes happens to reload, its contentWindow reference will become obsolete
      • Instead, when an iframe reloads, it just sends REQUEST_CHANNEL_IDS again and gets back the same channel ID it had before, allowing the "conversation" to continue

4. Child Frame

  • The iframe hears CHANNEL_ID and switches to the channel protocol, sending a SYN with along with the channelId it just received

5. Parent Frame

  • Parent frame hears SYN on a channel and sends ACK on that channel
  • The promise returned by connectChildIframe or connectChildWindow gets resolved

6. Child Frame

  • The iframe hears ACK and then it considers its connection established\
  • The promise returned by connectParentWindow gets resolved
  • At this point the connection is open and any application-layer message protocol can be carried out on this channel