I'd like to suggest new way of approaching minification and concatenation of
our JS code.
Currently, our strategy at build time is to gather all synchronous <scripts> in
./{appname}/index.html and jsmin them into a single "gaia_build_index.js", then
gather all deferred <scripts> and jsmin them into a single
"gaia_build_defer_index.js". In result instead of:
<script src="/js/endpoint.js"></script>
<script src="/js/config.js"></script>
<script src="/js/app.js"></script>
<script defer src="/components/bridge/bridge.js"></script>
<script defer src="/shared/js/intl/l20n-service.js"></script>
<script defer src="/shared/js/intl/l20n-client.js"></script>
<script defer src="/shared/js/intl_helper.js"></script>
<script defer src="/components/gaia-header/dist/gaia-header.js"></script>
<script defer src="/components/gaia-toolbar/gaia-toolbar.js"></script>
<script defer src="/js/db.js"></script>
<script defer src="/shared/js/lazy_loader.js"></script>
<!-- to be lazy loaded:
<script defer src="/js/async_db.js"></script>
<script defer src="/js/thumbnails.js"></script>
<script defer src="/js/mediadb.js"></script>
<script defer src="/elements/music-overlay.js"></script>
<script defer src="/elements/music-scan-progress.js"></script>
<script defer src="/elements/music-tab-bar.js"></script>
<script defer src="/elements/music-view-stack.js"></script>
-->
we have this:
<script src="./gaia_build_index.js"></script>
<script src="./gaia_build_defer_index.js"></script>
and then some LazyLoader is loading the remaining files one by one.
That's not a bad strategy, but it means that we have a lot of JS code that is
unnecessary during app startup that has to be loaded/parsed at the same time as
the code required for startup.
That leads us to use a "third stage" code that is commented out in <head> and
loaded using LazyLoader class inside JS.
=============== Proposal ==================
I'd like to suggest that we tie our JS code bundling to our bootstrap stages[0].
In that world, we assign a role="" to each <script> tag. That role allows us to
group scripts that are needed together. It also allows us to bundle the
lazyloaded groups of scripts and remove the need for LazyLoader completely.
Here's an example of how it might work (details to be decided):
<script role="navigationLoaded" src="/js/endpoint.js"></script>
<script role="navigationLoaded" src="/js/config.js"></script>
<script role="navigationLoaded" src="/js/app.js"></script>
<script role="visuallyLoaded" defer
src="/components/bridge/bridge.js"></script>
<script role="visuallyLoaded" defer
src="/shared/js/intl/l20n-service.js"></script>
<script role="visuallyLoaded" defer
src="/shared/js/intl/l20n-client.js"></script>
<script role="visuallyLoaded" defer src="/shared/js/intl_helper.js"></script>
<script role="visuallyLoaded" defer
src="/components/gaia-header/dist/gaia-header.js"></script>
<script role="visuallyLoaded" defer
src="/components/gaia-toolbar/gaia-toolbar.js"></script>
<script role="visuallyLoaded" defer src="/js/db.js"></script>
<!-- to be lazy loaded:
<script role="editView" src="/js/async_db.js"></script>
<script role="editView" src="/js/thumbnails.js"></script>
<script role="editView" src="/js/mediadb.js"></script>
<script role="settingsView" src="/elements/music-overlay.js"></script>
<script role="settingsView" src="/elements/music-scan-progress.js"></script>
<script role="settingsView" src="/elements/music-tab-bar.js"></script>
<script role="albumView" src="/elements/music-view-stack.js"></script>
-->
results in:
<script role="navigationLoaded"
src="./js-opt/index_navigationLoaded.js"></script>
<script role="visuallyLoaded" defer
src="./js-opt/index_visuallyLoaded.js"></script>
<script role="editView" data-lazy-src="./js-opt/index_editView.js"></script>
<script role="settingsView"
data-lazy-src="./js-opt/index_settingsView.js"></script>
<script role="albumView" data-lazy-src="./js-opt/index_albymView.js"></script>
And then the only thing you need in your code is:
scriptElement.addEventListener('load', () => {
console.log('My lazy loaded JS view is ready!');
});
if (scriptElement.dataset.lazySrc) {
scriptElement.setAttribute('src', scriptElement.dataset.lazySrc);
scriptElement.dataset.lazySrc = undefined;
}
or if we maintain some LazyLoader:
LazyLoader.load(['settings', 'editView']).then();
That enables pretty flexible per-app decisions on which scripts are loaded with
each group, and how is that group loaded (maybe navigationLoaded should be
deferred? Maybe it should be synchronous? maybe it should be async?).
You can go more granular, and have separate script group for
navigationInteractive, or, if you don't need to alter HTML at all, only have
navigationInteractive group for binding chrome to your glue code.
It would be easy to adjust webapp-optimize to handle that, and would allow us
to load the right JS at the right time. It also degrades gracefully to work the
way it does right now.
Thoughts? Opinions?
zb.
p.s.
1) We may still need some lazy_loader.js which would take the scripts with a
given role from head comments and load them for non optimized scenario. But in
the production code we could just remove it.
2) There may be lazy loaded scripts needed by multiple lazyloaded groups. In
those cases we could separate them into their own group the way we would with
shared CSS or L10n resources. In the worst case, each lazy loaded script would
have its own group which is basically what we do now.
[0]
https://developer.mozilla.org/en-US/Apps/Build/Performance/Firefox_OS_app_responsiveness_guidelines
_______________________________________________
dev-fxos mailing list
[email protected]
https://lists.mozilla.org/listinfo/dev-fxos