Преглед изворни кода

refactor: load zip.js asynchronously

Gerald пре 6 година
родитељ
комит
b3fd05709d

+ 0 - 1
.eslintrc.js

@@ -14,6 +14,5 @@ module.exports = {
   },
   globals: {
     browser: true,
-    zip: true,
   },
 };

+ 1 - 5
scripts/plaid.conf.js

@@ -22,11 +22,7 @@ exports.pages = {
   },
   'options/index': {
     entry: './src/options',
-    html: htmlFactory({
-      js: [
-        '/public/lib/zip.js/zip.js',
-      ],
-    }),
+    html: htmlFactory(),
   },
   'confirm/index': {
     entry: './src/confirm',

+ 2 - 73
src/common/index.js

@@ -1,3 +1,5 @@
+export * from './util';
+
 export function i18n(name, args) {
   return browser.i18n.getMessage(name, args) || name;
 }
@@ -42,47 +44,12 @@ export function sendMessage(payload) {
   return promise;
 }
 
-export function debounce(func, time) {
-  let timer;
-  function run(thisObj, args) {
-    timer = null;
-    func.apply(thisObj, args);
-  }
-  return function debouncedFunction(...args) {
-    if (timer) clearTimeout(timer);
-    timer = setTimeout(run, time, this, args);
-  };
-}
-
-export function throttle(func, time) {
-  let timer;
-  function run(thisObj, args) {
-    timer = null;
-    func.apply(thisObj, args);
-  }
-  return function throttledFunction(...args) {
-    if (!timer) {
-      timer = setTimeout(run, time, this, args);
-    }
-  };
-}
-
-export function noop() {}
-
 export function leftpad(input, length, pad = '0') {
   let num = input.toString();
   while (num.length < length) num = `${pad}${num}`;
   return num;
 }
 
-export function getRnd4() {
-  return Math.floor((1 + Math.random()) * 0x10000).toString(16).slice(-4);
-}
-
-export function getUniqId(prefix) {
-  return (prefix || '') + Date.now().toString(36) + getRnd4();
-}
-
 /**
  * Get locale attributes such as `@name:zh-CN`
  */
@@ -159,16 +126,6 @@ export function request(url, options = {}) {
   }
 }
 
-export function buffer2string(buffer) {
-  const array = new window.Uint8Array(buffer);
-  const sliceSize = 8192;
-  let str = '';
-  for (let i = 0; i < array.length; i += sliceSize) {
-    str += String.fromCharCode.apply(null, array.subarray(i, i + sliceSize));
-  }
-  return str;
-}
-
 export function getFullUrl(url, base) {
   const obj = new URL(url, base);
   // Use protocol whitelist to filter URLs
@@ -213,31 +170,3 @@ export function encodeFilename(name) {
 export function decodeFilename(filename) {
   return filename.replace(/-([0-9a-f]{2})/g, (_m, g) => String.fromCharCode(parseInt(g, 16)));
 }
-
-export function compareVersion(ver1, ver2) {
-  const parts1 = (ver1 || '').split('.');
-  const parts2 = (ver2 || '').split('.');
-  for (let i = 0; i < parts1.length || i < parts2.length; i += 1) {
-    const delta = (parseInt(parts1[i], 10) || 0) - (parseInt(parts2[i], 10) || 0);
-    if (delta) return delta < 0 ? -1 : 1;
-  }
-  return 0;
-}
-
-const units = [
-  ['min', 60],
-  ['h', 24],
-  ['d', 1000, 365],
-  ['y'],
-];
-export function formatTime(duration) {
-  duration /= 60 * 1000;
-  const unitInfo = units.find((item) => {
-    const max = item[1];
-    if (!max || duration < max) return true;
-    const step = item[2] || max;
-    duration /= step;
-    return false;
-  });
-  return `${duration | 0}${unitInfo[0]}`;
-}

+ 2 - 0
src/common/polyfills.js

@@ -8,6 +8,8 @@
 // import 'core-js/features/string/ends-with'; // Chrome >= 41, Firefox >= 17
 // import 'core-js/features/string/repeat'; // Chrome >= 41, Firefox >= 24
 
+// ParentNode#append // Chrome >= 54, Firefox >= 49
+
 // Must use native Promise for Firefox to work
 // import 'core-js/features/promise';
 

+ 93 - 0
src/common/util.js

@@ -0,0 +1,93 @@
+export function toString(param) {
+  if (param == null) return '';
+  return `${param}`;
+}
+
+export function memoize(func, resolver = toString) {
+  const cacheMap = {};
+  function memoized(...args) {
+    const key = resolver(...args);
+    let cache = cacheMap[key];
+    if (!cache) {
+      cache = {
+        value: func.apply(this, args),
+      };
+      cacheMap[key] = cache;
+    }
+    return cache.value;
+  }
+  return memoized;
+}
+
+export function debounce(func, time) {
+  let timer;
+  function run(thisObj, args) {
+    timer = null;
+    func.apply(thisObj, args);
+  }
+  return function debouncedFunction(...args) {
+    if (timer) clearTimeout(timer);
+    timer = setTimeout(run, time, this, args);
+  };
+}
+
+export function throttle(func, time) {
+  let timer;
+  function run(thisObj, args) {
+    timer = null;
+    func.apply(thisObj, args);
+  }
+  return function throttledFunction(...args) {
+    if (!timer) {
+      timer = setTimeout(run, time, this, args);
+    }
+  };
+}
+
+export function noop() {}
+
+export function getRnd4() {
+  return Math.floor((1 + Math.random()) * 0x10000).toString(16).slice(-4);
+}
+
+export function getUniqId(prefix) {
+  return (prefix || '') + Date.now().toString(36) + getRnd4();
+}
+
+export function buffer2string(buffer) {
+  const array = new window.Uint8Array(buffer);
+  const sliceSize = 8192;
+  let str = '';
+  for (let i = 0; i < array.length; i += sliceSize) {
+    str += String.fromCharCode.apply(null, array.subarray(i, i + sliceSize));
+  }
+  return str;
+}
+
+export function compareVersion(ver1, ver2) {
+  const parts1 = (ver1 || '').split('.');
+  const parts2 = (ver2 || '').split('.');
+  for (let i = 0; i < parts1.length || i < parts2.length; i += 1) {
+    const delta = (parseInt(parts1[i], 10) || 0) - (parseInt(parts2[i], 10) || 0);
+    if (delta) return delta < 0 ? -1 : 1;
+  }
+  return 0;
+}
+
+const units = [
+  ['min', 60],
+  ['h', 24],
+  ['d', 1000, 365],
+  ['y'],
+];
+export function formatTime(duration) {
+  duration /= 60 * 1000;
+  const unitInfo = units.find((item) => {
+    const max = item[1];
+    if (!max || duration < max) return true;
+    const step = item[2] || max;
+    duration /= step;
+    return false;
+  });
+  return `${duration | 0}${unitInfo[0]}`;
+}

+ 18 - 0
src/common/zip.js

@@ -0,0 +1,18 @@
+import { memoize } from './util';
+
+function loadScript(url) {
+  return new Promise((resolve, reject) => {
+    const script = document.createElement('script');
+    script.src = url;
+    script.onload = () => resolve();
+    script.onerror = () => reject();
+    document.body.append(script);
+  });
+}
+
+const loadZip = memoize(async () => {
+  await loadScript('/public/lib/zip.js/zip.js');
+  return window.zip;
+});
+
+export default loadZip;

+ 6 - 1
src/options/index.js

@@ -4,6 +4,7 @@ import {
 } from '#/common';
 import options from '#/common/options';
 import handlers from '#/common/handlers';
+import loadZip from '#/common/zip';
 import '#/common/ui/style';
 import { store } from './utils';
 import App from './views/app';
@@ -17,7 +18,6 @@ Object.assign(store, {
   sync: [],
   title: null,
 });
-zip.workerScriptsPath = '/public/lib/zip.js/';
 initialize();
 
 function initialize() {
@@ -30,6 +30,11 @@ function initialize() {
     })
     .$mount(el);
   });
