Package Exports
- rollup-plugin-chrome-extension
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (rollup-plugin-chrome-extension) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
rollup-plugin-chrome-extension
A feature-rich solution for bundled Chrome extensions! 💯
Build Chrome extensions using Rollup, with minimal configuration.
Use manifest.json
as the input. Every file in the manifest will
be bundled or copied to the output folder.
Table of Contents
Getting started
Chrome Extension Boilerplates
We have TypeScript and JavaScript boilerplates available.
Get started fast with the JavaScript React boilerplate:
git clone https://github.com/extend-chrome/js-react-boilerplate.git
Or use the TypeScript React boilerplate if you're feeling fancy:
git clone https://github.com/extend-chrome/ts-react-boilerplate.git
Special thanks to @kyrelldixon for this Svelte and Tailwind CSS boilerplate with optional TypeScript support:
git clone https://github.com/kyrelldixon/svelte-tailwind-extension-boilerplate.git
I want to do it myself
npm i rollup rollup-plugin-chrome-extension@latest -D
Install the plugins Node Resolve and CommonJS if you plan to use npm modules.
npm i @rollup/plugin-node-resolve @rollup/plugin-commonjs -D
Usage
Create a rollup.config.js
file in your project root.
// rollup.config.js
import resolve from '@rollup/plugin-node-resolve'
import commonjs from '@rollup/plugin-commonjs'
import {
chromeExtension,
simpleReloader,
} from 'rollup-plugin-chrome-extension'
export default {
input: 'src/manifest.json',
output: {
dir: 'dist',
format: 'esm',
},
plugins: [
// always put chromeExtension() before other plugins
chromeExtension(),
simpleReloader(),
// the plugins below are optional
resolve(),
commonjs(),
],
}
Add these scripts to your package.json
file.
// package.json
{
"scripts": {
"build": "rollup -c",
"start": "rollup -c -w"
}
}
Put your Chrome extension source code in a folder named src
in
the root of your project and build with the following command:
npm run build
Your extension build will be in the dist
folder. It has
everything it needs: manifest, scripts, and assets (images, css,
etc...).
Load it in Chrome chrome://extensions/
to test drive your
extension! 🚗
Features
⭐️ It's all in the Manifest
Why does the `rollup.config.js` only need the manifest as an entry point?
`rollup-plugin-chrome-extension` parses your manifest and bundles the scripts in your background page, content scripts, option page and popup page
Does that include the scripts in the Options page and Popup page?
`rollup-plugin-chrome-extension` uses the JS or even TS files in your HTML files as entry points. Shared code is split out into chunks automatically, so libraries like React and Lodash aren't bundled into your extension multiple times.
What happens with the assets? Like images, icons or css files?
All assets declared in the manifest (including files in `web_accessible_resources`, any image, icon, font, and even CSS files) are automatically copied into the output folder. Even the images in your HTML files get copied over. NOTE: This only includes assets in the html itself. If you import images or CSS in a JavaScript file, you will need an additional plugin.
Is the Manifest validated?
`rollup-plugin-chrome-extension` validates your output manifest, so you discover mistakes when you build, not in a cryptic Chrome alert later.
Does it detect permissions automatically?
`rollup-plugin-chrome-extension` statically analyzes your bundled code, detects any required permissions and adds them to the manifest in the `dist` folder. Any permissions in the source manifest are always included.
Do I have to copy/paste the package.json fields to the Manifest?
You can omit `manifest_version`, `version`, `name`, and `description` from your source `manifest.json`. We'll fill them out automatically from your `package.json`, if you use an npm script to run Rollup. Just manage your version number in `package.json` and it will reflect in your extension build.
Don't worry, any value in your source manifest will take over! 😉
⭐️ Reload Your Extension Automatically
Does this mean I don't have to manually reload my extension during development?
Improve your development experience with our reloader! You won't have to reload your Chrome extension every time you make a change to your code. We know what a pain it can be to forget and wonder, "Why isn't this change working? 😟".
Does it also reload the pages I am injecting content scripts?
Ever got the error `"Extension context invalidated"` in your content script? That happens when the extension reloads but the content script doesn't. Our reloader makes sure that doesn't happen by reloading your content scripts when it reloads your extension automatically.
How do I enable the reloader?
If you include the helper plugin `simpleReloader` in your config, when Rollup is in watch mode your background page will include an auto-reloader script. This will reload your extension every time Rollup produces a new build.
⭐️ Write Chrome Extensions In TypeScript
Includes Chrome extension API types
If you use the
@rollup/plugin-typescript
,
you can write your Chrome extension in TypeScript. That's right,
it bundles the scripts in your manifest and in your HTML script
tags.
TypeScript definitions are included, so no need to install an
additional @types
library!
⭐️ Use ES2015 Modules In Your Scripts
Chrome extensions don't support modules in background and content scripts. We've developed a module loader specifically for Chrome extension scripts, so you can take advantage of Rollup's great code splitting features.
⭐️ How does the dynamic import wrapper work?
TLDR; RPCE parses the manifest and replaces any script path with an IIFE wrapper that loads the script using a dynamic import statement.
See Why do we need to use dynamic import in scripts? for the reasons we need dynamic imports. Content scripts are pretty straight forward, and the wrapper they use is just an IIFE that loads the script and logs any import errors. Background pages need a special wrapper because wake events (onInstalled, onMessage, etc...) fire before the import completes. We make sure we don’t miss any events by capturing all events that occur before the import promise resolves and then re-dispatch them after the import completes.
⭐️ What About FireFox Support?
Until v89, Firefox did not support dynamic imports in web extensions, so any scripts needed to be in another format, like IIFE. The suggested solution was to run Parcel on the Rollup output, but this won’t be necessary once Firefox v89 is released.
⭐️ Use Promises like it's 2021
Add the excellent promisified Browser API polyfill by Mozilla to your Chrome extension with one easy option:
chromeExtension({ browserPolyfill: true })
This option adds browser
to the global scope, so you don't need to import anything.
Install this type package to get Intellisense. It's automatically updated on a regular basis.
⭐️ Plugins Take It To The Next Level
Take advantage of other great Rollup plugins to do awesome things with your Chrome extensions!
Some of our favorites are:
- Write your extension in TS with
@rollup/plugin-typescript
- Import CSS in JS files with
rollup-plugin-postcss
- Zip your extension when you build with
rollup-plugin-zip
. - Copy any assets not included in the manifest.json
rollup-plugin-copy
.
Two of our own plugins:
- Import a module as a string of code to use in
chrome.runtime.executeScript
withrollup-plugin-bundle-imports
- Empty your output folder before a new build with
rollup-plugin-empty-dir
⭐️ Outputs a Chrome Web Store friendly bundle
Every time you publish your Chrome extension to the Web Store,
your extension will be reviewed by a robot and then a human to
make sure it meets their guidelines. Even if you pass when you
first publish, your extension may be flagged at any time.
rollup-plugin-chrome-extension
helps you put your best foot
forward.
Wrong permissions are the number one reason that Chrome
extensions are rejected from the Chrome Web Store.
rollup-plugin-chrome-extension
can detect most of the commonly
used permissions in your code automatically, so you only need to
add a permission manually if you absolutely know that you need
it.
Imagine the person who reviews the code you submit. Common bundling options like webpack and Parcel produce code that is really hard to read. Rollup produces code that is easy to read! When you submit your extension for review, you want to avoid misunderstandings.
Rollup produces a nice clean bundle using code splitting, ES modules, and tree-shaking. If you don't use some piece of code, Rollup removes it. If you use a module in more than once place, Rollup splits it out into a chunk, so that it's only in your extension once.
All of this means a smaller Chrome extension. We've seen Chrome
extensions go from over 8Mb to less than 1Mb just by switching
from create-react-app
to Rollup. A smaller bundle means less
code to review, and less room for error during the review
process.