Skip to content

RFC Browser Support & Buffer Module #213

Open
@viglucci

Description

@viglucci

Providing a pleasant experience when using RSocket-js in browser environments is a goal of the work we are doing in #158, and as we approach a preview release, I would like to take a closer look at what changes might be needed, and what options we have.

As demonstrated in #212, we know that the Buffer module, which is native to node, but unavailable in Browser environments, is something that will need to be supported in some way (as suspected) as it is required to produce the Binary data involved with sending and receiving payloads.

There are a few possible directions to go with this, in no particular order:

A) require consumers to polyfill the Buffer module with their build tool of choice


Most frontend build tools (Webpack, etc.) support a mechanism to polyfill Node APIs with alternatives that support browser environments. For example, the webpack resolve.fallback configuration can be used to provide an alternative version of Buffer that has browser compact.

Learn more here.

const webpackConfig = {
    ...
    resolve: {
        ...
        fallback: {
            buffer: require.resolve('buffer/'),
        },
    },
};

Pros:

  • no additional changes are required to rsocket-js packages to support browser environments
  • consumers may provide whichever polyfill they see fit

Cons:

  • rsocket-js packages are not browser compatible without special build tool configuration
  • an increased learning curve for consumers

B) update APIs to accept browser compatible Buffer modules as a dependency


A dependency injection type pattern could be adopted by the public APIs to accept a browser compatible Buffer implementation. This pattern would likely involve introducing a similar configuration as the wsCreator on the WebsocketClientTransport API. See below.

Pros:

  • APIs support browser environments without special build tool configuration
  • consumers may provide whichever polyfill they see fit

Cons:

  • potentially significant changes needed to expose necessary configuration and dependency injection throughout various layers of the current package implementations
  • some packages that currently expose primarily functional APIs could require significant alteration to support dependency injection/configuration. @rsocket/composite-metadata being one such package.

Example:

Changing the encodeRoutes API could require adding an additional argument that would provide a browser-compliant Buffer implementation.

export function encodeRoutes(...routes: string[], bufferImpl: Buffer): Buffer {
  if (routes.length < 1) {
    throw new Error("routes should be non empty array");
  }

  return bufferImpl.concat(routes.map((route) => encodeRoute(route, bufferImpl)));
}

Alternatively, @rsocket/composite-metadata could be altered to provide a more class-based approach which could provide benefits to dependency injection patterns, but at the potential cost of losing module tree-shaking at build time, due to the loss of individually exported functions. Loss of module tree-shaking may not be a concern though due to the relatively minimal size of the composite-metadata APIs.

C) produce browser compatible build artifacts with pre-provided Buffer polyfills


Currently, the project builds for commonjs environments, which supports Node as well as build tooling such as Webpack quite well. We could additionally introduce build targets/configurations that would provide a browser-compatible Buffer module within scope.

"module": "commonjs",

Pros:

  • APIs support browser environments without special build tool configuration

Cons:

  • consumers cannot control which Buffer polyfill is used
  • potentially difficult to control the size of the artifacts produced, which is a consideration when building for browsers
  • more complex build configuration and tooling required to maintain the project
  • consumers required to import specific artifacts for usage in browser environments (ex: require('@rsocket/core/browser'))
  • likely challenges with inter-package dependencies and build tooling

I would argue that this approach may be the least appealing approach from the package's maintenance perspective.

Metadata

Metadata

Assignees

No one assigned

    Labels

    1.0Pullrequests & issues related to the Typescript rewrite and 1.0 releaseenhancementSuggests, requests, or implements a feature or enhancement

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions