Thread Tools Display Modes
09-22-16, 08:28 AM   #1
Kagura
A Fallenroot Satyr
Join Date: Nov 2008
Posts: 21
Journey to developing a complete UI in JS

Hello,

I am mainly looking for discussing and critique about the path I am currently walking. Without further ado:

I decided two weeks ago that I wanted to develop a new UI, but I wanted it to be a different journey and I wanted to have fun. I like javascript and I write React applications at work and in my private time and I like the way you 'develop' there. I thought it would be awesome to be able to write my own UI in javascript.

Fast forward to today, I am capable of doing next (Might look weird, but this is basically ES6 + JSX syntax): https://gist.github.com/Nimaear/33cf...0cae3366e54f0a

Which results in:


Now this already looks like things are working, but I am really unhappy with how I translate the render method to a UI. Mainly the nesting of children doesn't really work like I want.

Now my question here and mainly the thing I want to discuss is: How would you define a Component that can host nested Components in lua and what kind of structure would you put this in? My problem here is that I have taken maybe a too close approach to React and need to think out of the box. I have total control over how javascript gets translated to lua and would like some input here.

p.s. I know it sounds a little vague, I appreciate the thoughts.
  Reply With Quote
09-22-16, 03:42 PM   #2
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
Featured
Join Date: Oct 2006
Posts: 10,860
And how, exactly, do you plan on using JS in WoW?
__________________
"You'd be surprised how many people violate this simple principle every day of their lives and try to fit square pegs into round holes, ignoring the clear reality that Things Are As They Are." -Benjamin Hoff, The Tao of Pooh

  Reply With Quote
09-22-16, 04:19 PM   #3
Kagura
A Fallenroot Satyr
Join Date: Nov 2008
Posts: 21
I am not planning, I am already doing it, but this part is not my problem as it already works: (I basically compile JS to lua). What I am having second thoughts about is how to build up the UI using components like React does (or something similar).
  Reply With Quote
09-23-16, 03:07 AM   #4
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,313
The problem with developing a cross-compiler is trying to support everything that can be done. In the end, you'll end up with a bloated mess that wastes a ton of resources and overall, contributes nothing. It may be a fun project to undertake to test your capabilities, but don't expect to be able to use this in the real world with anywhere near the same performance you would get writing natively in Lua.
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)
  Reply With Quote
09-23-16, 05:12 AM   #5
Kagura
A Fallenroot Satyr
Join Date: Nov 2008
Posts: 21
Actually, the compiler itself is written in javascript and produces readable lua code. I had a very well performing ui written in lua before and this is actually at least as fast since the produced code resembles the final code very closely.

With this I can test different class implementations really easy by changing this in the compile step. My eventual goal is writing the same UI in a more readable way writing less code. I am 100% confident it will be as performant as anything out there if not even better since I can do some optimizations on compiler level automatically without my UI code becoming unreadable.

My only problem right now is for loops concerning addressing lua tables (array indexes starting with 1 instead of 0 is the only thing that's hard to guess).

I had a mindset of doing UI components like React does, but after playing another couple of hours with different implementations, I have the start of something that looks really promising. I might be nerding out about this, but I am going to continue on this path and publish a sample addon even if it's only for scientific purposes.
  Reply With Quote
09-23-16, 11:32 AM   #6
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,313
Readable isn't the same as efficient. You can have readable code that nukes system resources. The fundamental problem is now you're running through two compilers/interpreters now. You're not running Java bytecode in a VM built in C. You're running a JS compiler/interpreter on top of Lua's equivalent of Java VM. Of course this is depending on how well the JS-to-Lua compiler is written and the code that is ingested, but there will always be overhead you will have to contend with.
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)
  Reply With Quote
09-23-16, 02:35 PM   #7
EyalSK
A Deviate Faerie Dragon
 
