Skip to content

readme#7

Merged
hbmartin merged 1 commit intomainfrom
readme
Sep 17, 2025
Merged

readme#7
hbmartin merged 1 commit intomainfrom
readme

Conversation

@hbmartin
Copy link
Copy Markdown
Owner

@hbmartin hbmartin commented Sep 17, 2025

PR Type

Documentation


Description

  • Complete rewrite of README with comprehensive library documentation

  • Added detailed examples for UDF reducer IPC pattern

  • Added detailed examples for RPC promises IPC pattern

  • Added installation instructions and API reference


Diagram Walkthrough

flowchart LR
  A["Generic Vite Template"] --> B["Library Documentation"]
  B --> C["UDF Reducer IPC"]
  B --> D["RPC Promises IPC"]
  C --> E["Code Examples"]
  D --> E
  E --> F["API Reference"]
Loading

File Walkthrough

Relevant files
Documentation
README.md
Complete library documentation rewrite                                     

README.md

  • Replaced generic Vite template content with comprehensive library
    documentation
  • Added installation instructions and concept overview
  • Included detailed examples for both UDF reducer and RPC IPC patterns
  • Added sequence diagrams, troubleshooting tips, and API reference
+397/-66
Dependencies
package.json
Minor dependency and formatting updates                                   

package.json

  • Added jsdom as development dependency
  • Reformatted typesVersions arrays for better readability
+7/-2     


Important

Update README.md with detailed documentation for react-vscode-webview-ipc and add jsdom to package.json.

  • Documentation:
    • Overhaul README.md to document react-vscode-webview-ipc library.
    • Includes installation instructions, concepts overview, and detailed examples for UDF reducer IPC and RPC promises IPC.
    • Provides tips, troubleshooting, and API reference.
  • Dependencies:
    • Add jsdom as a development dependency in package.json.

This description was created by Ellipsis for ac9e21a. You can customize this summary. It will automatically update as commits are pushed.

Summary by CodeRabbit

  • Documentation
    • Overhauled project docs to introduce react-vscode-webview-ipc, detailing two IPC paradigms (UDF reducer and RPC promises), installation, host/client entry points, core concepts, minimal examples, end-to-end flow diagrams, combined usage, logging, troubleshooting, and a quick API reference.
  • Chores
    • Added jsdom as a development dependency.
    • Reformatted type version mappings for clarity with no functional changes.

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @hbmartin, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Sep 17, 2025

Walkthrough

Replaces README.md template with documentation for the react-vscode-webview-ipc library, detailing IPC paradigms, usage, and examples. Updates package.json formatting for typesVersions entries and adds jsdom as a devDependency. No source code or public API changes.

Changes

Cohort / File(s) Summary
Documentation overhaul
README.md
Rewrote content to document the react-vscode-webview-ipc library, including IPC paradigms, concepts, examples, and references; removed prior template/readme content. No code changes.
Tooling and dev dependencies
package.json
Reformatted typesVersions arrays without semantic change; added jsdom ^27.0.0 to devDependencies.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Suggested labels

Review effort 2/5

Poem

I thump with joy on README hills,
New IPC paths and diagram frills.
In burrows deep, jsdom hops in—
Dev nights bright, let tests begin.
Two entries marked, the warren’s neat;
Docs refreshed—now carrots sweet! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title Check ❓ Inconclusive The PR title "readme" is related to the changes (the README was replaced) but is overly terse and non-descriptive; it does not read as a short, clear sentence that conveys the primary change to reviewers. Because the title is vague and lacks meaningful context, this check is inconclusive. Please update the title to a concise, descriptive sentence (for example: "docs: Replace README with react-vscode-webview-ipc documentation" or "docs(readme): Add comprehensive README describing UDF reducer and RPC IPC paradigms") so reviewers can quickly understand the main change.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch readme

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary of Changes

Hello @hbmartin, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces comprehensive documentation for a new library, react-vscode-webview-ipc, designed to streamline and type-safely manage communication between VS Code extension hosts and their React-based webviews. It details two primary communication patterns—a unidirectional dataflow (UDF) reducer IPC and a Remote Procedure Call (RPC) promises IPC—providing clear examples and usage guidelines for both. The changes also include the necessary dependency updates to support the library's functionality, notably the addition of jsdom for development purposes.

