Browse Source

refactor browser.js with ES6

Gerald 8 years ago
parent
commit
8b49edcb3a

+ 2 - 1
.eslintignore

@@ -1 +1,2 @@
-scripts/**
+**/*.js
+!src/**

+ 1 - 0
package.json

@@ -19,6 +19,7 @@
     "babel-loader": "^6.4.1",
     "babel-plugin-transform-runtime": "^6.23.0",
     "babel-preset-env": "^1.2.2",
+    "core-js": "^2.4.1",
     "css-loader": "^0.27.3",
     "cssnano": "^3.10.0",
     "del": "^2.2.0",

+ 2 - 18
scripts/webpack.conf.js

@@ -8,7 +8,7 @@ const vueLoaderConfig = require('./vue-loader.conf');
 const IS_DEV = process.env.NODE_ENV !== 'production';
 const DIST = 'dist';
 
-function resolve (dir) {
+function resolve(dir) {
   return path.join(__dirname, '..', dir)
 }
 
@@ -96,23 +96,6 @@ targets.push(Object.assign({}, base, {
     ] : [
       // extract css into its own file
       new ExtractTextPlugin('[name].css'),
-      // generate dist index.html with correct asset hash for caching.
-      // you can customize output by editing /index.html
-      // see https://github.com/ampedandwired/html-webpack-plugin
-      // new HtmlWebpackPlugin({
-      //   filename: 'index.html',
-      //   template: 'src/public/index.ejs',
-      //   inject: true,
-      //   minify: {
-      //     removeComments: true,
-      //     collapseWhitespace: true,
-      //     removeAttributeQuotes: true
-      //     // more options:
-      //     // https://github.com/kangax/html-minifier#options-quick-reference
-      //   },
-      //   // necessary to consistently work with multiple chunks via CommonsChunkPlugin
-      //   chunksSortMode: 'dependency'
-      // }),
       new webpack.optimize.UglifyJsPlugin({
         compress: {
           warnings: false
@@ -125,6 +108,7 @@ targets.push(Object.assign({}, base, {
 targets.push(Object.assign({}, base, {
   entry: {
     injected: 'src/injected.js',
+    browser: 'src/browser.js',
   },
   plugins: IS_DEV ? [] : [
     new webpack.optimize.UglifyJsPlugin({

+ 6 - 1
src/.babelrc

@@ -4,8 +4,13 @@
       "targets": {
         "browsers": ["Chrome >= 41"]
       },
+      "modules": false,
+      // "useBuiltIns": true,
+      // "debug": true,
     }]
   ],
-  "plugins": ["transform-runtime"],
+  "plugins": [
+    ["transform-runtime", {"polyfill": false}]
+  ],
   "comments": false
 }

+ 1 - 1
src/background/index.html

@@ -3,7 +3,7 @@
 <head>
 <meta charset="utf-8">
 <title>ViolentMonkey</title>
-<script src="/public/browser.js"></script>
+<script src="/browser.js"></script>
 </head>
 <body></body>
 </html>

+ 96 - 0
src/browser.js

@@ -0,0 +1,96 @@
+/* global chrome */
+const global = window;
+
+function wrapAsync(func) {
+  return (...args) => new Promise((resolve, reject) => {
+    args.push(res => {
+      const err = chrome.runtime.lastError;
+      if (err) {
+        console.error(args);
+        reject(err);
+      } else {
+        resolve(res);
+      }
+    });
+    func(...args);
+  });
+}
+function wrapAPIs(source, meta) {
+  const target = {};
+  Object.keys(source).forEach(key => {
+    const metaVal = meta && meta[key];
+    if (metaVal) {
+      const value = source[key];
+      if (typeof metaVal === 'function') {
+        target[key] = metaVal(value);
+      } else if (typeof metaVal === 'object' && typeof value === 'object') {
+        target[key] = wrapAPIs(value, metaVal);
+      } else {
+        target[key] = value;
+      }
+    }
+  });
+  return target;
+}
+const meta = {
+  browserAction: true,
+  i18n: true,
+  notifications: {
+    onClicked: true,
+    onClosed: true,
+    create: wrapAsync,
+  },
+  runtime: {
+    getManifest: true,
+    getURL: true,
+    onMessage(onMessage) {
+      function wrapListener(listener) {
+        return function onChromeMessage(message, sender, sendResponse) {
+          const result = listener(message, sender);
+          if (result && typeof result.then === 'function') {
+            result.then(data => {
+              sendResponse({ data });
+            }, error => {
+              console.error(error);
+              sendResponse({ error });
+            });
+            return true;
+          } else if (typeof result !== 'undefined') {
+            // In some browsers (e.g Chrome 56, Vivaldi), the listener in
+            // popup pages are not properly cleared after closed.
+            // They may send `undefined` before the real response is sent.
+            sendResponse({ data: result });
+          }
+        };
+      }
+      return {
+        addListener(listener) {
+          return onMessage.addListener(wrapListener(listener));
+        },
+      };
+    },
+    sendMessage(sendMessage) {
+      const promisifiedSendMessage = wrapAsync(sendMessage);
+      return data => promisifiedSendMessage(data)
+      .then(res => {
+        if (res && res.error) throw res.error;
+        return res && res.data;
+      });
+    },
+  },
+  tabs: {
+    onUpdated: true,
+    create: wrapAsync,
+    get: wrapAsync,
+    query: wrapAsync,
+    reload: wrapAsync,
+    remove: wrapAsync,
+    sendMessage: wrapAsync,
+    update: wrapAsync,
+  },
+  webRequest: true,
+};
+if (typeof browser === 'undefined' && typeof chrome !== 'undefined') {
+  global.browser = wrapAPIs(chrome, meta);
+  global.browser.__patched = true;
+}

