plone / mockup

A collection of client side patterns for faster and easier web development
http://plone.github.io/mockup/
BSD 3-Clause "New" or "Revised" License
47 stars 93 forks source link

bootstrap is no longer available globally with latest mockup release #1175

Closed maethu closed 2 years ago

maethu commented 2 years ago

With the release 5.0.0-alpha.0 (before webpack module federation) there was a bootstrap object globally available.

With this I was for example able to control Modal instances via script

const customModal = new window.bootstrap.Modal(...)

This is no longer possible. I'm not sure why, For example jQuery ist still there (via https://github.com/plone/mockup/blob/master/src/index-jquery.js)

@thet You may have an idea?

maethu commented 2 years ago

Followup

I have now a webpack config with module federation:

const path = require("path");
const { VueLoaderPlugin } = require("vue-loader");

const package_json = require("./package.json");
const mf_config = require("@patternslib/patternslib/webpack/webpack.mf");

module.exports = (env) => {
  let config = {
    entry: {
      "mylib.min": path.resolve(
        __dirname,
        "./path/to/js/js/src/main.js"
      ),
    },
    ...
    plugins: [new VueLoaderPlugin()],
    ...
    },
  };

  config.plugins.push(
    mf_config({
      filename: "mylib-remote.min.js",
      package_json: package_json,
      remote_entry: config.entry["mylib.min"],
    })
  );

  return config;
};

So far so good.

Problem window.bootstrap is still not available -> It is loaded though, since bootstrap registered it's plugins as JQuery plugins as well. Which is accessible as window.JQuery.fn.modal.

If I do import { Modal } from "bootstrap"; in my code, which actually works kinda, but I have weird side effects. Seems like bootstrap gets initialised multiple times. The workaround via the JQuery plugin seems to work fine though.

Everything else seems to work as expected!! Thanks so much to put in the work to introduce module federation!

petschki commented 2 years ago

stumbled upon this too today ... @thet tried to fix it here, but still not working for me: #1177

maethu commented 2 years ago

@petschki @thet

I think something is really odd with bootstrap 5.2, or there might be integration issues with webpacks module federeation.

If I do await import("bootstrap") or import "bootstrap" anywhere in my code. DropDowns for example do no longer work.

The mentioned workaround via jQuery does not always work, since it does depend on load order.

maethu commented 2 years ago

Example: This shows all events registered on a click event for a dropdown button

Screenshot 2022-07-05 at 21 21 55

If I import a Plugin for bootstrap, for example import { Collapse } from "bootstrap";, alle events are then twice registered.

Screenshot 2022-07-05 at 21 22 09

Which does lead to side effects.

Any idea how I can mitigate this? Th solution from https://github.com/plone/mockup/pull/1177 most likely will work.

petschki commented 2 years ago

I do not know how to solve this yet but it seems to me that registering modules globally and MF configured modules are conceptually a bit against each other.

The MF configuration of @patternslib/dev (the new base package of mf_config ... see https://github.com/plone/mockup/blob/upgrade-dev/webpack.config.js#L6) registers the remote bundles to a special prefixed global namespace (https://github.com/Patternslib/dev/blob/main/webpack/webpack.mf.js#L42) and initialized these when the DOM is loaded (https://github.com/Patternslib/Patterns/blob/master/webpack/module_federation.js#L34) ... so far so good since we have jQuery and bootstrap as separate remote bundles.

But that means if you have your own "non-MF" configured addon-bundle loaded after the plone bundle and you want to use window.$ or window.bootstrap it does not exists (or may not exist).

So I think we should offer 2 possible "usages" for addon developers:

  1. Simple usage -> Use globally registered modules: This should be very straight forward and easy to use, for example if you have a simple <script> in your template and you want to use $ or bootstrap it should simply work (many addons depend on constructs like (function($) { ... })(jQuery) in their JS ... for eg the bda.plone.shop bundle).

  2. Advanced usage -> Configure your addon bundle with Module Federation and use all its benefits. Here you should be able to use for eg. import "bootstrap" and it shouldn't get initialized twice on the page.

Now the big question is, can both usages coexist without too much downgrades (page load etc.)?

Another question: if bootstrap is registered globally, how does module federation know about it and use it?

@thet we really should fix that soon and write some docs about it.

maethu commented 2 years ago

I do not know how to solve this yet but it seems to me that registering modules globally and MF configured modules are conceptually a bit against each other.

I totally agree.

I like the MF approach a lot. It also mostly works fine, for example with jQuery. I can do import $ from "jQuery" and it loads the module correctly. The webpack config seems to be quite easy as well, I just followed the steps documented and it did work right away.

thet commented 2 years ago

Fixed here: https://github.com/plone/mockup/pull/1185