*** NEW VERSION *** It was difficult to track down the problem. Now I have a better idea:
direct imports cannot reflects variables which are set after DOMContentLoaded
, and I don't know how to tackle this, excepting by adding data to the web workers, and not through imports.
Even window
, known by the main.js module, becomes unreachable by next occurrences of the web worker (which fetches different vector layers) :
Error: ReferenceError: window is not defined
for instance, I was using window.document.baseURI
and I must provide the full URL now.
Also I have a web worker that has two steps, the second step using user provided data (a hit point on the map). Therefore module import
cannot import functions created by closures: closures must be initialized again.
Any idea ?
*** Initial VERSION text of the question (- typo) ***
Presently main.js uses a startTiming() from global.js, and webworker.js also uses startTiming() via importScripts('./global.js'). Some other parts of code are in separate script files (eg. mapmaker.js). Presently, everything is working, but this is not "modular" and a bit ugly.
<body>
<script src="src/mapmaker.js"></script>
<script src="src/global.js"></script>
<script src="src/main.js"></script>
</body>
With main.js
async function(){
const timlog = startTiming();
const timing = (mess) => "MAIN" + timlog(mess);
// ...
}
global.js (simple script, not a module)
function startTiming(){ /* ... performance.now initial */ }
webworker.js called with new Worker("webworker.js")
importScripts('./global.js')
const timlog = startTiming();
I am trying to translates everything the import-export way: but I fail.
New main.js
import {f} from './global.js'
//instead of nothing
async function(){
//...
const context = f();
// but `export {context};` is not possible
}
New global.js (script with type=module)
export const NAME = "name";
export function f(){ /* ... */ }
New webworker.js called with new Worker("webworker.js", {type:'module'})
import {f} from './global.js'
//instead of importScripts('./global.js')
const samecontext = f();
// but `samecontext` can't be the same as `context`
I got an error (HTML failure) what is not very explicit.
These modifications are probably not enough.
I was suspecting that async
must be top level, and not in a module.
It is not necessarily difficult to code a module that exports functions and constants to both the main thread and web workers, BUT here is a summary of the indirect difficulties that can arise during this process, and a few solutions.
As soon as a script must add an import
or export
instruction, it must be translated as a module. And the quick conclusion is that, directly or transitively, all scripts must either export and/or import something. Because they all contribute to the web page in one way or another.
window
dependent code.The module which launches the main thread (here named main.js
) necessarily has a DOM interface, and it is better to avoid web workers importing directly from it (avoids ReferenceError: window is not defined
). You would better add intermediate modules (named tierWW1.js
, tierWW2
...) from which each WWi
would import, and in which there is no DOM dependency. And to isolate window
dependent code, or document
.
// main.js
import { morefunction } from "moremodule.js";
export { initiatedInMain };
const initiatedInMain = somevalue;
... (window independent section)...
if(typeof window !== undefined) {...(window dependent)... }
// tierWW1.js : lone intermediate with WW1
import { initiatedInMain, otherfunction } from "main.js";
export { initiatedInMain, specifTierWW };
function specificTierWW(){...}
// web worker WW1: ww1.js
import { initiatedInMain, specifTierWW } from "tierWW1.js";
self.onmessage = function(event){ ... }
If for lazy convenience you have embedded a function in an HTML element, for example
.sometag. onmouseover='return popover();'> marksign </.sometag.
then you should have this function in the module that knows about the window
environment (or import it there first), and force it to be at the top "window" by the instruction:
import {popover} from "othermod.js";
window.popover = popover;
Or, don't be lazy, remove the inline script, and replace it by coding addEventListener()
on the element that you need to recover first by proper identification.
async
function call.Only the state of the variable (object
, or function
closure reflecting a context) obtained before external updates is exported. Hence a two-steps web-worker has only access to the initial context. You must find a workaround to signify the changes, in particular modifying the way to communicate them.
Here are some of the hurdles I met when starting, last week, to post my initial question. Probably not exhaustive.
It turns out that if you have a website using javascript code divided into a large number of scripts and if you plan to translate them into modules, be prepared for a "hot" period before you start the process. The reward? the pride of having succeeded.
And finally it works!