Skip to content

v7.0.0

Latest
Compare
Choose a tag to compare
@Aaronius Aaronius released this 12 Mar 02:56
· 2 commits to master since this release

Version 7 is here! It contains quite a few new features and breaking changes, so let's get into it.

Migration

To ease the pain of migration, running Penpal v7 in a parent window is compatible with running Penpal v6 in a child iframe. Therefore, if it's difficult to upgrade Penpal in the parent window and iframe at the same time, update code in the parent window first and then update code in the child iframe. Compatibility with v6 will be removed in the next major version of Penpal (v8). Note that running Penpal v6 in the parent window is not compatible with running Penpal v7 in the child iframe.

Breaking changes

A WindowMessenger is now required

What

Message transmission details between a parent window and a child iframe have been moved to a new WindowMessenger class. You'll now pass an instance of WindowMessenger as the messenger option when calling connect. See Usage with an Iframe in the README.

Why

Separating message transmission into a dedicated class allows Penpal to support additional contexts—such as communication between a window and a worker—while keeping the shared, high-level logic inside connect.

connectToChild and connectToParent have been renamed

What

connectToChild and connectToParent are now unified into a single connect function.

Why

With WindowMessenger receiving a reference to the iframe window instead of connectToChild, the connectToChild and connectToParent functions essentially became identical and no longer needed to be separate functions.

Origin defaults have changed

What

When calling connectToChild, the default value for the childOrigin option was previously derived from the iframe’s src attribute. This is no longer the case. Penpal now defaults to restricting communication to the origin of the parent window’s HTML document. If you'd like to derive the origin from the iframe’s src when specifying the child origin, you can use new URL(iframe.src).origin. See Usage with an Iframe in the README.

When calling connectToParent, the default value for the parentOrigin option was *. This has been changed as well. Penpal now defaults to restricting communication to the origin of the child iframe’s HTML document.

Why

In this version, Penpal only receives a reference to the iframe’s content window (iframe.contentWindow) rather than the iframe itself, so it no longer attempts to derive the child’s origin when connecting.

When connecting to the parent window from the child iframe, I wasn’t comfortable with Penpal using * as the default parentOrigin. Even though the README recommended against using the default, developers might easily overlook it. As this library is security-conscious, it seems more appropriate to encourage developers to manually specify * when necessary, rather than rely on the default.

Debugging has changed

What

Previously, to enable debugging, you needed to set the debug option to true when calling connectToChild or connectToParent. Now, you’ll need to set the log option to a function of your choice. Penpal exports a simple debug function that logs debug messages to the console, and you can use this as the value for the log option. See Debugging in the README.

Why

Allowing a function to be provided instead of a boolean increases flexibility. For instance, you can use a more advanced logging library, like the popular debug package, or write your own custom logging function.

Errors have changed

What

Errors thrown by Penpal were previously instances of the native Error class. They are now instances of a new PenpalError class, which extends from Error. Additionally, error codes (found on the code property) have been updated. The code ConnectionDestroyed is now CONNECTION_DESTROYED, and ConnectionTimeout has changed to CONNECTION_TIMEOUT. If you were using ErrorCode.ConnectionDestroyed or ErrorCode.ConnectionTimeout properties to reference the error code strings, these properties remain unchanged. The NoIframeSrc error code has been removed because Penpal is now only provided with a reference to the iframe’s content window (iframe.contentWindow) rather than the iframe itself.

Note that some error codes have been added. See Errors in the README for all the latest error codes.

Why

I added the PenpalError class because I was uncomfortable with Penpal adding a code property directly to the native Error instance. TypeScript was uncomfortable with it as well. It made more sense to create a new class that extends Error and properly supports the code property.

Object containing remote methods is now a Proxy object

What

In earlier versions of Penpal, connection.promise resolved to an object containing methods that reflected the remote methods. These methods were defined as standard properties on the object. In this version, however, this object is now a Proxy and the methods are no longer defined as standard properties.

To illustrate, let's assume we're following this example from version 6 where multiply and divide methods are being exposed from an iframe and used in the parent window.

connection.promise.then((child) => {
  child.multiply(2, 6).then((total) => console.log(total));
  child.divide(12, 4).then((total) => console.log(total));
  console.log(Object.keys(child)); // ['multiply', 'divide']
});

Note how multiply and divide are both keys on child. Let's see how this plays out in version 7:

connection.promise.then((child) => {
  child.multiply(2, 6).then((total) => console.log(total));
  child.divide(12, 4).then((total) => console.log(total));
  console.log(Object.keys(child)); // []
});

The calls to multiply and divide are still the same and function properly, but notice how Object.keys returns an empty array. The child object is not pre-built with multiply and divide properties, but instead dynamically handles method calls as they occur.

Why

Using a proxy object simplifies and reduces the amount of work Penpal needs to perform as well as minimizes required code. Penpal no longer needs to extract names and "paths" of methods, send them to the remote, and then rebuild objects with the same structure.

Types have changed

What

The AsyncMethodReturns type has been renamed to RemoteProxy. The CallSender type has been removed.

Why

The name AsyncMethodReturns was overly focused on implementation details. The new name, RemoteProxy, more accurately reflects its role as a proxy for methods exposed by the remote. Additionally, the type has been enhanced to support new features such as method call timeouts and transferable objects.

The CallSender type was redundant. The existing Methods type serves as the replacement for CallSender.

New features

Support for workers, windows, and other things using ports

Penpal now supports workers (dedicated workers, shared workers, and service workers), windows opened using window.open(), and other things that use MessagePorts. This is facilitated by the new WindowMessenger, WorkerMessenger, and PortMessenger classes. See the usage examples in the README for more information.

Method call timeouts

When calling a remote method, you can now specify a timeout. If the timeout elapses before hearing back from the remote, the promise returned from the method call with be rejected with an error. See Method Call Timeouts for more information.

Support for transferable objects

Browsers natively support transferable objects for transferring large data between contexts. This functionality is now available in Penpal. See Transferring Large Data for more details.

Support for specifying multiple origins from either side of the connection

When connecting from an iframe to a parent window, you've been able to use a regular expression to restrict communication to multiple origins. However, this feature was not available when connecting from the parent window to an iframe. Now, this capability is available and identical when connecting from either direction. Furthermore, instead of specifying just one origin or regular expression, you can now provide an array of origins or regular expressions, making things easier and more flexible.

Enhanced handshake protocol

When establishing a connection, Penpal performs a handshake to ensure both participants can send and receive messages. Previously, this process required calling connectToChild in the parent window before calling connectToParent in the iframe. Penpal now uses an enhanced handshake protocol that allows either participant to call connect first.

MessagePort usage

In previous versions, Penpal transmitted all messages between the parent window and iframe using postMessage on the respective window objects. Now, Penpal uses postMessage only during the handshake, while all subsequent communication occurs over MessagePorts. This approach reduces noise on global window objects and reduces security check overhead.

Parallel connections

In rare cases, you may wish to establish parallel connections between two participants. Penpal now supports this through the use of channels. See Parallel Connections for more details.

Bug fixes

No bug fixes. There are no known bugs at the moment.