Highlights

  • New Library Documentation: The README.md has been completely rewritten to introduce and document react-vscode-webview-ipc, a library designed for type-safe, two-way communication between VS Code extension hosts and React webviews.
  • Dual IPC Paradigms Supported: The library offers two distinct communication patterns: UDF Reducer IPC for unidirectional state updates via actions and patches, and RPC Promises IPC for calling host functions with typed results and broadcasting events to webviews.
  • Dependency Updates: New development dependencies, including jsdom and various web parsing/styling libraries, have been added to support the functionality and testing of the react-vscode-webview-ipc library.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@qodo-code-review
Copy link
Copy Markdown

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Accuracy

Validate that the documented API names, generics, and message shapes (e.g., useVscodeState signature, BaseWebviewViewProvider methods, isViewApiRequest typing, WebviewProvider props) match the actual exported types and behavior in the published package to avoid misleading users.

## Concepts Overview

- WebviewKey: a branded string identifying your view instance. Use a stable id (often your view type).
- Messages:
  - Reducer IPC: `{ type: 'act' }` messages from webview → host; `{ type: 'patch' }` messages from host → webview.
  - RPC IPC: `{ type: 'request' }` from webview → host; `{ type: 'response'|'error' }` from host → webview; `{ type: 'event' }` from host → webview broadcast.
- Logging: webview logs are forwarded to the host’s Output channel.


## UDF Reducer IPC (Action → Patch → Reduce)

Use this when your webview wants unidirectional state updates managed via a reducer.

### Types and Building Blocks
- On the webview:
  - `useVscodeState<S, A>(vscode, providerId, postReducer, initialState)` returns `[state, actor]`.
    - `state: S` – your current state
    - `actor: A` – a proxy with methods matching your action interface
  - `postReducer: StateReducer<S, A>` maps each action key to `(prevState, patch) => newState`.
- On the host:
  - Extend `BaseWebviewViewProvider<A>` and implement:
    - `webviewActionDelegate: ActionDelegate<A>` – map action keys to host handlers that return a patch (sync or async)
    - `generateWebviewHtml(webview, extensionUri)` – return the webview HTML
    - `handleMessage(message, webview)` – handle any messages you want besides reducer IPC (e.g., your RPC requests)
  - Optionally pass a `WebviewApiProvider` instance to the base class constructor to enable host→webview event broadcasting (RPC paradigm).

### Minimal Example

Host (extension):
```ts
// src/extension/MyViewProvider.ts
import * as vscode from 'vscode';
import { BaseWebviewViewProvider, type ActionDelegate } from 'react-vscode-webview-ipc/host';
import type { WebviewKey } from 'react-vscode-webview-ipc/client';

// 1) Define the action interface A: methods return the “patch” type
interface MyActions {
  increment: (by: number) => number; // patch is a number
  setMessage: (msg: string) => { message: string }; // patch is an object
}

export class MyViewProvider extends BaseWebviewViewProvider<MyActions> {
  protected readonly webviewActionDelegate: ActionDelegate<MyActions> = {
    increment: (by) => by, // just echo back the increment amount as the patch
    setMessage: (msg) => ({ message: msg }),
  };

  constructor(
    private readonly id: WebviewKey,
    private readonly ctx: vscode.ExtensionContext
  ) {
    // You can also pass a WebviewApiProvider instance as 3rd arg to enable events
    super(id, ctx.extensionUri);
  }

  protected generateWebviewHtml(webview: vscode.Webview): string {
    const scriptUri = webview.asWebviewUri(
      vscode.Uri.joinPath(this.ctx.extensionUri, 'dist', 'webview.js')
    );
    const styleUri = webview.asWebviewUri(
      vscode.Uri.joinPath(this.ctx.extensionUri, 'dist', 'webview.css')
    );

    return `<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="Content-Security-Policy"
          content="default-src 'none'; img-src ${webview.cspSource} https:; style-src ${webview.cspSource} 'unsafe-inline'; script-src ${webview.cspSource};" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="${styleUri}">
    <title>My View</title>
  </head>
  <body>
    <div id="root"></div>
    <script src="${scriptUri}"></script>
  </body>