EyalSK's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2011
Posts: 13
Originally Posted by SDPhantom View Post
Readable isn't the same as efficient. You can have readable code that nukes system resources. The fundamental problem is now you're running through two compilers/interpreters now. You're not running Java bytecode in a VM built in C. You're running a JS compiler/interpreter on top of Lua's equivalent of Java VM. Of course this is depending on how well the JS-to-Lua compiler is written and the code that is ingested, but there will always be overhead you will have to contend with.
Your reply isn't clear but if you imply that he runs two VMs to execute the Lua code then that would be incorrect because he doesn't, he probably uses a transpiler that runs on top of NodeJS that produces a valid Lua code and finally that code is what he would use in his addons.

Now, to the OP I really don't know why would you do that to yourself, I mean I understand some transpilers like TypeScript, LESS, CoffeeScript, Babel and C# to JS, I completely understand why people would use these tools but JavaScript to Lua doesn't make sense to me at all outside to maybe research for few reasons that isn't really related to readability or efficiency, a JavaScript AST can be easily converted into Lua AST and you can actually produce a very efficient and readable Lua code but it also depends on the generator of the transpiler and optimizer if any.

The issue I see with it is Lua is pretty simple language and there is many concepts in JavaScript that you can bring with you to Lua due to the nature of both languages being dynamic languages.

I mean, the troubles that you need to go through to make things work doesn't worth it in my opinion and now you want to bring in React.js to WoW, a technology that aims to solve a specific problem with the DOM, a problem that doesn't really exist in WoW so why would you want to use it? however, to answer your question what you can do though is build yet another tool that trasnpiles React components into WoW's APIs... I don't think someone was that bored to create it yet.

In short, I'll be honest with you and tell you, you should really, really, REALLY, did I said really? yes I did.. really abandon this idea and use technologies where they are better used in a context in which they solve a problem or were designed for it unless you want to find yourself solving problems for fun! that don't exist! like writing a tool that maps React components into WoW's APIs just because... I'm not saying it's bad but you really need to ask yourself the following question "Do I really want to build a UI for WoW or a technology that brings the web stack into WoW?"

Anyway, good luck.

Last edited by EyalSK : 09-23-16 at 02:38 PM.
  Reply With Quote
09-23-16, 05:11 PM   #8
Kagura
A Fallenroot Satyr
Join Date: Nov 2008
Posts: 21
Why I want to do this myself is pretty simple:
- I really like the declarative way of creating a UI. Lua usually ends up being unreadable and especially because there are so many different possible solutions to the same problem (take class based OOP for example), one persons code becomes hard to read to others.
- I like coding with better tools and I want to switch out implementations easily without actually rewriting everything. This way I can 'compile' to a different class implementation without rewriting any of my code just to see the performance gain / loss.
- Last of all, I really thought it was a fun project :O

For clarity: I don't want to bring React to WoW at all. i just want to use the JSX syntax to create my 'components' because that really reads a lot easier.

Last edited by Kagura : 09-23-16 at 05:14 PM.
  Reply With Quote
09-23-16, 07:10 PM   #9
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
Featured
Join Date: Oct 2006
Posts: 10,860
Lua reads pretty easily to me. /shrug No formal coding education here, just self-taught. I'm a music/math teacher. And I teach a coding class on Friday mornings where we do Lua.

But that's me.
__________________
"You'd be surprised how many people violate this simple principle every day of their lives and try to fit square pegs into round holes, ignoring the clear reality that Things Are As They Are." -Benjamin Hoff, The Tao of Pooh

  Reply With Quote
09-23-16, 08:20 PM   #10
EyalSK
A Deviate Faerie Dragon
 
EyalSK's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2011
Posts: 13
Originally Posted by Kagura View Post
I really like the declarative way of creating a UI. Lua usually ends up being unreadable and especially because there are so many different possible solutions to the same problem (take class based OOP for example), one persons code becomes hard to read to others.
It's the programmer's job to make things readable not the language.

JavaScript classes are just syntactical sugar, a mask to the prototypical inheritance that is the foundation of the language, whether you use "class" or a "function" to donate a class doesn't make it declarative so I really don't understand what declarative means, do you even refer to declarative programming? because that would be the wrong context to use it as it's not really dependent on the language you use.

