Unable to import class from a npm package

Hi,
I want to import the library erobertson42/bootstrap-modbox in my app, which in turn depends on package bootstrap. My package.json:

"bootstrap": "^5.1.3",
"bootstrap-modbox": "^1.4.0"

Imports on client:

import bootstrap from "bootstrap";
import modbox from 'bootstrap-modbox';

And when the page loads on the client I get the exception on the second import line:

Uncaught ReferenceError: bootstrap is not defined
at Function.<static_initializer> (modules.js?hash=:16696:92)
at module (modules.js?hash=:16677:52)
at fileEvaluate (modules-runtime-hot.js?hash=:388:7)
at Module.require (modules-runtime-hot.js?hash=:270:27)
at Module.moduleLink [as link] (modules.js?hash=:331:22)
at hello.js:28:1

Which points to the line with the spread operator (…bootstrap.Modal.Default,) in static private property of the default export class:

export default class modbox {
	static version = '1.4.0';
	/* private members */
	#options;

	static #defaultOptions = {
		// bootstrap modal default options
		...bootstrap.Modal.Default, //THIS IS THROWING THE EXCEPTION
		// modbox default options
		icon: null,
		style: 'white',

All this on the latest Meteor version 2.6.1. Latest Edge Chromium. Bootstrap package alone works fine and bootstrap object is accessible from within the code, i.e. I can do console.log(bootstrap.Modal); works as expected.

So I’m just wondering how is this possible, that bootstrap is Undefined, when it is imported just before this class? Or anything wrong with the imports? I run out of ideas and stacktrace doesn’t seem to help.

Thanks for your help! Milos

Try

import 'bootstrap'

Hmm, no difference with import 'bootstrap' :frowning:

Looking at the code for bootstrap-modbox, it doesn’t import or require bootstrap in any way and just expects it to be globally defined (source, and built version)

To be clear, this is bad module design by bootstrap-modbox

But that does give us the information required to get it working! We just need to set bootstrap as a global before loading modbox

Make a new file globalize-bootstrap.js

import bootstrap from "bootstrap";
globalThis.bootstrap = bootstrap;
export bootstrap;

then import globalize-bootstrap.js before importing bootstrap-modbox

import bootstrap from "/utils/globalize-bootstrap";
import modbox from 'bootstrap-modbox';

Note: the reason we put setting a global var in another file instead of between the two import lines is because import statements are hoisted to the top of the file, so the global var will be set after modbox is imported. By putting it in the other file, that import runs to completion before the modbox import starts

5 Likes

Thanks to @coagmano it is now working. The solution is as follows.

  1. The globalize-bootstrap.js:
import * as bootstrap from "bootstrap";
globalThis.bootstrap = bootstrap;
export default bootstrap;
  1. and my .js imports it:
import bootstrap from "../lib/globalize_bootstrap";
import modbox from 'bootstrap-modbox/dist/bootstrap-modbox.esm';

Tricky indeed, but learned a lot about hoisting.

1 Like

Amazing that the hoisting docs you linked don’t even mention ESModule imports!!!
That’s the part that was relevant here

Not even the docs on the import statement mention that they get hoisted to the top :exploding_head: import - JavaScript | MDN

And I’m still wondering what shall the ideal solution be? Can we hint the author of the package?

Regarding the MDN doc: hoisting is only in Glossary, whereas import is in the Reference part. I’m going to update the part via pull-request. At least my days&nights spent on the issue are of some use for others.