worker-loader
worker-loader copied to clipboard
Inline workers does not work in Edge Legacy anymore
- Operating System: Windows 10
- Node Version: 12.14.0
- NPM Version: 6.13.4
- webpack Version: 4.44.2
- worker-loader Version: 3.0.3
Expected Behavior
Inline worker should execute in Edge Legacy
Actual Behavior
Inline worker does not execute in Edge Legacy
Code
// webpack.config.js
let HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './index.js',
plugins: [new HtmlWebpackPlugin()]
};
// index.js
import TestWorker from 'worker-loader?inline=no-fallback!./worker';
let worker = new TestWorker();
console.log(worker);
// worker.js
console.log('Log from worker');
How Do We Reproduce?
The code should write "Log from worker" into the console. However, it does not work in Edge Legacy browser (tested on version 18.18363). The worker is created successfully, but its contents are not executed, so nothing gets logged into the console.
I have looked at the worker-loader code and found out that the problem is in URL.revokeObjectURL(objectURL);
line in inline.js
. When I commented out that line, Edge executed the worker contents. Wrapping the call in setTimeout with 1000ms delay worked as well, but that solution seems quite hacky.
This issue is not present in worker-loader 2.0.0
Feel free to send a fix:
if (URL.revokeObjectURL) {
URL.revokeObjectURL(objectURL);
}
Should be easy
No, Edge Legacy actually supports URL.revokeObjectURL, but it does not like when the Blob URL is revoked "too quickly".
inline workers stopped working for me after upgrading to 3.x and changing inline: true
to inline: 'no-fallback'
Investigating network shows a script with contents:
importScripts('http://localhost:4000/[object%20Module]');
@mpk Can you create reproducible test repo?
@Rush It is not you problem, please provide reproducible test repo, I will help
@evilebottnawi Sure, here you go: https://github.com/mpk/worker-loader-edge
@mpk to be honestly I can't reproduce :confused:
I'm having a similar issue with Chrome (87.0.4280.88
) and Edgium (87.0.664.55
) on worker-loader v3.0.6
with webpack v5.10.0
.
It is worth noting that the worker loads fine on Firefox.
Definitely seems like a race condition because if I put a breakpoint at inline.js line 31
and continue after half a second then the worker loads correctly but if I disable the breakpoint then it does not load.
In light of this, the root cause appears to actually be a Chrome bug however I haven't found anything in their bug tracker.
I could reproduce this issue consistently on IE 11. Definitely revoking the object url immediately is issue. If I tried below code its working fine.
import TestWorker from 'worker-loader?inline=no-fallback!./worker';
let tmp = URL.revokeObjectURL;
URL.revokeObjectURL = function() {};
let worker = new TestWorker();
URL.revokeObjectURL = tmp;
console.log(worker);
Can you check revokeObjectURL
is exist?
yes its there
Weird, it should work, no errors? Can you add try/catch
for revokeObjectURL
and check again
yeah, no errors
Looks bug in browser...
I'm also running into this issue with inline workers in IE11. Changing the URL revocation in inline.js
to the following fixes it in my use case:
setTimeout(function() { URL.revokeObjectURL(objectURL) });
Very very very weird, somebody can provide versions and steps to reproduce, I am not against to fix it using setTimeout
, but I want to investigate it
Is there any chance to merge the patch about setTimeout on above or the other plan for this issue?
@elasim Can you provide screenshot/etc of the problem?
In this case, the screenshot is useless. there are no exception or error throws for this. following is the information about reproduced environment.
UA: Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; Tablet PC 2.0; rv:11.0) like Gecko WinVer 20H2.19042.928
test-project
├── @babel/[email protected]
├── @babel/[email protected]
├── @babel/[email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
└── [email protected]
// webpack.config.js
const path = require("path");
module.exports = ({ production }) => {
const webpackConfig = {
// Documentation: https://webpack.js.org/configuration/mode/
mode: production ? "production" : "development",
resolve: {
extensions: [".js", ".jsx", ".json"],
},
module: {
rules: [
{
test: /\-worker\.js$/,
use: {
loader: "worker-loader",
options: {
inline: "no-fallback",
},
},
},
{
test: /\.js$/,
exclude: [/node_modules/],
use: [
{
loader: "babel-loader",
options: {
presets: [
[
"@babel/preset-env",
{
targets: {
browsers: [
"chrome >= 51",
"firefox >= 51",
"ie >= 11",
"safari >= 8",
"ios >= 9",
"android >= 5",
],
},
},
],
],
plugins: [
[
"@babel/plugin-transform-runtime",
{
absoluteRuntime: false,
corejs: 3,
helpers: true,
regenerator: true,
},
],
],
},
},
],
},
{
test: /\.js$/,
enforce: "pre",
use: ["source-map-loader"],
},
],
},
entry: {
test: path.join(__dirname, "lib", "index.js"),
},
output: {
path: path.join(__dirname, "dist"),
filename: "[name].es5.js",
environment: {
arrowFunction: false,
bigIntLiteral: false,
const: true,
destructuring: false,
dynamicImport: false,
forOf: false,
module: false,
},
},
performance: {
maxEntrypointSize: 250000,
maxAssetSize: 250000,
},
devtool: production ? undefined : "source-map",
};
return webpackConfig;
};
hm, code is just not executed? Can you add console.log('BEFORE')
and ``console.log('After')` between https://github.com/webpack-contrib/worker-loader/blob/master/src/runtime/inline.js#L35 in your bundled code?
seems like worker is forked with empty script.
Can you console log https://github.com/webpack-contrib/worker-loader/blob/master/src/runtime/inline.js#L23 content
and blob
and show me it here?
Can you console log https://github.com/webpack-contrib/worker-loader/blob/master/src/runtime/inline.js#L23
content
andblob
and show me it here?
Are you sure L23 is the place what you want to put logpoint? (Blob is supported natively, so that line wasn't executed.) btw, it is the log of content and blob
Chrome
IE11
/******/ (function() { // webpackBootstrap
/******/ "use strict";
/******/ // The require scope
/******/ var __webpack_require__ = {};
/******/
/************************************************************************/
/******/ /* webpack/runtime/define property getters */
/******/ !function() {
/******/ // define getter functions for harmony exports
/******/ __webpack_require__.d = function(exports, definition) {
/******/ for(var key in definition) {
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ }
/******/ }
/******/ };
/******/ }();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ !function() {
/******/ __webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }
/******/ }();
/******/
/******/ /* webpack/runtime/make namespace object */
/******/ !function() {
/******/ // define __esModule on exports
/******/ __webpack_require__.r = function(exports) {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/ }();
/******/
/************************************************************************/
var __webpack_exports__ = {};
/*!*************************************************************************************************************************************************************************************************************************************************************!*\
!*** ../../common/temp/node_modules/.pnpm/[email protected]/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[1].use[0]!../../common/temp/node_modules/.pnpm/[email protected]/node_modules/source-map-loader/dist/cjs.js!./lib/ie-worker.js ***!
\*************************************************************************************************************************************************************************************************************************************************************/
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return __WEBPACK_DEFAULT_EXPORT__; }
/* harmony export */ });
function handleMessage(event) {
self.postMessage(event.data);
}
self.addEventListener("message", handleMessage);
var default_1 =
/** @class */
function () {
function default_1() {}
return default_1;
}();
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (default_1);
/******/ })()
;
I want to look at blob content here https://github.com/webpack-contrib/worker-loader/blob/master/src/runtime/inline.js#L29, maybey BlobBuilder
or getBlob
is broken
It's not. BlobBuilder won't used. https://github.com/webpack-contrib/worker-loader/blob/master/src/runtime/inline.js#L14-L25 is never reached because globalScope.Blob is available.
and Blob data is not broken either as you can see.
Can you show blob
value here https://github.com/webpack-contrib/worker-loader/blob/master/src/runtime/inline.js#L29, here two places for bug
- blob generation is broken
-
URL.createObjectURL
is broken with blob -
URL.revokeObjectURL
is broken without any reports
Also do you have CORS or other security headers?
I've already attached. see the last line of logs.
- blob generation is broken: No. It's working If I commented out revokeObjectURL or give some delay using setTimeout.
- CORS or Security Header: No. this script served via webpack-dev-server. there are no such a security header.
- URL.createObjectURL is broken with blob: No. As you can see the last image, We can read blob data via xhr and there are no error.
- URL.revokeObjectURL is broken without any reports: Maybe. but no way to figure out.
What about setImmediate
? Can you try? Maybe we can check setImmediate
is defined and use logic, so for good browser we will keep original logic
https://github.com/webpack-contrib/worker-loader/blob/master/src/runtime/inline.js#L35
~~Replacing that line with globalScope.setImmediate(URL.revokeObjectURL, objectURL);
works.~~
~~oops, no. Above approach throws an error on safari. I'll try another way.~~
It works now.
if (globalScope.setImmediate) {
globalScope.setImmediate(URL.revokeObjectURL, objectURL);
} else {
globalScope.setTimeout(0, URL.revokeObjectURL, objectURL);
}
Ideally we need if (globalScope.setImmediate) { globalScope.setImmediate(() => { URL.revokeObjectURL(objectURL) }); } else { URL.revokeObjectURL(objectURL); }