I'm working on a firefox extension for the first time, and thanks to the documentation, it's going on pretty fast.
I've a problem however : I wan't to redirect the users if they go on some domains.
const {Cc, Ci, Cr, Cu} = require("chrome");
const buttons = require('sdk/ui/button/action');
const tabs = require("sdk/tabs");
var httpRequestObserver =
{
observe: function(subject, topic, data)
{
if (topic == "http-on-modify-request") {
var httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);
var eTLDService = Cc["#mozilla.org/network/effective-tld-service;1"].getService(Ci.nsIEffectiveTLDService);
var suffix = eTLDService.getPublicSuffixFromHost(httpChannel.originalURI.host);
var regexp = new RegExp('google\.'+suffix,'i');
if (regexp.test(httpChannel.originalURI.host)) {
Cu.import("resource://gre/modules/Services.jsm");
httpChannel.redirectTo(Services.io.newURI("http://test.tld", null, null));
}
}
get observerService() {
return Cc["#mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
},
register: function()
{
this.observerService.addObserver(this, "http-on-modify-request", false);
},
unregister: function()
{
this.observerService.removeObserver(this, "http-on-modify-request");
}
};
httpRequestObserver.register();
I'm trying to do a little POC, but it seems to load indefinitely.
Do you know what I am doing wrong?
Don't test the originalURI! It will stay the same even after a redirect
/**
* The original URI used to construct the channel. This is used in
* the case of a redirect or URI "resolution" (e.g. resolving a
* resource: URI to a file: URI) so that the original pre-redirect
* URI can still be obtained. ...
*/
So you redirect, that creates a new channel with the same originalURI but different URI, so your test triggers again and again and again... causing the infinite redirection loop (and redirecting by this API also is not subject to the usual redirection limit).
Instead test the .URI of a channel, which gives the current URI.
Related
I've never received an error like this before,
I have a file that defines functions for making API calls, currently I'm reading the endpoint base URLs from the environment variables:
/**
* Prepended to request URL indicating base URL for API and the API version
*/
const VERSION_URL = `${process.env.NEXT_PUBLIC_API_BASE_URL}/${process.env.NEXT_PUBLIC_API_VERSION}`
I tried to make a quick workaround because environment variables weren't being loaded correctly, by hardcoding the URLS incase the variable wasn't defined.
/**
* Prepended to request URL indicating base URL for API and the API version
*/
const VERSION_URL = `${process.env.NEXT_PUBLIC_API_BASE_URL || 'https://hardcodedURL.com'}/${process.env.NEXT_PUBLIC_API_VERSION || 'v1'}`
In development and production mode when running on my local machine it works fine (docker container). However, as soon as it's pushed to production, I then get the following screen:
This is the console output:
framework-bb5c596eafb42b22.js:1 TypeError: Path must be a string. Received undefined
at t (137-10e3db828dbede8a.js:46:750)
at join (137-10e3db828dbede8a.js:46:2042)
at J (898-576b101442c0ef86.js:1:8158)
at G (898-576b101442c0ef86.js:1:10741)
at oo (framework-bb5c596eafb42b22.js:1:59416)
at Wo (framework-bb5c596eafb42b22.js:1:68983)
at Ku (framework-bb5c596eafb42b22.js:1:112707)
at Li (framework-bb5c596eafb42b22.js:1:98957)
at Ni (framework-bb5c596eafb42b22.js:1:98885)
at Pi (framework-bb5c596eafb42b22.js:1:98748)
cu # framework-bb5c596eafb42b22.js:1
main-f51d4d0442564de3.js:1 TypeError: Path must be a string. Received undefined
at t (137-10e3db828dbede8a.js:46:750)
at join (137-10e3db828dbede8a.js:46:2042)
at J (898-576b101442c0ef86.js:1:8158)
at G (898-576b101442c0ef86.js:1:10741)
at oo (framework-bb5c596eafb42b22.js:1:59416)
at Wo (framework-bb5c596eafb42b22.js:1:68983)
at Ku (framework-bb5c596eafb42b22.js:1:112707)
at Li (framework-bb5c596eafb42b22.js:1:98957)
at Ni (framework-bb5c596eafb42b22.js:1:98885)
at Pi (framework-bb5c596eafb42b22.js:1:98748)
re # main-f51d4d0442564de3.js:1
main-f51d4d0442564de3.js:1 A client-side exception has occurred, see here for more info: https://nextjs.org/docs/messages/client-side-exception-occurred
re # main-f51d4d0442564de3.js:1
Viewing the source at t (137-10e3db828dbede8a.js:46:750)
I'm completely at a lost at what this means or what is happening. Why would hardcoding in a string for the path result in this client error? The lack of a readable source code is making this impossible for me to understand what's happening.
Quick googling suggests that I should upgrade some package, but the error is so vague, I'm not even sure what package is giving the issue.
This is the roughly the how the version URL path is being used
/**
* Send a get request to a given endpoint
*
* **Returns a Promise**
*/
function GET(token, data, parent, api) {
return new Promise((resolve, reject) => {
try {
let req = new XMLHttpRequest()
let endpoint = `${VERSION_URL}/${parent}/${api}` // base url with the params not included
let params = new URLSearchParams() // URLSearchParams used for adding params to url
// put data in GET request params
for (const [key, value] of Object.entries(data)) {
params.set(key, value)
}
let query_url = endpoint + "?" + params.toString() // final query url
req.open("GET", query_url, true)
req.setRequestHeader("token", token) // put token into header
req.onloadend = () => {
if (req.status === 200) {
// success, return response
resolve([req.response, req.status])
} else {
reject([req.responseText, req.status])
}
}
req.onerror = () => {
reject([req.responseText, req.status])
}
req.send()
} catch (err) {
reject(["Exception", 0])
}
})
}
From my experience, this problem can happen for multiple reasons. The most common one is because you didn't put the data accessing checker properly when data comes from an API. Sometimes this things we don't see in browser but it gives such error when you deploy.
For example:
const response = fetch("some_url");
const companyId = response.data.companyId; ❌
const companyId = response?.data?.companyId; ✔️
I'm building a web app that uses EvaporateJS to upload large files to Amazon S3 using Multipart Uploads. I noticed an issue where every time a new chunk was started the browser would freeze for ~2 seconds. I want the user to be able to continue to use my app while the upload is in progress, and this freezing makes that a bad experience.
I used Chrome's Timeline to look into what was causing this and found that it was SparkMD5's hashing. So I've moved the entire upload process into a Worker, which I thought would fix the issue.
Well the issue is now fixed in Edge and Firefox, but Chrome still has the exact same problem.
Here's a screenshot of my Timeline:
As you can see, during the freezes my main thread is doing basically nothing, with <8ms of JavaScript running during that time. All the work is occurring in my Worker thread, and even that is only running for ~600ms or so, not the 1386ms that my frame takes.
I'm really not sure what's causing the issue, are there any gotchas with Workers that I should be aware of?
Here's the code for my Worker:
var window = self; // For Worker-unaware scripts
// Shim to make Evaporate work in a Worker
var document = {
createElement: function() {
var href = undefined;
var elm = {
set href(url) {
var obj = new URL(url);
elm.protocol = obj.protocol;
elm.hostname = obj.hostname;
elm.pathname = obj.pathname;
elm.port = obj.port;
elm.search = obj.search;
elm.hash = obj.hash;
elm.host = obj.host;
href = url;
},
get href() {
return href;
},
protocol: undefined,
hostname: undefined,
pathname: undefined,
port: undefined,
search: undefined,
hash: undefined,
host: undefined
};
return elm;
}
};
importScripts("/lib/sha256/sha256.min.js");
importScripts("/lib/spark-md5/spark-md5.min.js");
importScripts("/lib/url-parse/url-parse.js");
importScripts("/lib/xmldom/xmldom.js");
importScripts("/lib/evaporate/evaporate.js");
DOMParser = self.xmldom.DOMParser;
var defaultConfig = {
computeContentMd5: true,
cryptoMd5Method: function (data) { return btoa(SparkMD5.ArrayBuffer.hash(data, true)); },
cryptoHexEncodedHash256: sha256,
awsSignatureVersion: "4",
awsRegion: undefined,
aws_url: "https://s3-ap-southeast-2.amazonaws.com",
aws_key: undefined,
customAuthMethod: function(signParams, signHeaders, stringToSign, timestamp, awsRequest) {
return new Promise(function(resolve, reject) {
var signingRequestId = currentSigningRequestId++;
postMessage(["signingRequest", signingRequestId, signParams.videoId, timestamp, awsRequest.signer.canonicalRequest()]);
queuedSigningRequests[signingRequestId] = function(signature) {
queuedSigningRequests[signingRequestId] = undefined;
if(signature) {
resolve(signature);
} else {
reject();
}
}
});
},
//logging: false,
bucket: undefined,
allowS3ExistenceOptimization: false,
maxConcurrentParts: 5
}
var currentSigningRequestId = 0;
var queuedSigningRequests = [];
var e = undefined;
var filekey = undefined;
onmessage = function(e) {
var messageType = e.data[0];
switch(messageType) {
case "init":
var globalConfig = {};
for(var k in defaultConfig) {
globalConfig[k] = defaultConfig[k];
}
for(var k in e.data[1]) {
globalConfig[k] = e.data[1][k];
}
var uploadConfig = e.data[2];
Evaporate.create(globalConfig).then(function(evaporate) {
var e = evaporate;
filekey = globalConfig.bucket + "/" + uploadConfig.name;
uploadConfig.progress = function(p, stats) {
postMessage(["progress", p, stats]);
};
uploadConfig.complete = function(xhr, awsObjectKey, stats) {
postMessage(["complete", xhr, awsObjectKey, stats]);
}
uploadConfig.info = function(msg) {
postMessage(["info", msg]);
}
uploadConfig.warn = function(msg) {
postMessage(["warn", msg]);
}
uploadConfig.error = function(msg) {
postMessage(["error", msg]);
}
e.add(uploadConfig);
});
break;
case "pause":
e.pause(filekey);
break;
case "resume":
e.resume(filekey);
break;
case "cancel":
e.cancel(filekey);
break;
case "signature":
var signingRequestId = e.data[1];
var signature = e.data[2];
queuedSigningRequests[signingRequestId](signature);
break;
}
}
Note that it relies on the calling thread to provide it with the AWS Public Key, AWS Bucket Name and AWS Region, AWS Object Key and the input File object, which are all provided in the 'init' message. When it needs something signed, it sends a 'signingRequest' message to the parent thread, which is expected to provided the signature in a 'signature' message once it's been fetched from my API's signing endpoint.
I can't give a very good example or analyze what you are doing with only the Worker code, but I strongly suspect that the issue either has to do with either the reading of the chunk on the main thread or some unexpected processing that you are doing on the chunk on the main thread. Maybe post the main thread code that calls postMessage to the Worker?
If I were debugging it right now, I'd try moving your FileReader operations into the Worker. If you don't mind the Worker blocking while it loads a chunk, you could also use FileReaderSync.
Post-comments update
Does generating the presigned URL require hashing the file content + metadata + a key? Hashing file content is going to take O(n) in the size of the chunk and it's possible, if the hash is the first operation that reads from the Blob, that the loading of the file content could be deferred until the hashing starts. Unless you are compelled to keep the signing in the main thread (you don't trust the worker with key material?) that would be another good thing to bring into the worker.
If moving the signing into the Worker is too much, you could have the worker do something to force the Blob to be read and/or pass the ArrayBuffer(or Uint8Array or what have you) of file content back to the main thread for signing; this would ensure that reading the chunk does not occur on the main thread.
I am using nativescript to build an app that will programmatically send a pre-built text to multiple preset parties in case of emergency.
I have an array of phone numbers and want to iterate over each one, using SMSmanager to send the text and the sentIntent argument seen in android docs to verify that the text was sent before moving on to the next array item.
I have created the pendingIntent variable to pass into "sms.sendTextMessage" as follows:
var sms = android.telephony.SmsManager.getDefault();
var utils = require("utils/utils");
//Gets application's current state
var context = utils.ad.getApplicationContext();
//Create a replica of Android's intent object
var intent = new android.content.Intent(context, com.tns.NativeScriptActivity.class);
//Create a replica of Android's pendingIntent object using context and intent
var pendingIntent = android.app.PendingIntent.getActivity(context, 1, intent, android.app.PendingIntent.FLAG_UPDATE_CURRENT);
I then send the text, passing in the pending intent var:
sms.sendTextMessage("5555555555", null, "hello", pendingIntent, null);
I then attempt to make a basic broadcast receiver using the information I found in the nativescript docs which should just log something to the console when it recieves the expected data.
app.android.registerBroadcastReceiver(pendingIntent, function() {
console.log("##### text sent #####");
});
The problem is: nothing happens. I'd expect to get ""##### text sent #####" logged to the console. I've googled a lot and am thinking maybe I need to add something about this broadcast reciever in the manifest, or perhaps my implimentation is wrong somewhere, but this is my first crack at an android app and I'm at a bit of a loss. Any help would be appreciated.
I'm going to answer my own question here in case anyone else runs into this.
The code that worked is:
var app = require("application");
var utils = require("utils/utils");
var context = utils.ad.getApplicationContext();
var sms = android.telephony.SmsManager.getDefault();
var SendMessages = {
init: function() {
var id = "messageSent";
this.sendText(id, this.pendingIntent(id));
},
sendText: function(id, pendingIntent) {
sms.sendTextMessage("5555555555", null, "Hello :)", pendingIntent, null);
this.broadcastReceiver(id, function() {
console.log("$$$$$ text sent $$$$$");
});
},
pendingIntent: function(id) {
var intent = new android.content.Intent(id);
return android.app.PendingIntent.getBroadcast(context, 0, intent, 0);
},
broadcastReceiver: function(id, callback) {
app.android.registerBroadcastReceiver(id, function() {
callback();
});
}
};
module.exports = SendMessages;
To explain: it seems as #Mike M mentioned each intent object needs some string as an id.
Then to make the "pendingIntent" object, again as #Mike M. mentioned I needed to hook to "getBroadcast" method, then I needed to pass pending intent the app context as the first argument, then 0, then the intent object with the id.
The pending intent then is receivable in a simple broadcast receiver function by simply passing the intent id as the first argument and the callback as the second. I've tested and it's working perfectly.
Following is a simplified version, no bs code approach to what you need to make it run. You need permissions and to make sure the user accepts those permissions. This is also one of the two ways (this one is the context-registered receiver way) to create a broadcast receiver, read more about both types here: https://developer.android.com/guide/components/broadcasts#receiving-broadcasts
Info on registering broadcast receiver: https://docs.nativescript.org/api-reference/classes/application.androidapplication.html#registerbroadcastreceiver
AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="__PACKAGE__"
android:versionCode="10000"
android:versionName="1.0">
<!-- ...more code -->
<uses-permission android:name="android.permission.SEND_SMS" />
<!-- ...more code -->
</manifest>
JavaScript:
import * as application from 'tns-core-modules/application';
import * as platform from 'tns-core-modules/platform';
import * as utils from 'tns-core-modules/utils/utils';
import * as permissions from 'nativescript-permissions';
// ...more code
try {
await permissions.requestPermission(
android.Manifest.permission.SEND_SMS,
'Need to send.'
);
console.log('SEND_SMS permission accepted.');
const text = 'Herro.';
const mobileNumber = '55555555';
const intentFilter = 'something_here';
const context = utils.ad.getApplicationContext();
const intent = new android.content.Intent(intentFilter);
const pendingIntent = android.app.PendingIntent.getBroadcast(context, 0, intent, 0);
const sms = android.telephony.SmsManager.getDefault();
application.android.registerBroadcastReceiver(intentFilter, function() {
console.log(`Text has been sent: ${text}`);
});
setTimeout(() => {
console.log('Sending text.');
sms.sendTextMessage(mobileNumber, null, text, pendingIntent, null);
}, 5000);
} catch (error) {
console.log('Permission error:', error);
}
The code above is created inside the activity and uses the main ui thread. This means that if the user exits the activity, the broadcast receiver will linger in limbo and android can destroy it.
I want to create an url-routing script using javascript as much as possible, but also accepting jQuery in the code. The js file has to change the url path (although I used location.hash instead of location.pathname) and the content of a div with the view id (from external files) accordingly.
Example configuration:
root/index.html
root/tpl/home.html
root/tpl/about.html
home.html content:
<p>This is content of home page</p>
about.html content:
<p>This is the content of the about page </p>
What I have done so far:
'use strict';
var Router = {
root: '/',
routes: [],
urls: [],
titles: [],
navigate: function() {
location.hash = this.root;
return this;
},
add: function(thePath, theUrl, theTitle) {
this.routes.push(thePath);
this.urls.push(theUrl);
this.titles.push(theTitle);
},
loading: function() {
this.navigate();
var r = this.routes;
var u = this.urls;
window.onload = function() {
$("#view").load("tpl/home.html");
};
window.onhashchange = function() {
for (var i = 0; i < r.length; i++) {
if (location.hash == r[i]) {
$("#view").load(u[i]);
}
}
};
}
};
Router.add("#/home", "tpl/home.html", "Home Page");
Router.add("#/about", "tpl/about.html", "About Page");
Router.loading();
Desired type of url:
http://mywebsite.com/
http://mywebsite.com/about
I know there are more than enough libraries that make the routing, like AngularJS and Crossroad, I want to know how this could be done.
To make this URL work - http://mywebsite.com/about - you need a server that knows how to route this request. Since the actual file name is about.html your server must know what to do with extensionless URLs.
Usually, the server uses the file extension as a clue for how to serve up content. For example, if it sees file.php it knows to use the PHP component, for .aspx it knows to use the ASP.NET component, and for .htm or .html it knows to respond with plain HTML (and usually serves the file instead of processing it). Your server must have some rules for what to do with any request, whether it has an extension or not, but without an extension you need to provide an explicit routing rule for that request..
The capabilities for JavaScript to do routing are limited because it requires the user to already be on your site. You can do some interesting things if you parse the URL parameters or use hashes and use them for routing, but that still requires requesting a page from your site as the first step.
For example: the server is already doing some level of "extensionless routing" when you give it this request:
http://mywebsite.com/
The parts of the URL are:
http - protocol
(port 80 is implied because it is default HTTP port)
mywebsite.com - domain AKA host
/ the path
The server sees / and uses what IIS calls a "default document" (I think apache calls it "default index" or "default page"). The server has been configured to return a file such as "index.html" or "default.htm" in this case. So when you request http://mywebsite.com/ you actually may get back the equivalent of http://mywebsite.com/index.html
When the server sees http://mywebsite.com/about it may first look for a folder named about and next for a file named about, but since your file is actually named about.html and is in a different folder (/tpl) the server needs some help to know how to translate http://mywebsite.com/about into the appropriate request - which for you would be http://mywebsite.com/#/about so that it requests the routing page (assuming it is the default document in the web app root folder) so that the browser can parse and execute the JavaScript that does the routing. Capisce?
You might be interested by frontexpress.
My library fix your case like below:
// Front-end application
const app = frontexpress();
const homeMiddleware = (req, res) => {
document.querySelector('#view').innerHTML = '<p>This is content of home page</p>';
}
app.get('/', homeMiddleware);
app.get('/home', homeMiddleware);
app.get('/about', (req, res) => {
document.querySelector('#view').innerHTML = '<p>This is the content of the about page </p>';
});
Obviously, you can get the template files from the server.
The #view will be feeded as below:
document.querySelector('#view').innerHTML = res.responseText;
More detailed sample in this gist
I have worked with what your answers and I have build the following Router. The only issue remains that it still uses location.hash
(function() {
var Router = {
root: '#/',
routes: [],
urls: [],
titles: [],
add: function(thePath, theUrl, theTitle) {
this.routes.push(thePath);
this.urls.push(theUrl);
this.titles.push(theTitle);
},
navigate: function() {
var routes = this.routes,
urls = this.urls,
root = this.root;
function loading() {
var a = $.inArray(location.hash, routes),
template = urls[a];
if (a === -1) {
location.hash = root;
$("#view").load(urls[0]);
}
else {
$("#view").load(template);
if (a === 0) {
window.scrollTo(0, 0);
}
else {
window.scrollTo(0, 90);
}
}
}
window.onload = loading;
window.onhashchange = loading;
}
};
Router.add("#/", "tpl/home.html", "Home Page");
Router.add("#/about", "tpl/about.html", "About Page");
Router.add("#/licence", "tpl/licence.html", "MIIT Licence");
Router.add("#/cabala", "tpl/cabala.html", "Cabala Checker");
Router.add("#/articles/esp", "tpl/article1.html", "ESP");
Router.add("#/fanfics/the-chupacabra-case", "tpl/article2.html", "The Chupacabra Case");
Router.navigate();
})();
Your request reads like what you're attempting to do is to add a "path+file" ("/tpl/about.html") to a base url ("www.myhost.com"). If that's the case, then you need to dynamically extract the host name from your current document and then append the new URL to the existing base. You can get the existing host name by executing the following commands in javascript:
var _location = document.location.toString();
var serverNameIndex = _location.indexOf('/', _location.indexOf('://') + 3);
var serverName = _location.substring(0, serverNameIndex) + '/';
This will return a string like: "http://www.myhost.com/" to which you can now append your new URL. All of this can be done in javascript prior to sending to the server.
If you only want the server name, without the leading http or https, then change the last line to be:
var serverName = _location.substring(_location.indexOf('://') + 3, serverNameIndex) + '/';
Lets break your code down a little bit:
function loading() {
"location.hash" is set based on the URL most recently clicked (www.myhost.home/#about). One essential question is, is this the action that you want, or do you want to pass in a value from the html for the onClick operation? It seems like that would be a more effective approach for you.
var a = $.inArray(location.hash, routes),
template = urls[a];
var a will be set to either -1 or the location of "location.hash" in the "routes array. If location.hash does not exist in routes, then a==-1 and the script will fail, because you're setting template = urls[-1]. You may want to move setting template to inside the "else" statement.
if (a === -1) {
location.hash = root;
$("#view").load(urls[0]);
}
else {yada yada yada
}
You could use a sequence in your html analogous to:
<a onclick="loading('#about')">Go to About Page</a>
I am working on a small project of mine using karma, and jasmine. My targeted browser is chrome 32.
I am trying to import scripts within a web worker whom I have instanciated through a blob as follows :
describeAsyncAppliPersephone("When the application project to DOM", function()
{
it("it should call the function of DomProjection in the project associated with its event", function()
{
var eventSentBack = {
eventType: 'testReceived',
headers: { id: 14, version: 4 },
payLoad: { textChanged: 'newText' }
};
var isRendered = false;
var fnProjection = function(event, payload)
{
isRendered = true;
}
var bootstrap = [
{ eventType: 'testReceived', projection: fnProjection },
{ eventType: 'test2Received', projection: function() { } }
];
runs(function()
{
var factory = new WorkerFactory();
var worker = factory.CreateByScripts('importScripts("/base/SiteWeb/project/js/app/application.js"); var app = new application(self); app.projectOnDOM(' + JSON.stringify(eventSentBack) + '); ');
console.log(worker.WorkerLocation);
var applicationQueue = new queueAsync(worker);
var projectQueue = new queueSync(worker);
var p = new project(applicationQueue, persephoneQueue, bootstrap);
applicationQueue.publish(eventSentBack);
});
waitsFor(function() { return isRendered }, "Projection called", 500);
runs(function()
{
expect(isRendered).toBe(true);
});
});
});
workerFactory is as follows :
this.CreateByScripts = function(scripts, fDefListener, fOnError)
{
var arrayScripts = scripts;
if (!arrayScripts)
throw "unable to load worker for undefined scripts";
if (Object.prototype.toString.call(arrayScripts) !== '[object Array]')
arrayScripts = [arrayScripts];
var blob = new Blob(arrayScripts, { type: "text/javascript" });
var w = createWorker(window.URL.createObjectURL(blob));
return new QueryableWorker(w, fDefListener, fOnError);
}
where createWorker is :
createWorker = function(sUrl)
{
return new Worker(sUrl);
}
But the importScripts throws me the following error :
Uncaught SyntaxError: Failed to execute 'importScripts': the URL
'/base/SiteWeb/project/js/app/application.js' is invalid.
I have tried with the path within the browser :
http://mylocalhost:9876/base/SiteWeb/project/js/app/application.js
and it does work well.
What is the path I should use to make importScripts working successfully ?
Thanks,
You can't use relative path in worker created with Blob.
Had this problem today. Solution is explained in "The Basics of Web Workers", but a little hidden in length of the article:
The reason being: the worker (now created from a blob URL) will be resolved with a blob: prefix, while your app will be running from a different (presumably http://) scheme. Hence, the failure will be due to cross origin restrictions.
If you are determined to avoid hardcoding domain name in your workers the article has also a solution for this. Import your scripts on receiving a message with URL as one of its parameters:
self.onmessage = function(e) {
importScripts(e.data.url + 'yourscript.js');
};
and start your worker with sending that url
worker.postMessage({url: document.location.protocol + '//' + document.location.host});
The code above is simplified for clarity.