worker-loader icon indicating copy to clipboard operation
worker-loader copied to clipboard

Inline workers does not work in Edge Legacy anymore

Open mpk opened this issue 4 years ago • 54 comments

  • 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

mpk avatar Sep 29 '20 17:09 mpk

Feel free to send a fix:

if (URL.revokeObjectURL) {
  URL.revokeObjectURL(objectURL);
}

Should be easy

alexander-akait avatar Sep 29 '20 17:09 alexander-akait

No, Edge Legacy actually supports URL.revokeObjectURL, but it does not like when the Blob URL is revoked "too quickly".

mpk avatar Sep 29 '20 17:09 mpk

inline workers stopped working for me after upgrading to 3.x and changing inline: true to inline: 'no-fallback'

image

Investigating network shows a script with contents:

importScripts('http://localhost:4000/[object%20Module]');

Rush avatar Oct 02 '20 01:10 Rush

@mpk Can you create reproducible test repo?

alexander-akait avatar Oct 02 '20 10:10 alexander-akait

@Rush It is not you problem, please provide reproducible test repo, I will help

alexander-akait avatar Oct 02 '20 10:10 alexander-akait

@evilebottnawi Sure, here you go: https://github.com/mpk/worker-loader-edge

mpk avatar Oct 02 '20 14:10 mpk

@mpk to be honestly I can't reproduce :confused:

alexander-akait avatar Dec 02 '20 12:12 alexander-akait

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.

KallynGowdy avatar Dec 07 '20 20:12 KallynGowdy

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);

Shravan-Joopally avatar Mar 11 '21 17:03 Shravan-Joopally

Can you check revokeObjectURL is exist?

alexander-akait avatar Mar 11 '21 17:03 alexander-akait

yes its there

Shravan-Joopally avatar Mar 11 '21 17:03 Shravan-Joopally

Weird, it should work, no errors? Can you add try/catch for revokeObjectURL and check again

alexander-akait avatar Mar 11 '21 17:03 alexander-akait

yeah, no errors

Shravan-Joopally avatar Mar 11 '21 17:03 Shravan-Joopally

Looks bug in browser...

alexander-akait avatar Mar 11 '21 17:03 alexander-akait

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) });

lawrence-witt avatar Mar 11 '21 23:03 lawrence-witt

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

alexander-akait avatar Mar 12 '21 12:03 alexander-akait

Is there any chance to merge the patch about setTimeout on above or the other plan for this issue?

elasim avatar May 10 '21 00:05 elasim

@elasim Can you provide screenshot/etc of the problem?

alexander-akait avatar May 10 '21 13:05 alexander-akait

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;
};

elasim avatar May 10 '21 14:05 elasim

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?

alexander-akait avatar May 10 '21 14:05 alexander-akait

seems like worker is forked with empty script.

image image image

elasim avatar May 10 '21 14:05 elasim

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?

alexander-akait avatar May 10 '21 14:05 alexander-akait

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?

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 image

IE11 image

/******/ (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);
/******/ })()
;

elasim avatar May 10 '21 15:05 elasim

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

alexander-akait avatar May 10 '21 16:05 alexander-akait

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.

image

and Blob data is not broken either as you can see.

image

elasim avatar May 10 '21 17:05 elasim

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?

alexander-akait avatar May 10 '21 17:05 alexander-akait

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.

elasim avatar May 11 '21 03:05 elasim

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

alexander-akait avatar May 11 '21 13:05 alexander-akait

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);
}

elasim avatar May 11 '21 14:05 elasim

Ideally we need if (globalScope.setImmediate) { globalScope.setImmediate(() => { URL.revokeObjectURL(objectURL) }); } else { URL.revokeObjectURL(objectURL); }

alexander-akait avatar May 11 '21 14:05 alexander-akait