skip to Main Content

I have a TS based / ViteJS project that build a small library.

I’d like to expose one of my object to the global window (or equivalent), to be used outside of my modules, after the library has been builded.

Here is a simplified exemple, I want to use my Test() function directly in my HTML page :

index.html (root of my project)

<!DOCTYPE html>
<html>
  <head>
  </head>
  <body>
    <script type="module" src="/src/main.ts"></script>
    <script>

      console.log("Hello vite...");
      Test();

    </script>

  </body>
</html>

src/main.ts

console.log("Hello from main.ts");

function Test(){
  console.log("Hello TEST !");
}

window.Test = Test;

the builded dist/index.html (no error during the build)

<!DOCTYPE html>
<html lang="en">
  <head>
    <script type="module" crossorigin src="/assets/index-3ba57d45.js"></script>
  </head>
  <body>
    
    <script>

      console.log("Hello vite...");
      Test();

    </script>

  </body>
</html>

When I run the dist/index.html in the browser (from a local server), "Test" is not defined

Hello vite...
ERROR: Uncaught ReferenceError: Test is not defined
Hello from main.ts

How can I use my Test() on my index.html scripts ?

Thanks!

2

Answers


  1. Chosen as BEST ANSWER

    Thanks to @dandavis to pointing it : The modules scripts <script type="module" ...> are loaded asynchronously.

    There is no issue on the window.Test = ... side (even if globalThis seems more modern)

    So the simplest answer to that is to wait for the DOMContentLoaded event before using the global Test() method :

    <script>
          
       console.log("Hello vite ...");
    
       document.addEventListener("DOMContentLoaded", function(){
          Test();
       })
    
    </script>
    

    Now the bonus question is How to NOT generate a script "module" with ViteJS?


  2. As with doing this inside function scope, you can create a global in module scope by assigning to a property on globalThis (or window in older environments):

    function Test() {
        // ...
    }
    globalThis.Test = Test;
    

    Properties on that object are global variables.

    But, your example still won’t work because the module code isn’t executed until the HTML has been fully parsed. You could use it in an event handler (see below), but not inline as shown in the question, because you’re trying to use it before it’s been created.

    Example (using function scope, but it works the same in module scope):

    function main() {
        function Test() {
            console.log("Hi there");
        }
        globalThis.Test = Test;
    }
    main();
    <!-- I don't recommend using `onclick` attributes (use modern event handling instead), but this is to demonstrate it's a global -->
    <input type="button" onclick="Test()" value="Click Me">
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search