Unable to connect to Openfire server from the script running browser side - javascript

At first, I was connecting to Openfire using following script.
const {Client} = require('#xmpp/client')
const client = new Client()
client.start('xmpp://localhost:5222').catch(err => {
console.error('start failed', err)
})
client.handle('authenticate', authenticate => {
return authenticate('gabbar', 'gabbar#123')
})
But it shows me an error 'require is not defined'. so I searched the internet and found that browserify could do my work. so I made the bundle.js file using index.js of my HTML page and included it in the HTML page.
<head>
<meta charset="UTF-8"/>
<title>xmpp.js example</title>
<script src="bundle.js"></script>
<!-- <script src="index.js"></script>-->
</head>
but then I am getting the error
no compatible connection method found
Is anybody can tell any other way of doing it. I tried also same as given in example directory of xmpp.js client package, but that is giving me error like XMPP is not a function. Following is the code which I wrote after looking at example files.
index.js
const {xmpp, xml} =
typeof require === 'undefined' ? window.xmpp : require('#xmpp/client') // For you; require('#xmpp/client')
const {client} = xmpp()
client.start('xmpp://localhost:5222').catch(err => {
console.error('start failed', err)
})
client.handle('authenticate', authenticate => {
return authenticate('gabbar', 'gabbar#123')
})
sample.html
<head>
<meta charset="UTF-8"/>
<title>xmpp.js example</title>
<script src="node_modules/xmpp.js/dist/xmpp.min.js"></script>
<script src="index.js"></script>
</head>
these are the two ways I tried connecting to openfire from the browser side but none of them worked for me. please, can anybody tell me what I am doing wrong or any other possible better way of doing this?

