Skip to content

Commit

Permalink
feat: library wrapped as an UMD module
Browse files Browse the repository at this point in the history
This addresses [issue 7] by making it possible for users to run:

```sh
npm install webextension-polyfill
```

and download a module that they can use with a bundler as follows:

```js
import browser from 'webextension-polyfill';
```

Also, add a [prepublish script] so that users who clone the repo don't
need to run `grunt` manually. In addition, specify [files] in
package.json so that this module can be published to npm without
including miscellanea. This can be verified by running:

```sh
npm pack && tar -tvf webextension-polyfill-0.1.0.tgz
```

[issue 7]: mozilla#7
[files]: https://docs.npmjs.com/files/package.json#files
[prepublish script]: https://docs.npmjs.com/misc/scripts
  • Loading branch information
josephfrazier authored and rpl committed Apr 11, 2017
1 parent 52791c8 commit f9248e6
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 34 deletions.
14 changes: 12 additions & 2 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ module.exports = function(grunt) {
options: {
patterns: [
{
match: /\{\/\* include\("(.*?)"\) \*\/\}/,
match: /require\("..\/(.*?)"\)/,
replacement: (match, filename) => {
return grunt.file.read(filename)
.replace(/\n$/, "")
Expand All @@ -55,6 +55,15 @@ module.exports = function(grunt) {
},
},

umd: {
all: {
src: "dist/browser-polyfill.js",
template: "unit",
globalAlias: "browser",
amdModuleId: "webextension-polyfill",
},
},

"closure-compiler": {
dist: {
files: {
Expand Down Expand Up @@ -88,8 +97,9 @@ module.exports = function(grunt) {

grunt.loadNpmTasks("gruntify-eslint");
grunt.loadNpmTasks("grunt-replace");
grunt.loadNpmTasks("grunt-umd");
grunt.loadNpmTasks("grunt-coveralls");
require("google-closure-compiler").grunt(grunt);

grunt.registerTask("default", ["eslint", "replace", "closure-compiler"]);
grunt.registerTask("default", ["eslint", "replace", "umd", "closure-compiler"]);
};
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ simply run:

```sh
npm install
grunt
```

This will build both non-minified and minified versions of the final library,
Expand Down
10 changes: 9 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
"name": "webextension-polyfill",
"version": "0.1.0",
"description": "A lightweight polyfill library for Promise-based WebExtension APIs in Chrome.",
"main": "src/browser-polyfill.js",
"files": [
"api-metadata.json",
"src",
"dist"
],
"repository": {
"type": "git",
"url": "git+https://github.com/mozilla/webextension-polyfill.git"
Expand All @@ -19,6 +25,7 @@
"grunt": "^1.0.1",
"grunt-coveralls": "^1.0.1",
"grunt-replace": "*",
"grunt-umd": "^2.4.0",
"gruntify-eslint": "*",
"istanbul-lib-instrument": "^1.1.3",
"jsdom": "^9.6.0",
Expand All @@ -38,6 +45,7 @@
"build": "grunt",
"test": "mocha",
"test-coverage": "COVERAGE=y nyc mocha",
"publish-coverage": "grunt coveralls"
"publish-coverage": "grunt coveralls",
"prepublish": "npm run build"
}
}
10 changes: 8 additions & 2 deletions src/browser-polyfill.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ if (typeof browser === "undefined") {
// never actually need to be called, this allows the polyfill to be included
// in Firefox nearly for free.
const wrapAPIs = () => {
const apiMetadata = {/* include("api-metadata.json") */};
// Note that `require` does NOT work in general. See discussion here:
// https://github.com/mozilla/webextension-polyfill/pull/17#discussion_r99170958
const apiMetadata = require("../api-metadata.json"); // eslint-disable-line no-undef

/**
* A WeakMap subclass which creates and stores a value for any key which does
Expand Down Expand Up @@ -336,5 +338,9 @@ if (typeof browser === "undefined") {
return wrapObject(chrome, staticWrappers, apiMetadata);
};

this.browser = wrapAPIs();
// The build process adds a UMD wrapper around this file, which makes the
// `module` variable available.
module.exports = wrapAPIs(); // eslint-disable-line no-undef
} else {
module.exports = browser; // eslint-disable-line no-undef
}
32 changes: 32 additions & 0 deletions test/helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"use strict";

const {deepEqual, equal, ok} = require("chai").assert;

module.exports.testCustomProperties = window => {
Object.defineProperty(window.browser, "myns", {
enumerable: true,
configurable: true,
value: {mykey: true},
});

ok("myns" in window.browser, "The custom property exists");
ok("mykey" in window.browser.myns,
"The content of the custom property exists");

deepEqual(window.browser.myns, {mykey: true},
"The custom property has the expected content");

delete window.browser.myns;

ok(!("myns" in window.browser),
"The deleted custom defined property has been removed");
};

module.exports.testUndefinedProperties = window => {
equal(window.browser.myns.mykey, true,
"Got the expected result from a wrapped property");
equal(window.browser.myns.nonexistent, undefined,
"Got undefined for non existent property");
equal(window.browser.nonexistent, undefined,
"Got undefined for non existent namespaces");
};
33 changes: 5 additions & 28 deletions test/test-browser-global.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
"use strict";

const {deepEqual, equal, ok} = require("chai").assert;
const {deepEqual, equal} = require("chai").assert;

const {setupTestDOMWindow} = require("./setup");

const {testCustomProperties, testUndefinedProperties} = require("./helpers");

describe("browser-polyfill", () => {
it("wraps the global chrome namespace with a global browser namespace", () => {
const fakeChrome = {};
Expand All @@ -29,37 +31,12 @@ describe("browser-polyfill", () => {
describe("browser wrapper", () => {
it("supports custom properties defined using Object.defineProperty", () => {
const fakeChrome = {};
return setupTestDOMWindow(fakeChrome).then(window => {
Object.defineProperty(window.browser, "myns", {
enumerable: true,
configurable: true,
value: {mykey: true},
});

ok("myns" in window.browser, "The custom property exists");
ok("mykey" in window.browser.myns,
"The content of the custom property exists");

deepEqual(window.browser.myns, {mykey: true},
"The custom property has the expected content");

delete window.browser.myns;

ok(!("myns" in window.browser),
"The deleted custom defined property has been removed");
});
return setupTestDOMWindow(fakeChrome).then(testCustomProperties);
});

it("returns undefined for property undefined in the target", () => {
const fakeChrome = {myns: {mykey: true}};
return setupTestDOMWindow(fakeChrome).then(window => {
equal(window.browser.myns.mykey, true,
"Got the expected result from a wrapped property");
equal(window.browser.myns.nonexistent, undefined,
"Got undefined for non existent property");
equal(window.browser.nonexistent, undefined,
"Got undefined for non existent namespaces");
});
return setupTestDOMWindow(fakeChrome).then(testUndefinedProperties);
});
});
});
47 changes: 47 additions & 0 deletions test/test-node-export.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"use strict";

const {deepEqual, strictEqual, notStrictEqual, throws} = require("chai").assert;
const {testCustomProperties, testUndefinedProperties} = require("./helpers");

describe("node-export", () => {
beforeEach(() => {
delete global.browser;
delete global.chrome;
delete require.cache[require.resolve("../")];
});

it("exports the global browser namespace if it already exists", () => {
global.browser = {key: "value"};

const exported = require("../");

strictEqual(exported, browser);
});

it("exports a wrapper around the global chrome namespace", () => {
global.chrome = {key: "value"};

const exported = require("../");

deepEqual(exported, chrome);
notStrictEqual(exported, chrome);
});

it("throws an error if the global chrome namespace is missing", () => {
throws(() => require("../"), ReferenceError, /chrome is not defined/);
});

describe("browser wrapper", () => {
it("supports custom properties defined using Object.defineProperty", () => {
global.chrome = {};
global.browser = require("../");
testCustomProperties(global);
});

it("returns undefined for property undefined in the target", () => {
global.chrome = {myns: {mykey: true}};
global.browser = require("../");
testUndefinedProperties(global);
});
});
});

0 comments on commit f9248e6

Please sign in to comment.