From 440857e5f890bae2d3000be27f1665a2cdcc98a9 Mon Sep 17 00:00:00 2001 From: Luca Greco Date: Thu, 19 Jul 2018 15:56:49 +0200 Subject: [PATCH] doc: Rewrite README.md and move build and contribution details into a separate doc file (#147) --- CONTRIBUTING.md | 106 ++++++++++++++++++++++++++++++++ README.md | 159 +++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 244 insertions(+), 21 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..d1f85bd --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,106 @@ +Hi! Thanks for your interest in helping to make the "cross-browser extension" developers life easier by contributing to the `webextension-polyfill` library. + +This document provides some additional information that you may find useful while looking at how to apply changes to this library and submit them for review. + +Table of contents +================= + +* [Building](#building) +* [Test Suites](#test-suites) +* [Writing commit messages](#writing-commit-messages) + +## Building + +To build, assuming you've already installed [node >= 6](https://nodejs.org) and +[npm](https://www.npmjs.com/), simply run: + +```sh +git clone https://github.com/mozilla/webextension-polyfill.git + +cd webextension-polyfill + +npm install + +npm run test +``` + +This will install all the npm dependencies and build both non-minified and minified versions +of the final library, and output them to `dist/browser-polyfill.js` and `dist/browser-polyfill.min.js`, +respectively, and finally execute the unit tests on the generated dist files. + +## Test Suites + +This project provides two test suites: + +- unit tests (which only require Node.js to run) +- module bundlers smoke tests (which requires also browserify and webpack to be installed globally) +- integration tests (which requires also a stable version of Chrome and Firefox) + +### Unit Tests + +The unit tests run in Node.js with [Mocha](https://mochajs.org), and use jsdom and +[Sinon](https://sinonjs.org) to mock a browser-like environment for testing the library. + +The unit tests are located in the `"test/"` directory and they have to be named `"test/test-*.js"`. + +`npm run test` run all the unit tests on the non-minified version of the library, +whereas `npm run test-minified` can be used to run the unit tests on the minified version. + +Optionally code coverage data can be collected and reported while running the unit tests, +by running `npm run test-coverage`. + +### Module Bundler smoketests + +The shell script `test/run-module-bundlers-smoketests.sh` runs browserify and webpack, +to verify that the most commonly used module bundlers are not raising any unexpected error +while building a bundle that requires this library. + +### Integration Tests + +This repository also includes a small set of integration tests, located at `"test/integration/"`. +The integration tests use selenium-webdriver to run a set of test extensions +(located at `"test/fixtures/"`) on real browsers, currently Chrome (as the browser officially +supported by this library) and Firefox (to compare the polyfilled APIs with the ones natively +provided on Firefox). + +The shell script `test/run-browsers-smoketests.sh` (executed by the Travis CI service on every +pull request) runs this test suite on both the browsers. + +To run the integration tests on a single browser: + +```sh +TEST_BROWSER_TYPE=chrome npm run test-integration +``` +or + +```sh +TEST_BROWSER_TYPE=firefox npm run test-integration +``` + +These tests emit their results using the TAP protocol. To get a nicer output on the console +you may want to pipe the results to `tap-nirvana`, e.g. + +```sh +TEST_BROWSER_TYPE=chrome npm run test-integration | ./node_modules/.bin/tap-nirvana +``` + +## Writing commit messages + +The subject of the pull requests and commit messages must adhere to the Angular style of +[semantic messages](https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#commits). +This allows us to auto-generate a changelog without too much noise in it. +Additionally, write the commit message in past tense so it will read +naturally as a historic changelog. + +Examples: +* `feat: Added newAmazingAPI namespace to the metadata` +* `fix: newAmazingAPI.create should reject on errors` +* `docs: Improved contributor docs` +* `style: Added no-console linting, cleaned up code` +* `refactor: Split out myHelperFunction` +* `perf: Changed myHelperFunction to be 2x faster` +* `test: Added more tests for newAmazingAPI` +* `chore: Upgraded yargs to 3.x.x` + +If you want to use scopes then it would look more like: +`test(integration): Added test extension for newAmazingAPI`. diff --git a/README.md b/README.md index 7514419..94f8342 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,73 @@ -# WebExtension `browser` API Polyfill [![Build Status](https://travis-ci.org/mozilla/webextension-polyfill.svg?branch=master)](https://travis-ci.org/mozilla/webextension-polyfill) +# WebExtension `browser` API Polyfill [![Build Status](https://travis-ci.org/mozilla/webextension-polyfill.svg?branch=master)](https://travis-ci.org/mozilla/webextension-polyfill) [![npm version](https://img.shields.io/npm/v/webextension-polyfill.svg?style=flat)](https://www.npmjs.com/package/webextension-polyfill) -This library allows extensions written for the Promise-based -WebExtension/BrowserExt API being standardized by the [W3 Browser -Extensions][w3-browserext] group to be used without modification in Google -Chrome. +This library allows extensions that use the Promise-based WebExtension/BrowserExt API being standardized by the +[W3 Browser Extensions][w3-browserext] group to run on Google Chrome with minimal or no changes. + +> This library doesn't (and it is not going to) polyfill API methods or options that are missing on Chrome but natively provided +> on Firefox, and so the extension has to do its own "runtime feature detection" in those cases (and then eventually polyfill the +> missing feature on its own or enable/disable some of the features accordingly). [w3-browserext]: https://www.w3.org/community/browserext/ - Table of contents ================= -* [Building](#building) +* [Supported Browsers](#supported-browsers) +* [Installation](#installation) * [Basic Setup](#basic-setup) + * [Basic Setup with module bundlers](#basic-setup-with-module-bundlers) * [Using the Promise-based APIs](#using-the-promise-based-apis) * [Examples](#examples) +* [Known Limitations and Incompatibilities](#known-limitations-and-incompatibilities) +* [Contributing to this project](#contributing-to-this-project) -## Building +Supported Browsers +================== -To build, assuming you've already installed [node >= 6](https://nodejs.org) and -[npm](https://www.npmjs.com/), simply run: +| Browser | Support Level | +| ------------- | ---------------------------------------------------------------------------------------------------- | +| Chrome | *Officially Supported* (with automated tests) | +| Firefox | *Officially Supported as a NO-OP* (with automated tests for comparison with the behaviors on Chrome) | +| Opera | *Unofficially Supported* as a Chrome-compatible target (but not explicitly tested in automation) | +| Edge | *Not supported* (may become unofficially supported once [#114][PR-114] lands) | -```sh -npm install -npm run build -npm run test +The polyfill is being tested explictly (with automated tests that run on every pull request) on **officially supported** +browsers (that are currently the last stable versions of Chrome and Firefox). + +On Firefox, this library is actually acting as a NO-OP: it detects that the `browser` API object is already defined +and it does not create any custom wrappers. +Firefox is still included in the automated tests, to ensure that no wrappers are being created when running on Firefox, +and for comparison with the behaviors implemented by the library on Chrome. + +## Installation + +A new version of the library is built from this repository and released as an npm package. + +The npm package is named after this repo: [webextension-polyfill](https://www.npmjs.com/package/webextension-polyfill). + +For the extension that already include a package.json file, the last released version of this library can be quickly installed using: + +``` +npm install --save-dev webextension-polyfill ``` -This will install all the npm dependencies and build both non-minified and minified versions -of the final library, and output them to `dist/browser-polyfill.js` and `dist/browser-polyfill.min.js`, -respectively, and finally executes the unit tests on the generated dist files. +Inside the `dist/` directory of the npm package, there are both the minified and non-minified builds (and their related source map files): + +- node_modules/webextension-polyfill/dist/browser-polyfill.js +- node_modules/webextension-polyfill/dist/browser-polyfill.min.js + +For extensions that do not include a package.json file and/or prefer to download and add the library directly into their own code repository, all the versions released on npm are also available for direct download from unpkg.com: + +- https://unpkg.com/webextension-polyfill/dist/ + +and linked to the github releases: + +- https://github.com/mozilla/webextension-polyfill/releases ## Basic Setup -In order to use the polyfill, it must be loaded into any context where -`browser` APIs are accessed. The most common cases are background and -content scripts, which can be specified in `manifest.json`: +In order to use the polyfill, it must be loaded into any context where `browser` APIs are accessed. The most common cases +are background and content scripts, which can be specified in `manifest.json`: ```javascript { @@ -84,6 +116,45 @@ browser.tabs.executeScript({file: "content.js"}).then(result => { }); ``` +### Basic Setup with module bundlers + +This library is built as a **UMD module** (Universal Module Definition), and so it can also be used with module bundlers (and explictly tested on both **webpack** and **browserify**) or AMD module loaders. + +**src/background.js**: +```javascript +var browser = require("webextension-polyfill"); + +browser.runtime.onMessage.addListener(async (msg, sender) => { + console.log("BG page received message", msg, "from", sender); + console.log("Stored data", await browser.storage.local.get()); +}); + +browser.browserAction.onClicked.addListener(() => { + browser.tabs.executeScript({file: "content.js"}); +}); +``` + +**src/content.js**: +```javascript +var browser = require("webextension-polyfill"); + +browser.storage.local.set({ + [window.location.hostname]: document.title, +}).then(() => { + browser.runtime.sendMessage(`Saved document title for ${window.location.hostname}`); +}); +``` + +By using `require("webextension-polyfill")`, the module bundler will use the non-minified version of this library, and the extension is supposed to minify the entire generated bundles as part of its own build steps. + +If the extension doesn't minify its own sources, it is still possible to explicitly ask the module bundler to use the minified version of this library, e.g.: + +```javascript +var browser = require("webextension-polyfill/dist/browser-polyfill.min"); + +... +``` + ## Using the Promise-based APIs The Promise-based APIs in the `browser` namespace work, for the most part, @@ -162,7 +233,7 @@ Communication between a background page and a tab content script, for example, looks something like this from the background page side: ```javascript -browser.tabs.sendMessage("get-ids").then(results => { +browser.tabs.sendMessage(tabId, "get-ids").then(results => { processResults(results); }); ``` @@ -194,3 +265,49 @@ browser.runtime.onMessage.addListener(async function(msg) { ``` Or vice versa. + +## Known Limitations and Incompatibilities + +This library tries to minimize the amount of "special handling" that a cross-browser extension has to do to be able to run on the supported browsers from a single codebase, but there are still cases when polyfillling the missing or incompatible behaviors or features is not possible or out of the scope of this polyfill. + +This section aims to keep track of the most common issues that an extension may have. + +### No callback supported by the Promise-based APIs on Chrome + +While some of the asynchronous API methods in Firefox (the ones that return a promise) also support the callback parameter (mostly as a side effect of the backward compatibility with the callback-based APIs available on Chrome), the Promise-based APIs provided by this library do not support the callback parameter (See ["#102 Cannot call browser.storage.local.get with callback"][I-102]). + +### No promise returned on Chrome for some API methods + +This library takes its knowledge of the APIs to wrap and their signatures from a metadata JSON file: +[api-metadata.json](api-metadata.json). + +If an API method is not yet included in this "API metadata" file, it will not be recognized. +Promises are not supported for unrecognized APIs, and callbacks have to be used for them. + +File an issue in this repository for API methods that supports a callback on Chrome and +are currently missing from the "API metadata" file. + +### Issues that happen only when running on Firefox + +When an extension that uses this library doesn't behave as expected on Firefox, it is almost never an issue in this polyfill, but an issue with the native implementation in Firefox. + +"Firefox only" issues should be reported upstream on Bugzilla: +- https://bugzilla.mozilla.org/enter_bug.cgi?product=WebExtensions&component=Untriaged + +### API methods or options that are only available when running in Firefox + +This library does not provide any polyfill for API methods and options that are only available on Firefox, and they are actually considered out of the scope of this library. + +### tabs.executeScript + +On Firefox `browser.tabs.executeScript` returns a promise which resolves to the result of the content script code that has been executed, which can be an immediate value or a Promise. + +On Chrome, the `browser.tabs.executeScript` API method as polyfilled by this library also returns a promise which resolves to the result of the content script code, but only immediate values are supported. +If the content script code result is a Promise, the promise returned by `browser.tabs.executeScript` will be resolved to `undefined`. + +## Contributing to this project + +Read the [contributing section](CONTRIBUTING.md) for additional information about how to build the library from this repository and how to contribute and test changes. + +[PR-114]: https://github.com/mozilla/webextension-polyfill/pull/114_ +[I-102]: https://github.com/mozilla/webextension-polyfill/issues/102#issuecomment-379365343