search
HomeWeb Front-endJS TutorialChrome extension - environment setup

I want some goofy functionality in my browser. Maybe I can add it with a simple extension? It doesn't exist, but writing it myself should be easy, right?

That's what I thought a couple of days ago. While I wasn't completely wrong, some parts of the development process were a bit more time-consuming than I expected. I won't say difficult, but rather hard to figure out using available documentation. While API documentation, core concepts, etc. are described quite nicely on developer.chrome.com, I wanted a specific developer experience:

  • TypeScript with proper typing of chrome namespace
  • Splitting the code into multiple files and import/export what was necessary
  • Debugging my code with simple console.log and/or debugger
  • Autocompletion in my manifest.json
  • Simple setup, without any bundlers and half of the Internet in my node_modules
  • Simple way of updating and testing the extension in the browser

In a better or worse way, I managed to set things up as I wanted. In this post, I'll briefly explain general extension concepts and show you how I've set up my development environment. In the next post or two I'll focus on the implementation details of my simple page-audio extension.

TLDR:
If you just want the code, here's the boilerplate repo:

Chrome extension  - environment setup Voodu / chromium-extension-boilerplate

Chromium extension boilerplate

This repository aims at being a starting point for developing a chromium extension.

It's as minimalistic as possible, but comes with pre-configured:

  • autocompletion for manifest.json
  • TypeScript transpilation from ts folder to dist directory
  • types for chrome namespace
  • properly working exporting and importing (with VS Code workspace setting for correct auto import format)
  • example manifest.json

Happy coding!


View on GitHub


ℹ️ I use Windows 11, MS Edge, VS Code and npm everywhere below ℹ️


Brief intro to extensions

Chrome extension  - environment setup

Let's start with a crash course on general extension concepts.

Every extension has a manifest.json file that defines its name, version, required permissions, and used files. Extensions can provide functionality in several different ways:

  • via popup - extension popup is this small window that opens when you click the extension icon in the extension bar,
  • via content scripts - scripts that are injected directly into websites and have DOM access,
  • via background (service worker) scripts - scripts run in a separate context, independent from opened websites

There are other ways, but I'll stick to these three in this guide.

Another important concept is messaging. Usually, we need to combine the above methods, as all of them have different limitations. For example, background scripts don't depend on opened tabs and can be more useful for persisting state, but can't access the DOM of any website. Therefore, we might need to get some extension-wide data from the background script, pass it using a message to a content script, and modify the website from there.

It can also be useful to understand some basics about permissions. In short, some APIs won't work as expected if manifest.json doesn't specify the correct permissions. For example, if we don't specify "tabs" permission, objects returned from the tabs API won't have a url field. On the other hand, we shouldn't ask for too many permissions - if the extension is going to be public, users might be concerned about giving access to too many things.


Creating a simple extension

Chrome extension  - environment setup

Inspired by https://developer.chrome.com/docs/extensions/get-started/tutorial/hello-world

Let's start with understanding the core concepts of our development workflow using an extremely simple extension that just displays some text in a popup.

Files

First of all, we need a manifest.json file:

// manifest.json
{
  "name": "Hello World",
  "description": "Shows Hello World text",
  "version": "1.0",
  "manifest_version": 3,
  "action": {
    "default_popup": "hello.html",
    "default_icon": "icon.png"
  }
}

name, description, version, and manifest_version are probably self-explanatory. action.default_popup is a path to an HTML file that will be rendered upon clicking the extension icon. default_icon is a path to extension icon. Both paths are relative to manifest.json location.

Now, add icon.png (for example, this one) and hello.html files in the same directory as manifest.json.
hello.html can look like that:

<!-- hello.html -->
<p>Hello world</p>

And your whole directory should look like that:

// manifest.json
{
  "name": "Hello World",
  "description": "Shows Hello World text",
  "version": "1.0",
  "manifest_version": 3,
  "action": {
    "default_popup": "hello.html",
    "default_icon": "icon.png"
  }
}

Activating the extension

To activate your extension:

  1. Go to edge://extensions/
  2. In the left sidebar, enable "Developer mode"
    • "Allow extensions from other stores" might also be needed
  3. Above the extension list click "Load unpacked"
  4. Select the folder with your extension files
  5. Your extension should appear on the list and its icon in the extensions toolbar ?

