I'm seeing the following error message when using Popper 1.9.8:
Uncaught TypeError: Popper is not a constructor
I'm trying to import Popper as a module using Webpack (Laravel Mix) and tried several combinations:
import Popper from 'popper.js';
require('popper.js/dist/popper.js' );
require('popper.js/dist/esm/popper.js' );
require('popper.js/dist/umd/popper.js' );
window.Popper = require('popper.js/dist/esm/popper.js' );
How can I import Popper, it doesn't matter if I use import * from or require().
Please provide a repository I can clone & run to reproduce your problem.
Sure thing!
git clone [email protected]:tillkruss/popper-debug.git
npm install
npm run dev
Open up index.html in Chrome, or similar.
You have to manually assign Popper to window.Popper since Bootstrap isn't importing the dependency but just checking for its existence in window
window.jQuery = window.$ = require('jquery');
import Popper from 'popper.js';
window.Popper = Popper;
require('bootstrap/js/src/dropdown');
Thanks!
@FezVrasta
Hi there, I'm running into the same issue as OP (so therefor I'm not going to open a duplicate), but in my case I'm using expose-loader together with webpack. expose-loader should expose a dependency on the global context and it works fine with e.g. jquery (and also worked before with Tether when that one was used in Bootstrap), but not with popper.js:
require("expose-loader?Popper!popper.js");
Popper is correctly assigned to Popper on window, Bootstrap however still complains:
Uncaught TypeError: Popper is not a constructor
Any ideas?
I never used expose-loader, try to put a console.log(window.Popper); before Bootstrap to see what's inside.
@FezVrasta Thanks for your time.
console.log(window.Popper) yields the following:

