Dragging the icons with no icon out of the customization window into the Touch Bar reveals that they do in fact have an icon: it's just not being shown in the customization window. What I think is happening is that the
NSTouchBarDelegate defers initializing the inputs not in the Touch Bar until they are needed. That is, until they are about to be displayed in the customization view.
nsTouchBarInputIcon is initialized for those inputs as the customization view opens. Since the
nsIconLoaderService is async, the icon isn't loaded in time for the customization view opening, and it's displayed as blank, even though the underlying input has an icon. The customization window doesn't show "live" versions of the input, but rather snapshots of how they appear as the customization window opens.
updateAll command as the customization view is opening doesn't fix this issue either, presumably because that still isn't enough time for the icons to load. I think the icons are displayed for the first Firefox window opened because the label strings aren't yet localized, so we localize those strings and then update the inputs with the new strings. This update triggers loading the icon, even on those inputs not in the Touch Bar. On subsequent window opens, the strings are already localized. We cache the localized strings, so no update occurs, and thus the icons aren't loaded for non-visible inputs.
The Back, Forward, Add Bookmark, and Reader View inputs (should) always have icons because they are frequently updated for other reasons.
What is required to fix this is manually initializing every Touch Bar input, including those that aren't in the Touch Bar, whenever
nsTouchBar is initialized. We might also be able to fix this from the JS side; we could just run
_updateTouchBarInputs on any inputs that haven't already been updated. We could defer this a little so it doesn't block window startup time; maybe on the first location change?