Now, after clicking the icon it will show a small popup with "Hello world" text.

That covers the most important basics. Let's move to something more interesting.

Chrome extension  - environment setup


Page-Audio extension environment setup

Chrome extension  - environment setup

Autocomplete in manifest.json

We'll start again with the manifest.json and empty directory.

It would be awesome to have autocomplete when writing the manifest.json file, wouldn't it? Fortunately, it's a well-defined standard and has a JSON schema at https://json.schemastore.org/chrome-manifest. We just need it under the "$schema" key at the beginning of manifest.json:

<!-- hello.html -->
<p>Hello world</p>

and VS Code instantly starts helping us by suggesting field names and showing warnings if mandatory fields are missing. Awesome!?

To have something working for testing our setup, use manifest.json looking this way:

.
├── hello.html
├── icon.png
└── manifest.json
  • icons - it's just a different way of specifying extension icons
  • background section - specifies the path with the service worker JS file and its type; it's module as the code will use export and import later on

TypeScript

Using TypeScript... well, requires TypeScript. If you don't have it installed, start with

// manifest.json
{
    "$schema": "https://json.schemastore.org/chrome-manifest"
}

Basic config

To have things organized, but not too complicated, I'll keep .ts source files in the ts directory. They will be taken from there by the transpiler and put in the dist directory as .js files.

This is described by the following .tsconfig:

// manifest.json
{
    "$schema": "https://json.schemastore.org/chrome-manifest",
    "name": "Page Audio",
    "version": "0.0.0.1",
    "manifest_version": 3,
    "icons": {
        "16": "icons/logo16x16.png",
        "32": "icons/logo32x32.png",
        "48": "icons/logo48x48.png",
        "128": "icons/logo128x128.png"
    },
    "background": {
        "service_worker": "dist/background.js",
        "type": "module"
    }
}

The most important bits are compiler.rootDir and compiler.outDir. The other fields can have different values or be completely removed (at least some of them).

That's the basic configuration - placing some files in the ts directory and running tsc in the root directory will create a corresponding .js file in dist. However, we're missing one important part - types for the chrome namespace that we'll be using. The simplest solution is to add them via npm.

Adding chrome types

Create an empty package.json, just with the brackets:

// manifest.json
{
  "name": "Hello World",
  "description": "Shows Hello World text",
  "version": "1.0",
  "manifest_version": 3,
  "action": {
    "default_popup": "hello.html",
    "default_icon": "icon.png"
  }
}

and in the command line run:

<!-- hello.html -->
<p>Hello world</p>

You can also add scripts to run tsc build and in the watch mode. Final package.json should look like this:

.
├── hello.html
├── icon.png
└── manifest.json

ℹ️ chrome-types version might be higher in your case. ℹ️

After adding the types, we need to let TypeScript know about them. To do this, simply update .tsconfig.json:

// manifest.json
{
    "$schema": "https://json.schemastore.org/chrome-manifest"
}

To test if our setup works correctly:

  1. In the ts folder, create background.ts file with the following content

    // manifest.json
    {
        "$schema": "https://json.schemastore.org/chrome-manifest",
        "name": "Page Audio",
        "version": "0.0.0.1",
        "manifest_version": 3,
        "icons": {
            "16": "icons/logo16x16.png",
            "32": "icons/logo32x32.png",
            "48": "icons/logo48x48.png",
            "128": "icons/logo128x128.png"
        },
        "background": {
            "service_worker": "dist/background.js",
            "type": "module"
        }
    }
    
    
  2. In the command line, run

    npm install -g typescript
    
  3. Verify if the dist directory was created and background.js file appeared there

  4. Change something in the console.log string in ts/background.ts file and save it

  5. Check if it automatically updated dist/background.js.

If that works, awesome! We have nearly everything set up ?

You can also verify if your directory structure looks similar to that:

// .tsconfig
{
    "compilerOptions": {
        "target": "ES6",
        "module": "ES6",
        "outDir": "./dist",
        "rootDir": "./ts",
        "strict": true,
    }
}

import and export

As I've mentioned, I would like to split the code into smaller files. To do this, exporting and importing must work correctly.