Make sure your module system is properly resolving default.
I ended up doing the following
(<any>window).Popper = require('popper.js').default;
...and things started suddenly working. It's ugly, but at least it works. Popper.js is now available both for Popper and window.Popper and window.Popper returns the .ctor instead of an object.
As far as I understand, the reason seems to be how Popper.js is being exported:
export default class Popper {}
In this case, default is treated as a _named export_. When I invoke require('expose-loader?Popper!popper.js'), I get just the class (which ends up in window.Popper due to expose-loader) and not the default export, which is just a property. So I have to manually assign it to window.
This effect could be changed by writing:
module.exports = class Popper {}
I'm pretty much a beginner in JS, the various module systems and what not, so please correct me if I'm wrong on this assumption so I don't confuse others. :)
export default is the standard way to export stuff with ES Modules.
If you use CommonJS you can use the /dist/umd/popper.js build.
I have the same issue as @tillkruss, and I'm using Laravel Mix as well.
I have tried every combination of import or require, set window.Popper to Popper or Popper.default, and so on. I also added autoloading options to Laravel Mix config file:
mix.autoload({
jquery: ['jQuery'], // Bootstrap
'popper.js': ['Popper'] // Bootstrap
});
However, the only way I got this working was by manually editing Bootstrap's dropdown.js to use new Popper.default(...) instead of just new Popper(...).
Anybody knows its ways around this? What am I doing wrong?
I haven't experience with Laravel, but it looks like it's importing the ESM bundle as if it was a CJS one, and then it's exposing the library as .default.
I noticed the same with webpack 2-3 in some circumstances. Any chance Laravel is using webpack under the hood?
Laravel Mix — which is often used with Laravel but is out of the framework package, and can be used without Laravel too — does indeed use webpack under the hood.
May you try to manually edit the package.json of Popper.js and replace the module entry with esnext?
This?
"module": "dist/esm/popper.js",
What should it look like?
"esnext": "dist/esm/popper.js",
Oh, you meant the key!
It does indeed work, but only if I manually do:
import Popper from 'popper.js';
window.Popper = Popper;
It would be enough for my usage case, but using Laravel Mix's autoload does not register neither Popper as as window.Popper or window.Popper.default anymore.
If you want Popper.js to register as global object you should import the umd bundle (import 'popper.js/dist/umd/popper.js').
In your case webpack is importing the ES Module which will never register itself as global object.
The esnext thing is something I don't understand, I already opened a bug report on the webpack repo.
https://github.com/webpack/webpack/issues/5405
I got into an event stranger situation:
My main file (stripped down):
import Popper from 'popper.js/dist/umd/popper.js';
window.Popper = Popper;
import 'bootstrap/js/src/util';
import 'bootstrap/js/src/dropdown';
This leads to an error: Uncaught Error: Bootstrap dropdown require Popper.js.
Adding the umd bundle as an alias in Mix's autoload makes it work:
mix.autoload({
jquery: ['jQuery'],
'popper.js/dist/umd/popper.js': ['Popper']
});
Now, I'm actually happy that it works, but I don't fully understand why it wont if I do not add it to webpack aliases (via mix.autoload). I'm not asking you to answer my question, I'm just leaving this here for the records.
Just to add to this discussion, I got popper.js working with bootstrap (latest version, bootstrap 4 beta) in my laravel 5.4 application by changing Laravel's bootstrap.js file (located in path/to/app/resources/assets/js/) as follows:
try {
window.$ = window.jQuery = require('jquery');
window.Popper = require('popper.js').default; //for popper
require('bootstrap'); //for bootstrap v4 instead of bootstrap-sass package
} catch (e) {}
This ensures popper is loaded before bootstrap, and seems to work fine. If I encounter any difficulties or gotchas with this approach I'll report back.
This works for me in my Laravel 5.4
bootstrap.js file
try {
window.$ = window.jQuery = require('jquery');
window.Popper = require('popper.js').default;
require('bootstrap');
} catch (e) {}
webpack.mix.js file
mix.autoload({
jquery: ['$', 'jQuery', 'window.jQuery'],
'popper.js': ['Popper', 'window.Popper'],
});
why is the .default needed?
Here is what fixed it for me:
mix.webpackConfig({
resolve: {
alias: {
jquery: "jquery/src/jquery",
'popper.js' : "popper.js/dist/umd/popper.js"
}
}
});
Now you can do autoload with no problems:
mix.autoload({
'jquery': ['$', 'jQuery', 'window.jQuery'],
'popper.js': ['Popper', 'window.Popper']
});
Yes, this could be done as one but I just like to separate it. Hope this helps someone
Webpack: 3.5.6
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
Popper: 'popper.js/dist/umd/popper.js'
})
This works for me.
@f3l1x with webpack 3 you should be able to use the esm build, may you verify?
new webpack.ProvidePlugin({
jQuery: 'jquery',
Popper: ['popper.js', 'default'],
}),
I am on webpack 3.5.6 as well and had to use @f3l1x 's solution. Referencing the UMD build was the only way to get Popper as a global variable that bootstrap would recognize.
Does this config makes the lib available as window.Popper?
If so, then it's okay to refer to the UMD build.
If you still have to do import Popper ... ; window.Popper = Popper then something is wrong
@FezVrasta correct. I was trying to avoid the globals which is why I ended up using @lukas-pierce 's solution. Seems that the esm build needs default called in order to find its proper place in the dependency tree for bootstrap.
This should change in the next Bootstrap release, fortunately 🙂
I'm not so sure....I'm on v4.0.0-beta :(
I said, next release, after the first beta. They have rewritten the way they manage the dependencies.
Here's what worked for me using Laravel Mix
import 'jquery';
import Popper from 'popper.js'; //instead of import Popper from 'popper.js/dist/umd/popper.js'; for a small file size
window.Popper = Popper;
import 'bootstrap';
and in my webpack.mix.js file i auto them like so
.autoload({
'jquery': ['$', 'window.$', 'jQuery', 'window.jQuery'], //extract into the global variable space
'popper.js': ['Popper', 'window.Popper']
})
Most helpful comment
I got into an event stranger situation:
My main file (stripped down):
This leads to an error:
Uncaught Error: Bootstrap dropdown require Popper.js.Adding the umd bundle as an alias in Mix's autoload makes it work:
Now, I'm actually happy that it works, but I don't fully understand why it wont if I do not add it to webpack aliases (via
mix.autoload). I'm not asking you to answer my question, I'm just leaving this here for the records.