Service worker and messaging

Design message contracts

Use named message types, narrow payloads, clear responses, and error handling across popup, worker, and content script.

8 minute lesson

~~~

As an extension grows, ad hoc messages become an undocumented internal API.

Define the allowed message shapes in one module or type declaration. Include only serializable data, validate senders where trust differs, return explicit results, and handle runtime.lastError or rejected promises.

type PageNoteMessage =
  | { type: 'SHOW_PAGE_NOTE'; note: string }
  | { type: 'HIDE_PAGE_NOTE' }
  | { type: 'GET_ACTIVE_NOTE'; url: string }

type MessageResult =
  | { ok: true }
  | { ok: false; code: 'INVALID_MESSAGE' | 'UNAVAILABLE' }

Validate at runtime as well as with TypeScript because a sender can be old, compromised, or plain JavaScript. Check sender.id for external or cross-extension surfaces and sender.tab or URL when the receiver’s authority depends on the source. Do not echo exception stacks or storage contents in errors.

Chrome messaging uses JSON serialization. For broadly compatible asynchronous listeners, call sendResponse and return the literal true so the channel stays open. Current Chrome is rolling out returned-promise support, but choosing it without a minimum-version decision can produce inconsistent behavior across installed clients.

Document the three message types with sender, receiver, payload, response, authorization rule, and failure codes. Exercise an unknown type, malformed data, no receiver, two listeners attempting to respond, and a response that cannot be serialized.

Lesson completed

Take this course offline

Get every free book and course as PDF and EPUB files.

Get the download library →