Search code examples
javascriptnode-modulesimporterror

Import local module inside of script from external html


I've got frontend and backend. From backend I get prerendered html (Symfony form) which includes script with source tag. Origin is localhost:8001.

<html>
    <head>
        ...
    </head>
    <body>
        ...
        <div class="container">
            {% block javascripts %}
                <script type="module" src="http://localhost:8020/build/form_generator/script.js"></script>
            {% endblock %}
        </div>
    </body>
</html>

In frontend (localhost:8020) script.js is located in Public folder. The script loads fine, but inside script I want to load another module from frontend (Select2, which is installed to node_modules) but I am not able to load it correctly. Select2 is imported correctly within other scripts in frontend. script.js:

/** @module script*/

  import 'select2'; // gives log error 1
  import select2 from "../../../node_modules/select2/dist/js/select2"; // gives log error 2

log error 1: Uncaught TypeError: Failed to resolve module specifier "select2". Relative references must start with either "/", "./", or "../".

log error 2: GET http://localhost:8020/node_modules/select2/dist/js/select2 net::ERR_ABORTED 404 (Not Found)


Solution

  • Modules loaded by the browser cannot use Node.JS module resolution rules.

    They do not have access to the file system. They cannot search a node_modules directory.

    You need to:

    1. Ensure the module you want to use does not depend on APIs that are available in Node.js but not in browsers
    2. Ensure the module you want to load has a URL (how you do this depends on your HTTP server)
    3. Import that URL

    e.g.

    import select2 from '/static/js/select2.js';
    

    An alternative to steps 2 and 3 is to use a bundler (such as Webpack or Parcel) which can do Node.js module resolution to bundle all the modules up into a single JS file that you can load as a regular script.