Profile picture
Max Antonucci @Maxwell_Dev
, 49 tweets, 11 min read Read on Twitter
All right, time for a live-tweeting journey I should have done long ago. I'm going to explore the @emberjs source code!
This is just a basic "crack open the files, understand as much as possible, and ask questions about everything else" kinda deal. I definitely won't learn anything major since I'm not that wise about JS. Yet.
*cues up music from Fantastic Beasts and Where to Find Them* all right here I go!
Flipping through the root folders now and have a few ideas to their uses. I think Broccoli is the build tool, config is the overall configuration (duh), node-tests is testing Ember's internal code, tests is the setup for tests coders write...
The "server" folder has one file, the basic server when running Ember. Looking this code, I'm guessing the app's homepage redirects to the test page? But with my new apps I've seen a placeholder instead. Unsure about this 🤔
I'm incredibly confused by the generators folder. It has no code, just a license agreement in some comments. Why put this here and not the README? Does it relate specifically to JS generators or something else entirely?
The packages folder looks to be where the party is at. Everything from controllers, routers, components, etc. I'm guessing this is where lots of the base classes are defined. Digging in deeper to this.
Looks like each folder here follows a similar pattern regardless of purpose: the index.js file takes code from nearby folders, like its relative "lib" folder, and exports a few key classes. I recognize a few of them.
For example in "ember-testing" I think I recognize "QUnitAdaptor" or something similar being exported. Looking into this may tell me more about how Ember tests are run!
ember-testing/lib/helpers has a LOT of functions I recognize! They're all helpers for basic integration interactions, like clicking elements. This is something I've used often and have better context for. My first unofficial goal is try to figure out how they function here.
Looking at the code for "find," some clear conclusions: it needs jQuery, limits the scope to the current app instance, and otherwise finds the element as one typically would with jQuery.
Lots of different testing functions are being imported between these. Makes it harder to fully understand the details, since one file could require three functions, which each require three each, etc...
Guess I'm also seeing why things are broken down in such small chunks then, since it saves a lot of time. I'm better understanding why my team is always pushing for smaller commits and changes, in a weird way.
I'm going to take a step back from testing and try to figure out something simple instead. Controllers let you define wrapper classes with "classNames," let's see how all that is handled.
Searched around and think I found the file where the basic Component class is defined (the one all custom components extend from). Seeing reference to classNames here too.
Lots of basic component hooks are being defined here, like 'willRender' and whatnot. Unsurprisingly, classNamesSupport is imported from another file.

Makes me wonder, is classNameBindings partially or totally separate from classNames here?
Huh, looks like classNamesSupport is being imported from outside glimmer, where this file was. Is it used in contexts other than components? I've never seen that, but seeing this makes me wonder.
Found classNamesSupport, it's a Mixin so it's easier to combine it with other Ember properties. There's surprisingly little here, seems like it just declares the properties, puts in some assertions for how to use them, and LOTS of usage docs.
This doesn't satisfy me. Where's the logic that attaches them to the component DOM? Is it in the base Mixin this one is apparently working off of?
Thinking about this, that's unlikely. I'm going to backtrack to the glimmer code and see if I can find answers there.
Back in the glimmer code, the component-managers folder has a "curly.ts" file I assume relates to curly braces in the HTML. Found some conditionals that seem to be behind how the className values get put on the DOM itself.
But this just leads to another question: how does this connect back to the component class itself?
Looks like they're all part of a larger hook that runs when the component is created. I'm assuming that means when it's made in the DOM, but I could be wrong.
Ah my bad, that was the hook about the stuff with classNames. That code actually runs in DidCreateElement. So after confirming the component was made, then the code to add the classes is run.
Looks like all this is being exported as part of a class called "CurlyComponentManager." So I'm going to follow to see where else this class is imported.
Aha! Looks like this class is used as a basis for something called RootComponentManager! One step closer to seeing how it gets set into the DOM.
Weird, there's another "create" method in this class. It's being extended off one that already has it. Is it overwriting it or building off it? From my knowledge I think it was overwriting this method.
No mention of "didCreateElement" here, which is the hook that holds the classNames magic I'm focusing on. Going to keep following the breadcrumb trail and see where THIS class is used.

