OpenComponents Browser Client
The `oc-client-browser` package is the client-side JavaScript library for the OpenComponents (OC) framework, facilitating browser-based rendering of independently deployed micro-frontends. OpenComponents, an open-source framework developed at OpenTable, enables building and managing self-contained UI components (HTML, CSS, JS, often with server-side Node.js logic) that are published to a central OC registry. Currently at version 2.1.10, the client integrates by being included as a script in a web page, exposing a global `oc` object. It automatically scans the DOM for `<oc-component>` custom elements, fetches component data and compiled views from a configured OC registry, and dynamically injects rendered HTML and executes client-side JavaScript. This library is crucial for the OC philosophy, which emphasizes framework-agnosticism, granular UI ownership, and independent deployment to combat monolithic frontend architectures.
Common errors
-
Uncaught ReferenceError: oc is not defined
cause The `oc-client-browser` script has not been loaded or has not finished initializing before `oc` is accessed.fixEnsure the `<script src="..."></script>` tag for `oc-client-browser` is correctly placed in your HTML, typically at the end of the `<body>`. If you need to interact with `oc` immediately, wrap your code in `window.oc.cmd.push(function(ocClient) { /* ... */ });` to defer execution until the client is ready. -
Component stuck on 'Loading component...' or displaying fallback content indefinitely.
cause The browser client failed to fetch or render the component from the registry. This can be due to an incorrect component `href`, an unreachable registry, network errors, or an issue with the component itself (e.g., server-side logic error, invalid template).fixCheck the browser's developer console for network errors (e.g., 404, 500 status codes for component requests) or JavaScript errors. Verify the component's `href` URL is correct and the OC registry is online and accessible. If `data-oc-params` is used, ensure the JSON is valid. Check the registry logs for errors related to the component. -
TypeScript Error: Property 'oc' does not exist on type 'Window'.
cause The TypeScript compiler does not know about the global `oc` object that `oc-client-browser` exposes.fixAdd a global declaration file (e.g., `src/types/oc-client-browser.d.ts`) to your project. Inside, declare the global `oc` interface and its types. For example: `declare global { interface Window { oc: OCObject; } } interface OCObject { build: (options: any) => string; /* ... other methods */ }`.
Warnings
- gotcha The `oc-client-browser` library is designed to be included as a global script in HTML. Attempting to `import` or `require` it as an ES module or CommonJS module directly in a Node.js or bundler environment without specific configuration (e.g., polyfills, shims, or a browser field in `package.json`) will likely result in errors or unexpected behavior.
- gotcha When including the `oc-client-browser` script in your HTML, the order relative to `<oc-component>` tags matters for automatic rendering. If the script is placed before your component tags, components might not render until `window.oc.renderUnloadedComponents()` is manually called.
- gotcha Client-side rendering of OpenComponents relies on successful HTTP requests to the configured OC registry. Network issues, registry downtime, or incorrect component `href` attributes can cause components to fail to load, often displaying their fallback content or a loading message indefinitely.
- breaking While no specific major version breaking changes for `oc-client-browser` were detailed, the broader OpenComponents ecosystem (including the registry and component definitions) is under active development. Breaking changes in component contracts or registry APIs can indirectly affect the browser client's ability to render components correctly.
Install
-
npm install oc-client-browser -
yarn add oc-client-browser -
pnpm add oc-client-browser
Imports
- oc
import oc from 'oc-client-browser'; const oc = require('oc-client-browser');<!-- Add <script src="https://your-registry.com/oc-client/client.js"></script> to your HTML --> <script> window.oc.cmd.push(function(ocClient) { // Use ocClient object here console.log(ocClient); }); </script> - OCObject
import { OCObject } from 'oc-client-browser';declare global { interface Window { oc: OCObject; } } // Then use `window.oc` in your TypeScript code // import type { OCObject } from 'oc-client-browser'; // For types if bundled and exported - oc.build
import { build } from 'oc-client-browser'; // Incorrect for runtime usagewindow.oc.cmd.push(function(ocClient) { const componentHtml = ocClient.build({ name: 'my-component', version: '~1.0.0', parameters: { data: 'value' } }); document.getElementById('container').innerHTML = componentHtml; });
Quickstart
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>OC Client Browser Quickstart</title>
<style>
body { font-family: sans-serif; margin: 20px; }
.component-container { border: 1px dashed #ccc; padding: 15px; margin-top: 20px; }
oc-component { display: block; min-height: 50px; background-color: #f9f9f9; padding: 10px; }
</style>
</head>
<body>
<h1>OpenComponents Browser Client Example</h1>
<p>This page demonstrates client-side rendering of an OpenComponent fetched from a registry.</p>
<div class="component-container">
<h2>Hello World Component</h2>
<!-- The oc-component tag tells the client where to render -->
<oc-component
href="https://your-oc-registry.com/components/hello-world/~1.0.0/?name=RegistryUser"
data-oc-params='{"message":"Hello from the browser!"}'>
Loading 'hello-world' component...
</oc-component>
</div>
<div class="component-container">
<h2>Dynamic Component</h2>
<div id="dynamic-component-mount">Loading dynamic component...</div>
</div>
<!-- Optional: Configure global 'oc' settings before loading the client script -->
<script>
var oc = oc || {};
oc.conf = oc.conf || {};
oc.conf.retryInterval = 1500; // Retry fetching components every 1.5 seconds on failure
oc.conf.baseUrl = 'https://your-oc-registry.com/components'; // Base URL for `oc.build` calls
</script>
<!-- Load the OpenComponents browser client script, ideally at the end of <body> -->
<script src="https://your-oc-registry.com/oc-client/client.js"></script>
<script>
// Ensure the global 'oc' object is ready before using it
window.oc.cmd.push(function(ocClient) {
console.log("OpenComponents client is ready! Version:", ocClient.version);
// Example of dynamically building and rendering a component
const dynamicComponentHtml = ocClient.build({
name: 'another-component', // Replace with a valid component name from your registry
version: '~1.0.0', // Specify version
parameters: { title: 'Generated Component', content: 'This component was built dynamically!' }
});
const mountPoint = document.getElementById('dynamic-component-mount');
if (mountPoint) {
mountPoint.innerHTML = dynamicComponentHtml;
ocClient.renderUnloadedComponents(); // Important: Render dynamically added <oc-component> tags
}
});
</script>
</body>
</html>