xmpp:// is not supported in the browser. Only ws:// (websockets) is supported in browser. If the server supports websockets, you would do something like:
client.start('ws://domain:port) or client.start('ws://domain:port/xmpp-websockets)
The other option is to use Node not in a browser. Which would be accomplished by running node on it's own without a browser or running that code in the background process of Electron (same as just running node by itself, but you can communicate with the renderer process to interact with a UI)

Related

CertStream Javascript gives error "Uncaught ReferenceError: require is not defined"

I'm setting up a HTML page that want to use the data from CertStream.
The Javascript library is located at https://github.com/CaliDog/certstream-js
In the install instructions it says " if you're using this in the browser, just add dist/certstream.min.js to a tag, and interact with it as normal!".
I have therefor created a HTML page that uses this tag:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Certstream</title>
<meta name="viewport" content="width=device-width; initial-scale=1.0;"/>
<meta http-equiv="Content-Type" content="text/html; charset=UFT-8" />
</head>
<body>
<h1>CertStream</h1>
<!-- CertStream script -->
<script src="dist/certstream.min.js"></script>
<script>
const CertStreamClient = require('certstream');
let client = new CertStreamClient(function(message){
console.log("Received -> ", message)
});
client.connect();
</script>
<!-- //CertStream script -->
</body>
</html>
But I get the error:
Uncaught ReferenceError: require is not defined
http://localhost/certstream-js/test.html:15
certstream.min.js is located on in the folder "dist":
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CertStream=t():e.CertStream=t()}(this,function(){return function(e){function t(o){if(n[o])return n[o].exports;var c=n[o]={exports:{},id:o,loaded:!1};return e[o].call(c.exports,c,c.exports,t),c.loaded=!0,c.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}function c(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var r=function(){function e(e,t){for(var n=0;n<t.length;n++){var o=t[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}return function(t,n,o){return n&&e(t.prototype,n),o&&e(t,o),t}}(),i=n(1),s=o(i),a=function(){function e(t){var n=arguments.length>1&&void 0!==arguments[1]&&arguments[1];c(this,e),this.context={},this.callback=t,this.skipHeartbeats=n}return r(e,[{key:"connect",value:function(){var e=this;console.log("Connecting..."),this.ws=new s.default("wss://certstream.calidog.io/"),console.log("Created ws -> ",this.ws),this.ws.onmessage=function(t){console.log("onmessage called!");var n=JSON.parse(t.data);"heartbeat"===n.message_type&&e.skipHeartbeats||e.callback(t,e.context)},this.ws.onopen=function(){console.log("Connection established to certstream! Waiting for messages...")},this.ws.open()}}]),e}();t.default=a},function(e,t,n){var o,c,r;!function(n,i){c=[],o=i,r="function"==typeof o?o.apply(t,c):o,!(void 0!==r&&(e.exports=r))}(this,function(){function e(t,n,o){function c(e,t){var n=document.createEvent("CustomEvent");return n.initCustomEvent(e,!1,!1,t),n}var r={debug:!1,automaticOpen:!0,reconnectInterval:1e3,maxReconnectInterval:3e4,reconnectDecay:1.5,timeoutInterval:2e3,maxReconnectAttempts:null};o||(o={});for(var i in r)"undefined"!=typeof o[i]?this[i]=o[i]:this[i]=r[i];this.url=t,this.reconnectAttempts=0,this.readyState=WebSocket.CONNECTING,this.protocol=null;var s,a=this,u=!1,l=!1,d=document.createElement("div");d.addEventListener("open",function(e){a.onopen(e)}),d.addEventListener("close",function(e){a.onclose(e)}),d.addEventListener("connecting",function(e){a.onconnecting(e)}),d.addEventListener("message",function(e){a.onmessage(e)}),d.addEventListener("error",function(e){a.onerror(e)}),this.addEventListener=d.addEventListener.bind(d),this.removeEventListener=d.removeEventListener.bind(d),this.dispatchEvent=d.dispatchEvent.bind(d),this.open=function(t){if(s=new WebSocket(a.url,n||[]),t){if(this.maxReconnectAttempts&&this.reconnectAttempts>this.maxReconnectAttempts)return}else d.dispatchEvent(c("connecting")),this.reconnectAttempts=0;(a.debug||e.debugAll)&&console.debug("ReconnectingWebSocket","attempt-connect",a.url);var o=s,r=setTimeout(function(){(a.debug||e.debugAll)&&console.debug("ReconnectingWebSocket","connection-timeout",a.url),l=!0,o.close(),l=!1},a.timeoutInterval);s.onopen=function(n){clearTimeout(r),(a.debug||e.debugAll)&&console.debug("ReconnectingWebSocket","onopen",a.url),a.protocol=s.protocol,a.readyState=WebSocket.OPEN,a.reconnectAttempts=0;var o=c("open");o.isReconnect=t,t=!1,d.dispatchEvent(o)},s.onclose=function(n){if(clearTimeout(r),s=null,u)a.readyState=WebSocket.CLOSED,d.dispatchEvent(c("close"));else{a.readyState=WebSocket.CONNECTING;var o=c("connecting");o.code=n.code,o.reason=n.reason,o.wasClean=n.wasClean,d.dispatchEvent(o),t||l||((a.debug||e.debugAll)&&console.debug("ReconnectingWebSocket","onclose",a.url),d.dispatchEvent(c("close")));var r=a.reconnectInterval*Math.pow(a.reconnectDecay,a.reconnectAttempts);setTimeout(function(){a.reconnectAttempts++,a.open(!0)},r>a.maxReconnectInterval?a.maxReconnectInterval:r)}},s.onmessage=function(t){(a.debug||e.debugAll)&&console.debug("ReconnectingWebSocket","onmessage",a.url,t.data);var n=c("message");n.data=t.data,d.dispatchEvent(n)},s.onerror=function(t){(a.debug||e.debugAll)&&console.debug("ReconnectingWebSocket","onerror",a.url,t),d.dispatchEvent(c("error"))}},1==this.automaticOpen&&this.open(!1),this.send=function(t){if(s)return(a.debug||e.debugAll)&&console.debug("ReconnectingWebSocket","send",a.url,t),s.send(t);throw"INVALID_STATE_ERR : Pausing to reconnect websocket"},this.close=function(e,t){"undefined"==typeof e&&(e=1e3),u=!0,s&&s.close(e,t)},this.refresh=function(){s&&s.close()}}if("WebSocket"in window)return e.prototype.onopen=function(e){},e.prototype.onclose=function(e){},e.prototype.onconnecting=function(e){},e.prototype.onmessage=function(e){},e.prototype.onerror=function(e){},e.debugAll=!1,e.CONNECTING=WebSocket.CONNECTING,e.OPEN=WebSocket.OPEN,e.CLOSING=WebSocket.CLOSING,e.CLOSED=WebSocket.CLOSED,e})}])});
//# sourceMappingURL=certstream.min.js.map
What they mean by
...if you're using this in the browser, just add dist/certstream.min.js to a tag, and interact with it as normal!
...is that you don't need the require call (require is CommonJS, not standard JavaScript, and not provided by default on browsers). If you just include the script file in your page, it defines a global CertStream object with a default property providing the default export of the module. (I suspected this was the case, so I grabbed a copy and tried it.)
The docs could be clearer.🙂 In particular, it looks like after including the library in the browser, you have to use CertStream.default rather than CertStreamClient. I'd probably do that by doing this up-front:
const CertStreamClient = CertStream.default;
(It's too bad they don't provide a native JavaScript module [ESM] file in their dist folder.)
I looked up into certstream.js module in the dist folder and it is a UMD module. Basically, a UMD module is a JavaScript file that tries to guess at runtime which module system it’s being used in, and then it acts as that kind of module. So you can load the file in a plain <script>, or you can load it from an AMD module loader, or you can load it as a Node.js module, and it will always do something sensible.
In your code since you have already loaded the module using <script> tag, the global CertStream object can be directly used without requiring the module again.

XML Encryption and Decryption

I want to encrypt and decrypt my xml file.
I read w3c recommendation about this process.
by some searching
I found npm xml-encryption 1.2.0
https://www.npmjs.com/package/xml-encryption
Has anyone tried it before?
I've installed it but it shows me that error
"require is not defined"
Have you guys any other ways to encrypt xml?
my code
<html>
<head>
<script>
var xmlenc = require('xml-encryption');
var options = {
rsa_pub: fs.readFileSync('./public.pem'),
pem: fs.readFileSync('./public.pem'),
encryptionAlgorithm: 'http://www.w3.org/2001/04/xmlenc#aes256-cbc',
keyEncryptionAlgorithm: 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p',
disallowEncryptionWithInsecureAlgorithm: true,
warnInsecureAlgorithm: true
};
xmlenc.encrypt('content to encrypt', options, function(err, result) {
console.log(result);
})
</script>
</head>
<body>
</body>
</html>
I found the solution here
Client on node: Uncaught ReferenceError: require is not defined
firstly I thought this error is related to the package xml-encryption because I already have installed nodejs

Define CSP HTTP Header in Electron App

Following the API documentation, I don't understand how to define a Content-Security-Policy HTTP Header for the renderer of my Electron application. I always get a warning in the DevTools.
I tried:
1) Copy/Paste the code in the API Doc, blindly:
app.on('ready', () => {
const {session} = require('electron')
session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
callback({responseHeaders: `default-src 'self'`})
})
win = new BrowserWindow(...)
win.loadUrl(...)
}
(By the way, I don't get why "Content-Security-Policy:" is missing in the string. But adding it don't change anything)
2) Modifying the session of the renderer with the same code:
win = new BrowserWindow(...)
win.loadUrl(...)
const ses = win.webContents.session;
ses.webRequest.onHeadersReceived((details, callback) => {
callback({responseHeaders: `default-src 'self'`})
})
3) Add an extra header to ther renderer:
win = new BrowserWindow(...)
win.loadURL(`file://${__dirname}/renderer.html`,{
extraHeaders: `Content-Security-Policy: default-src 'self'`
});
...
The only thing that works is using a meta tag in the renderer HTML file:
<meta http-equiv="Content-Security-Policy" content="default-src 'self'>
Not sure why the documentation contains this broken code. It confused the hell out of me but I found a working solution by trial and error:
session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
callback({ responseHeaders: Object.assign({
"Content-Security-Policy": [ "default-src 'self'" ]
}, details.responseHeaders)});
});
So the headers argument must be an object with the same structure as the original headers received in details.responseHeaders. And the original headers must be included in the passed object as well because this object seems to completely replace the original response headers.
The extraHeaders option isn't for response headers. It is for request headers sent to the server.
If your aim is to be able to use CSP in both dev mode (with resources loaded by http:// protocol) and prod mode (file:// protocol) here's how you can do it:
First, remove the Content-Security-Policy meta from src/index.html - we need to inject it only for prod mode, because
onHeadersReceived will not work for file:// protocol as Electron docs confirm, and also because
if we keep it in src/index.html for Dev mode it will override the onHeadersReceived at least for part of resources, and for Dev mode we need different settings.
Then we can inject it for Prod mode with gulp-inject:
// in project dir
npm install --save-dev gulp-inject gulp
// src/index.html
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<base href="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- inject:prod-headers -->
<!-- src/prod-headers.html content will be injected here -->
<!-- endinject -->
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root>Loading...</app-root>
</body>
</html>
// src/prod-headers.html
<meta http-equiv="Content-Security-Policy" content="default-src 'self'">
// gulpfile.js
var gulp = require('gulp');
var inject = require('gulp-inject');
gulp.task('insert-prod-headers', function () {
return gulp.src('./dist/index.html')
.pipe(inject(gulp.src('./src/prod-headers.html'), {
starttag: '<!-- inject:prod-headers -->',
transform: function (filePath, file) {
// return file contents as string
return file.contents.toString('utf8')
}
}))
.pipe(gulp.dest('./dist'));
});
Then make sure npx gulp insert-prod-headers is run after e.g. ng build generates dist/index.html.
And for dev mode let's use onHeadersReceived similarly to Electron docs example:
const args = process.argv.slice(1);
const devMode = args.some((val) => val === '--serve');
app.on('ready', () => {
if (devMode) {
const {session} = require('electron')
session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
callback({responseHeaders: `default-src http: ws:`})
})
}
win = new BrowserWindow(...)
win.loadUrl(...)
}
This solution was tested on Electron 4.0.3.
As pointed out in the Electron docs, you will have to use a Content Security Policy (CSP) Meta Tag in the html file when you load your renderer.html via file:// scheme (IIRC you do that in above example).
If you want to adjust the content security policy conditionally for prod and dev environment, you can dynamically generate this string inside the html in your build step. I suggest using a template engine like mustache.js (used in the example).
Example (file resources)
In my case I wanted to enable Hot Module Replacement (HMR) via websockets and file:// resource in dev mode, which required relaxing the CSP rules (but only in dev!).
index.mustache:
<html>
<head>
<meta
http-equiv="Content-Security-Policy"
content="{{{cspContent}}}"
/>
</head>
...
cspContent.json for dev:
{
"cspContent": "default-src 'self'; connect-src 'self' ws:"
}
build step in dev (for prod default values could be used):
npx mustache cspContent.json index.mustache > index.html
URL resources
For usage with URL resources, you can stick to this example:
const { session } = require('electron')
session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
callback({
responseHeaders: {
...details.responseHeaders,
'Content-Security-Policy': ['default-src \'none\'']
}
})
})
Make sure to merge your custom CSP response headers with the default ones - you don't do that in your pasted example above. Here, you can also check conditionally for the environment.
Hope, it helps.
There isn't enough detail in your question to know whether you are having issues on initial load or subsequent web requests, but my issue was for the initial file load. With an Electron app using React, I was getting warnings about using inline scripts even with kayahr's code. This is because the onHeadersReceived method only catches requests that are made after the application has loaded initially. It will not stop any warnings from the initial application load.
I ended up having to use templating during my application build to add a nonce to the inline script and style and to the CSP header in the HTML file that the application loads initially.
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'nonce-<%= scriptNonce %>'; style-src 'nonce-<%= styleNonce %>';">
<link rel="stylesheet" type="text/css" href="./index.css" nonce=<%= styleNonce %>>
<title>Basic Electron App</title>
</head>
<body>
<div id="app"></div>
<script type="application/javascript" nonce=<%= scriptNonce %>>
require('./index.js');
</script>
</body>
</html>
index.css
body {
margin: 0px;
}
.hello {
font-family: "Century Gothic";
width: 800px;
margin: 70px auto;
text-align: center;
}
and in gulfile.js add the following to what you already have and make sure this task is included in your pipeline. You can also just update your current html task with the code below.
const template = require('gulp-template');
const uuidv4 = require('uuid/v4');
gulp.task('copy-html', () => {
// Create nonces during the build and pass them to the template for use with inline scripts and styles
const nonceData = {
scriptNonce: new Buffer(uuidv4()).toString('base64'),
styleNonce: new Buffer(uuidv4()).toString('base64')
};
return gulp.src('src/*.html')
.pipe(template(nonceData))
.pipe(gulp.dest('dist/'));
});
This is a very stripped down example. I have a more complete example at https://github.com/NFabrizio/data-entry-electron-app if anyone is interested, though there is still one warning when running the application because one of the packages I am using pulls in react-beautiful-dnd, which adds inline styles but does not currently accept nonces.
Set the following meta tag in the renderers.
<meta http-equiv="Content-Security-Policy" content="script-src 'nonce-xxx or sha256-yyy' " />
Kindly checkout my github repo electron-renderer-CSP-sample, containing samples for both nonce & SHA methods for internal & external js files as well.