("this" is a bad javascript joke...like the concept itself it's tough for me to understand)
Whoa, this file's export has lots of class terminology I don't know. Implements? State and Manager? I should look these up later, but right now the big takeaway is that "RootComponentDefinition" is the breadcrumb I should follow, since it's what's exported.
Forgot the image with the last tweet:
Thankfully this class is only used in one place: the Renderer class, which is even more complicated. But it looks like it deals with the much broader functions of how, and if, any kind of template code gets rendered into the DOM.
That last class is only used here, as part of the appendTo hook.
Basically, looking for "how do components add class bindings" brought us up to "how do components manage its properties" up to "how to components get rendered" and then to "how does everything get rendered." It's seeing the focused, modular breakdown of code in reverse basically.
I am seeing a few DOM references here though. Maybe I can find some more direct info on that somewhere here. My goal right now is to see how it takes all this JS functionality and connected it to the page itself.
WHOA there's a for loop here?! Was not expecting that. Roughly speaking, I think it checks to stop infinite invalid renders? Although it may just be saying "if you fail to render more than ten times, kill it as infinite and invalid." If so I agree it could be better.
Hmm looks like this Renderer class is also used in the code that handles {{outlet}} and {{yield}} in templates. More support for my notion that it's the larger, general purpose render class.
Having a hard time finding the next breadcrumb here. I am seeing lots of imports related to rendering from glimmer/runtime. Worth checking out.
I may have had a better idea before. This Rendered class is referenced in the outlet file I found before. And in a class method called "appendTo." Could this be the one adding it all to the DOM?
Or could this just be carrying out a similar function to the AppendTo class method in Renderer? These could be two different ways to manage a similar task of appending to the DOM.
I'm investigating further in kind of a sideways way: Tests! There are glimmer tests for rendering components that use similar (hopefully the same) methods as this Renderer class. Maybe these can give me another clue as to how it's done.
Found the specific test for appending components, and this seems to be the point in which the component is appended to the DOM.
Seems like whenever I find imported modules related to constructing the DOM, it goes back to the Glimmer source code that's not inlcuded in this repo. There's literally a DOM.ts file here, and it's mostly just Glimmer imports.
I do recall Glimmer being mentioned to fill this basic role in Ember at the last EmberConf, so I probably should have remembered this sooner. Plus a fast google reveals it to be a DOM rendering engine. glimmerjs.com
So in a weird way, I already knew how all this component rendering was done! But I didn't understand how the logic being passed into Glimmer was being constructed, so I at least saw some of that 😄
For one thing, I didn't know there was such a broad "Rendering" class used to handle both components, outlets, and probably other situations. I didn't think these different parts of the code could use a common extraction for so much!
Plus I saw how so many modules I import for tests and components are being written, and the structure for some of the Ember "magic" in things like class bindings.
I'm going to call it a day on digging into the Ember source code here, but I think I'll focus on something less DOM related. Maybe something like how controllers manage actions and how those even LOOK in the source code.
Regardless, this isn't the end. There shall be more live-tweeting of peeking around the source code later on!
@threadreaderapp Unroll this for easier reference later please!
Missing some Tweet in this thread?
You can try to force a refresh.

Like this thread? Get email updates or save it to PDF!

Subscribe to Max Antonucci
Profile picture

Get real-time email alerts when new unrolls are available from this author!

This content may be removed anytime!

Twitter may remove this content at anytime, convert it as a PDF, save and print for later use!

Try unrolling a thread yourself!

how to unroll video

1) Follow Thread Reader App on Twitter so you can easily mention us!

2) Go to a Twitter thread (series of Tweets by the same owner) and mention us with a keyword "unroll" @threadreaderapp unroll

You can practice here first or read more on our help page!

Did Thread Reader help you today?

Support us! We are indie developers!


This site is made by just three indie developers on a laptop doing marketing, support and development! Read more about the story.

Become a Premium Member and get exclusive features!

Premium member ($30.00/year)

Too expensive? Make a small donation by buying us coffee ($5) or help with server cost ($10)

Donate via Paypal Become our Patreon

Thank you for your support!