Are minified plugins allowed?

I’m aware that Roblox does not permit obfuscated scripts, as it makes moderating plugins that utilize it nearly impossible, and just not worth inspecting.

However, I’m wondering whether minification is allowed, since it doesn’t try to obscure the functionality, but rather decrease the size of source files, and make them faster to execute by removing comments, and unnecessary characters from the source code.

For example, in JavaScript, source code usually looks like this:

// let the world know you exist
let name = 'Grant';
alert(`Hello World, this is ${name}!`);

Minified code looks something like this:

let n='Grant';alert(`Hello World, this is ${n}!`);

And finally, a simple obfuscated code will look something like this:

const _0x25ddb4=_0x1570;function _0x4119(){const _0x41bf68=['4658335EetETs','477bKtyYa','__proto__','bind','info','Hello\x20World,\x20this\x20is\x20','length','table','4813094qPbTqp','error','{}.constructor(\x22return\x20this\x22)(\x20)','exception','2406686TbAVYd','constructor','search','4200hkzOoV','1kAwSFQ','4mdOcWZ','apply','6278142ZPKoTq','3465717fAgpzS','log','toString','1630pAzeYD','prototype','36NfIjcg','Grant','warn','5992FTDaLA','console'];_0x4119=function(){return _0x41bf68;};return _0x4119();}function _0x1570(_0x213821,_0xda5f55){const _0x82ba0c=_0x4119();return _0x1570=function(_0x1d9438,_0x17e147){_0x1d9438=_0x1d9438-0x15a;let _0xbfe6f6=_0x82ba0c[_0x1d9438];return _0xbfe6f6;},_0x1570(_0x213821,_0xda5f55);}(function(_0x50e94a,_0xcfdb81){const _0x59b16e=_0x1570,_0x14a377=_0x50e94a();while(!![]){try{const _0x2f4616=-parseInt(_0x59b16e(0x15f))/0x1*(-parseInt(_0x59b16e(0x15b))/0x2)+parseInt(_0x59b16e(0x163))/0x3+parseInt(_0x59b16e(0x160))/0x4*(-parseInt(_0x59b16e(0x16d))/0x5)+parseInt(_0x59b16e(0x162))/0x6+parseInt(_0x59b16e(0x15e))/0x7*(-parseInt(_0x59b16e(0x16b))/0x8)+-parseInt(_0x59b16e(0x16e))/0x9*(parseInt(_0x59b16e(0x166))/0xa)+parseInt(_0x59b16e(0x175))/0xb*(-parseInt(_0x59b16e(0x168))/0xc);if(_0x2f4616===_0xcfdb81)break;else _0x14a377['push'](_0x14a377['shift']());}catch(_0x52d8ce){_0x14a377['push'](_0x14a377['shift']());}}}(_0x4119,0xab86b));const _0x2c36fc=(function(){let _0x6865a=!![];return function(_0x494279,_0x246e9d){const _0x22331d=_0x6865a?function(){const _0x252fb5=_0x1570;if(_0x246e9d){const _0x408ead=_0x246e9d[_0x252fb5(0x161)](_0x494279,arguments);return _0x246e9d=null,_0x408ead;}}:function(){};return _0x6865a=![],_0x22331d;};}()),_0x1e24fe=_0x2c36fc(this,function(){const _0xee864a=_0x1570;return _0x1e24fe[_0xee864a(0x165)]()['search']('(((.+)+)+)+$')[_0xee864a(0x165)]()[_0xee864a(0x15c)](_0x1e24fe)[_0xee864a(0x15d)]('(((.+)+)+)+$');});_0x1e24fe();const _0x17e147=(function(){let _0x2690e9=!![];return function(_0x30493c,_0x950ab4){const _0x40b750=_0x2690e9?function(){const _0x178006=_0x1570;if(_0x950ab4){const _0x54013b=_0x950ab4[_0x178006(0x161)](_0x30493c,arguments);return _0x950ab4=null,_0x54013b;}}:function(){};return _0x2690e9=![],_0x40b750;};}()),_0x1d9438=_0x17e147(this,function(){const _0x199185=_0x1570;let _0x5d17a1;try{const _0x11d318=Function('return\x20(function()\x20'+_0x199185(0x177)+');');_0x5d17a1=_0x11d318();}catch(_0x5e2f2){_0x5d17a1=window;}const _0x399f55=_0x5d17a1[_0x199185(0x16c)]=_0x5d17a1[_0x199185(0x16c)]||{},_0x322699=[_0x199185(0x164),_0x199185(0x16a),_0x199185(0x171),_0x199185(0x176),_0x199185(0x15a),_0x199185(0x174),'trace'];for(let _0x23c263=0x0;_0x23c263<_0x322699[_0x199185(0x173)];_0x23c263++){const _0x45ed12=_0x17e147[_0x199185(0x15c)][_0x199185(0x167)][_0x199185(0x170)](_0x17e147),_0x2f25a8=_0x322699[_0x23c263],_0x153a42=_0x399f55[_0x2f25a8]||_0x45ed12;_0x45ed12[_0x199185(0x16f)]=_0x17e147[_0x199185(0x170)](_0x17e147),_0x45ed12['toString']=_0x153a42['toString'][_0x199185(0x170)](_0x153a42),_0x399f55[_0x2f25a8]=_0x45ed12;}});_0x1d9438();let name=_0x25ddb4(0x169);alert(_0x25ddb4(0x172)+name+'!');

