Git Product home page Git Product logo

async-post-message's Introduction

Async Post Message

built with Codeium contributions welcome X (formerly Twitter) Follow

NPM

The async / await for window-based communication. Fully typed and works with Typescript, React, and NextJS.

const resp = await window.postMessage(req)

Demo

Demo

Motivation

I have been using the Javascript postMessage [docs] to communicate between frames, but have been frustrated that communication is not strongly guaranteed. You can send a message reliably, but there is no notion of an async call --> response. Rather, you can send a message to the other context and hope you get a response. You need to instrument listening to the correct response and yet this is still quite complex if you want to run an async request.

In this demo, I create a promise wrapper around the postMessage Javascript API and handle sending messages between contexts so that you can simply run await asyncPromise.send('functionName', [...args]) in your client code.

Installation

Installation with popular package managemers:

npm install async-post-message
yarn add async-post-message
bun install async-post-message

Usage

Getting Started

Define the promises types that you would like to execute across the frame contexts:

export type MyPromises = {
    getText: () => string;
    multiplyByFour: (n: number) => number;
};

The parent process needs to be set up to handle the promise requests:

var iframe: HTMLIFrameElement = ...;

const unsubscribe = handleWebViewRequest<MyPromises>(
    iframe.contentWindow,
    async (request) => {
        const { uid, functionName, args } = event.data;
        switch (functionName) {
            case "multiplyByFour": {
                iframeRef.current.contentWindow.postMessage({
                    uid,
                    functionName: "multiplyByFour",
                    response: 4 * args[0],
                });
                break;
            }
        }
    }
);

On the iFrame page (or other web view that can postMessage), create a new AsyncPostMessage singleton instance with the promise interface as the generic argument. You can then call execute with the function name and signature.

const asyncPostMessage = WebViewRequester.getInstance<MyPromises>();

// Execute the asynchronous request to the parent.
const response = await asyncPostMessage.execute("multiplyByFour", 4);
console.log(response); // 16

Usage in React

You may want to use this system in React. The big change here is that you'll want to wrap things in ref's and useEffects.

Define the promises types that you would like to execute across the frame contexts:

export type MyPromises = {
    getText: () => string;
    multiplyByFour: (n: number) => number;
    induceError: () => boolean;
};

Parent Window

The parent process needs to be set up to handle the promise requests:

const iframeRef = useRef<HTMLIFrameElement>(null);

useEffect(() => {
    if (!iframeRef.current?.contentWindow) return;

    const unsubscribe = handleWebViewRequest<MyPromises>(
        iframeRef.current.contentWindow,
        async (request) => {
        const { uid, functionName, args } = request;
        switch (functionName) {
            case "multiplyByFour": {
                const argsTyped = args as Parameters<MyPromises["multiplyByFour"]>;
                const response = 4 * argsTyped[0];
                return {
                    uid,
                    functionName: "multiplyByFour",
                    response,
                };
            }
        }
    );

    return () => {
        unsubscribe();
    };
}, []);

iFrame Web View

On the iFrame page, create a new AsyncPostMessage instance with the promise interface as the generic argument.

const asyncPostMessage = useRef(new AsyncPostMessage<MyPromises>());

// Check to ensure it can run in an iFrame.
useEffect(() => {
    if (!window) {
        setError(new Error("Not an iFrame"));
    }
    asyncPostMessage.current = WebViewRequester.getInstance<MyPromises>();
}, []);

Now to call a promise you can simply call the send():

const response = await asyncPostMessage.current.send("multiplyByFour", 4);
console.log(response); // 16

Development

Building

  1. yarn install
  2. yarn build which will generate the dist/ folder
  3. To deploy to NPM, run npm publish

Running Demo Locally

First, navigate to /apps/www.

  1. Install dependencies: bun install
  2. Run dev server: bun dev
  3. Open http://localhost:3000 with your browser to see the result.

async-post-message's People

Contributors

khou22 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

async-post-message's Issues

two way communication

Hi
there is a infinite loop happen when you want have 2 way send / receive from both iframe and iframe parent
this happens when i return response in message handler like this:

   return {
          uid,
          functionName,
          response: null,
        };

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.