feat: library wrapped as an UMD module
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]: https://github.com/mozilla/webextension-polyfill/issues/7 [files]: https://docs.npmjs.com/files/package.json#files [prepublish script]: https://docs.npmjs.com/misc/scripts
This commit is contained in:
parent
52791c8633
commit
f9248e62e7
14
Gruntfile.js
14
Gruntfile.js
|
@ -28,7 +28,7 @@ module.exports = function(grunt) {
|
||||||
options: {
|
options: {
|
||||||
patterns: [
|
patterns: [
|
||||||
{
|
{
|
||||||
match: /\{\/\* include\("(.*?)"\) \*\/\}/,
|
match: /require\("..\/(.*?)"\)/,
|
||||||
replacement: (match, filename) => {
|
replacement: (match, filename) => {
|
||||||
return grunt.file.read(filename)
|
return grunt.file.read(filename)
|
||||||
.replace(/\n$/, "")
|
.replace(/\n$/, "")
|
||||||
|
@ -55,6 +55,15 @@ module.exports = function(grunt) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
umd: {
|
||||||
|
all: {
|
||||||
|
src: "dist/browser-polyfill.js",
|
||||||
|
template: "unit",
|
||||||
|
globalAlias: "browser",
|
||||||
|
amdModuleId: "webextension-polyfill",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
"closure-compiler": {
|
"closure-compiler": {
|
||||||
dist: {
|
dist: {
|
||||||
files: {
|
files: {
|
||||||
|
@ -88,8 +97,9 @@ module.exports = function(grunt) {
|
||||||
|
|
||||||
grunt.loadNpmTasks("gruntify-eslint");
|
grunt.loadNpmTasks("gruntify-eslint");
|
||||||
grunt.loadNpmTasks("grunt-replace");
|
grunt.loadNpmTasks("grunt-replace");
|
||||||
|
grunt.loadNpmTasks("grunt-umd");
|
||||||
grunt.loadNpmTasks("grunt-coveralls");
|
grunt.loadNpmTasks("grunt-coveralls");
|
||||||
require("google-closure-compiler").grunt(grunt);
|
require("google-closure-compiler").grunt(grunt);
|
||||||
|
|
||||||
grunt.registerTask("default", ["eslint", "replace", "closure-compiler"]);
|
grunt.registerTask("default", ["eslint", "replace", "umd", "closure-compiler"]);
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,7 +14,6 @@ simply run:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npm install
|
npm install
|
||||||
grunt
|
|
||||||
```
|
```
|
||||||
|
|
||||||
This will build both non-minified and minified versions of the final library,
|
This will build both non-minified and minified versions of the final library,
|
||||||
|
|
10
package.json
10
package.json
|
@ -2,6 +2,12 @@
|
||||||
"name": "webextension-polyfill",
|
"name": "webextension-polyfill",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"description": "A lightweight polyfill library for Promise-based WebExtension APIs in Chrome.",
|
"description": "A lightweight polyfill library for Promise-based WebExtension APIs in Chrome.",
|
||||||
|
"main": "src/browser-polyfill.js",
|
||||||
|
"files": [
|
||||||
|
"api-metadata.json",
|
||||||
|
"src",
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/mozilla/webextension-polyfill.git"
|
"url": "git+https://github.com/mozilla/webextension-polyfill.git"
|
||||||
|
@ -19,6 +25,7 @@
|
||||||
"grunt": "^1.0.1",
|
"grunt": "^1.0.1",
|
||||||
"grunt-coveralls": "^1.0.1",
|
"grunt-coveralls": "^1.0.1",
|
||||||
"grunt-replace": "*",
|
"grunt-replace": "*",
|
||||||
|
"grunt-umd": "^2.4.0",
|
||||||
"gruntify-eslint": "*",
|
"gruntify-eslint": "*",
|
||||||
"istanbul-lib-instrument": "^1.1.3",
|
"istanbul-lib-instrument": "^1.1.3",
|
||||||
"jsdom": "^9.6.0",
|
"jsdom": "^9.6.0",
|
||||||
|
@ -38,6 +45,7 @@
|
||||||
"build": "grunt",
|
"build": "grunt",
|
||||||
"test": "mocha",
|
"test": "mocha",
|
||||||
"test-coverage": "COVERAGE=y nyc mocha",
|
"test-coverage": "COVERAGE=y nyc mocha",
|
||||||
"publish-coverage": "grunt coveralls"
|
"publish-coverage": "grunt coveralls",
|
||||||
|
"prepublish": "npm run build"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,9 @@ if (typeof browser === "undefined") {
|
||||||
// never actually need to be called, this allows the polyfill to be included
|
// never actually need to be called, this allows the polyfill to be included
|
||||||
// in Firefox nearly for free.
|
// in Firefox nearly for free.
|
||||||
const wrapAPIs = () => {
|
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
|
* A WeakMap subclass which creates and stores a value for any key which does
|
||||||
|
@ -336,5 +338,9 @@ if (typeof browser === "undefined") {
|
||||||
return wrapObject(chrome, staticWrappers, apiMetadata);
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
||||||
|
};
|
|
@ -1,9 +1,11 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const {deepEqual, equal, ok} = require("chai").assert;
|
const {deepEqual, equal} = require("chai").assert;
|
||||||
|
|
||||||
const {setupTestDOMWindow} = require("./setup");
|
const {setupTestDOMWindow} = require("./setup");
|
||||||
|
|
||||||
|
const {testCustomProperties, testUndefinedProperties} = require("./helpers");
|
||||||
|
|
||||||
describe("browser-polyfill", () => {
|
describe("browser-polyfill", () => {
|
||||||
it("wraps the global chrome namespace with a global browser namespace", () => {
|
it("wraps the global chrome namespace with a global browser namespace", () => {
|
||||||
const fakeChrome = {};
|
const fakeChrome = {};
|
||||||
|
@ -29,37 +31,12 @@ describe("browser-polyfill", () => {
|
||||||
describe("browser wrapper", () => {
|
describe("browser wrapper", () => {
|
||||||
it("supports custom properties defined using Object.defineProperty", () => {
|
it("supports custom properties defined using Object.defineProperty", () => {
|
||||||
const fakeChrome = {};
|
const fakeChrome = {};
|
||||||
return setupTestDOMWindow(fakeChrome).then(window => {
|
return setupTestDOMWindow(fakeChrome).then(testCustomProperties);
|
||||||
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");
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns undefined for property undefined in the target", () => {
|
it("returns undefined for property undefined in the target", () => {
|
||||||
const fakeChrome = {myns: {mykey: true}};
|
const fakeChrome = {myns: {mykey: true}};
|
||||||
return setupTestDOMWindow(fakeChrome).then(window => {
|
return setupTestDOMWindow(fakeChrome).then(testUndefinedProperties);
|
||||||
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");
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue