diff --git a/README.md b/README.md
index 57d3f3c2..7d9606d8 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@ A Webpack plugin to automatically reload browser extensions during development.
-
+
[](https://www.npmjs.com/package/webpack-ext-reloader)
[](https://github.com/SimplifyJobs/webpack-ext-reloader/actions?query=branch%3Amaster)
[](https://snyk.io/test/github/SimplifyJobs/webpack-ext-reloader/)
@@ -17,13 +17,13 @@ A Webpack plugin to automatically reload browser extensions during development.
## Installing
-npm
+For npm:
```bash
npm install webpack-ext-reloader --save-dev
```
-yarn
+For yarn:
```bash
yarn add webpack-ext-reloader --dev
@@ -31,20 +31,19 @@ yarn add webpack-ext-reloader --dev
## What is this?
-This is a webpack plugin that allows you to bring hot reloading functionality to WebExtensions, essentially `webpack-dev-server`, but for (WebExtensions)[https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions].
+This is a webpack plugin that brings hot reloading functionality to WebExtensions, essentially resembling `webpack-dev-server` but for [WebExtensions](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions).
-This is a fork from [`webpack-extension-reloader`](https://github.com/rubenspgcavalcante/webpack-extension-reloader), maintained and updated by the team here at Simplify. The goal here is to continue to support the latest version of webpack (`webpack-extension-reloader` only supports webpack v4) while adding new improvements (i.e. HMR).
+This project is a fork of [`webpack-extension-reloader`](https://github.com/rubenspgcavalcante/webpack-extension-reloader), maintained and updated by the team at Simplify. The goal is to continue supporting the latest version of webpack (`webpack-extension-reloader` only supports webpack v4) while introducing new improvements, such as HMR.

-**Note**: This plugin doesn't support [**Hot Module Replacement (HMR)**](https://webpack.js.org/concepts/hot-module-replacement/) yet.
+**Note**: This plugin does not support [**Hot Module Replacement (HMR)**](https://webpack.js.org/concepts/hot-module-replacement/) yet.
## How to use
### Using as a plugin
-Add `webpack-ext-reloader` to the plugins section of your webpack configuration file. Note that this plugin don't outputs the manifest (at most read it to gather information).
-For outputing not only the `manifest.json` but other static files too, use `CopyWebpackPlugin`.
+Add `webpack-ext-reloader` to the plugins section of your webpack configuration file. This plugin does not output the manifest; it might read it for information at most. For outputting not only the `manifest.json` but other static files as well, use `CopyWebpackPlugin`.
```js
const ExtReloader = require('webpack-ext-reloader');
@@ -58,7 +57,7 @@ plugins: [
]
```
-You can point to your `manifest.json file`...
+You can point to your `manifest.json` file...
```js
plugins: [
@@ -81,7 +80,7 @@ module.exports = {
background: './my-background-script.js',
popup: 'popup',
},
- //...
+ // ...
plugins: [
new ExtReloader({
port: 9090, // Which port use to create the server
@@ -97,89 +96,86 @@ module.exports = {
}
```
-**Note I**: `entry` or `manifest` are needed. If both are given, entry will override the information comming from `manifest.json`. If none are given the default `entry` values (see above) are used.
+**Note I**: Either `entry` or `manifest` is needed. If both are provided, the `entry` will override the information from `manifest.json`. If neither is provided, the default `entry` values (as shown above) are used.
-And then just run your application with Webpack in watch mode:
+Run your application with Webpack in watch mode:
```bash
NODE_ENV=development webpack --config myconfig.js --mode=development --watch
```
-**Note II**: You need to set `--mode=development` to activate the plugin (only if you didn't set on the webpack.config.js already) then you need to run with `--watch`, as the plugin will be able to sign the extension only if webpack triggers the rebuild (again, only if you didn't set on webpack.config).
+**Note II**: You need to set `--mode=development` to activate the plugin. If you didn't set it in the webpack.config.js already, you need to run with `--watch` since the plugin will be able to sign the extension only if webpack triggers the rebuild.
### Multiple Content Script and Extension Page support
-If you use more than one content script or extension page in your extension, like:
+If your extension uses more than one content script or extension page, like:
```js
entry: {
'my-first-content-script': './my-first-content-script.js',
'my-second-content-script': './my-second-content-script.js',
- // and so on ...
background: './my-background-script.js',
'popup': './popup.js',
'options': './options.js',
- // and so on ...
}
```
-You can use the `entries.contentScript` or `entries.extensionPage` options as an array:
+Use the `entries.contentScript` or `entries.extensionPage` options as an array:
```js
plugins: [
new ExtReloader({
entries: {
- contentScript: ['my-first-content-script', 'my-second-content-script', /* and so on ... */],
+ contentScript: ['my-first-content-script', 'my-second-content-script'],
background: 'background',
- extensionPage: ['popup', 'options', /* and so on ... */],
+ extensionPage: ['popup', 'options'],
}
}),
- // ...
]
```
### CLI
-If you don't want all the plugin setup, you can just use the client that comes with the package.
-You can use by installing the package globally, or directly using `npx`:
+If you'd rather skip the plugin setup, you can use the client included with the package. Install the package globally or use `npx`:
```bash
npx webpack-ext-reloader
```
-If you run directly, it will use the default configurations, but if you want to customize
-you can call it with the following options:
+If run directly, it will use the default configurations. But if you'd like customization:
```bash
npx webpack-ext-reloader --config wb.config.js --port 9080 --no-page-reload --content-script my-content.js --background bg.js --extension-page popup.js
```
-If you have **multiple** content scripts or extension pages, just use comma (with no spaces) while passing the option
+For **multiple** content scripts or extension pages, separate the options with commas (without spaces):
```bash
-npx webpack-ext-reloader --content-script my-first-content.js,my-second-content.js,my-third-content.js --extension-page popup.js,options.js
+npx webpack-ext-reloader --content-script my-first-content.js,my-second-content.js --extension-page popup.js,options.js
```
### Client options
-| name | default | description |
-| ---------------- | ----------------- | ----------------------------------------------------------------- |
-| --help | | Shows this help |
-| --config | webpack.config.js | The webpack configuration file path |
-| --port | 9090 | The port to run the server |
-| --manifest | | The path to the extension **manifest.json** file |
-| --content-script | content-script | The **entry/entries** name(s) for the content script(s) |
-| --background | background | The **entry** name for the background script |
-| --extension-page | popup | The **entry/entries** name(s) for the extension pages(s) |
-| --no-page-reload | | Disable the auto reloading of all **pages** which runs the plugin |
+| Name | Default | Description |
+| ----------------- | ----------------- | ----------------------------------------------------------------- |
+| --help | | Shows help |
+| --config | webpack.config.js | Path to the webpack configuration file |
+| --port | 9090 | Port to run the server on |
+| --manifest | | Path to the extension's **manifest.json** file |
+| --content-script | content-script | **Entry/entries** name(s) for the content script(s) |
+| --background | background | **Entry** name for the background script |
+| --extension-page | popup | **Entry/entries** name(s) for the extension page(s) |
+| --no-page-reload | | Disable auto-reloading of all **pages** running the plugin |
-Every time content or background scripts are modified, the extension is reloaded :)
-**Note:** the plugin only works on **development** mode, so don't forget to set the NODE_ENV before run the command above
+Whenever content or background scripts are modified, the extension will reload.
+**Note**: This plugin only works in **development** mode. Remember to set the NODE_ENV before running the commands above.
### Contributing
-Please before opening any **issue** or **pull request** check the [contribution guide](/.github/CONTRIBUTING.MD).
+Before opening any **issue** or **pull request**, please refer to the [contribution guide](/.github/CONTRIBUTING.MD).
### License
-This project has been forked from [rubenspgcavalcante/webpack-extension-reloader](https://github.com/rubenspgcavalcante/webpack-extension-reloader), which is licensed under the [MIT license](https://github.com/rubenspgcavalcante/webpack-extension-reloader/blob/master/LICENSE). All changes made in this fork have been licensed via the [MIT license](https://github.com/SimplifyJobs/webpack-ext-reloader/blob/master/LICENSE).
+This project is a fork from [rubenspgcavalcante/webpack-extension-reloader](https://github.com/rubenspgcavalcante/webpack-extension-reloader), which is licensed under the [MIT license](https://github.com/rubenspgcavalcante/webpack-extension-reloader/blob/master/LICENSE
+
+). All modifications made in this fork are also licensed under the [MIT license](https://github.com/SimplifyJobs/webpack-ext-reloader/blob/master/LICENSE).
diff --git a/package-lock.json b/package-lock.json
index ddb209ba..fb93772d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15,6 +15,7 @@
"clean-webpack-plugin": "^4.0.0",
"colors": "^1.4.0",
"cross-env": "^7.0.3",
+ "json5": "^2.2.3",
"lodash": "^4.17.21",
"minimist": "^1.2.6",
"useragent": "^2.3.0",
@@ -6317,7 +6318,6 @@
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
- "dev": true,
"bin": {
"json5": "lib/cli.js"
},
diff --git a/package.json b/package.json
index fe0cb1a5..7ec26081 100644
--- a/package.json
+++ b/package.json
@@ -23,10 +23,10 @@
]
},
"scripts": {
- "build": "NODE_ENV=production webpack",
- "test": "NODE_ENV=test webpack && mocha dist/tests.js",
- "analyze": "NODE_ENV=production webpack --env.analyze",
- "start:dev": "NODE_ENV=development webpack --watch",
+ "build": "cross-env NODE_ENV=production webpack",
+ "test": "cross-env NODE_ENV=test webpack && mocha dist/tests.js",
+ "analyze": "cross-env NODE_ENV=production webpack --env.analyze",
+ "start:dev": "cross-env NODE_ENV=development webpack --watch",
"start:sample:chrome": "cross-env NODE_ENV=development cross-env TARGET_BROWSER=chrome webpack --config sample/webpack.plugin.js --watch",
"start:sample:firefox": "cross-env NODE_ENV=development cross-env TARGET_BROWSER=firefox webpack --config sample/webpack.plugin.js --watch",
"prepublishOnly": "npm run build",
@@ -56,6 +56,7 @@
"clean-webpack-plugin": "^4.0.0",
"colors": "^1.4.0",
"cross-env": "^7.0.3",
+ "json5": "^2.2.3",
"lodash": "^4.17.21",
"minimist": "^1.2.6",
"useragent": "^2.3.0",
diff --git a/src/messages/errors.ts b/src/messages/errors.ts
index ded58890..5c48dfc8 100644
--- a/src/messages/errors.ts
+++ b/src/messages/errors.ts
@@ -10,4 +10,8 @@ the provided on 'manifest.json' or 'entry.background' \
option of the plugin",
);
-export const bgScriptManifestRequiredMsg = new Message(ERROR, 2, "Background script on manifest is required");
+export const bgScriptManifestRequiredMsg = new Message(
+ ERROR,
+ 2,
+ "Background script or service worker on manifest is required",
+);
diff --git a/src/middleware/wer-middleware.raw.ts b/src/middleware/wer-middleware.raw.ts
index 2f6089ab..9f16dd8a 100644
--- a/src/middleware/wer-middleware.raw.ts
+++ b/src/middleware/wer-middleware.raw.ts
@@ -5,7 +5,7 @@
/* This will be converted into a lodash templ., any */
/* external argument must be provided using it */
/* -------------------------------------------------- */
-(function(window) {
+(function() {
const injectionContext = this || window || {browser: null};
@@ -71,7 +71,9 @@
if (type === SIGN_CHANGE && (!payload || !payload.onlyPageChanged)) {
tabs.query({ status: "complete" }).then(loadedTabs => {
loadedTabs.forEach(
- tab => tab.id && tabs.sendMessage(tab.id, { type: SIGN_RELOAD }),
+ // in MV3 tabs.sendMessage returns a Promise and we need to catch the errors
+ // https://groups.google.com/a/chromium.org/g/chromium-extensions/c/st_Nh7j3908/m/1muOgSX5AwAJ
+ tab => tab.id && tabs.sendMessage(tab.id, { type: SIGN_RELOAD })?.catch(() => null),
);
socket.send(
JSON.stringify({
@@ -137,9 +139,10 @@
// ======================= Bootstraps the middleware =========================== //
runtime.reload
- ? extension.getBackgroundPage() === window ? backgroundWorker(new WebSocket(wsHost)) : extensionPageWorker()
+ // in MV3 background service workers don't have access to the DOM
+ ? (typeof window === 'undefined' || extension.getBackgroundPage() === window) ? backgroundWorker(new WebSocket(wsHost)) : extensionPageWorker()
: contentScriptWorker();
-})(window);
+})();
/* ----------------------------------------------- */
/* End of Webpack Hot Extension Middleware */
diff --git a/src/utils/manifest.ts b/src/utils/manifest.ts
index b3ed89f2..81e5ced8 100644
--- a/src/utils/manifest.ts
+++ b/src/utils/manifest.ts
@@ -1,5 +1,6 @@
import { readFileSync } from "fs";
import { flatMapDeep } from "lodash";
+import JSON5 from "json5";
import { Compiler, Entry } from "webpack";
import { bgScriptEntryErrorMsg, bgScriptManifestRequiredMsg } from "../messages/errors";
@@ -8,19 +9,19 @@ export function extractEntries(
manifestPath: string,
webpackOutput: Compiler["options"]["output"] = {},
): IEntriesOption {
- const manifestJson = JSON.parse(readFileSync(manifestPath).toString()) as IExtensionManifest;
- const { background, content_scripts } = manifestJson;
+ const manifestJson = JSON5.parse(readFileSync(manifestPath).toString()) as IExtensionManifest;
+ const { background, content_scripts: contentScripts } = manifestJson;
const { filename } = webpackOutput;
if (!filename) {
throw new Error("Please specify the `output.filename` in your webpack config.");
}
- if (!background?.scripts) {
+ if (!(background?.scripts || background?.service_worker)) {
throw new TypeError(bgScriptManifestRequiredMsg.get());
}
- const bgScriptFileNames = background.scripts;
+ const bgScriptFileNames = background.service_worker ? [background.service_worker] : background.scripts ?? [];
const toRemove = (filename as string).replace("[name]", "");
const bgWebpackEntry = Object.keys(webpackEntry).find((entryName) =>
@@ -31,9 +32,9 @@ export function extractEntries(
throw new TypeError(bgScriptEntryErrorMsg.get());
}
- const contentEntries: unknown = content_scripts
+ const contentEntries: unknown = contentScripts
? flatMapDeep(Object.keys(webpackEntry), (entryName) =>
- content_scripts.map(({ js }) =>
+ contentScripts.map(({ js }) =>
js.map((contentItem) => contentItem.replace(toRemove, "")).filter((contentItem) => contentItem === entryName),
),
)
diff --git a/typings/declarations.d.ts b/typings/declarations.d.ts
index eb3bc18c..e088f087 100644
--- a/typings/declarations.d.ts
+++ b/typings/declarations.d.ts
@@ -10,10 +10,7 @@ declare interface IMiddlewareTemplateParams {
reloadPage: boolean;
}
-declare type InjectMiddleware = (
- assets: Record,
- chunks: Set,
-) => Record;
+declare type InjectMiddleware = (assets: Record, chunks: Set) => Record;
declare type MiddlewareInjector = (
{ background, contentScript, extensionPage }: IEntriesOption,
@@ -22,10 +19,7 @@ declare type MiddlewareInjector = (
declare type Triggerer = (onlyPageChanged: boolean) => Promise;
-declare type TriggererFactory = (
- port: number,
- reloadPage: boolean,
-) => Triggerer;
+declare type TriggererFactory = (port: number, reloadPage: boolean) => Triggerer;
declare type VersionPair = [number | undefined, number | undefined];
@@ -45,13 +39,7 @@ declare type LOG_WARN = 3;
declare type LOG_ERROR = 4;
declare type LOG_DEBUG = 5;
-declare type LOG_LEVEL =
- | LOG_NONE
- | LOG_LOG
- | LOG_INFO
- | LOG_WARN
- | LOG_ERROR
- | LOG_DEBUG;
+declare type LOG_LEVEL = LOG_NONE | LOG_LOG | LOG_INFO | LOG_WARN | LOG_ERROR | LOG_DEBUG;
declare interface IWebpackChunk {
files: string[];
@@ -73,13 +61,11 @@ declare interface IExtensionManifest {
background?: {
page?: string;
scripts?: string[];
+ service_worker?: string;
};
icons?: {
[key: string]: string;
};
- browser_action?: {
- default_popup: string;
- };
content_scripts?: [
{
matches: string[];
diff --git a/typings/webpack-ext-reloader.d.ts b/typings/webpack-ext-reloader.d.ts
index baf886f9..3fd6b023 100644
--- a/typings/webpack-ext-reloader.d.ts
+++ b/typings/webpack-ext-reloader.d.ts
@@ -11,9 +11,15 @@ export interface IExtensionReloaderInstance {
apply(compiler: Compiler): void;
}
-export type ExtensionReloader = new (options?: IPluginOptions) => IExtensionReloaderInstance;
+export declare class ExtensionReloader implements IExtensionReloaderInstance {
+ constructor(options?: IPluginOptions);
-declare module "webpack-extension-reloader" {
+ apply(compiler: Compiler): void;
+}
+
+export default ExtensionReloader;
+
+declare module "webpack-ext-reloader" {
export default ExtensionReloader;
export = IExtensionReloaderInstance;
}