+  loadZip()
+  .then((zip) => {
+    store.zip = zip;
+    zip.workerScriptsPath = '/public/lib/zip.js/';
+  });
 }
 
 function initScript(script) {

+ 7 - 4
src/options/views/tab-settings/vm-export.vue

@@ -31,6 +31,7 @@ import options from '#/common/options';
 import { isFirefox } from '#/common/ua';
 import SettingCheck from '#/common/ui/setting-check';
 import { downloadBlob } from '#/common/download';
+import loadZip from '#/common/zip';
 import { store } from '../../utils';
 
 /**
@@ -69,19 +70,21 @@ export default {
 };
 
 function getWriter() {
-  return new Promise((resolve) => {
+  return loadZip()
+  .then(zip => new Promise((resolve) => {
     zip.createWriter(new zip.BlobWriter(), (writer) => {
       resolve(writer);
     });
-  });
+  }));
 }
 
 function addFile(writer, file) {
-  return new Promise((resolve) => {
+  return loadZip()
+  .then(zip => new Promise((resolve) => {
     writer.add(file.name, new zip.TextReader(file.content), () => {
       resolve(writer);
     });
-  });
+  }));
 }
 
 function leftpad(src, length, pad = '0') {

+ 10 - 6
src/options/views/tab-settings/vm-import.vue

@@ -21,6 +21,7 @@
 import { i18n, sendMessage } from '#/common';
 import options from '#/common/options';
 import SettingCheck from '#/common/ui/setting-check';
+import loadZip from '#/common/zip';
 import { showMessage } from '../../utils';
 
 export default {
@@ -76,7 +77,8 @@ function getVMConfig(text) {
 function getVMFile(entry, vmFile) {
   if (!entry.filename.endsWith('.user.js')) return;
   const vm = vmFile || {};
-  return new Promise((resolve) => {
+  return loadZip()
+  .then(zip => new Promise((resolve) => {
     const writer = new zip.TextWriter();
     entry.getData(writer, (text) => {
       const data = { code: text };
@@ -97,11 +99,12 @@ function getVMFile(entry, vmFile) {
       })
       .then(() => resolve(true), () => resolve());
     });
-  });
+  }));
 }
 
 function getVMFiles(entries) {
-  return new Promise((resolve) => {
+  return loadZip()
+  .then(zip => new Promise((resolve) => {
     const data = { entries };
     const i = entries.findIndex(entry => entry.filename && entry.filename.toLowerCase() === 'violentmonkey');
     if (i < 0) {
@@ -114,17 +117,18 @@ function getVMFiles(entries) {
       data.vm = getVMConfig(text);
       resolve(data);
     });
-  });
+  }));
 }
 
 function readZip(file) {
-  return new Promise((resolve, reject) => {
+  return loadZip()
+  .then(zip => new Promise((resolve, reject) => {
     zip.createReader(new zip.BlobReader(file), (res) => {
       res.getEntries((entries) => {
         resolve(entries);
       });
     }, (err) => { reject(err); });
-  });
+  }));
 }
 
 function importData(file) {