|
| 1 | +import mitt from 'mitt'; |
| 2 | +import uuid from 'uuid-v4'; |
| 3 | +import fetch, { Response } from 'node-fetch'; |
| 4 | + |
| 5 | +if (!global.URL) global.URL = {}; |
| 6 | +if (!global.URL.$$objects) { |
| 7 | + global.URL.$$objects = new Map(); |
| 8 | + global.URL.createObjectURL = blob => { |
| 9 | + let id = uuid(); |
| 10 | + global.URL.$$objects[id] = blob; |
| 11 | + return `blob:http://localhost/${id}`; |
| 12 | + }; |
| 13 | + |
| 14 | + let oldFetch = global.fetch || fetch; |
| 15 | + global.fetch = function(url, opts) { |
| 16 | + if (url.match(/^blob:/)) { |
| 17 | + return new Promise( (resolve, reject) => { |
| 18 | + let fr = new FileReader(); |
| 19 | + fr.onload = () => { |
| 20 | + let Res = global.Response || Response; |
| 21 | + resolve(new Res(fr.result, { status: 200, statusText: 'OK' })); |
| 22 | + }; |
| 23 | + fr.onerror = () => { |
| 24 | + reject(fr.error); |
| 25 | + }; |
| 26 | + let id = url.match(/[^/]+$/)[0]; |
| 27 | + fr.readAsText(global.URL.$$objects[id]); |
| 28 | + }); |
| 29 | + } |
| 30 | + return oldFetch.call(this, url, opts); |
| 31 | + }; |
| 32 | +} |
| 33 | + |
| 34 | +if (!global.document) { |
| 35 | + global.document = {}; |
| 36 | +} |
| 37 | + |
| 38 | +function Event(type) { this.type = type; } |
| 39 | +if (!global.document.createEvent) { |
| 40 | + global.document.createEvent = function(type) { |
| 41 | + let Ctor = global[type] || Event; |
| 42 | + return new Ctor(type); |
| 43 | + }; |
| 44 | +} |
| 45 | + |
| 46 | + |
| 47 | +global.Worker = function Worker(url) { |
| 48 | + let messageQueue = [], |
| 49 | + inside = mitt(), |
| 50 | + outside = mitt(), |
| 51 | + scope = { |
| 52 | + onmessage: null, |
| 53 | + dispatchEvent: inside.emit, |
| 54 | + addEventListener: inside.on, |
| 55 | + removeEventListener: inside.off, |
| 56 | + postMessage(data) { |
| 57 | + outside.emit('message', { data }); |
| 58 | + }, |
| 59 | + fetch: global.fetch |
| 60 | + }, |
| 61 | + getScopeVar; |
| 62 | + inside.on('message', e => { let f = getScopeVar('onmessage'); if (f) f.call(scope, e); }); |
| 63 | + this.addEventListener = outside.on; |
| 64 | + this.removeEventListener = outside.off; |
| 65 | + this.dispatchEvent = outside.emit; |
| 66 | + outside.on('message', e => { this.onmessage && this.onmessage(e); }); |
| 67 | + this.postMessage = data => { |
| 68 | + if (messageQueue!=null) messageQueue.push(data); |
| 69 | + else inside.emit('message', { data }); |
| 70 | + }; |
| 71 | + this.terminate = () => { |
| 72 | + throw Error('Not Supported'); |
| 73 | + }; |
| 74 | + global.fetch(url) |
| 75 | + .then( r => r.text() ) |
| 76 | + .then( code => { |
| 77 | + let vars = 'var self=this,global=self'; |
| 78 | + for (let k in scope) vars += `,${k}=self.${k}`; |
| 79 | + // eval('(function() {'+vars+'\n'+code+'\n})').call(scope); |
| 80 | + getScopeVar = eval('(function() {'+vars+'\n'+code+'\nreturn function(__){return eval(__)}})').call(scope); |
| 81 | + let q = messageQueue; |
| 82 | + messageQueue = null; |
| 83 | + q.forEach(this.postMessage); |
| 84 | + }) |
| 85 | + .catch( e => { outside.emit('error', e); console.error(e); }); |
| 86 | +}; |
0 commit comments