One step in that direction was specifying our service_worker in manifest.json as "type": "module". However, there's one difference between TypeScript and JavaScript when working with modules - while TypeScript doesn't need file extensions when importing, JavaScript does. So, for example, this import:

// package.json
{
}

will work in TS, but JS needs

npm i -D chrome-types

It's also important to understand, that TS transpiler does nothing to the import paths. And it's "smart" enough to understand that when importing from file.js it should also look for file.ts.

Combining all of that, TS will also be happy with JS-style import and will use the corresponding TS file when importing from file.js. What we need to do is make sure that all imports in TS files have a .js extension. To automate it in VS Code:

  1. Press CTRL , to open settings
  2. Switch to "Workspace" tab
  3. Search for typescript.preferences.importModuleSpecifierEnding
  4. Set it to ".js / .ts" option

Now, whenever you auto import using VS Code, it will add .js to the filename ?

To test if things work correctly:

  1. Create ts/hello.ts file with the following content

    // package.json
    {
        "scripts": {
            "build": "tsc",
            "watch": "tsc -w"
        },
        "devDependencies": {
            "chrome-types": "^0.1.327"
        }
    }
    
  2. In ts/background.ts remove the current console.log line and start typing "hello"

  3. VS Code should autocomplete it and add the correct import after you accept the suggestion with Tab

  4. In the end, the file should look like this:

    // manifest.json
    {
      "name": "Hello World",
      "description": "Shows Hello World text",
      "version": "1.0",
      "manifest_version": 3,
      "action": {
        "default_popup": "hello.html",
        "default_icon": "icon.png"
      }
    }
    

Note that import ends with the .js extension. If you check dist/background.js the extension is there as well and that's what makes everything work correctly.

To make sure we are at the same stage, you can compare the directory structure:

<!-- hello.html -->
<p>Hello world</p>

Dev Tools for service worker

Okay, we have a decent development experience. We've also added some console.log calls... but where to find them now?

If you add console.log inside a content script, you can simply open Dev Tools and they will be there, as content scripts work in the same context as the page they are injected into. However, console.logs from background scripts are hidden a bit more.

  1. Open edge://extensions/ and load your extension if you haven't done that yet
  2. Find your extension on the list
  3. Click "service worker" link in "Inspect views" line:

    Chrome extension  - environment setup

  4. A new Dev Tools window should open and you'll see logs from the service worker there

    • if you don't see the logs, click "Reload" below the "Inspect views"

The three links at the bottom of the tile are also very important

  • "Reload" - refreshes the whole extension, including changes to manifest.json; checkout this table to understand when reloading might be needed
  • "Remove" - deletes the extension
  • "Details" - shows more information about the extension, for example, its permissions
  • (optional) "Errors" - if there are errors when installing the service worker, this link will appear and take you to the list of errors

Phew. That took a moment, but, finally, our environment is set up nicely. From now on, we'll just have to

  1. Run npm run watch (if you stopped it)
  2. Write our code in ts directory
  3. (Optionally) Reload the extension from the extensions tab

And our extension will be automatically updated! ⚙️

If you have an idea how to also "Reload" automatically (w/o elaborate hacking), let me know in the comments

Summary

Chrome extension  - environment setup

We have our environment ready!

  • Autocomplete works in manifest.json, so we don't have to guess what are the correct values
  • TypeScript helps us with using chrome API correctly
  • Code can be split into smaller, logical files
  • The code we write in the ts folder is updated automatically
  • We know where to find Dev Tools for the service worker and content scripts

In the next part, I'll describe the implementation details of my small "Page audio" extension.

Thanks for reading!

The above is the detailed content of Chrome extension - environment setup. For more information, please follow other related articles on the PHP Chinese website!

Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
JavaScript's Role: Making the Web Interactive and DynamicJavaScript's Role: Making the Web Interactive and DynamicApr 24, 2025 am 12:12 AM

JavaScript is at the heart of modern websites because it enhances the interactivity and dynamicity of web pages. 1) It allows to change content without refreshing the page, 2) manipulate web pages through DOMAPI, 3) support complex interactive effects such as animation and drag-and-drop, 4) optimize performance and best practices to improve user experience.

