Thanks for a lot of great feedback, Gijs! W dniu piątek, 10 czerwca 2016 11:49:16 UTC+2 użytkownik Gijs Kruitbosch napisał:
> Mutation observers or mutation events? How do you decide which elements > you observe? Observing the entire DOM tree seems like it'd likely be > terrible for performance once we start mutating the DOM. Have you done > any measurements on the performance of this approach when large amounts > of DOM are inserted (ie not about:support :-) )? How do you decide on > which documents you add these observers to? We use Mutation Observers. Actually, just one per document, which observes document.documentElement for subtree inserts and changes to the data-l10n-* attributes. I don't currently have perf numbers for large DOM inserts but generally we've been very satisfied with this approach in Firefox OS. We saw perf wins even on low-memory handsets. I'm sure we'll measure a lot more once we're closer to having a working fork of Firefox. > MutationObservers are async, and dtd localization in XHTML is currently > synchronous on parsing. That seems like a large change that will cause a > lot of problems relating to reflow / flashes of unlocalized content > (keep in mind we use l10n data for style as well), tests that expect > synchronous changes as a result of actions, as well as issues where we > would want the localized changes in elements that aren't in the page DOM > (so constructed in JS, but not included in the DOM (yet)). You don't > mention a JS/C++ API, which we need for e.g. strings we pass to message > boxes or into the argument strings for about:neterror/about:certerror. > What are your plans in that department? These are all valid concerns. The API is async by design, which allow us to also do runtime fallback on missing or broken translations. document.l10n.get('main').formatValue('hello', { user: '…' }).then(hello => …); In this example 'main' is the name of the bundle and 'hello' is an identifier of a translation. We used this API in Firefox OS and it has proven to be versatile and easy to use. It turns out that there are very few use-cases when it's necessary to use this API. Usually it OK to pass string _identifiers_ around and only elem.setAttribute('data-l10n-id', id) when it's time to show it to the user. Same goes for tests: if we have good tests for the Mutation Observer, then in other tests we could just test if the data-l10n-id was properly set. We could expose something like document.l10n.translateFragment to deal with node trees which are not yet attached to the DOM, although working on data-l10n-id and then just translating once (via the observer) when the nodes are inserted would be our preferred approach. FOUCs can also be a problem and something that's constantly on our radar. The Firefox OS experience allows us to be optimistic, and we're sure to follow up with much more perf testing in the near future to make sure we don't regress. > > 1) HTML API > > > > The open questions are: > > > > * Would it be better to instead use custom elements like > > <l10n-bundle> <l10n-source src="…"/> </l10n-bundle>? > > Less markup is better, so please don't wrap in more custom elements. The idea of <l10n-bundle> element came about when considering where to expose the JS API (like formatValue above). Similar to <stringbundle> in XUL, one idea was to expose it on the element itself: document.querySelector('l10n-bundle').formatValue(…). As you can see, we solved it with document.l10n.get() for now. Having it on an element has one more interesting consequence: it's widely understood that you need to wait for DOMContentLoaded or readystate === 'interactive' to query the element and start using the API. With document.l10n.get() it might look like those bundles are available synchronously while in reality we still need to query the <links> to even create them. > I don't have a strong opinion on custom elements over <link> ones, > though I'd note that there's existing architecture for link elements > being added/modified/removed that fire specific events to chrome code > that you may be able to leverage. That's great to know, we're definitely interested in this! > It's not clear to me why we need a key/value object rather than a > sequence as we use now. Perhaps just a semicolon-separated string with > \; as an escape for literal ; ? That'd certainly be easier to read/write. That's an interesting alternative. One reason we went for named args is that they make it much easier for localizers to understand what they're translating. > Otherwise, it also seems wrong to require the bundle name > (data-l10n-bundle) on every localized element. The observer should be > able to simply iterate through the stringbundles in declaration order > until it finds a matching symbol. Yes, that's definitely the plan and it's even implemented right now. The default bundle is called 'main' and data-l10n-bundle="main" is implied if missing from the localizable node. > > 2) XUL API > I think so. Again, I'd prefer not to have a wrapper element. Would you say introducing a new XUL element <link> is OK, or perhaps we should reuse <html:link> here as well? > > 3) XBL API > > > > For XBL, we plan to use the same XUL bindings but inside of the > > anonymous content. Again, this creates a localization bundle object > > which is available via the document.l10n collection. > > > > <content> <xul:localization name="tabbrowser"> <xul:source > > src="/browser/tabbrowser.ftl"/> </xul:localization> <xul:label > > data-l10n-bundle="tabbrowser" data-l10n-id="foo"></xul:label> > > </content> One more question here about XBL, related to the XUL API. If we go for <link> elements in XUL, I think it would make sense to keep things consistent in XBL as well. If I understand correctly, XBL doesn't support <script> tags which would allow us to add the required behavior to make those <link> elements work. With <localization> we can bind the desired behavior via more XBL. Are there other ways to include external scripts in XBL other than 1) more XBL, and 2) Cu.import() in <constructor>? > > Open questions: > > > > * We understand that this creates and destroys the element each time > > the parent is bound/unbound. Is there UI that does that on a > > timing-sensitive path extensively? That'd be good to measure. > > I'm not sure. I'd assume that you can/want/should just cache the > contents of bundles in a JSM or equivalent, though, so that the actual > element instantiation should be reasonably quick once the resource has > loaded? This would also help in the case where you have 500 identical > XUL elements that are all bound to include the same localization resource... Great point. Right now bundle names are expected to be unique and if one already exists in the document.l10n collection, the XBL binding won't create a new one. And we only remove them when no other bindings are in use. > > 4) Performance measuring > > Question: Which performance tests should we run to ensure that L20n > > is indeed not regressing performance of Firefox? > > tpaint, ts_paint, sessionrestore, sessionrestore_no_auto_restore, > tsvg-opacity, tart, cart > > (and their e10s equivalents, of course) would be my prime suspects. IIRC > these come under "other,svgr" in try syntax, but trychooser can confirm > this for you (hover over suites tells you what tests they run). > > See https://wiki.mozilla.org/Buildbot/Talos/Tests for descriptions, > which also explains why I'm listing tsvg-opacity. :-) Thanks, this is very helpful indeed! -Staś _______________________________________________ dev-platform mailing list dev-platform@lists.mozilla.org https://lists.mozilla.org/listinfo/dev-platform