• Stars
    star
    1,842
  • Rank 25,059 (Top 0.5 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created about 8 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

πŸ“­ A powerful, simple, promise-based postMessage library.

A powerful, simple, promise-based postMessage iFrame communication library.

npm CircleCI Share

Postmate is a promise-based API built on postMessage. It allows a parent page to speak with a child iFrame across origins with minimal effort.

You can download the compiled javascript directly here


Features

Greenkeeper badge

  • Promise-based API for elegant and simple communication.
  • Secure two-way parent <-> child handshake, with message validation.
  • Child exposes a retrievable model object that the parent can access.
  • Child emits events that the parent can listen to.
  • Parent can call functions within a child
  • Zero dependencies. Provide your own polyfill or abstraction for the Promise API if needed.
  • Lightweight, weighing in at ~ 1.6kb (minified & gzipped).

NOTE: While the underlying mechanism is window.postMessage(), only iFrame is supported.

Installing

Postmate can be installed via NPM.

NPM

$ yarn add postmate # Install via Yarn
$ npm i postmate --save # Install via NPM

Glossary

  • Parent: The top level page that will embed an iFrame, creating a Child.
  • Child: The bottom level page loaded within the iFrame.
  • Model: The object that the Child exposes to the Parent.
  • Handshake: The process by which the parent frame identifies itself to the child, and vice versa. When a handshake is complete, the two contexts have bound their event listeners and identified one another.

Usage

  1. The Parent begins communication with the Child. A handshake is sent, the Child responds with a handshake reply, finishing Parent/Child initialization. The two are bound and ready to communicate securely.

  2. The Parent fetches values from the Child by property name. The Child can emit messages to the parent. The Parent can call functions in the Child Model.


Example

parent.com

// Kick off the handshake with the iFrame
const handshake = new Postmate({
  container: document.getElementById('some-div'), // Element to inject frame into
  url: 'http://child.com/page.html', // Page to load, must have postmate.js. This will also be the origin used for communication.
  name: 'my-iframe-name', // Set Iframe name attribute. Useful to get `window.name` in the child.
  classListArray: ["myClass"] //Classes to add to the iframe via classList, useful for styling.
});

// When parent <-> child handshake is complete, data may be requested from the child
handshake.then(child => {

  // Fetch the height property in child.html and set it to the iFrames height
  child.get('height')
    .then(height => child.frame.style.height = `${height}px`);

  // Listen to a particular event from the child
  child.on('some-event', data => console.log(data)); // Logs "Hello, World!"
});

child.com/page.html

const handshake = new Postmate.Model({
  // Expose your model to the Parent. Property values may be functions, promises, or regular values
  height: () => document.height || document.body.offsetHeight
});

// When parent <-> child handshake is complete, events may be emitted to the parent
handshake.then(parent => {
  parent.emit('some-event', 'Hello, World!');
});

API

Postmate.debug

// parent.com or child.com
Postmate.debug = true;
new Postmate(options);
Name Type Description Default
debug Boolean Set to true to enable logging of additional information false

Postmate.Promise

// parent.com or child.com
Postmate.Promise = RSVP.Promise;
new Postmate(options);
Name Type Description Default
Promise Object Replace the Promise API that Postmate uses window.Promise

Postmate(options)

// parent.com
new Postmate({
  container: document.body,
  url: 'http://child.com/',
  classListArray: ["myClass"]
  model: { foo: 'bar' }
});

This is written in the parent page. Creates an iFrame at the specified url. Initiates a connection with the child. Returns a Promise that signals when the handshake is complete and communication is ready to begin.

Returns: Promise(child)

Properties

Name Type Description Default
container (optional) DOM Node Element An element to append the iFrame to document.body
url String A URL to load in the iFrame. The origin of this URL will also be used for securing message transport none
classListArray Array An Array to add classes to the iFrame. Useful for styling none
model Object An object literal to represent the default values of the Childs model none

Postmate.Model(model)

// child.com
new Postmate.Model({
  // Serializable values
  foo: "bar",
  // Functions
  height: () => document.height || document.body.offsetHeight,
  // Promises
  data: fetch(new Request('data.json'))
});

This is written in the child page. Calling Postmate.Model initiates a handshake request listener from the Child. Once the handshake is complete, an event listener is bound to receive requests from the Parent. The Child model is extended from the model provided by the Parent.

Returns: Promise(handshakeMeta)

Parameters

Name Type Description Default
model Object An object of gettable properties to expose to the parent. Value types may be anything accepted in postMessage. Promises may also be set as values or returned from functions. {}

child.get(key)

// parent.com
new Postmate({
  container: document.body,
  url: 'http://child.com/'
}).then(child => {
  child.get('something').then(value => console.log(value));
});

Retrieves a value by property name from the Childs model object.

Returns: Promise(value)

Parameters

Name Type Description
key String (required) The string property to lookup in the childs model

child.call(key, data)

// parent.com
new Postmate({
  container: document.body,
  url: 'http://child.com/'
}).then(child => {
  child.call('sayHi', 'Hello, World!');
});

Calls the function sayHi in the Child Model with the parameter Hello, World!

Returns: undefined

Parameters

Name Type Description
key String (required) The string property to lookup in the childs model
data Mixed The optional data to send to the child function

child.destroy()

// parent.com
new Postmate({
  container: document.body,
  url: 'http://child.com/'
}).then(child => child.destroy());

Removes the iFrame element and destroys any message event listeners

Returns: undefined


child.frame

new Postmate(options).then(child => {
  child.get('height')
    .then(height => child.frame.style.height = `${height}px`);
});

The iFrame Element that the parent is communicating with

Troubleshooting/FAQ

General

Why use Promises for an evented API?

Promises provide a clear API for fetching data. Using an evented approach often starts backwards. if the parent wants to know the childs height, the child would need to alert the parent, whereas with Postmate, the Parent will request that information from the child in a synchronous-like manner. The child can emit events to the parent as well, for those other use-cases that still need to be handled.

Silent Parent/Child

I've enabled logging but the parent or child is not logging everything.

Postmate.debug needs to be set in both the parent and child for each of them to log their respective information

The child does not respond to communication from the Parent

Make sure that you have initialized Postmate.Model in your child page.

Restrictive Communication

I want to retrieve information from the parent by the child

Postmate (by design) is restrictive in its modes of communication. This enforces a simplistic approach: The parent is responsible for logic contained within the parent, and the child is responsible for logic contained within the child. If you need to retrieve information from parent -> child, consider setting a default model in the parent that the child may extend.

I want to send messages to the child from the parent

This is specifically what the call function is for.

Security

What is the Handshake and why do I need one?

By default, all message events received by any (parent) page can come from any (child) location. This means that the Parent must always enforce security within its message event, ensuring that the child (origin) is who we expect them to be, that the message is a response from an original request, and that our message is valid. The handshake routine solves this by saving the identities of the child and parent and ensuring that no changes are made to either.

How are messages validated?

The origin of the request, the message type, the postMessage mime-type, and in some cases the message response, are all verified against the original data made when the handshake was completed.

License

MIT

More Repositories

1

stickybits

Stickybits is a lightweight alternative to `position: sticky` polyfills 🍬
JavaScript
2,188
star
2

shave

πŸ’ˆ Shave is a 0 dep JS plugin that truncates text to fit within an element based on a set max-height ✁
JavaScript
2,110
star
3

reframe.js

πŸ–Ό Reframe unresponsive elements responsively.
JavaScript
1,598
star
4

scrolldir

0 dependency JS plugin to leverage scroll direction with CSS ⬆⬇ πŸ”ŒπŸ’‰
JavaScript
663
star
5

cloudworker

Run Cloudflare Worker scripts locally
JavaScript
518
star
6

es-check

Checks the version of ES in JavaScript files with simple shell commands πŸ†
JavaScript
460
star
7

ImageButter

Makes dealing with images buttery smooth.
C
394
star
8

furan

Scale out Docker builds
Go
344
star
9

study

A simple, progressive, client/server AB testing library πŸ“š
JavaScript
312
star
10

polymerase

A tool for populating templates with environment variables and Vault values
Go
85
star
11

react-passage

Link and Redirect to routes safely in your react applications πŸŒ„
JavaScript
58
star
12

package-diff

Diffs the packages used between two node_modules folders
JavaScript
57
star
13

ex_cluster

Clustered Elixir OTP application on Kubernetes with Horde and LibCluster
Elixir
52
star
14

ember-responds-to

Simple mixins for browser event handling.
JavaScript
41
star
15

fastboot-docker

[DEPRECATED] Ember FastBoot App Server in a box.
JavaScript
34
star
16

e2e

Make End-to-End Testing Great For Once
JavaScript
32
star
17

line

An easy to use golang package for stylizing terminal output
Go
27
star
18

ember-route-layers

Wire up your cancel buttons in easy mode.
JavaScript
26
star
19

ember-uni-form

Powerful forms without the confusion.
JavaScript
23
star
20

dynamo-drift

Go
23
star
21

terraform-provider-nrs

A Terraform provider for New Relic Synthetics
Go
22
star
22

monitor

A remote uptime monitoring framework for running monitors as a CRON job
JavaScript
21
star
23

vault-dev-docker

Vault docker image for local development
Shell
16
star
24

s3-uploader

Concurrent streaming upload to Amazon S3
Go
16
star
25

guardian

Go
13
star
26

ember-cli-anybar

A non-intrusive build notification system built atop AnyBar.
JavaScript
12
star
27

golang-protobuf-base-docker

Shell
9
star
28

psst

A secret sharing tool
Go
9
star
29

runtype

Runtype converts Typescript type aliases, interfaces, and enums to Javascript that can be used during runtime
JavaScript
9
star
30

vaultenvporter-go

A tool for turning a set of Vault secrets into environment variables
Go
8
star
31

talcum

Talcum allows members of a distributed system to auto-configure themselves πŸ‘₯
Go
8
star
32

harmless-changes

Ignore unnecessary build steps if changes are harmless to make builds faster 🏎 πŸ’¨
Shell
7
star
33

node-auto-repair-operator

A Kubernetes operator that can repair problematic nodes (under development)
Go
6
star
34

eslint-config-dollarshaveclub

Base eslint configs for Dollar Shave Club.
JavaScript
5
star
35

dependents

Shows package dependency versions in specified repositories
JavaScript
5
star
36

new-relic-synthetics-go

A New Relic Synthetics API client for Go
Go
5
star
37

pvc

Applications secrets access library
Go
4
star
38

Swift-WebP

Easy WebP usage in your iOS app!
C
4
star
39

ember-link-after-build

Symlink a folder in lieu of copying files for faster build times
JavaScript
4
star
40

fastboot-cluster-node-cache

A FastBoot app server cache built atop cluster-node-cache
JavaScript
3
star
41

jobmanager

Go
3
star
42

crudite

Go
3
star
43

go-productionize

A set of libraries that will help Go services be more production ready
Go
3
star
44

thermite

Removes old Amazon Elastic Container Registry images that are not deployed in a Kubernetes cluster
Go
2
star
45

go-lib

Go
2
star
46

sysctl-write-docker

Go
2
star
47

ember-shave

A simple wrapper over DSC's super fast and simple text truncation library called shave.
JavaScript
2
star
48

redis-resp

Go
2
star
49

ember-qualtrics

Ember Qualtrics Site Intercept addon.
JavaScript
1
star
50

eslint-plugin-dollarshaveclub

Linting code to shave the world.
JavaScript
1
star
51

ember-preapp-adapter

Request a payload before your Ember app has loaded.
JavaScript
1
star
52

go-for-newbs

Sample applications for people learning Go
Go
1
star
53

vault-shared-users

Vault Shared Users for securely allowing access to robot accounts across the organization
Go
1
star