I like coding with better tools and I want to switch out implementations easily without actually rewriting everything. This way I can 'compile' to a different class implementation without rewriting any of my code just to see the performance gain / loss.
What do you mean by better tools? because in most cases they would be quite close in terms of tooling although many editors use the TypeScript language service to provide better JavaScript support or/and have some sort of enhanced support to detect JavaScript specific patterns but still it isn't as reliable as you would have with a statically typed language mostly due to the dynamic nature of the language.

For clarity: I don't want to bring React to WoW at all. i just want to use the JSX syntax to create my 'components' because that really reads a lot easier.
Yes but for this to happen you need to write a tool that knows how to take this presentation and transpile it into pure Lua using WoW's API.

Last of all, I really thought it was a fun project :O
Well, if you're doing it for fun that's another story, if you enjoy it then the technical reasons don't matter at all... have fun coding!

Last edited by EyalSK : 09-23-16 at 08:36 PM.
  Reply With Quote
09-24-16, 12:51 AM   #11
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,313
Originally Posted by Lynxium View Post
Your reply isn't clear but if you imply that he runs two VMs to execute the Lua code then that would be incorrect because he doesn't, he probably uses a transpiler that runs on top of NodeJS that produces a valid Lua code and finally that code is what he would use in his addons.
The only part of my post where I mentioned VMs was the comparison of how JS is run in native applications and the process done here to cross-compile JS to Lua code.

The comparison I'm making is like trying to run a Windows program through Wine on Linux versus running a native Linux version of the same program.
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)
  Reply With Quote
09-24-16, 06:46 AM   #12
Kagura
A Fallenroot Satyr
Join Date: Nov 2008
Posts: 21
I agree that it's the programmer's job to make code readable up to a certain point. You can write the most beautiful piece of art in assembly, but it's gonna be damn hard for anyone else to understand it right away. On the other hand of the spectrum, you could say : 'window with two buttons in the middle of the screen (which is probably possible to be deconstructed into an AST and finally converted to LUA)'.

I am trying to find a middle ground where it's gonna be easy for me (the developer) to write something that is fun to code, easy to read and easy to change implementation.

I also know about the prototypical nature of both JS and LUA, but what I mean to say is this: When you are using a Class based approach to programming OOP, there's A LOT of different ways (both in LUA and JS) to achieve this. Of course you can be a purist and say: write it in the original language, it's good enough, but I can literally change all my code to use closure based class implementation instead of metatable based class implementation by changing one option in my compiler (This is not so easy in LUA since how you call instance methods will be different depending on your approach : class:method() vs class.method())

I know all of this all personal preference, but I wanted to share this weird journey either way. I would like to share the next piece of code (also available as gist for better readability: https://gist.github.com/Nimaear/33cf...0cae3366e54f0a)

Maybe it's just me, but I really like how it reads compared to doing the same in LUA (even with a proper class implementation). I did find a way to get my original problem solved, so I am journeying towards creating my UI toolkit after which I will port my unitframes.


Code:
import WindowWithTitle from 'UI/Window/WindowWithTitle';
import SmallButton from 'UI/Button/SmallButton';
import Text from 'UI/Text';
import UI, { Component } from 'UI';

export default class Test extends Component {
  events = [
    'UNIT_AURA'
  ];

  UNIT_AURA(___) {
    console.log('Someone gained aura!', ___);
  }

  ok() {
    console.log('You pressed ok');
  }

  cancel() {
    console.log('You pressed cancel');
  }

  render() {
    return (
      <WindowWithTitle movable title={'Broxxigar the red'} width={512} height={512} anchors={[['CENTER']]}>
        <Text anchors={[['TOPLEFT'], ['BOTTOMRIGHT', 'parent', 'RIGHT']]} align={'LEFT'} vAlign={'TOP'}>
          Even for an orc, Broxigar the Red was obsessed with honor and felt he had lost his by living. While he served the Horde with distinction all his life, his true shame came from an action he took long after the Blood Curse had lifted and Thrall has assumed the mantle of Warchief. During the Third War, as the Horde struggled to prevent the demonic army of the Burning Legion from claiming Mount Hyjal as their own, Broxigar led a force of orc warriors in the defense of a vital choke point that would give the Legion their path. Rather than allow the demons to proceed, the orcs stood and died. All of them.

          All of them save Broxigar.
        </Text>
        <SmallButton anchors={[['BOTTOMLEFT']]} onClick={() => this.ok()}>
          <Text anchors={'*'}>OK</Text>
        </SmallButton>
        <SmallButton anchors={[['BOTTOMRIGHT']]} onClick={() => this.cancel()}>
          <Text anchors={'*'}>Cancel</Text>
        </SmallButton>
      </WindowWithTitle>
    )
  }
}
De generated LUA looks like this:
Code:
  do
    local WindowWithTitle = __Modules.k.__default__
    local SmallButton = __Modules.m.__default__
    local Text = __Modules.i.__default__
    local UI = __Modules.d.__default__
    local Component = __Modules.d.Component
    local Panel = __Modules.n.__default__
    local Test = Component:extend({ events = { "UNIT_AURA" } })

    Test.__class = 'Test'


    function Test:Test__UNIT_AURA(...)
      prettyPrint("Components\Test.js:13", "Someone gained aura!", ...)
    end
    Test.UNIT_AURA = Test.Test__UNIT_AURA

    function Test:Test__ok()
      prettyPrint("Components\Test.js:17", "You pressed ok")
    end
    Test.ok = Test.Test__ok

    function Test:Test__cancel()
      prettyPrint("Components\Test.js:21", "You pressed cancel")
    end
    Test.cancel = Test.Test__cancel

    function Test:Test__render()
      return { WindowWithTitle, { movable = true, title = "Broxxigar the red", width = 512, height = 512, anchors = { { "CENTER" } } }, { Text, { anchors = { { "TOPLEFT" }, { "BOTTOMRIGHT", "parent", "RIGHT" } }, align = "LEFT", vAlign = "TOP" }, "Even for an orc, Broxigar the Red was obsessed with honor and felt he had lost his by living. While he served the Horde with distinction all his life, his true shame came from an action he took long after the Blood Curse had lifted and Thrall has assumed the mantle of Warchief. During the Third War, as the Horde struggled to prevent the demonic army of the Burning Legion from claiming Mount Hyjal as their own, Broxigar led a force of orc warriors in the defense of a vital choke point that would give the Legion their path. Rather than allow the demons to proceed, the orcs stood and died. All of them. All of them save Broxigar." }, { SmallButton, { anchors = { { "BOTTOMLEFT" } }, onClick = function ()
        self:ok()
      end }, { Text, { anchors = "*" }, "OK" } }, { SmallButton, { anchors = { { "BOTTOMRIGHT" } }, onClick = function ()
        self:cancel()
      end }, { Text, { anchors = "*" }, "Cancel" } } }
    end
    Test.render = Test.Test__render

    __Modules.o = __Modules.o or {}
    __Modules.o.__default__ = Test
  end
  Reply With Quote
09-24-16, 11:42 AM   #13
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
Featured
Join Date: Oct 2006
Posts: 10,860
To me, personally, that Lua code looks like a mess.
__________________
"You'd be surprised how many people violate this simple principle every day of their lives and try to fit square pegs into round holes, ignoring the clear reality that Things Are As They Are." -Benjamin Hoff, The Tao of Pooh

  Reply With Quote
09-24-16, 01:41 PM   #14
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,313
I feel sorry for whatever system that has to run that code.

In all seriousness. It's pretty much as bad as I described. Tons of bloat (memory/CPU usage) for only a frame with a couple buttons and text. I suspect that's just the beginning of it. We can't even see how __Modules is being generated either.

The XML-based Widget API supports making virtual UI objects that act as classes would and can be used as templates by importing them. Defining these are an XML-exclusive feature, but we can easily do something similar by creating generator functions.
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)