Browser loading html in js file (node.js)

Apologies for the confusing title, the confusing title is a byproduct of my own confusion.
I am working with Node.js to write a web server and an api. Everything was going well, until I ran into this problem. Here is my server/api code:
const express = require('express');
const app = express();
const port = 9001;
const bodyParser = require('body-parser');
const mysql = require('mysql');
app.get('/profile/:url', (request, response) =>{
app.use('/profile/:url', express.static(__dirname+'/static_pages'));
response.sendFile('static_pages/test.html', {root: __dirname});
});
Here is test.html:
<!DOCTYPE html>
<html lang= "en">
<head>
<script src="https://code.jquery.com/jquery-1.10.2.js"></script>
<script type="text/javascript" src="./test.js"></script>
</head>
<body>
<div class="test">test</div>
</body>
</html>
here is test.js:
console.log('i run correctly!');
Now test.html does everything as expected if I open the file with a browser. However, if I run the server and navigate to 127.0.0.1:9001/profile/XXXXX , I get the following error:
Uncaught SyntaxError: Unexpected token <
Confused, I checked under "Sources" in Chrome devtools, and despite Chrome saying that it's loading "test.js" the code that it's running as "test.js" is identical to that of "test.html". Does anyone know why this is happening?
I used an identical method in order to deliver html/css/js in my other rest calls in the same file, and all of those pages are working as intended.
app.get('/profile/:url', (request, response) =>{
app.use('/profile/:url', express.static(__dirname+'/static_pages'));
response.sendFile('static_pages/test.html', {root: __dirname});
});
That doesn't make sense.
Every time you get a request for /profile/:url you try to set up the static plugin, then you return the contents of test.html.
When the browser asks for /profile/test.js that code … returns the contents of test.html.
Presumably you are planning to put some dynamic code in there to generate the profile page dynamically. That means you should not put the JS under `/profile/ because it isn't a profile page.
So:
Configure the static plugin properly:
app.get('/profile/:url', (request, response) =>{
response.sendFile('static_pages/test.html', {root: __dirname});
});
app.use(express.static(__dirname+'/static_pages'));
Point the URL at the right place:
<script src="/test.js"></script>
Note the . is removed so you are accessing from the root instead of from the current path segment.

Chrome can't load web worker

I am working on a project that uses a web worker.
In my head section I have this code:
var worker = new Worker("worker.js");
// More code
This works fine in Safari, but Chrome reports the following error:
Uncaught SecurityError: Failed to create a worker: script at '(path)/worker.js' cannot be accessed from origin 'null'.
Why does this work perfectly in Safari but not Chrome? How do I fix this?
Thank you.
Chrome doesn't let you load web workers when running scripts from a local file.
I use a workaround. Chrome blocks Worker but not <script>. Hence the best way to make a universal solution is this:
function worker_function() {
// all code here
}
// This is in case of normal worker start
// "window" is not defined in web worker
// so if you load this file directly using `new Worker`
// the worker code will still execute properly
if(window!=self)
worker_function();
You then link it as normal <script src="...". And once the function is defined, you use this abomination of a code:
new Worker(URL.createObjectURL(new Blob(["("+worker_function.toString()+")()"], {type: 'text/javascript'})));
The problem has been properly explained by Noble Chicken but I have a more general solution for it. Instead of installing wamp or xamp, with python you can navigate to the folder your project is hosted in and type: python -m http.server
Just that and you will have a running server on that folder, reachable from localhost.
You can also use the --allow-file-access-from-files flag when you launch Chrome.
Example for MacOsX :
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --allow-file-access-from-files
More info : Web worker settings for chrome
It is because of the security restrictions. You need to use http:// or https:// protocol instead of file:///.
If you have NodeJS installed, you can simply do the following.
- Note that this is one of many options available
Install local-web-server
$ npm install -g local-web-server
Now you can use it in any folder that you want to access the contents through http .
$ ws
Navigate to http://localhost:8000 (default port: 8000)
I had the same problem as your post too. The solution is that you have to run it with localhost (wamp or xamp). It will done.
Another workaround is use Google's web server for Chrome extension. Choose your work directory and start the server, Done!
This is inspired by Thomas answer above. But with one caveat that
I wanted to distribute only the HTML, so i manually converted the js to dataURL. and enabling the data URL check box in it.
const myWorker = new Worker("data:application/x-javascript;base64,b25tZXNzYW...");
Easy way to make local http server in chrome is this app:
Web Server for Chrome
https://chrome.google.com/webstore/detail/web-server-for-chrome/ofhbbkphhbklhfoeikjpcbhemlocgigb/related
Description:
A Web Server for Chrome, serves web pages from a local folder over the network, using HTTP. Runs offline.
Web Server for Chrome is an open source (MIT) HTTP server for Chrome.
It runs anywhere that you have Chrome installed, so you can take it anywhere. It even works on ARM chromebooks.
It now has the option to listen on the local network, so other computers can access your files. Additionally, it can try and get an internet address.
Many people use this to do basic web development on a chromebook. It is also handy for sharing files over a local network between computers, or even on the internet.
Once you install it, navigate to http://127.0.0.1:8887
And it is not unsecure as flag --allow-file-access-from-files
you need a web server for request from HTTP protocol Instead of local file
and work correctly :)
Chrome load the file but cannot run it. Use Firefox. It's working for me.
With Python 2.x being more widely deployed than Python 3.x, something like python -m SimpleHTTPServer 8000 is more generally applicable, and not just for Mac OS X. I found it necessary for use under Cygwin, for instance.
With that in place, this example worked like a champ.
function worker_fun(num){
num ++
// console.log(num)
postMessage(num);
setTimeout(worker_fun.bind(null,num), 500)
}
var w
function startWorker(){
var blob = new Blob([
"onmessage = function(e){\
" + worker_fun.toString() + "\
worker_fun(e.data.num);}"
]);
var blobURL = window.URL.createObjectURL(blob);
if (typeof(Worker) != 'undefined'){
if (typeof(w) == 'undefined'){
w = new Worker(blobURL);
w.onmessage = function(event){
document.getElementById('num').innerHTML = event.data;
}
w.postMessage({
num:parseInt(document.getElementById('num').innerHTML)})
}
}
}
function stopWorker() {
w.terminate();
w = undefined;
}
As mentioned chrome does not support it. I like to define my workers in the same file. This is a working workaround which will increase a number found in innerHTML of the element the with id=num every 500ms.
A probably reason is chrome doesn't let you load web workers when running scripts from a local file. And I try run the code on my firefox, can not either.
To load web worker from file in a project set up with Webpack and TypeScript I used a script as Tomáš Zato suggested. However, I had to modify the worker file.
worker.ts
(() => {
console.log("worker_function loaded");
// #ts-ignore
window.worker_function = () => {
self.onmessage = ({ data: { question } }) => {
// #ts-ignore
self.postMessage({
answer: 42,
});
};
}
})();
index.ts
async function run() {
console.log('run()');
const worker = new Worker(
// #ts-ignore
URL.createObjectURL(new Blob(["("+worker_function.toString()+")()"], { type: 'text/javascript' }))
);
worker.postMessage({
question: 'The Answer to the Ultimate Question of Life, The Universe, and Everything.',
});
worker.onmessage = ({ data: { answer } }) => {
console.log(answer);
};
}
run();
index.html
<html lang="en-us">
<head>
<meta charset="utf-8" />
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
<title>Offscreen canvas with web worker sample project</title>
<script async type="text/javascript" src="worker.js"></script>
<script async type="text/javascript" src="app.js"></script>
</head>
<body>
<h1>web worker sample project</h1>
</body>
</html>
webpack.config.js (version 5)
const path = require("path");
const CopyPlugin = require("copy-webpack-plugin");
module.exports = {
mode: "production",
entry: {
app: "./src/index.ts",
worker: "/src/worker.ts"
},
output: {
filename: "[name].js",
path: path.resolve(__dirname, "build")
},
performance: {
hints: false
},
module: {
rules: [
{
test: /\.tsx?$/,
use: "ts-loader",
exclude: /node_modules/
},
]
},
resolve: {
extensions: [".js", ".ts"]
},
plugins: [
new CopyPlugin({
patterns: [
{ from: "src/index.html", to: "" }
]
})
]
};
Yes, It will not work in chorome if your are loading local file. But it will work fine in firefox browser. And you have to add below code in HTML file.
<head>
<meta charset="UTF-8" />
</head>

Categories