Skip to content

Dependencies and Runtime

Jonathan Pierce edited this page Nov 7, 2023 · 8 revisions

Local Client NPM Dependencies

The local client contains a small set of dependencies. These dependencies were chosen such that:

  • they are common libraries, which are likely already installed
  • they are using the up-to-date versions, likely to be compatible
  • a React-based application can include Embedded UIs within their existing React tree without issue, since the same React instance will be used for each

These dependencies will also be passed-into the remote client, allowing it to be significantly smaller.

These dependencies are:

  • React/ReactDOM 16, 17, or 18 (18 is recommended)
  • PropTypes (for React)
  • Lodash
  • moment.js

These do NOT need to be manually added to your package.json if they are not already there: npm will automatically handle installing them when @nextcapital/client is installed.

If you do have these libraries in your package.json, make sure to use the ^x.y.z syntax instead of hardcoding a specific version. For best results, the major version should match those on the @nextcapital/client package.json.

Preventing Duplicates

Minor version differences between your package.json and that of our package can result in duplicate packages/instances in your app. This can be avoided by:

  • Making sure your package.json uses the ^x.y.z notation for the shared packages, instead of hardcoding a version
  • Running npm up whenever bumping the nextcapital package
  • Using a webpack alias to ensure that only a single instance of the package from the root is used

React, in particular, requires a single shared instance for all code on your page in order to work properly. In general, we recommended defining aliases on your webpack config for:

  • react
  • react-dom
  • lodash

Browser Support

The NextCapital Client supports the same set of browsers that our NextCapital-hosted UIs do. This means at least the last two versions of:

  • Chrome
  • Edge (Chromium-based)
  • Safari
  • Firefox

In practice, we do support older versions of these browsers than the last two as well. Please contact us for specifics. The client may fail to run on an unsupported browser (eg: IE11).

Runtime Interactions

CSS

The local client's configure call will automatically attach the CSS needed for Embedded UIs to the head element. Obviously, CSS conflicts are a concern, but rest assured that NextCapital has worked to minimize this potential as much as possible.

To avoid conflicts, all NextCapital CSS rules are scoped under .blocks-{something} classes. So, there should be no issue as long as your CSS:

  • does not use .blocks-{something} class names
  • does not use !important on element selectors
  • does not attempt to style NextCapital embedded content
  • does not use --vds--prefixed CSS variables

All NextCapital embedded UIs make use of CSS variables under-the-hood for colors. This allows to change colors dynamically at runtime. The CSS variables used will all have a --vds- prefix, and are defined on :root. Any overrides set by ColorService will live on document.documentElement.

If you encounter an issue with a CSS conflict, please let us know so that we can resolve it.

Scripts and Global Variables

Currently, the local client's configure call will attach these scripts to the body element:

  • PDFJS
  • Plaid
  • the remote client

We use PDFJS to render stuff like Investor Consent and the Doc Vault. PDFJS will be downloaded from a CDN at:

https://cdn.jsdelivr.net/npm/pdfjs-dist@2.4.456/build/pdf.min.js

We use Plaid to add synced accounts from outside institutions. Plaid will be downloaded from a CDN at:

https://cdn.plaid.com/link/v2/stable/link-initialize.js

These will define pdfjsLib and Plaid global variables. If your application also uses PDFJS or Plaid, please let us know, and we can hopefully come to some resolution. Do note that if you use either of these today the following may occur:

  • If pdfjsLib is already present, we'll use it if it is a compatible version (2.x), and otherwise throw an error
  • If Plaid is already present, we will throw an error to prevent configuration mismatches

PDFJS needs to be included as a separate script since it depends on a Web Worker to function with a high degree of performance, and web workers and webpack do not currently get along.

Meanwhile, the remote client will define a NextCapitalClient global variable. We do not recommend accessing this directly, instead use getClient or waitForConfiguredClient from the local client.

Apart from the externalized dependencies from the local client, the remote client is entirely self-contained. We don't expect any interaction with the parent webpage (except for the few exceptions listed below).

React Portals

To render modals, tooltips, popups, etc... the Embedded UIs use React Portals. The client will add an element to document.body when the portal displays, and remove it when it hides. So, do not be surprised if some UI content renders outside of its container.

Avoid React 18 Concurrent Mode

The nextcapital-client is not compatible with React 18's opt-in concurrent rendering support (eg: useTransition). Do not render client content as a subtree of something using transitions, or you may experience "tearing" in the UI.

Accessibility Helper

To support great accessibility and keyboard navigation, we attach a blocks-using-keyboard class to document.body whenever we detect that keyboard navigation is being used. This class is used to properly apply focus styles only when keyboard navigation is used.

Browser Storage

The NextCapital Client is designed to not interact with browser storage (local storage, session storage, indexedDB, etc...) at all. So, there should be no fear of impacts from browser storage collisions.

Tracking/Analytics (Segment/NewRelic)

NextCapital uses segment.io for analytics. When trackingEnabled is true on the environment config (as we recommend), expect occasional traffic to Segment's servers. We will update this documentation if anything changes.

Visit the NextCapital Privacy Policy for more information.

Viewport / Mobile Support

Some of our CSS for mobile support depends on the following HTML viewport being set:

<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

This viewport is pretty standard and is likely to be already present on your page.

Router-less History

Many single-page applications depend on defined URLs (routes) for each page to function. Our UI framework is routerless, meaning that its history system is totally decoupled from the current URL. This means that:

  • NextCapital embedded UIs can have history independent of the parent application
  • The parent application does not need to define routes for pages within NextCapital UIs
  • There will not be a conflict with any defined routes on the parent application

One less thing to worry about!

Shadow DOM? Web components?

Shadow DOM and Web Components are some emerging technologies that have been suggested to eliminate some of these potential issues. However, NextCapital has determined that they are either not quite mature enough yet or do not actually solve issues.

Shadow DOM

The Shadow DOM would solve any potential CSS issues by separating the CSS for embedded UIs and the parent page entirely. However, there are still some issues:

  • The specification is still considered a draft and still has some variation between browsers (especially Safari)
  • React overall does not have good support for it. Stuff like event handling can break. Future versions may resolve this.
  • React Portals and our accessibility helpers struggle with it

Once these issues are resolved, we may reconsider in the future.

Web Components

The Web Components spec allows for native support of custom elements.

It has been suggested to us that Web Components could solve potential React version incompatibility issues, but this is only true if:

  • React is removed as a dependency from the local client, and bundle internally within the remote client
  • A web component renders a React tree (using the local client's React) from the root of the web component

This would work, but has some downsides:

  • There would still be multiple versions of React on the page
  • When used within a parent React-based view, we need two React roots. The roots cannot communicate, reducing the utility of React's tree-diff algorithm for performance.
  • Prior to React 17, there can be some issues with event handling when this is done.

If your app uses web components, it is trivial to use the NextCapital Client with them: simply define a Web Component that renders the embedded client into it's root DOM node. The NextCapital Client itself will not provide any web components.

See also, React's documentation on Web Components: https://reactjs.org/docs/web-components.html