</html>`;
  }

  protected async handleMessage(_message: unknown, _webview: vscode.Webview): Promise<void> {
    // No-op for reducer-only example. Use this for RPC too (see later).
  }
}

Register the provider in your extension activation:

// src/extension/activate.ts
import * as vscode from 'vscode';
import { MyViewProvider } from './MyViewProvider';

export function activate(context: vscode.ExtensionContext) {
  const viewType = 'myExtension.myView' as unknown as WebviewKey; // brand to WebviewKey
  const provider = new MyViewProvider(viewType, context);
  context.subscriptions.push(
    vscode.window.registerWebviewViewProvider(viewType, provider)
  );
}

Webview (React):

// src/webview/App.tsx
import { useMemo } from 'react';
import { useVscodeState, type StateReducer, type WebviewKey } from 'react-vscode-webview-ipc/client';

declare function acquireVsCodeApi(): {
  postMessage(message: unknown): Thenable<boolean>;
  getState(): unknown;
  setState(state: unknown): void;
};

interface State { count: number; message: string }
interface MyActions {
  increment: (by: number) => number;
  setMessage: (msg: string) => { message: string };
}

const initial: State = { count: 0, message: '' };

const reducers: StateReducer<State, MyActions> = {
  increment: (prev, by) => ({ ...prev, count: prev.count + by }),
  setMessage: (prev, patch) => ({ ...prev, message: patch.message }),
};

export default function App() {
  const vscode = useMemo(() => acquireVsCodeApi(), []);
  const providerId = 'myExtension.myView' as unknown as WebviewKey;
  const [state, act] = useVscodeState(vscode, providerId, reducers, initial);

  return (
    <div>
      <p>Count: {state.count}</p>
      <p>Message: {state.message}</p>
      <button onClick={() => act.increment(1)}>+1</button>
      <button onClick={() => act.setMessage('Hello!')}>Set Message</button>
    </div>
  );
}

UDF Flow (Sequence)

sequenceDiagram
  participant W as Webview (React)
  participant VS as VS Code API
  participant H as Extension Host
  W->>VS: postMessage { type: 'act', providerId, key, params }
  VS->>H: onDidReceiveMessage(message)
  H->>H: webviewActionDelegate[key](...params) => patch
  H-->>VS: postMessage { type: 'patch', providerId, key, patch }
  VS-->>W: window message
  W->>W: postReducer[key](prev, patch) => newState
Loading

RPC Promises IPC (Typed Requests/Responses + Events)

Use this when your webview needs to call host functions and await results. The host can also broadcast typed events back to all connected webviews.

Types and Building Blocks

  • On the webview:
    • Wrap your app in <WebviewProvider viewType contextKey>.
    • Use createCtxKey<T>() to create a unique key tying the context to your API type T.
    • Call const { api, addListener, removeListener, vscode } = useWebviewApi(ctxKey) inside components.
      • api.method(...) returns a promise (typed from your ClientCalls interface).
      • addListener('eventKey', cb) / removeListener(...) manage host-pushed events.
  • On the host:
    • Create a WebviewApiProvider<HostEvents>() and pass it to your BaseWebviewViewProvider constructor (to register views for events).
    • In your provider’s handleMessage, detect requests via isViewApiRequest(message), dispatch to your host API handlers, and respond with { type: 'response'|'error', id, value }.
    • Use apiProvider.triggerEvent('eventKey', ...args) to broadcast events to connected webviews.

Minimal Example

Shared types:

// Host receives these requests from the webview (must return promises)
import type { ClientCalls } from 'react-vscode-webview-ipc/client';
import type { HostCalls } from 'react-vscode-webview-ipc/client';

export interface MyClientApi extends ClientCalls {
  fetchGreeting: (name: string) => Promise<string>;
  saveCount: (count: number) => Promise<void>;
}

// Host can push these events to all webviews
export interface MyHostEvents extends HostCalls {
  onTick: (count: number) => void;
}

Host (extension):

import * as vscode from 'vscode';
import {
  BaseWebviewViewProvider,
  WebviewApiProvider,
  isViewApiRequest,
  type ViewApiResponse,
  type ViewApiError,
} from 'react-vscode-webview-ipc/host';
import type { MyClientApi, MyHostEvents } from './types';
import type { WebviewKey } from 'react-vscode-webview-ipc/client';

export class MyRpcViewProvider extends BaseWebviewViewProvider<{}> {
  protected readonly webviewActionDelegate = {}; // not using reducer actions here

  constructor(
    private readonly id: WebviewKey,
    private readonly ctx: vscode.ExtensionContext,
    private readonly api = new WebviewApiProvider<MyHostEvents>()
  ) {
    super(id, ctx.extensionUri, api);
  }

  protected generateWebviewHtml(webview: vscode.Webview): string {
    const scriptUri = webview.asWebviewUri(
      vscode.Uri.joinPath(this.ctx.extensionUri, 'dist', 'webview.js')
    );
    return `<div id="root"></div><script src="${scriptUri}"></script>`;
  }

  protected async handleMessage(message: unknown, webview: vscode.Webview): Promise<void> {
    if (isViewApiRequest<MyClientApi>(message)) {
      try {
        switch (message.key) {
          case 'fetchGreeting': {
            const [name] = message.params;
            const value = `Hello, ${name}!`;
            const response: ViewApiResponse<MyClientApi, 'fetchGreeting'> = {
              type: 'response', id: message.id, value,
            };
            await webview.postMessage(response);
            return;
          }
          case 'saveCount': {
            const [count] = message.params;
            // persist count...
            const response: ViewApiResponse<MyClientApi, 'saveCount'> = {
              type: 'response', id: message.id,
            };
            await webview.postMessage(response);
            return;
          }
        }
        const error: ViewApiError = {
          type: 'error', id: message.id, value: `Unknown method: ${String(message.key)}`,
        };
        await webview.postMessage(error);
      } catch (e) {
        const error: ViewApiError = {
          type: 'error', id: message.id, value: e instanceof Error ? e.message : String(e),
        };
        await webview.postMessage(error);
      }
    }
  }
}

// elsewhere in your extension, you can broadcast events
// provider.api.triggerEvent('onTick', currentCount)

Webview (React):

import React, { useEffect } from 'react';
import {
  WebviewProvider,
  useWebviewApi,
  createCtxKey,
  type CtxKey,
} from 'react-vscode-webview-ipc/client';
import type { MyClientApi, MyHostEvents } from './types';

const Ctx: CtxKey<MyClientApi> = createCtxKey<MyClientApi>('my-rpc');

function Inner() {
  const { api, addListener, removeListener } = useWebviewApi(Ctx);

  useEffect(() => {
    const onTick = (n: number) => console.log('tick', n);
    addListener('onTick', onTick as MyHostEvents['onTick']);
    return () => removeListener('onTick', onTick as MyHostEvents['onTick']);
  }, [addListener, removeListener]);

  useEffect(() => {
    (async () => {
      const greeting = await api.fetchGreeting('VS Code');
      console.log(greeting);
      await api.saveCount(42);
    })();
  }, [api]);

  return <div/>
}

export default function App() {
  return (
    <WebviewProvider<MyClientApi> viewType="myExtension.myView" contextKey={Ctx}>
      <Inner />
    </WebviewProvider>
  );
}

RPC Flow (Sequence)

sequenceDiagram
  participant W as Webview (React)
  participant VS as VS Code API
  participant H as Extension Host
  W->>VS: postMessage { type: 'request', id, key, params, context }
  VS->>H: onDidReceiveMessage(message)
  alt success
    H-->>VS: postMessage { type: 'response', id, value }
    VS-->>W: resolve pending promise
  else error
    H-->>VS: postMessage { type: 'error', id, value }
    VS-->>W: reject pending promise
  end
  H-->>VS: postMessage { type: 'event', key, value[] }
  VS-->>W: Invoke registered listeners for key
Loading

Using Both Paradigms Together

  • They are designed to coexist. The webview can dispatch reducer actions for state, and call RPC methods for imperative operations.
  • The library ensures messages don’t conflict:
    • useVscodeState listens for { providerId, type: 'patch' } messages.
    • WebviewProvider listens for { type: 'response'|'error'|'event' } messages and ignores messages with providerId present.
  • In your host provider, resolveWebviewView (from the base class) handles reducer act/patch automatically; implement handleMessage for RPC requests.

Logging

  • Webview: useLogger(tag, vscode) returns a logger that posts to the host output channel.
  • Host: getLogger(tag) returns an Output channel logger; BaseWebviewViewProvider automatically routes webview log messages to it.

Webview example:

import { useLogger } from 'react-vscode-webview-ipc/client';
const logger = useLogger('MyView', acquireVsCodeApi());
logger.info('hello');

Tips & Troubleshooting

  • Brand your view type to WebviewKey at the edges to keep types happy: const id = 'ext.view' as unknown as WebviewKey.
  • Always use stable providerIds; the reducer IPC ties messages to a specific provider.
  • Clean up listeners on unmount in the webview.
  • When posting RPC responses/errors from the host, always echo the same id you received.
  • If you use both paradigms, keep your reducer patches focused on state updates and use RPC for IO or long‑running tasks.

API Surface (Quick Reference)

Host exports (react-vscode-webview-ipc/host):

  • BaseWebviewViewProvider<A>
  • WebviewApiProvider<T extends HostCalls>
  • isViewApiRequest(message)
  • Logger, getLogger, disallowedLogKeys

Client exports (react-vscode-webview-ipc/client):

  • WebviewProvider<T extends ClientCalls>
  • useWebviewApi(ctxKey) and createCtxKey<T>()
  • useVscodeState<S, A>(vscode, providerId, postReducer, initial)
  • useLogger(tag, vscode)
  • Types: ClientCalls, HostCalls, CtxKey, WebviewKey, StateReducer

</details>

<details><summary><a href='https://github.com/hbmartin/react-vscode-webview-ipc/pull/7/files#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5R88-R103'><strong>CSP Example</strong></a>

The HTML CSP in the example allows 'unsafe-inline' styles; confirm this is required and aligns with VS Code recommendations, or adjust guidance to avoid overly permissive policies.
</summary>

```markdown
    return `<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="Content-Security-Policy"
          content="default-src 'none'; img-src ${webview.cspSource} https:; style-src ${webview.cspSource} 'unsafe-inline'; script-src ${webview.cspSource};" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="${styleUri}">
    <title>My View</title>
  </head>
  <body>
    <div id="root"></div>
    <script src="${scriptUri}"></script>
  </body>
</html>`;
  }
