Ver en Español
Exploring How to Build Chrome Extensions with Esbuild
Jun 24, 2026
Updated: Jun 25, 2026

Exploring How to Build Chrome Extensions with Esbuild

This time I wanted to learn how esbuild works for Chrome extensions, so I did a quick Google search and found a very interesting repository created by Marton Lederer. I decided to clone it and see what happened when I ran it. Here I share my experience and a few key takeaways, step by step, so you can follow along with me.

The repository is available on GitHub: martonlederer/esbuild react chrome extension.

A note on Manifest V3. Every new extension must use Manifest V3. Manifest V2 is deprecated and Chrome no longer loads MV2 extensions, so this is a point we cannot skip. This repository predates that migration, so it is worth checking its manifest.json: if it still declares "manifest_version": 2, you will have to migrate it to MV3 before the extension will load in a current Chrome.

Cloning the repository

First I cloned the repository with git clone. Once it was on my machine, I ran yarn install to install all the necessary dependencies. Then I loaded the extension in the browser to see how it worked.

Project structure

There is a public folder that contains the popup.html file and the manifest.json. When I loaded the extension, an error appeared at first that said "could not load content scripts". After some investigation, I found there was a content script that was not needed for this demo, so I removed it and reloaded the extension.

Build process

To build the extension I used the yarn build command, which generates the necessary files in the build folder. Then I loaded these unpacked files into Chrome through the extensions page (chrome://extensions/). The extension loaded correctly and I could see a pop up that said "React Pop up".

Exploring the code

The package.json file includes dependencies like Babel, esbuild, Prettier, React, and TypeScript. There is also a dependency called Yorkie, similar to Husky, which is used to run pre commit commands and keep the code clean.

The entry point for esbuild includes files like background.ts, content_script.ts, popup.ts, and injected.ts. In the public folder, the manifest.json defines the accessible resources and the URLs the extension applies to.

Esbuild configuration

In the esbuild configuration file, several important options are specified, such as bundle, minify, and sourcemap. It also defines the target runtime environment and the output directory for the compiled files.

Here is an example esbuild configuration:

const esbuild = require('esbuild');

esbuild.build({
  entryPoints: ['src/background.ts', 'src/content_script.ts', 'src/popup.ts', 'src/injected.ts'],
  bundle: true,
  minify: true,
  sourcemap: process.env.NODE_ENV !== 'production',
  target: ['chrome120'],
  outdir: 'public/build',
  define: {
    'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
  },
}).catch(() => process.exit(1));

A note on target: that option tells esbuild what level of JavaScript syntax it should down level your code to. The original repository used ['chrome58'], a version from April 2017, which forced it to transform modern syntax for no reason. Since extensions run on an evergreen Chrome that updates itself, we can use a much more recent baseline like ['chrome120'], or even ['esnext'] if we want to emit the most modern JavaScript possible. The result is a cleaner and usually smaller bundle.

A note on CommonJS vs ESM. The example uses require('esbuild'), which is still a valid and current API. If your project is set up as an ESM module, the equivalent form is import * as esbuild from 'esbuild'. The esbuild.build({... }) call is identical in both cases.

Conclusion

Learning to use esbuild to build Chrome extensions can be a rewarding and quite efficient process compared to other build tools. This particular repository offers a good base to get started and to explore esbuild's capabilities in more depth.

I want to thank Marton Lederer for sharing his work. If you are interested in learning more about building Chrome extensions with esbuild, I recommend checking out his repository: martonlederer/esbuild react chrome extension.

Suggested exercises

  1. Clone the repository, check its manifest.json, and if it is still MV2, migrate the basic fields to Manifest V3 (for example, service_worker instead of background.scripts and action instead of browser_action).
  2. Change esbuild's target from ['chrome120'] to ['esnext'] and compare the resulting bundle size with yarn build.
  3. Add a new entry point to the entryPoints array (for example an options.ts) and check that it shows up compiled in public/build.

3-point summary

  1. esbuild is a fast and efficient way to bundle Chrome extensions, and a base repository like Marton Lederer's is a good starting point.
  2. Every new extension must use Manifest V3; verify the repo's manifest.json before loading it into a current Chrome.
  3. The target option controls JavaScript syntax down leveling; with an evergreen Chrome you can target a modern baseline like ['chrome120'] or ['esnext'].

That's all, I hope this post is useful to you and that you can apply it to a project you have in mind. Leave me a comment if it helped or if you have any questions, and remember that if you liked it, you can also share it using the social links below. Good luck and keep building!

Sebastian Gomez

Sebastian Gomez

Creador de contenido principalmente acerca de tecnología.

Leave a Reply

0 Comments

Advertisements

Related Posts

Categorias