+ 1 - 1
src/common/index.js

@@ -1,4 +1,4 @@
-// import './polyfills';
+import './polyfills';
 
 export function i18n(name, args) {
   return browser.i18n.getMessage(name, args) || name;

+ 50 - 42
src/common/polyfills.js

@@ -1,43 +1,51 @@
-function polyfill(obj, name, value) {
-  if (!obj[name]) {
-    Object.defineProperty(obj, name, { value });
-  }
-}
+import 'core-js/fn/object/assign';
+import 'core-js/fn/array/includes';
+import 'core-js/fn/array/find';
+import 'core-js/fn/array/find-index';
+import 'core-js/fn/string/includes';
+import 'core-js/fn/string/starts-with';
+import 'core-js/fn/string/ends-with';
 
-polyfill(Object, 'assign', (obj, ...args) => {
-  args.forEach(arg => arg && Object.keys(arg).forEach((key) => {
-    obj[key] = arg[key];
-  }));
-  return obj;
-});
-
-polyfill(String.prototype, 'startsWith', function startsWith(str) {
-  return this.slice(0, str.length) === str;
-});
-
-polyfill(String.prototype, 'endsWith', function endsWith(str) {
-  return this.slice(-str.length) === str;
-});
-
-polyfill(String.prototype, 'includes', function includes(str) {
-  return this.indexOf(str) >= 0;
-});
-
-polyfill(Array.prototype, 'findIndex', function findIndex(predicate) {
-  let index = -1;
-  this.some((item, i, thisObj) => {
-    if (predicate(item, i, thisObj)) {
-      index = i;
-      return true;
-    }
-  });
-  return index;
-});
-
-polyfill(Array.prototype, 'find', function find(predicate) {
-  return this[this.findIndex(predicate)];
-});
-
-polyfill(Array.prototype, 'includes', function includes(item) {
-  return this.indexOf(item) >= 0;
-});
+// function polyfill(obj, name, value) {
+//   if (!obj[name]) {
+//     Object.defineProperty(obj, name, { value });
+//   }
+// }
+//
+// polyfill(Object, 'assign', (obj, ...args) => {
+//   args.forEach(arg => arg && Object.keys(arg).forEach((key) => {
+//     obj[key] = arg[key];
+//   }));
+//   return obj;
+// });
+//
+// polyfill(String.prototype, 'startsWith', function startsWith(str) {
+//   return this.slice(0, str.length) === str;
+// });
+//
+// polyfill(String.prototype, 'endsWith', function endsWith(str) {
+//   return this.slice(-str.length) === str;
+// });
+//
+// polyfill(String.prototype, 'includes', function includes(str) {
+//   return this.indexOf(str) >= 0;
+// });
+//
+// polyfill(Array.prototype, 'findIndex', function findIndex(predicate) {
+//   let index = -1;
+//   this.some((item, i, thisObj) => {
+//     if (predicate(item, i, thisObj)) {
+//       index = i;
+//       return true;
+//     }
+//   });
+//   return index;
+// });
+//
+// polyfill(Array.prototype, 'find', function find(predicate) {
+//   return this[this.findIndex(predicate)];
+// });
+//
+// polyfill(Array.prototype, 'includes', function includes(item) {
+//   return this.indexOf(item) >= 0;
+// });

+ 1 - 1
src/manifest.json

@@ -26,7 +26,7 @@
   "content_scripts": [
     {
       "js": [
-        "public/browser.js",
+        "browser.js",
         "injected.js"
       ],
       "matches": [

+ 1 - 1
src/options/index.html

@@ -5,7 +5,7 @@
 <title></title>
 <link rel="shortcut icon" type="image/png" href="/public/images/icon16.png">
 <script src="/public/lib/zip.js/zip.js"></script>
-<script src="/public/browser.js"></script>
+<script src="/browser.js"></script>
 </head>
 <body>
 <div id="app"></div>

+ 1 - 1
src/popup/index.html

@@ -3,7 +3,7 @@
 <head>
 <meta charset="utf-8">
 <title>Popup Menu - Violentmonkey</title>
-<script src="/public/browser.js"></script>
+<script src="/browser.js"></script>
 </head>
 <body>
 <div id="app"></div>

+ 0 - 102
src/public/browser.js

@@ -1,102 +0,0 @@
-/* global chrome */
-!function (win) {
-  function wrapAsync(func) {
-    return function () {
-      var args = [];
-      for (var i = 0; i < arguments.length; i ++) args.push(arguments[i]);
-      return new Promise(function (resolve, reject) {
-        args.push(function (res) {
-          var err = chrome.runtime.lastError;
-          if (err) {
-            console.error(args);
-            reject(err);
-          } else {
-            resolve(res);
-          }
-        });
-        func.apply(null, args);
-      });
-    };
-  }
-  function wrapAPIs(source, meta) {
-    var target = {};
-    Object.keys(source).forEach(function (key) {
-      var metaVal = meta && meta[key];
-      if (metaVal) {
-        var value = source[key];
-        if (typeof metaVal === 'function') {
-          target[key] = metaVal(value);
-        } else if (typeof metaVal === 'object' && typeof value === 'object') {
-          target[key] = wrapAPIs(value, metaVal);
-        } else {
-          target[key] = value;
-        }
-      }
-    });
-    return target;
-  }
-  var meta = {
-    browserAction: true,
-    i18n: true,
-    notifications: {
-      onClicked: true,
-      onClosed: true,
-      create: wrapAsync,
-    },
-    runtime: {
-      getManifest: true,
-      getURL: true,
-      onMessage: function (onMessage) {
-        function wrapListener(listener) {
-          return function onMessage(message, sender, sendResponse) {
-            var result = listener(message, sender);
-            if (result && typeof result.then === 'function') {
-              result.then(function (data) {
-                sendResponse({data: data});
-              }, function (err) {
-                console.error(err);
-                sendResponse({error: err});
-              });
-              return true;
-            } else if (typeof result !== 'undefined') {
-              // In some browsers (e.g Chrome 56, Vivaldi), the listener in
-              // popup pages are not properly cleared after closed.
-              // They may send `undefined` before the real response is sent.
-              sendResponse({data: result});
-            }
-          };
-        }
-        return {
-          addListener: function (listener) {
-            return onMessage.addListener(wrapListener(listener));
-          },
-        };
-      },
-      sendMessage: function (sendMessage) {
-        var promisifiedSendMessage = wrapAsync(sendMessage);
-        return function (data) {
-          return promisifiedSendMessage(data)
-          .then(function (res) {
-            if (res && res.error) throw res.error;
-            return res && res.data;
-          });
-        };
-      },
-    },
-    tabs: {
-      onUpdated: true,
-      create: wrapAsync,
-      get: wrapAsync,
-      query: wrapAsync,
-      reload: wrapAsync,
-      remove: wrapAsync,
-      sendMessage: wrapAsync,
-      update: wrapAsync,
-    },
-    webRequest: true,
-  };
-  if (typeof browser === 'undefined' && typeof chrome !== 'undefined') {
-    win.browser = wrapAPIs(chrome, meta);
-    win.browser.__patched = true;
-  }
-}(this);