Last edited by SDPhantom : 09-24-16 at 01:58 PM.
  Reply With Quote
09-24-16, 04:05 PM   #15
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
My current project at work is all in React, and I agree that JSX is great ... for generating JavaScript applications.

I also agree with SDPhantom that that generated Lua code is massively cringe-worthy. It's bloated, convoluted, overly verbose, visually unappealing (those underscores everywhere!) and just generally hard to read and follow.

Compare:

lua Code:
  1. local window = New("WindowWithTitle")
  2. -- ^ Let's pretend here that "New" is your constructor function,
  3. -- and returns a valid frame with all the appropriate parts.
  4. window:SetMovable(true)
  5. window:SetWidth(512)
  6. window:SetHeight(512)
  7. window:SetPoint("CENTER")
  8.  
  9. window.title:SetText("Broxxigar the red")
  10.  
  11. local text = window:CreateFontString()
  12. text:SetPoint("TOPLEFT")
  13. text:SetPoint("BOTTOMRIGHT", window, "RIGHT")
  14. text:SetJustifyH("LEFT")
  15. text:SetJustifyV("TOP")
  16.  
  17. text:SetText("Even for an orc, Broxigar the Red was obsessed with honor ...")
  18. -- ^ Truncated for the sake of brevity in this example.
  19.  
  20. local button1 = New("SmallButton")
  21. button1:SetParent(window)
  22. button1:SetPoint("BOTTOMLEFT")
  23. button1:SetText("OK")
  24. button1:SetScript("OnClick", function(self, mouseButton)
  25.     print("You pressed ok")
  26. end)
  27.  
  28. local button2 = New("SmallButton")
  29. button2:SetParent(window)
  30. button2:SetPoint("BOTTOMRIGHT")
  31. button2:SetText("Cancel")
  32. button2:SetScript("OnClick", function(self, mouseButton)
  33.     print("You pressed cancel")
  34. end)
  35.  
  36. window:RegisterEvent("UNIT_AURA")
  37. window:SetScript("OnEvent", function(self, event, ...)
  38.     if event == "UNIT_AURA" then
  39.         print("Someone gained aura!", ...)
  40.     end
  41. end)

Now there's no mystery variables, you're not creating a billion unnecessary tables and functions, and it's very clear to anyone who looks at it what's going on at any place in the code.
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.

Last edited by Phanx : 09-25-16 at 09:51 PM. Reason: Forgot to parent the buttons in my example code.
  Reply With Quote
09-24-16, 05:36 PM   #16
EyalSK
A Deviate Faerie Dragon
 
EyalSK's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2011
Posts: 13
Originally Posted by SDPhantom View Post
The comparison I'm making is like trying to run a Windows program through Wine on Linux versus running a native Linux version of the same program.
Yes but this is vastly different from what's happening, what happens with WINE is they map the Win32 APIs to Linux APIs so there's a layer of abstraction and sometimes it won't perform as good as native Win32 APIs due to differences in architectures and underlying issues but a transpiler can actually produce much better code then what you would write yourself if not equal to a professional Lua programmer.

Some C++ compilers can transpile C++ into Assembly with a flag and the output is matched with a professional assembly programmer if not more at a time mostly because the optimizer can recognize patterns in the code and replace them with a faster implementation in the final output, there's no reason any other transpiler that takes language X and produces Y can't do the same regardless to the language but it also requires more research and analysis so I don't expect all compilers to have it, definitely not a transpiler of this kind.

Just a note I'm not speaking about producing idiomatic Lua code but mostly on performance, the code can be terribly unreadable but performance can be great these aren't mutually exclusive because I totally agree that the output code he posted is ugly in many ways.

Another good example is TypeScript, the compiler do a great job at producing both idiomatic and efficient JavaScript code but even then it isn't as readable as I would write myself.

