Code Monkey home page Code Monkey logo

ihop's Introduction

IHop: The <iframe> Hopping Library

IHop is a utility to allow for objects and functions from one iframe context to be usable from many connected contexts - even cross-origin - as though those objects were local.

The term "iframe hopping" refers to the fact that each participant in the "network" (tree, really) of window objects only communicates only with it's immediate parent and children. Sending messages to window contexts beyond the immediate family must be done by routing through each intermediate node(s) (ie. hopping).

At its core, IHop is three things:

  1. A proxy engine that can generate proxies for complex objects (even DOM elements!)
  2. A network-agnostic routing fabric designed for hierarchical topologies
  3. A globally-coherent state built on top of the routing fabric

Table of Contents

Get It

  1. Clone the repository
  2. npm install
  3. npm run build

You will then have ihop.js and ihop.min.js in the ./dist directory. They are both UMD modules and therefore should work with the most popular module systems or as a script tag.

NOTE: The non-minified file does very noisy console.debug logging of every message that goes through the Router and should only be used for development.

Quick Usage

Step1 - Include IHop on your page

<script type="text/javascript" src="ihop.min.js"></script>

Step 2 - Initialize ihop

  const ihop = new IHop('pick_a_namespace');

Step 3a - Either export an object...

  ihop.export('test', { foo: 'bar' });

Step 3b - ...or a function

  ihop.export('func', () => 'Hello world!');

Step 4 - Use what you exported from another iframe or the parent context

<script type="text/javascript">
  // This is assuming that we are in another iframe:
  Promise.all([
    ihop.import('pick_a_namespace.test'),
    ihop.import('pick_a_namespace.func')
  ]).then(async ([test, func]) => {
    console.log(await test.foo);  //=> bar
    console.log(await func());    //=> Hello world!
  });
</script>

Congratulations! You’ve just successfully used IHop to export an object and a function across those pesky iframe barriers!

API

IHop(nameSpace, options) ⇒ instance

Construct the local IHop instance.

Kind: constructor of IHop

Param Type Description
nameSpace string A globally available name-space to hold all of this context's exported objects.
options object Options to alter default behavior.
[options.model] object Container for Model-related options.
[options.model.forceRoot] boolean Set to true to stop this node from attempting to contact it's parent.
[options.network] object Container for Network-related options.
[options.network.allowedOrigins] array<string> A list of allowed origins for child nodes. Any messages received from origins not listed are immediately dropped. Leave empty to allow all origins.
[options.network.parentOrigin] string The allowed origin to use when communicating with the context's parent.
[options.network.parentWindow] window Override the default parent context. Mainly useful when initializing IHop in an Worker context.

Example

> const ihop = new IHop('myNameSpace');

ihop.export(name, object) ⇒ void

Makes object available to every connected iframe via name within this iframe's namespace.

Kind: instance method of IHop

Param Type Description
name string The name to export the object under in the current namespace.
object object function

Example

> const ihop = new IHop('foo');
> const bar = {baz: 'hello!'};

// Make the 'bar' object available in other contexts under 'foo.bar'
> ihop.export('bar', baz);

ihop.import(path) ⇒ Promise

Waits for a specific path to becomes available and then resolves the promise with the object or namespace at that path.

Kind: instance method of IHop

Param Type Description
path string A path is one or more namespaces separated by a period (.) and optionally a final exported name.

Example

// An iframe with the namespace `A` is the root namespace and contains another iframe with the namespace `B`
// The iframe `B` exports an object named `foo`
> ihop.import('A.B.foo').then((foo) => {
    // Do something with 'foo'
  });

// Wait for more than one export
> Promise.all([
      ihop.import('A.B.foo'),
      ihop.import('A.bar')
    ]).then(([foo, bar]) => {
    // Do something with 'foo' and 'bar'
  });

ihop.registerWorker(worker) ⇒ void

Register a web worker context. Workers are not able to automatically register themselves like iframes and must be explicitly linked in their parent context.

Kind: instance method of IHop

Param Type Description
worker Worker An instance of a Web Worker.

Example

> const worker = new Worker('worker.js');
> ihop.registerWorker(worker);

ihop.tree ⇒ object

Contains the exported namespace hierarchy.

Kind: instance property of IHop

Example

// An iframe with the namespace `A` contains another iframe with the namespace `B`
// The iframe `B` exports an object named `foo`
> ihop.import('A.B.foo').then(() => {
    // We can also access foo via:
    const foo = ihop.tree.A.B.foo;
  });

Advanced

IHop has support for some pretty advanced proxying. Not only can you export DOM nodes and manipulate them as though they were local, but you can also treat functions as local too!

This means that you can pass functions across the proxy as arguments and even return functions from other functions. The proxy engine handles all the fun stuff behind the scenes for you.

For example let's say that you export a function that returns a function from iframe A:

<script type="text/javascript">
  const ihop = new IHop('A');

  const compose = (fnA, fnB) => async (...args) => await fnA(await fnB(...args));

  ihop.export('compose', compose);
</script>

NOTE: When we execute the fnA and fnB functions, we need to await - any function passed between contexts has it’s return value encapsulated in a promise.

Now in B, you want to use that function:

<script type="text/javascript">
  const ihop = new IHop('B');

  ihop.import('A.compose').then(async (compose) => {
    const add = (a, b) => a + b;
    const double = (n) => n * 2;

   const sumAndDouble = await compose(double, add);

   console.log(await sumAndDouble(3, 4));
  });
</script>

And it just works!

Architecture

Blue labels represent event types.

Caveats

There are a few things to be aware of when using this library.

Performance

Don't expect performing magic to be fast. This library should not be used for performance intensive operations. Even events that trigger more than a few times a second are not a good fit for cross-frame access.

Synchronization

Exported objects are running in different threads and the library doesn't provide any synchronization primitives. Operations can happen out of order and nothing is atomic. It's best to avoid making changes to an object from more than one context.

Proxying

There are obviously going to be places where the proxying breaks down but every attempt has been made to make it as transparent as possible.

Currently unsupported operations on proxies:

  1. Both getPrototypeOf/setPrototypeOf
  2. The delete operator
  3. The in operator

ihop's People

Contributors

imbcmdth avatar

Watchers

 avatar

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.