1.0.25 • Published 2 years ago

@tnotifier/embed v1.0.25

Weekly downloads
-
License
GPL-3.0-only
Repository
github
Last release
2 years ago

@tnotifier/embed provides a single Vue 3 hook which can be used to communicate between an iFrame and its parent via postMessage IPC.

  • sync/async messaging/responses
  • Configurable timeouts
  • Bi-directional communication
  • Cross-origin support
  • Same usage/API for both Host & Client
  • Support for enforcing origins for increased security
  • No limit to number of instances you can use/create at any given time
  • TypeScript
  • Tiny (1.73kb)

Installation

This package is available via NPM:

yarn add @tnotifier/embed

# or

npm install @tnotifier/embed

Usage

For this example, we'll assume the host is a webpage (example.com) and the client is a webpage embedded in an iFrame (frame.example.com). The only difference between a host and a client is that the host requires an iFrame ref for binding and sending the messages.

/**
 * Host
 */
<template>
    <iframe
        src="https://frame.example.com"
        ref="iframe"
        sandbox="allow-scripts"
    />
</template>

<script lang="ts" setup>
    import { useEmbed } from '@tnotifier/embed';
    import { ref, onMounted } from 'vue';

    const iframe = ref<InstanceType<typeof HTMLIFrame>>();

    const { send, events } = useEmbed('host', {
        id: 'shared-id',
        iframe,
        remote: 'https://frame.example.com',
    });

    // Listen for any synchronous events being emitted over IPC
    events.on('yay', payload => {
        console.log(payload);
    });

    onMounted(async () => {
        // Send an event to the iFrame and wait for a response.
        const response = await send('hello-world', {
            hello: 'world',
        });
    });
</script>

/**
 * Client
 */
<template>
    <button @click.prevent="submit">Click me!</button>
</template>

<script lang="ts" setup>
    import { useEmbed } from '@tnotifier/embed';

    const { handle, post } = useEmbed('client', {
        id: 'shared-id',
        remote: 'https://example.com',
    });

    // Resolves incoming (a)synchronous operations.
    handle('hello-world', async (payload) => {
        if (payload.hello === 'world') {
            return 'hey';
        }

        return 'go away';
    });

    const submit = () => {
        // Send a synchronous event to the host
        post('yay', { test: 123 });
    };
</script>

This example shows:

  • Initializing the Host and Client
  • Sending and waiting for asynchronous events
  • Sending and receiving synchronous events

Since communication is bi-directional, you can use any of the methods on either Host or Client. For example, asynchronous operations aren't limited to Host -> Client, the Client can also call asynchronous operations and the Host can register handlers/resolvers.

OptionDefaultTypeDescription
idRequiredstringThe Host and Client that you want to talk to each other should share the _same_ ID.
timeout15000numberConfigures the global timeout for all asynchronous operations against this ID pair.
iframeRequired for HostRef<InstanceType<typeof HTMLIFrame>>A Vue 3 ref for a Template reference.
remote*stringA remote URL to limit who can recieve/process Events over this Host/Client pair.
debugfalsebooleanWhether to print Debug messages to the console, providing an overview of the IPC process.

Security Note

By default, if you don't supply a remote, the library will process all incoming messages and send events that any party can recieve. By setting this to a URL (See above example), you can limit this and hugely reduce the impact it has on security.

To-do

  • Add a test suite
1.0.25

2 years ago

1.0.24

2 years ago