typesVersions

Ensure the added typesVersions mapping ("host"/"client") resolves correctly for consumers and aligns with the package exports and published file structure.

"typesVersions": {
  "*": {
    "host": [
      "./dist/host.d.ts"
    ],
    "client": [
      "./dist/client.d.ts"
    ]
  }

@qodo-code-review
Copy link
Copy Markdown

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
General
Memoize event listener with useCallback

Wrap the onTick event listener in useCallback and add it to the useEffect
dependency array to ensure a stable function reference for adding and removing
the listener.

README.md [306-308]

-const onTick = (n: number) => console.log('tick', n);
-addListener('onTick', onTick as MyHostEvents['onTick']);
-return () => removeListener('onTick', onTick as MyHostEvents['onTick']);
+const onTick = useCallback((n: number) => console.log('tick', n), []);
+useEffect(() => {
+  addListener('onTick', onTick as MyHostEvents['onTick']);
+  return () => removeListener('onTick', onTick as MyHostEvents['onTick']);
+}, [addListener, removeListener, onTick]);
  • Apply / Chat
Suggestion importance[1-10]: 5

__

Why: The suggestion correctly applies the useCallback hook to ensure listener reference stability, which is a React best practice that improves the quality of the example code.

Low
Refactor async IIFE in useEffect

Refactor the useEffect hook by replacing the async IIFE with a declared async
function that is then called, improving code readability and adhering to React
best practices.

README.md [311-317]

 useEffect(() => {
-  (async () => {
+  const fetchData = async () => {
     const greeting = await api.fetchGreeting('VS Code');
     console.log(greeting);
     await api.saveCount(42);
-  })();
+  };
+  fetchData();
 }, [api]);
  • Apply / Chat
Suggestion importance[1-10]: 4

__

Why: The suggestion improves the code example by replacing an async IIFE with a named async function, which enhances readability and aligns with modern React best practices.

Low
  • More

Copy link
Copy Markdown

@ellipsis-dev ellipsis-dev Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

Looks good to me! 👍

Reviewed everything up to ac9e21a in 1 minute and 41 seconds. Click for details.
  • Reviewed 498 lines of code in 2 files
  • Skipped 1 files when reviewing.
  • Skipped posting 2 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. README.md:118
  • Draft comment:
    Consider providing a helper to brand view keys rather than using the repetitive 'as unknown as WebviewKey' cast. This could improve type safety and code clarity.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 20% vs. threshold = 50% While the suggestion could improve code clarity, it's more of an optional enhancement than a required change. The current approach is already documented in the Tips section and works fine. The comment is suggesting a nice-to-have refactor rather than pointing out a real problem that needs fixing. The suggestion could improve type safety and reduce repetition. However, I might be underestimating the maintenance burden of the current approach. The current approach is already documented, working, and simple enough. The benefit of adding a helper function doesn't outweigh the overhead of maintaining another API surface. While the suggestion is reasonable, it's not important enough to warrant a comment. The current approach is documented and functional.
2. package.json:87
  • Draft comment:
    The addition of the 'jsdom' dependency should be confirmed as necessary for tests to avoid potential version conflicts.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 0% <= threshold 50% The comment is asking the PR author to confirm the necessity of a dependency addition, which violates the rule against asking for confirmation or ensuring behavior is intended. It also touches on potential version conflicts, which is related to dependencies, another area we should not comment on.

Workflow ID: wflow_UHMVCBcYWqcffyAo

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request is a fantastic improvement, replacing the boilerplate README with comprehensive documentation for the library. The new README is well-structured, with clear explanations of the core concepts, detailed examples for both UDF and RPC patterns, and helpful sequence diagrams. I've added a few minor suggestions to further improve clarity and code style in the examples. Overall, great work on making the library much more approachable for new users.

Comment thread README.md
])
# react-vscode-webview-ipc

