'How to share functions and variables between one Javascript file that IS a module, and another Javascript file that is NOT a module

I have a project built using Javascript, jQuery, and Vite.js. I need to share functions and variables between one JS file that is a module, and another JS file that is not a module. I'm specifically talking about whether the script tag has type="module" or not. Is this possible? I understand that if I could just set both script file types to "module", this would solve my problem and I could easily just use import/export syntax to share functions and variables. However, the 2nd script cannot be set to type="module", as that would break snippets of code using certain dependencies.

Just to illustrate what I'm saying -- here's an HTML file linked to two different JS files:

test.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>

    <script type="module" src="./script1"></script>
    <script src="./script2"></script>
  </head>
  <body></body>
</html>

Now, script1.js has a variable we want to access from script2.js:

script1.JS

const testVariable = "hello test variable";

script2.js

console.log(testVariable) //returns undefined

Obviously I can't use import/export or require since the 2nd script is not a module. Is there any way around this? I know that normally script files can access functions from script tags placed above them, but this doesn't seem to hold true for two different script types.

I thought maybe I could use jQuery $.getScript per this S/O post, but as far as I can tell, that executes the requested script, but doesn't allow me to dynamically access specific variables and/or functions in the requested script?



Solution 1:[1]

Script modules do not implicitly create global variables. Variable, or named class or function names declared in a module are held in a closure created for module content, making them inaccessible by direct means from outside the module.

Global Variable Usage

If the only issue is not being able to access variables exported by a module script, consider creating the variables as properties of the global window object in the module file instead of using variable declarations.

This would change module declarations like

let brandName = "fooware";

to

window.brandName = "fooware";

This would then allow code in any script to access brandName as a variable.

Setters and Getters

If a script module is to remain unchanged, you could set up an intermediate module to import exported items and republish them as setters and getters of a global object property name, using Object.defineProperty* E.G.

 <script type="module">
    import {brandName} from "./script1.js";
    Object.defineProperty(window, "brandName", {
       get() { return brandName; },
       set(newValue) { brandName = newValue; },
       enumerable: true
    });
 </script>

Note this kind of module (which doens't export any values) can be included inline in HTML using <script> tags without a src attribute.

*Object.defineProperties can be used to define multiple accessor properties at a time using slightly different syntax.

Deferring the non-modular script

Module scripts are deferred automatically without requiring the browser to load and parse then synchronously. Try adding a defer attribute to the non-modular script so it is executed in the same order as module script tags provided in page source. When deferred, the script will not be parsed before body HTML has been parsed.

Summary

JavaScript Modules are not designed to interact with non module script files. Refactoring non modular scripts into modules is generally preferred over more intrusive solutions.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1