Plone 6. Overriding @plone/mockup upload pattern, practical example

Thank you for sharing your experience!

Unfortunately there is not very much documentation for @plone/mockup left in Plone 6 docs (but there's an upcoming PR Integrate Mockup's documentation by thet · Pull Request #1548 · plone/documentation · GitHub ) ... I know that this topic was covered in the Plone 5 trainings and I've found these parts here https://github.com/plone/training/blob/2022/docs/javascript/exercises/8.md ... I gave this a try in my latest Plone 6 integration package and this was my experience:

  1. My integration package was created with plonecli
  2. There's a template called mockup_pattern which I ran like this:
$ cd src/<my_integration_package>
$ plonecli add mockup_pattern
...
--> Pattern name: upload

this creates all the webpack/MF config related files for you and generates basically what you have outlined above. (You can find the templates here https://github.com/plone/bobtemplates.plone/tree/main/bobtemplates/plone/mockup_pattern)

webpack.config.js

process.traceDeprecation = true;
const mf_config = require("@patternslib/dev/webpack/webpack.mf");
const package_json = require("./package.json");
const package_json_mockup = require("@plone/mockup/package.json");
const package_json_patternslib = require("@patternslib/patternslib/package.json");
const path = require("path");
const webpack_config = require("@patternslib/dev/webpack/webpack.config").config;

module.exports = () => {
    let config = {
        entry: {
            "<integration-package>.min": path.resolve(__dirname, "resources/index.js"),
        },
    };

    config = webpack_config({
        config: config,
        package_json: package_json,
    });
    config.output.path = path.resolve(__dirname, "src/<integration-package-path>/browser/static/bundles");

    config.plugins.push(
        mf_config({
            name: "<integration-package>",
            filename: "<integration-package>-remote.min.js",
            remote_entry: config.entry["<integration-package>.min"],
            dependencies: {
                ...package_json_patternslib.dependencies,
                ...package_json_mockup.dependencies,
                ...package_json.dependencies,
            },
        })
    );

    if (process.env.NODE_ENV === "development") {
        config.devServer.port = "8011";
        config.devServer.static.directory = path.resolve(__dirname, "./resources/");
    }

    // console.log(JSON.stringify(config, null, 4));

    return config;
};

NOTE: for the MF entry name you can choos what you want as long as its unique.

resources/index.js

// Webpack entry point for module federation.
// This import needs to be kept with brackets.
import("./bundle");

resources/bundle.js

import registry from "@patternslib/patternslib/src/core/registry";

import "./pat-upload/upload";

registry.init();

And our pat-upload pattern code with the overriding of the existing patternn

resources/pat-upload/upload.js

import $ from "jquery";
import registry from "@patternslib/patternslib/src/core/registry";
import Upload from "@plone/mockup/src/pat/upload/upload";

// delete default registered pattern:
delete registry.patterns.upload;
delete $.fn.patUpload;

class Pattern extends Upload {
    static name = "upload";
    static trigger = ".pat-upload";
    static parser = "mockup";

    async init() {
        let self = this;
        self.options = {
            ...self.options,
            maxFiles: 1,
            maxFilesize: 10,
        };
        Upload.prototype.init.call(self);
    }
};


// Register Pattern class in the global pattern registry and make it usable there.
registry.register(Pattern);

// Export Pattern as default export.
// You can import it as ``import AnyName from "./energieinstitut";``
export default Pattern;
// Export BasePattern as named export.
// You can import it as ``import { Pattern } from "./energieinstitut";``
export { Pattern };

As you can see that we are deleting the "default" registered pattern from the registry before re-registering our pattern code.
Make sure you override the options before calling Upload.prototype.init.call().

Maybe this helps to simplify your code above.

But there's one caveat: as I've tried this out, it worked with the upload pattern called from markup with class="pat-upload" but it didn't work when the pattern gets directly imported as module, like pat-structure does (aka folder_contents) ... maybe @thet has some more insights on this as he is one of the main Patternslib developer nowadays ...

Extra tip
when working with patterns and mockup I find the debug log on the console sometimes useful. This can be enabled by adding ?loglevel=DEBUG to your browser URL.

3 Likes