A small library to make two-way communication between a VS Code extension host and a React webview simple and type‑safe.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The documentation uses a non-breaking hyphen () in "type‑safe". This might have been unintentional. Using a standard hyphen (-) is recommended for consistency and to avoid potential issues with text processing, searching, or copy-pasting. This character is also used in "long‑running" on line 379.

Suggested change
A small library to make two-way communication between a VS Code extension host and a React webview simple and typesafe.
A small library to make two-way communication between a VS Code extension host and a React webview simple and type-safe.

Comment thread README.md
Comment thread README.md
Comment on lines +285 to +286
// provider.api.triggerEvent('onTick', currentCount)
```
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This example snippet is inside a code block and is also commented out, which might be confusing. Consider moving this example outside the main code block and presenting it as a separate, standalone snippet for clarity. For example:

...
}
```

Elsewhere in your extension, you can broadcast events:

```ts
// Assuming `provider` is an instance of MyRpcViewProvider
provider.api.triggerEvent('onTick', currentCount);
```

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (5)
package.json (1)

38-40: Mark package as side‑effect free for better tree‑shaking

If builds are pure ESM/CJS outputs without global side effects, declare sideEffects: false.

Apply:

   "files": [
     "dist"
   ],
+  "sideEffects": false,
README.md (4)

