RMMV Only IIFEs allowed at top level of plug-in source file - guideline or hard rule?

TheBeardyMan

Villager
Member
Joined
Mar 24, 2012
Messages
15
Reaction score
6
First Language
English
Primarily Uses
N/A
Quoting the Basics section of the Plugin Specifications page of the documentation:

In order to limit the scope of variables in plugin scripts, they will all be enclosed in immediate functions.

This appears to be a requirement that only IIFEs may appear at the top level of a plugin source file. And there's a good reason for such a requirement. The alternative way to limit the scope of names would be to enclose their declarations in braces, but Javascript has a feature called variable hoisting that weakens the protection against accidentally polluting the containing namespace that braces would otherwise provide:

JavaScript:
{
    // MyVariable is declared in these braces, so this is the scope it's in, right?
    var MyVariable = 0;
}

// Ha ha, surprise! MyVariable was hoisted into this scope!
MyVariable = 1;

If you're using braces and you want to avoid polluting the containing namespace, you have to be careful to declare your variables with "let" instead of "var":

JavaScript:
{
    // MyVariable is declared in these braces, so this is the scope it's in, right?
    let MyVariable = 0;
}

// Yes, this time it is. Variables declared with "let" aren't hoisted and the following line is an error.
MyVariable = 1;

IIFEs don't have any such weakness - you can declare a variable inside an IIFE without being careful about which keyword you declare it with, and there's no risk of polluting the IIFE's containing namespace:

JavaScript:
(() => {
    {
        // MyVariable is declared here ...
        var MyVariable = 0;
    }

    // ... and it gets hoisted to here ...
    MyVariable = 1;
})();

// ... but no higher, because variables are not hoisted out of IIFEs - this line is an error.
MyVariable = 2;

But when I look at the code of some example plug-ins, I see declarations outside of IIFEs at the top level of the source file. This even happens in one of the official plug-ins MadeWithMv.js - the first few non-comment lines are:

JavaScript:
var Liquidize = Liquidize || {};
Liquidize.MadeWithMV = {};
Liquidize.MadeWithMV.Parameters = PluginManager.parameters('MadeWithMv');

Liquidize.MadeWithMV.ShowMV = JSON.parse(Liquidize.MadeWithMV.Parameters["Show Made With MV"]);
Liquidize.MadeWithMV.MVImage = String(Liquidize.MadeWithMV.Parameters["Made with MV Image"]);
Liquidize.MadeWithMV.ShowCustom = JSON.parse(Liquidize.MadeWithMV.Parameters["Show Custom Splash"]);
Liquidize.MadeWithMV.CustomImage = String(Liquidize.MadeWithMV.Parameters["Custom Image"]);
Liquidize.MadeWithMV.FadeOutTime = Number(Liquidize.MadeWithMV.Parameters["Fade Out Time"]) || 120;
Liquidize.MadeWithMV.FadeInTime = Number(Liquidize.MadeWithMV.Parameters["Fade In Time"]) || 120;
Liquidize.MadeWithMV.WaitTime = Number(Liquidize.MadeWithMV.Parameters["Wait Time"]) || 160;

and they're not in an IIFE, so they add the name Liquidize to the containing namespace.

So it looks like "Only IIFEs allowed at top level of plug-in source" isn't a hard rule - it's just a guideline. Is this the case? Or does the engine have some way of enforcing it that'll come back to bite me later?
 

Another Fen

Veteran
Veteran
Joined
Jan 23, 2013
Messages
662
Reaction score
377
First Language
German
Primarily Uses
I'm no authority on this topic with limited Javascript knowledge, so others may give you better advice here, but my few cents:

Generally, I don't know of a way that would allow one to enforce this rule, and in some cases you may actually want to establish variables that other plugins may reference.

Most of the time I've seen plugins introduce a global variable like in your example its name is strongly linked to either the author or the purpose of the plugin itself, so name collision should be rather rare.

The advantage of having your plugin settings stored globally is that other plugins have an easy option to check them for compatibility (Like checking if another plugin is already present and adjust their function definitions accordingly).