As you can see, minification is nothing compared to actual obfuscation, which can be taken even further than what I shown. In context of Luau, source can may look something like this:

-- Here we have a lerp function
local function lerp(a: number, b: number, t: number)
	return (1 - t) * a + t * b
end

-- Here we will print a result
print("Result", lerp(1, 2, 0.5))

When you minify this, it will look something like this:

local function a(b,c,d)return(1-d)*b+d*c;end;print("Result",a(1,2,.5))

If anyone wants to glance at the functionality of the code, they can simply format the code, just like this:

local function a(b, c, d)
	return (1 - d) * b + d * c
end

print("Result", a(1, 2, 0.5))

As you can see, the functionality isn’t necessarily obscured when properly formatted, although most information has been lost such as the variable, and function names as well as the comments. It is still fairly readable.

By minifying code, I get the following benefits:

  • Reduce overall size of my plugin.
  • Slightly improve performance by removing redundant characters that compiler would otherwise have to process.

And as a bonus, I can possibly deter some people from modifying my plugin, or attempting to claim ownership of my plugin, as it requires substantial effort to figure out how exactly everything works. Additionally, it can make usage of pirated code less encouraging as some people might be reluctant to use minified code that they don’t want to bother going through the effort of reading it through.

Also, Chrome Web Store disallows obfuscated extensions, but allows minified ones.

Therefore, I do not think that minification should not be allowed, especially in paid plugins where I want people to actually buy the plugin, and support me instead of turning around to piracy. With this being said, is there any rule that prohibits minification in plugins?

3 Likes

UPDATE October 2024:

As of May 2024, we no longer allow minified code for assets distributed on Creator Store. You can freely use this in private assets.


Hey @Daw588, there currently aren’t any rules prohibiting minification, so that should be fine to utilize in marketplace assets! We appreciate the effort to maximize efficiency while keeping in mind the safety of the ecosystem. Note that our safety rules are constantly evolving, so we will let the community know if our stance on minification ever changes in the future.

3 Likes

I don’t believe you’ll get any meaningful benefit from this. You’ll be removing just some newline from blank lines and some indent characters. Newlines at the end of non-blank lines are just replaced by a semi-colon with no change in string size. When websites do this, its because they expect the code to be loaded millions of times a day, but plugin code loads just when you launch studio. You don’t really save file size either; computer storage devices like hard drives and SSDs already waste space padding small files to the nearest block size, and you have no control over this. Hundreds of bytes of whitespace removal can easily have zero effect on actual storage device file size.

Your lua is getting read into byte code in nanoseconds. Whitespace is not going to measurably affect this, and your plugin’s end users will certainly not see any performance benefit.

IMHO, for a Roblox plugin, code minification falls under the umbrella of premature optimization: a misguided optimization that hurts readability, wastes development time to add to your publishing pipeline, and ultimately makes no difference to the final product.

I’m fine with the fact that it doesn’t provide much of benefit, as I personally prefer not to supply raw source code to my paid plugins, which I want to be purchased, and left unmodified. At most I can slightly deter people from re-using my original code by getting rid of comments, documentation, names of variables and functions, while at the same time saving a bit of space both storage and network wise, when downloading. In my case I saved 64kb which is basically nothing, but it’s better than nothing.

I like to optimize things, especially if all it takes is run a command, which minifies my program, and puts !optimize 2 on top of the main program to let the Luau runtime know to apply aggressive optimizations. Then all I need to do is right click, and hit publish.

It probably is, but it doesn’t cost me anything besides running a command on my folder that will minify my plugin when I’m ready to release it. It’s just matter of myprogram build --release.

In my case, this is intended side effect.

There is also other optimizations that are applied by the pre-processor, such as static expression evaluation, and dead code removal.

For example if __DEV__ is false:

if __DEV__ then print("Hello Dev!") end
print("This is a test")

This will be pre-processed to:

print"This is a test"

The Luau compiler doesn’t seem to remove dead code thus I chose to use a pre-processor before handing the code to the compiler.

Yeah, you won’t hurt anything with all of this, and if you find it fun to do, go for it. Just know that if it becomes an obsession, you can always just skip most of it. I commented because I’ve watched a lot of devs go down that sink hole of micro-optimizations to the point where they lost focus in the game they were trying to make and got burned out chasing microseconds of runtime optimizations that didn’t really matter to their game. Some of Roblox’s own optimizations to Luau has also made some old optimization patterns now actually slower than if they were not used.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.