16-18: Add a language to fenced code block (MD040)

Specify bash to appease markdownlint and enable syntax highlighting.

Apply:

-```
+```bash
 npm i react-vscode-webview-ipc

---

`92-96`: **Avoid style-src 'unsafe-inline' where possible**

For stricter CSP, prefer a nonce or hashed styles over 'unsafe-inline' (keep external CSS). Note: VS Code webviews support nonces.

Example:

```diff
- content="default-src 'none'; img-src ${webview.cspSource} https:; style-src ${webview.cspSource} 'unsafe-inline'; script-src ${webview.cspSource};"
+ content="default-src 'none'; img-src ${webview.cspSource} https:; style-src ${webview.cspSource}; script-src 'nonce-${nonce}';"

and add nonce to your script tag and injected styles.


117-124: Branded WebviewKey ergonomics

Double cast as unknown as WebviewKey is noisy. Consider exporting a helper (e.g., asWebviewKey('my.view')) to brand safely, or document a recommended pattern.


303-309: Remove unnecessary cast in listener registration

Type the callback as MyHostEvents['onTick'] to avoid as at call sites.

Apply:

-  useEffect(() => {
-    const onTick = (n: number) => console.log('tick', n);
-    addListener('onTick', onTick as MyHostEvents['onTick']);
-    return () => removeListener('onTick', onTick as MyHostEvents['onTick']);
-  }, [addListener, removeListener]);
+  useEffect(() => {
+    const onTick: MyHostEvents['onTick'] = (n) => console.log('tick', n);
+    addListener('onTick', onTick);
+    return () => removeListener('onTick', onTick);
+  }, [addListener, removeListener]);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c986e53 and ac9e21a.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (2)
  • README.md (1 hunks)
  • package.json (2 hunks)
🧰 Additional context used
🪛 markdownlint-cli2 (0.17.2)
README.md

16-16: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🔇 Additional comments (3)
package.json (2)

18-23: typesVersions formatting LGTM

Reformat to arrays is fine and preserves resolution for subpaths host/client.


87-87: Confirm jsdom + Vitest env config

No vitest.config.* found and vite.config.ts has no test.environment — Vitest will not pick up jsdom just from package.json; add test: { environment: 'jsdom' } to vite.config.ts (or create vitest.config.ts / add a vitest config in package.json), or annotate DOM tests with @vitest-environment jsdom.

README.md (1)

351-358: Nice clarity on coexistence rules

Good separation of message channels; consumers will appreciate the non-interference guarantees.

If feasible, add a small “both paradigms” example repo link later.

Comment thread README.md
Comment on lines +132 to +137
declare function acquireVsCodeApi(): {
postMessage(message: unknown): Thenable<boolean>;
getState(): unknown;
setState(state: unknown): void;
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

🧩 Analysis chain

Verify acquireVsCodeApi().postMessage return type

Docs snippet types postMessage as Thenable. In the webview context it may be void; host-side webview.postMessage is Thenable. Confirm to prevent copy/paste type drift.


🌐 Web query:

In a VS Code webview (window context), what is the return type of acquireVsCodeApi().postMessage(message)? Is it void or Thenable<boolean>?

💡 Result:

acquireVsCodeApi().postMessage(...) (webview/window side) returns void. (npmjs.com)

Notes: the VS Code extension-side Webview.postMessage(...) (webview object in extension API) returns Thenable, which is a different API. (cocalc.com)

Citations:


Change acquireVsCodeApi().postMessage return type to void

acquireVsCodeApi().postMessage in the webview/window context returns void (the extension-side Webview.postMessage returns Thenable). Update README.md (lines 132–137) to:

declare function acquireVsCodeApi(): {
  postMessage(message: unknown): void;
  getState(): unknown;
  setState(state: unknown): void;
};
🤖 Prompt for AI Agents
In README.md around lines 132 to 137, the TypeScript declaration for
acquireVsCodeApi incorrectly types postMessage as returning Thenable<boolean>;
update the declaration so postMessage returns void instead. Edit the block to
change the postMessage return type from Thenable<boolean> to void, leaving
getState and setState as-is, so the README matches the webview/window context
behavior.

@hbmartin hbmartin merged commit e1e6f26 into main Sep 17, 2025
3 checks passed
@hbmartin hbmartin deleted the readme branch September 18, 2025 19:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant