Structure

Messaging

Communicate between your extension's components.

Messaging API makes communication between different parts of your extension easy. Add a file to your background messages directory, and Plasmo will handle all the rest.

Plasmo Messaging is a declarative, type-safe, functional, promise-based API for sending, relaying, and receiving messages between your extension components.

Handling messages

The @plasmohq/messaging library requires the background service worker to live inside a ap/background/index.ts folder, and all message handlers to live inside app/background/messages/* folders.

For example, TurboStarter comes with predefined message handler for retrieving and parsing auth session. It's defined in app/background/messages/session.ts and the file structure looks like this:

session.ts
index.ts

To create a message handler, create a ts module in the background/messages directory. The file name should be the message name, and the default export should be the handler function:

app/background/messages/example.ts
import type { PlasmoMessaging } from "@plasmohq/messaging";
 
const handler: PlasmoMessaging.MessageHandler = async (req, res) => {
  const message = await querySomeApi(req.body.id);
 
  res.send({
    message,
  });
};
 
export default handler;

It's fully type-safe!

On compilation, Plasmo will generate static types for all of your message handlers. This means that you can't accidentally send the wrong type of message.

Sending messages

Extension pages, content scripts, or tab pages can send messages to the handlers using the @plasmohq/messaging library. Since Plasmo Framework orchestrates your handlers behind the scenes, the message names are typed and will enable autocompletion in your editor:

app/popup/index.tsx
import { sendToBackground } from "@plasmohq/messaging"
 
...
 
const response = await sendToBackground({
  name: "example",
  body: {
    id: 123
  }
});
 
console.log(response);
 
...

As it's an asynchronous operation, it's advisable to use @tanstack/react-query integration to handle the response on the client side.

We're already doing it that way when fetching auth session in the User component:

app/components/layout/header.tsx
export const User = () => {
  const { data, isLoading } = useQuery({
    queryKey: ["session"],
    queryFn: () =>
      sendToBackground<
        {
          type: typeof SESSION_MESSAGE_TYPE.GET;
        },
        {
          session: Session | null;
        }
      >({
        name: "session",
        body: { type: SESSION_MESSAGE_TYPE.GET },
      }),
  });
 
  if (isLoading) {
    return <p>Loading...</p>;
  }
 
  /* do something with the session data... */
  return <p>{data.session?.user?.email}</p>;
};

E2E type safety is in progress on Plasmo side

As you can see, we're explicitly defining the type using generics together with sendToBackground function. It's because currently Plasmo doesn't support extracting message handler types automatically. It's in progress, and we'll migrate to it in the future.

Last updated on

On this page

Ship your startup everywhere. In minutes.Get TurboStarter