One of the things you learn in engineering is to measure, measure, measure and check your facts so maybe you're right but at the same time you likely to be wrong it's all up to the code and the benchmark god.

To me, personally, that Lua code looks like a mess.
I agree but then again it makes him happy and he's fine with it so that's great!

Last edited by EyalSK : 09-24-16 at 09:30 PM.
  Reply With Quote
09-25-16, 04:11 AM   #17
Kagura
A Fallenroot Satyr
Join Date: Nov 2008
Posts: 21
How pretty the produced LUA code looks depends completely what kind of 'class' implementation you choose and if you mimify the method names or not. I would also urge you to do performance and memory checking on the generated code before you judge it My original goal wasn't for the LUA code to be readable at all. And again: if I had written the same thing in LUA (just think modules/packages (without polluting the global namespace), inheritance, class variables (not instance), super calls, method hooks and decorators,) the result would have been the same save the method names.

When it comes to space-time tradeoff of the generated LUA code, I chose time over space since I care about performance and the extra table entry per method to accomodate easy super calls is not that big of a price to pay.

If you have concrete pointers to where I can improve the performance of the generated LUA code, I'd be delighted to hear them.

On the other hand, Phanx's code is exactly what I meant:
To visualize how the UI element is setup you are going through 32 lines of code just to realise it won't work (You can figure out why).

Let's now say I want to split my window into two panels and all I had in the first one goes into second one and on the left one I want buttons. In Phanx's example, I'd have to go through the created ui elements that are a 'child' of my original one and change either the creation of all these elements or the parenting (SetParent) for each of the created UI element. In my original example, I would change nothing except the indenting after (I am referring to the JSX here, not LUA)

Code:
      <WindowWithTitle>
        <Frame anchors={[['TOPRIGHT'], ['BOTTOMLEFT', 'parent', 'BOTTOM']]}>
          {/* Buttons here */}
        </Frame>
        <Frame anchors={[['TOPLEFT'], ['BOTTOMRIGHT', 'parent', 'BOTTOM']]}>
          {/* Paste original content here */}
        </Frame>
      </WindowWithTitle>
And this brings me finally to my original question
How would you go around creating a UI component library/anything in LUA that allows you to do exactly this (with exactly I don't mean JSX markup, but the parenting/anchoring nightmare)?

Last edited by Kagura : 09-25-16 at 05:38 AM.
  Reply With Quote
09-25-16, 05:53 AM   #18
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,313
Originally Posted by Kagura View Post
I would also urge you to do performance and memory checking on the generated code before you judge it
Originally Posted by Kagura View Post
Code:
  do
    local WindowWithTitle = __Modules.k.__default__
    local SmallButton = __Modules.m.__default__
    local Text = __Modules.i.__default__
    local UI = __Modules.d.__default__
    local Component = __Modules.d.Component
    local Panel = __Modules.n.__default__
    local Test = Component:extend({ events = { "UNIT_AURA" } })

    Test.__class = 'Test'


    function Test:Test__UNIT_AURA(...)
      prettyPrint("Components\Test.js:13", "Someone gained aura!", ...)
    end
    Test.UNIT_AURA = Test.Test__UNIT_AURA

    function Test:Test__ok()
      prettyPrint("Components\Test.js:17", "You pressed ok")
    end
    Test.ok = Test.Test__ok

    function Test:Test__cancel()
      prettyPrint("Components\Test.js:21", "You pressed cancel")
    end
    Test.cancel = Test.Test__cancel

    function Test:Test__render()
      return { WindowWithTitle, { movable = true, title = "Broxxigar the red", width = 512, height = 512, anchors = { { "CENTER" } } }, { Text, { anchors = { { "TOPLEFT" }, { "BOTTOMRIGHT", "parent", "RIGHT" } }, align = "LEFT", vAlign = "TOP" }, "Even for an orc, Broxigar the Red was obsessed with honor and felt he had lost his by living. While he served the Horde with distinction all his life, his true shame came from an action he took long after the Blood Curse had lifted and Thrall has assumed the mantle of Warchief. During the Third War, as the Horde struggled to prevent the demonic army of the Burning Legion from claiming Mount Hyjal as their own, Broxigar led a force of orc warriors in the defense of a vital choke point that would give the Legion their path. Rather than allow the demons to proceed, the orcs stood and died. All of them. All of them save Broxigar." }, { SmallButton, { anchors = { { "BOTTOMLEFT" } }, onClick = function ()
        self:ok()
      end }, { Text, { anchors = "*" }, "OK" } }, { SmallButton, { anchors = { { "BOTTOMRIGHT" } }, onClick = function ()
        self:cancel()
      end }, { Text, { anchors = "*" }, "Cancel" } } }
    end
    Test.render = Test.Test__render

    __Modules.o = __Modules.o or {}
    __Modules.o.__default__ = Test
  end
Without the full code, it's impossible to run any tests.
Test.lua:2: attempt to index global '__Modules' (a nil value)


Many of us here have already done research on the backend of Lua and know how everything runs on C-side. We know what to avoid to make sure our code is solid, clean, and smooth running. We aren't picking on your code just because we think it's ugly. We have years, some of us even decades of experience in Lua specifically that gives us insight on how the computer is going to approach it.

If you're interested in trimming down your CPU usage, the most expensive Lua operations are function calls followed by table indexing. Indexing operations are what surprise a lot of people because of how much they can stack up. Accessing a global is an indexing operation on Lua's environment table. Metatables add at least two indexing operations each whenever they need to be accessed if __index is another table. If it's a function, then it's an indexing operation plus the function call.

You should also keep an eye on memory usage. Garbage collection cycles are notorious for causing large amounts of framerate drops. Because of this, avoid creating dynamic tables and functions and releasing them very often.
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)