C   and JavaScript: The Connection ExplainedC and JavaScript: The Connection ExplainedApr 23, 2025 am 12:07 AM

C and JavaScript achieve interoperability through WebAssembly. 1) C code is compiled into WebAssembly module and introduced into JavaScript environment to enhance computing power. 2) In game development, C handles physics engines and graphics rendering, and JavaScript is responsible for game logic and user interface.

From Websites to Apps: The Diverse Applications of JavaScriptFrom Websites to Apps: The Diverse Applications of JavaScriptApr 22, 2025 am 12:02 AM

JavaScript is widely used in websites, mobile applications, desktop applications and server-side programming. 1) In website development, JavaScript operates DOM together with HTML and CSS to achieve dynamic effects and supports frameworks such as jQuery and React. 2) Through ReactNative and Ionic, JavaScript is used to develop cross-platform mobile applications. 3) The Electron framework enables JavaScript to build desktop applications. 4) Node.js allows JavaScript to run on the server side and supports high concurrent requests.

Python vs. JavaScript: Use Cases and Applications ComparedPython vs. JavaScript: Use Cases and Applications ComparedApr 21, 2025 am 12:01 AM

Python is more suitable for data science and automation, while JavaScript is more suitable for front-end and full-stack development. 1. Python performs well in data science and machine learning, using libraries such as NumPy and Pandas for data processing and modeling. 2. Python is concise and efficient in automation and scripting. 3. JavaScript is indispensable in front-end development and is used to build dynamic web pages and single-page applications. 4. JavaScript plays a role in back-end development through Node.js and supports full-stack development.

The Role of C/C   in JavaScript Interpreters and CompilersThe Role of C/C in JavaScript Interpreters and CompilersApr 20, 2025 am 12:01 AM

C and C play a vital role in the JavaScript engine, mainly used to implement interpreters and JIT compilers. 1) C is used to parse JavaScript source code and generate an abstract syntax tree. 2) C is responsible for generating and executing bytecode. 3) C implements the JIT compiler, optimizes and compiles hot-spot code at runtime, and significantly improves the execution efficiency of JavaScript.

JavaScript in Action: Real-World Examples and ProjectsJavaScript in Action: Real-World Examples and ProjectsApr 19, 2025 am 12:13 AM

JavaScript's application in the real world includes front-end and back-end development. 1) Display front-end applications by building a TODO list application, involving DOM operations and event processing. 2) Build RESTfulAPI through Node.js and Express to demonstrate back-end applications.

JavaScript and the Web: Core Functionality and Use CasesJavaScript and the Web: Core Functionality and Use CasesApr 18, 2025 am 12:19 AM

The main uses of JavaScript in web development include client interaction, form verification and asynchronous communication. 1) Dynamic content update and user interaction through DOM operations; 2) Client verification is carried out before the user submits data to improve the user experience; 3) Refreshless communication with the server is achieved through AJAX technology.

Understanding the JavaScript Engine: Implementation DetailsUnderstanding the JavaScript Engine: Implementation DetailsApr 17, 2025 am 12:05 AM

Understanding how JavaScript engine works internally is important to developers because it helps write more efficient code and understand performance bottlenecks and optimization strategies. 1) The engine's workflow includes three stages: parsing, compiling and execution; 2) During the execution process, the engine will perform dynamic optimization, such as inline cache and hidden classes; 3) Best practices include avoiding global variables, optimizing loops, using const and lets, and avoiding excessive use of closures.

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

mPDF

mPDF

mPDF is a PHP library that can generate PDF files from UTF-8 encoded HTML. The original author, Ian Back, wrote mPDF to output PDF files "on the fly" from his website and handle different languages. It is slower than original scripts like HTML2FPDF and produces larger files when using Unicode fonts, but supports CSS styles etc. and has a lot of enhancements. Supports almost all languages, including RTL (Arabic and Hebrew) and CJK (Chinese, Japanese and Korean). Supports nested block-level elements (such as P, DIV),

VSCode Windows 64-bit Download

VSCode Windows 64-bit Download

A free and powerful IDE editor launched by Microsoft

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

PhpStorm Mac version

PhpStorm Mac version

The latest (2018.2.1) professional PHP integrated development tool

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

Powerful PHP integrated development environment