Develop Chrome Extension with Angular CLI

I've been developing extensions for Chrome for a long time and during this time I have gone a whole way from Greasemonkey user scripts to a full-fledged Angular application in the chrome-extension shell. My task is that I will patch some already working sites in order to change their functionality and automate some processes on these sites. Sometimes my application grows to a large scale and it becomes difficult to support plain-js extension (there are a lot of settings in the application, CRUD functionality, etc.). And then Angular comes to the rescue.

In this article, I’ll tell you how I made friends with Chrome Extension and Angular CLI , and set up the development process, as well as what difficulties I encountered and how to solve them.
Create a new folder and initialize a new application in it.

mkdir new-project
cd new-project
ng new frontend --routing=true --skipGit=true --style=scss --skipTests=true

At the development stage, Angular generates a dynamic html file in which development takes place, and the Chrome extension needs to be fed a static html file to see the result of the work. Of course, you can separately assemble the Angulyarovsk project and then build the build version in addition, but it will be convenient if this happens automatically.

After generating a new application, go to the frontend folder and in the package.json file in the scripts section add a new script to build our project

"developing": "ng build --watch --deploy-url /frontend/dist/frontend/ --base-href /frontend/dist/frontend/index.html?/"

Pay attention to deploy-urland base-href.

Then, in the root of the project, create another extension folder and create the extension.js file in it , which will be the background script for our extension. Current project structure:

| new-project/
| | extension/
| | | extension.js
| | frontend/
| | | ...

Content extension.js

const ANGULAR_HTML_URL = "../../frontend/dist/frontend/index.html";
chrome.browserAction.onClicked.addListener(function () {
        url: chrome.runtime.getURL(ANGULAR_HTML_URL)

This will be browserAction , which will open a new tab with our angular application, which in assembled form will already be stored along this path.

Add manifest.json to our project
  "manifest_version": 2,
  "name": "Simple Chrome Ext",
  "description": "Simple Chrome Extension as an example",
  "version": "1.00",
  "author": "Bogdan",
  "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
  "background": {
    "persistent": true,
    "scripts": ["/extension/extension.js"]
  "browser_action": {
    "default_title": "Chrome ext"

Now we can assemble our project into an extension. We go in chrome: // extensions / , enable developer mode and select Download unpacked extension .


The convenience is that we have almost hot-reloading. We launched ng build with the watch flag and when the code changes, the project will be rebuilt and the js files will be replaced. That is, on the extension page, we only need to reload the page and all updates will be picked up. This greatly speeds up the development of add-ons.

Another point at which I ate the dog is that in the routing configuration:

   useHash: true

and also we will return above, base-href at build we registered as /frontend/dist/frontend/index.html?/ - pay attention to a question mark before the last slash. The fact is that on some systems, when you click on the links in the Angular application, everything crashes without this sign. Apparently, the static web server of the chrome engine perceived the URL change as a request to another file (even though useHash: true) and when updating the page it returned a 404 error. Only in this combination I managed to achieve stable operation on all systems.

Let's go back to the package.json of our application and add another script

"prod": "ng build --sourceMap false --prod true --deploy-url /frontend/dist/frontend/ --base-href /frontend/dist/frontend/index.html?/"

This will be the script to build our application for the production version.

In the Chrome Web Store, a zip archive with the extension is posted and to simplify the assembly I made a script for these purposes
rm -rf ./prod-build
mkdir -p prod-build/frontend
cd frontend
npm run prod
cd ..
cp -R ./frontend/dist ./prod-build/frontend
cp -R ./extension ./prod-build
cp ./manifest.json ./prod-build
zip -r prod-build{.zip,}
rm -rf ./prod-build

The source code can be found here .

Total: we created a pre-development kit for Angular Chrome Extension with the correct routing and convenient update / build of the application.

PS: in order to get rid of such a / frontend / dist / frontend / path, you can configure the environment and specify the path in the production assembly differently, but this is not the key point.

Also popular now: