Random Observations About the Plugin Builder

Yeah, yeah, so I wasn’t super active in the Bubbleverse for a while, and all this may have been announced or is generally known to plugin devs, but I wanted to share a few recent observations about the plugin builder, some of which I think might not have been announced (I’ve actually done A LOT of plugin dev this year, but nothing publicly released until Floppy:

  1. The lib that Bubble uses to minify plugin code still seems to be Google’s Closure Compiler, and either Closure still sucks or the version Bubble leverages doesn’t support ES6, but there’s been a change: If Closure fails, Bubble SILENTLY goes to do-not-minify mode and your plugin will automatically NOT minify. Just know this. (You no longer have to set manually set do_not_minify_plugin, but just because your plugin runs in production mode does not mean the code is minified!)

  2. Since I’ve been writing async/await code and like to use things like ?? (nullish coalescing operator) Closure always fails, and I’ve been using a VS Code extension (edit: it’s this one, which is an implementation of Terser) to minify my main plugin code for production. (I write all of my code as an essentially self-executing function in initialize.js, which you should, too.) And this plugin lets you just select code to be minified and minify it by hitting F1. (This is useful because of Bubble’s ABJECTLY STUPID use of non-compliant JS to indicate the start of all functions. What a bunch of sadistic turds y’all are. Seriously, you Bubble effs: Get a clue.) Also, this VSCode extension is the only one I’ve found that supports ?? and other completely valid ES6 syntax. (Uglify does not for whatever reason and other Terser-based extensions make similar mistakes.)

  3. The copy/paste plugin element/action right-click option creates a COPY now rather than a CLONE, which is great (used to be that copied actions and such would have identical UIDs which leads to problems. This SEEMS to be fixed.

  4. but you still can’t reorder Actions in an element plugin’s Action list, which is just stupid. Also, Bubble, please just let us copy and paste an Action in an element plugin (clone the effing Action and make a new Action starting with the props from some existing action which took me hours to set up). The setup of new actions is fucking torturous and literally kills the development of new and useful plugins. C’mon people: Do ya want avocados or not?

EDIT:

  1. Bubble gods, please let us save a plugin version without having to “publish” it. (It would be in the “versions” list, but not available to our plugin users. Because of the minification stuff, what I’m doing now in my commercial plugins is saving a snapshot by publishing the plugin with UNMINIFIED code with a note that says, “hey dummy don’t use this” and then properly labeling my “production” pushes. But this is extremely dumb for many reasons. (And no, syncing to GitHub – while essential – is not a substitute for the feature I’m requesting.)

Anyway, hope this is new and helpful to someone.

So, my summary review: The Bubble Plugin Builder interface is still a steaming pile of you-know-what, but slightly less smelly than before. Also, the reduction in smell was not announced publicly, AFAICT. :wink:

These snarky comments aside, if you’re serious about using Bubble, you should really learn at least a bit of JavaScript and learn the basics of Bubble plugin development as this will expand your palette of capabilities exponentially. You won’t make any money from it so don’t try, but hey you can still buy my plugins here or if the given plugin is “free” (Karma-Ware) you can make a contribution here.

8 Likes

I love your musings. As a budding JS student, what do you mean by this?

Have you never noticed that:

function(instance, context) {
}

isn’t valid JavaScript? (There should be a space between function and the opening paren.) This kluge is how Bubble detects your code block. It’s literally sadistic.

1 Like

Just tell us to write a code block. There’s no function there. And yet, if we don’t include this phony “code”, Bubble won’t evaluate your actual code (which it does using eval()… groan). And, because it’s not valid code, no minifier will parse it. So you gotta select anything EXCEPT that and minify THAT.

Ahh… that’s why anytime I try to prettify whatever I have in those code blocks the prettifier yells at me.

Yes, correct. There’s always an error on line 1. If you’re using VSCode the problems window will always see that error because it IS an error. I’m filling in the damn box, don’t make me put fake code in the box. Just let me know that I’m writing a code block and be done with it. I get that you’re going to put a wrapper on it and pass instance and context to the block wrapped in a function. We’re not idiots here.

I do the exact same thing in my Floppy function “Code Action” but I don’t force the user to write fake code. I just say, “hey, this block is gonna become a function”. (And you can see the parameters if you turn on debug mode.)

Bubble is so dumb in this respect.

1 Like

BTW if you want a free copy of Floppy just tell me what app name you want authorized and I’ll add it there.

1 Like

To me the greatest pains are:

  1. No way to reuse JS libraries used in Bubble. For example the Google Maps JS. If you directly load your own then it create conflicts

  2. Not all fields or inputs can be rearranged

  3. Can’t creat your own objects! I know this can be hacked via the API connector. This is a big pain point

  4. I should be able to define my external JS libraries to Bubble to load. Something like CodePen or JS fiddle. I am wasting so much time figuring out if a library is loaded so I can continue with JS execution.

  5. Old version of Node! This is a massive pain. Also need better support for JS modules (import this from that)

  6. The ability to use the Code input for the front end. Developers are using the text input for things like Custom CSS, HTML or JS that ask end users to add

  7. Can we have a VS Code extension? We can probably form a group where we can build it our selves. But we will need Bubble’s support to connect all the APIs

  8. Async/await please. Not Bubble’s built in method but the regular JS way

3 Likes

Yep, I haven’t run into that specifically, but have run into plugins stomping each other’s code due to library conflicts. This is perhaps one of the harder challenges to solve.

Yep, that drives me bananas. (It seems you can do this manually if you sync your code to github and then fiddle with the order of things in the info functions that are created there but it’s a real bother, seems error-prone, and I don’t bother to do it.)

This is basically THE huge weakness in Bubble’s architecture ATM.

Agreed, though personally, because of limitations in SSAs for anything custom (like in my own projects) I’ve taken to using Google Cloud Functions instead of running the same code in an SSA. But it would be nice to be able to build Bubble plugins in somewhat more modern ways.

In my original post, I was speaking specifically of feature changes I’ve noted in the plugin builder itself (not the plugin API architecture so much), but while we are speaking of SSAs, it sure would be nice if client-side Actions and Element Actions could return values to the workflow similar to SSAs. This would result in plugins that would more sanely address deficiencies in Bubble.

(A lot of the plugins I build could really be collections of client-side Actions, rather than monolithic element plugins, if Actions could return values to the workflow.)

Other types of inputs would be very welcome. Particularly dynamic numbers of inputs. As it is, the plugin dev has to decide, welp, “how many thingies should this element support for the user”? (Like in Floppy Reader I chose an arbitrary number of 6 scalar fields and 6 list fields.)

You can write fully ES6 code, but you’ll need to minify it yourself. (As I mentioned, I’m using this VS Code extension for that. Seems to be the only one that really supports all the features and is easily customizable.)

But yes, it’s unclear what use context.async() is as it only ever fires once.

A little more on async/await: you can write asynchronous functions in Bubble plugins and you can use asynchronous libraries and await their results. The trick is not stomping on the weird synchronous way that lists must be read. (I would say that when I got started with Bubble plugin development, I sort of appreciated the fact that you could just pretend like getting a List was synchronous, but ultimately it’s a little bonkers (perhaps not at the time it was implemented, but certainly in today’s browser environment).

So, let’s say you have an element action (the following is a real example from Floppy) that needs to read a List or Lists, but then later needs to await the results of some asynchronous function call. You have to break that up into two separate functions where the first function is synchronous and the second is asynchronous and can contain any awaits.

instance.data.funcActionSetRamList = function actionSetRamList(instance, props) {
    // ☝️ this is the synchronous function we will call from the Code Action block in our plugin

    instance.data.ram_list_value = props.list_value ? instance.data.funcGetList(props.list_value) : []
    // this action has a field "list_value" that is a list, funcGetList ☝️ is my list reading function
    // that list loading may cause this function to start and cancel several times, and won't
    // proceed with code execution until that's done.

    // 👇 once the list is loaded, we can call the asynchronous part of our code
    instance.data.funcActionSetRamList_2(instance, props)
}

instance.data.funcActionSetRamList_2 = async function actionSetRamList2(instance, props) {
    // ☝️ note that part 2 of our action is anynchronous

    props.store && await instance.data.funcStoreKey(instance, instance.data.key_name_list, instance.data.ram_list_value)
    // funcStoreKey() is asynchronous ☝️ and so must be awaited

    // 👇 finish up our action, which publishes some state (example code simplified here)
    // and triggers an event
    instance.publishState('ram_list_value', some_value)
    instance.triggerEvent('updated_ram_list_value')
}
2 Likes

For me, the biggest most baddest limitation is the inability for client side actions to return data (result of step x …)

The second thing is having to use events to time client side actions correctly. Why can’t the next action just wait until this action is completed?

This makes plugins a lot less intuitive for a user … which is more important than anything else. If the user has to break their heads to understand something that isn’t the same way the rest of bubble works, then there’s a problem :confused:

3 Likes