Speaking of compatibility, many plugins try to alias/snapshot functions they want to add to. In some cases you may need a compatibility patch to merge two competing function definitions. Without access to the original snapshot you can't replicate the function and would have to either modify the original plugin source or not use an alias and merge all changes made by all plugins to the function manually rather than only the competing ones.
Late Edit: Correction here, most of the time you can get around this by making your own function snapshots before running the problematic plugin. Not great, but rarely needs to be done anyways.

That would at least be the things that would come to my mind about this.^^
 
Last edited:

KelIy

JS Plugin Writer
Member
Joined
Jul 8, 2022
Messages
28
Reaction score
46
First Language
English
Primarily Uses
RMMZ
It's a guideline I personally don't strictly adhere to since I want to give other plugin authors the opportunity to modify and extend my plugins without needing to modify the source file itself. I personally have run into compatibility issues with other plugins that cannot be fixed without modifying the source of said other plugins, and I hope that I can prevent that from occurring if another developer needs to work around my code. The main downside I've found is that I can't use Intellisense without some JSDoc-fu! With that said, I do want to keep my pollution of the global namespace to a minimum to avoid conflicting with other plugins, so I use the same method seen in that portion of MadeWithMv.js in the OP, where I add a single global variable associated with my name and have my plugins add on to that variable.

Oh and also, I've had zero issues with the engine trying to "enforce" this guideline since it does not do that at all in both MV and MZ.
 

Trihan

Speedy Scripter
Veteran
Joined
Apr 12, 2012
Messages
6,019
Reaction score
6,005
First Language
English
Primarily Uses
RMMZ
I'm in the same boat as Kelly. I declare my variables in a TLB object to expose them to other developers in case they need to extend or modify my plugins.
 

Another Fen

Veteran
Veteran
Joined
Jan 23, 2013
Messages
662
Reaction score
377
First Language
German
Primarily Uses
Since everyone mentions it:

One of the first instances I saw a plugin use an IIFE was the EnemyBook plugin bundled with the RMMV.
And yes, if you like the plugin but maybe you want to also display another line, or move the enemy graphic a bit, there is no way to access either the Scene or the display window classes outside the plugin itself.
Having some way to modify these classes without tampering with the plugin itself or rewriting everything would have been a boon.
 

Aerosys

Veteran
Veteran
Joined
Apr 23, 2019
Messages
877
Reaction score
878
First Language
german
Primarily Uses
RMMZ
You may want to read this: http://www.yanfly.moe/wiki/An_Argument_Against_Requiring_IIFEs

In my opinion, IIFEs are a beginner's move. Experiences programmers create their namespace like this:

Code:
var AeroSys = AeroSys || { }

// add some function
AeroSys.shuffleArray = function(array) {
  // some algorithm
}

I avoid extending RPG Maker's classes because another dev may choose the same name when I add some function. But if you need to, an IIFE will not protect you from naming collisions. This is why programmers usually put a personal prefix in their function names:

Code:
Game_Character.prototype.aerosys_flash = function() {
  // make this character flash
}

Wrapping these examples in an IIFE is pretty much useless. Doesn't hurt, but it doesn't bring you any safety, as seen in the example above.

IIFEs sometimes even cause problems. Usually, they prohibit other devs from writing compatibility patches as they erase your functions for other programmers. When a programmer guards his code in an IIFE, and he/she doesn't instantiate a global variable (i.e. "AeroSys" from my example is global), then I would have no option to write compatibility patches.

I recommend you to learn how plugin developers instantiate their personal global object, e.g., "YEP", "VisuMZ", "MK" (that's mine) ... Just don't wrap your code in an IIFE because you think it automatically resolves all the problems for you. As you have seen, it doesn't.
 

Eliaquim

Hakuen Studio
Veteran
Joined
May 22, 2018
Messages
3,173
Reaction score
2,433
First Language
Portuguese - Br
Primarily Uses
RMMZ
Hi there!

I guess you must consider why you are writing that plugin to better understand the way you will write it.

This means, that if you are doing this only for your project, you don't need to care about compatibility at all. So you can choose to use IIFEs or whatever you want.

But if you want to develop plugins that others can use, then you should consider using the Namespace "feature" like others already said. Because if you are doing something for the community, then would be nice to let them work on it if they need/like it.

But one thing I would say is: Don't learn how to write your plugin code from other plugin developers. Just learn Javascript.

Because you can have the wrong assumption that a famous plugin developer is writing nice code. But that is not always true.
A lot of experienced programmers alerted me in the early days of my plugin development about that, because I was doing that, learning JS from other plugin makers.
And when I just jump to learn Javascript from any internet tutorial, I was able to confirm what they said was true.

The thing is, RPG Maker is a strange environment xD
You will see all kinds of crazy stuff on plugin codes(including mine haha) because each developer can have a different goal in writing their plugins.
  • Some will just want to release a lot of plugins in a short time.
  • Some will want to do that, but also make it compatible with a huge library in mind.
  • Some already work with code in their real-life job and when it comes down to RPG Maker, they are just hobbyists trying to get some fun.
- Every one of these reasons can influence how they will write their code.

But when it comes down to understanding RPG Maker core codes, then I guess it's fine to look at other plugin codes.
For example, how to write a plugin command, plugin parameters, etc...

I believe my main point is: When you are confident that you learned at least the basics of Javascript, you can safely take a look at other plugin makers' code without getting any bad habits because you will have better knowledge to judge that.


In my opinion, IIFEs are a beginner's move.
I don't use IIFEs, but I guess using it or not, has nothing to do with being a beginner.
Maybe the developer doesn't care about compatibility. That doesn't mean he is a beginner.
 

Poryg

Dark Lord of the Castle of Javascreeps
Veteran
Joined
Mar 23, 2017
Messages
4,228
Reaction score
11,121
First Language
Czech
Primarily Uses
RMMV
IIFEs are the worst thing Javascript has introduced imo. It promotes bad code due to bad handling of local variables and creates compatibility issues that are potentially impossible to solve, as has been well described by earlier posters. In fact, it can even kill plugins.
When I needed to create a compatibility patch, the first thing I would do was open the original script and remove the IIFE. But then one day I encountered a plugin that I couldn't create a compatibility patch for, because their TOU did not allow edits.
 

Arthran

Veteran
Veteran
Joined
Jun 25, 2021
Messages
867
Reaction score
1,074
First Language
English
Primarily Uses
RMMZ
IIFEs are the worst thing Javascript has introduced imo.
If we're talking about JavaScript as a whole, then I don't think that IIFEs are necessarily a bad thing. There could be times when you actively want to prevent other people from being able to overwrite/call your functions and tamper with your code from the outside--especially if you're writing web applications. But in the context of RPG Maker plugins, I agree that IIFEs are both unnecessary and annoying.
 

eomereolsson

Veteran
Veteran
Joined
Sep 29, 2021
Messages
543
Reaction score
462
First Language
German
Primarily Uses
RMMV
I am with @Poryg . Though I don't necessarily see them as the worst thing ever (tm), I have encountered several plugins which did what I wanted them to do, kind of. But to extend them to actually do what I want, I needed to go and "unwrap" them from their IIFEs. This is annoying for myself already, but if I ever get around to actually publishing these I am not looking forward to answering support questions about why my plugin extension doesn't work. :rsrs:
 

TheBeardyMan

Villager
Member
Joined
Mar 24, 2012
Messages
15
Reaction score
6
First Language
English
Primarily Uses
N/A
Lots of good replies here. So the conclusion is that IIFEs only at top level is just a guideline, and not a particularly good one.

IIFEs would never have been my first choice for writing a plugin, but the prescriptive tone of that part of the documentation plus understanding the reasons for it led me to believe that it might be a hard requirement.

  • Some already work with code in their real-life job and when it comes down to RPG Maker, they are just hobbyists trying to get some fun.

I'm in that boat, but Javascript isn't my first programming language, and what experience I do have with it is Node.js - a completely different environment from RPGMaker.
 

Latest Threads

Latest Posts

Latest Profile Posts

I'm thinking about studying Latin.
Playing with more game sound effects and fake sound attenuation in 30 minutes or so. Definitely a lot of game dev this week.

Funny how 90% of my usual struggles vanished when I used Frontview battle xD
For some reason a vegan webpage was suggested for me on FB. So I thought let's troll them. Because some of the posters needed a reality check.
I intended to start losing some weight starting today but It's apparently my birthday and I was given 2 big Toblerone's. So....Tomorrow then :p

Forum statistics

Threads
129,825
Messages
1,205,546
Members
170,954
Latest member
Carum
Top