Last edited by SDPhantom : 09-25-16 at 06:19 AM.
  Reply With Quote
09-25-16, 07:38 AM   #19
EyalSK
A Deviate Faerie Dragon
 
EyalSK's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2011
Posts: 13
If you have concrete pointers to where I can improve the performance of the generated LUA code, I'd be delighted to hear them.
Well, the generated code you posted is purely data so it all depends on how you process it and you didn't provide it but I'd really try to keep the amount of tables and lookup down as much as possible, I don't think the generated code needs to have 1:1 or high fidelity with the source code especially if you aim for performance first therefor you can get rid of some things, for example,

Code:
{ 
						SmallButton, 
						{ 
							anchors = { 
								{ "BOTTOMLEFT" } 
							}, 
							onClick = function()
			self:ok()
		end
						}, 
						{ 
							Text, 
							{ 
								anchors = "*" 
							}, 
							"OK" 
						} 
					},
Can become the following.

Code:
{ 
	SmallButton, 
	{ 
		anchors = "BOTTOMLEFT", 
		onClick = function()
			self:ok()
		end
	}, 
	{ 
		Text, 
		anchors = "*", 
		"OK" 
	} 
},
But then again, this is just a hunch because this change might complicate the rendering logic and buy nothing so to really provide insights to how you can improve performance one needs to know the full story beyond the generated code.

Code:
How would you go around creating a UI component library/anything in LUA that allows you to do exactly this (with exactly I don't mean JSX markup, but the parenting/anchoring nightmare)?
Not sure what you're asking here or maybe it was just rhetorical.

p.s. Just a minor note Lua isn't an acronym but a word so you actually need to write Lua instead of LUA.

Last edited by EyalSK : 09-25-16 at 07:50 AM.
  Reply With Quote
09-25-16, 12:38 PM   #20
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,313
Something I just spotted, your backslashes aren't escaped.
Code:
prettyPrint("Components\Test.js:17", "You pressed ok")
Should be:
Code:
prettyPrint("Components\\Test.js:17", "You pressed ok")
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)
  Reply With Quote

WoWInterface » Developer Discussions » General Authoring Discussion » Journey to developing a complete UI in JS

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off