1

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?

Mickey Vershbow
  • 215
  • 3
  • 17
  • 1
    Modules export variable bindings which can't be accessed by non-modular scripts. To advance from this, could you indicate in the question (please) if parsing `script2.js` can be deferred until after the module (`script1.js`) has loaded (i.e. parsing body HTML doesn't need `script2`), and if `script2` needs to read or update variables exported by the module which do not remain constant? If it does need access to "live" variable values, are you in a position to modify `script1.js` (the module script) or should it stay the same? – traktor May 14 '22 at 03:23
  • Thanks for your response. Yes let me be more specific about what is happening here. In `script1.js`, we have several buttons that the user can click on; each button is the name of a brand such as "nike" or "adidas", etc. Once the user clicks on a brand, we store the brand name in a global variable `globalBrand`. Several other functions then use that `globalBrand` variable to pass to API calls, which request more data about the selected brand. `script2.js` contains one of those functions that makes an API call, using the brand name, and then displays the data in a chart. – Mickey Vershbow May 14 '22 at 03:51
  • The only reason that the code contained in `script2.js` isn't simply written in `script1.js` to simplify things, is that the code in `script2.js` doesn't work in a module. – Mickey Vershbow May 14 '22 at 03:51
  • Here is a working example of the `script2.js` file. It is currently using mock data to build the D3 data visualization. I need to figure out how to grab the current value of the `globalBrand` variable from `script1.js` and pass it to this D3 function in `script2.js` so that it can make an API call and build the visualization with the actual returned data. https://codepen.io/Mickey_Vershbow/pen/ExQNWMq – Mickey Vershbow May 14 '22 at 03:54

1 Answers1

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.

traktor
  • 17,588
  • 4
  • 32
  • 53