@@ -12,14 +12,26 @@ import { WidgetConfigProvider } from './widget-list/widget-config.provider.js';
1212import { Settings } from './settings.js' ;
1313import { Components } from './components/Components.jsx' ;
1414import { widgetEntryPoint } from './widget-list/WidgetList.js' ;
15+ import { callWithRetry } from '../../../shared/call-with-retry.js' ;
1516
1617/**
18+ * @import {Telemetry} from "./telemetry/telemetry.js"
19+ * @import { Environment } from "../../../shared/environment";
20+ * @param {Element } root
1721 * @param {import("../src/js").NewTabPage } messaging
1822 * @param {import("./telemetry/telemetry.js").Telemetry } telemetry
19- * @param {import("../../../shared/environment").Environment } baseEnvironment
23+ * @param {Environment } baseEnvironment
24+ * @throws Error
2025 */
21- export async function init ( messaging , telemetry , baseEnvironment ) {
22- const init = await messaging . init ( ) ;
26+ export async function init ( root , messaging , telemetry , baseEnvironment ) {
27+ const result = await callWithRetry ( ( ) => messaging . init ( ) ) ;
28+
29+ // handle fatal exceptions, the following things prevent anything from starting.
30+ if ( 'error' in result ) {
31+ throw new Error ( result . error ) ;
32+ }
33+
34+ const init = result . value ;
2335
2436 if ( ! Array . isArray ( init . widgets ) ) {
2537 throw new Error ( 'missing critical initialSetup.widgets array' ) ;
@@ -28,9 +40,6 @@ export async function init(messaging, telemetry, baseEnvironment) {
2840 throw new Error ( 'missing critical initialSetup.widgetConfig array' ) ;
2941 }
3042
31- // Create an instance of the global widget api
32- const widgetConfigAPI = new WidgetConfigService ( messaging , init . widgetConfigs ) ;
33-
3443 // update the 'env' in case it was changed by native sides
3544 const environment = baseEnvironment
3645 . withEnv ( init . env )
@@ -39,63 +48,39 @@ export async function init(messaging, telemetry, baseEnvironment) {
3948 . withTextLength ( baseEnvironment . urlParams . get ( 'textLength' ) )
4049 . withDisplay ( baseEnvironment . urlParams . get ( 'display' ) ) ;
4150
42- const strings =
43- environment . locale === 'en'
44- ? enStrings
45- : await fetch ( `./locales/${ environment . locale } /new-tab.json` )
46- . then ( ( x ) => x . json ( ) )
47- . catch ( ( e ) => {
48- console . error ( 'Could not load locale' , environment . locale , e ) ;
49- return enStrings ;
50- } ) ;
51+ // read the translation file
52+ const strings = await getStrings ( environment ) ;
5153
54+ // create app-specific settings
5255 const settings = new Settings ( { } )
5356 . withPlatformName ( baseEnvironment . injectName )
5457 . withPlatformName ( init . platform ?. name )
5558 . withPlatformName ( baseEnvironment . urlParams . get ( 'platform' ) ) ;
5659
57- console . log ( 'environment:' , environment ) ;
58- console . log ( 'settings:' , settings ) ;
59- console . log ( 'locale:' , environment . locale ) ;
60+ if ( ! window . __playwright_01 ) {
61+ console . log ( 'environment:' , environment ) ;
62+ console . log ( 'settings:' , settings ) ;
63+ console . log ( 'locale:' , environment . locale ) ;
64+ }
6065
6166 const didCatch = ( error ) => {
6267 const message = error ?. message || error ?. error || 'unknown' ;
6368 messaging . reportPageException ( { message } ) ;
6469 } ;
6570
66- const root = document . querySelector ( '#app' ) ;
67- if ( ! root ) throw new Error ( 'could not render, root element missing' ) ;
68-
69- document . body . dataset . platformName = settings . platform . name ;
70-
71+ // return early if we're in the 'components' view.
7172 if ( environment . display === 'components' ) {
72- document . body . dataset . display = 'components' ;
73- return render (
74- < EnvironmentProvider debugState = { environment . debugState } injectName = { environment . injectName } willThrow = { environment . willThrow } >
75- < SettingsProvider settings = { settings } >
76- < TranslationProvider translationObject = { strings } fallback = { strings } textLength = { environment . textLength } >
77- < Components />
78- </ TranslationProvider >
79- </ SettingsProvider >
80- </ EnvironmentProvider > ,
81- root ,
82- ) ;
73+ return renderComponents ( root , environment , settings , strings ) ;
8374 }
8475
85- const entryPoints = await ( async ( ) => {
86- try {
87- const loaders = init . widgets . map ( ( widget ) => {
88- return widgetEntryPoint ( widget . id ) . then ( ( mod ) => [ widget . id , mod ] ) ;
89- } ) ;
90- const entryPoints = await Promise . all ( loaders ) ;
91- return Object . fromEntries ( entryPoints ) ;
92- } catch ( e ) {
93- const error = new Error ( 'Error loading widget entry points:' + e . message ) ;
94- didCatch ( error ) ;
95- console . error ( error ) ;
96- return { } ;
97- }
98- } ) ( ) ;
76+ // install global side effects that are not specific to any widget
77+ installGlobalSideEffects ( environment , settings ) ;
78+
79+ // Resolve the entry points for each selected widget
80+ const entryPoints = await resolveEntryPoints ( init . widgets , didCatch ) ;
81+
82+ // Create an instance of the global widget api
83+ const widgetConfigAPI = new WidgetConfigService ( messaging , init . widgetConfigs ) ;
9984
10085 render (
10186 < EnvironmentProvider
@@ -129,3 +114,70 @@ export async function init(messaging, telemetry, baseEnvironment) {
129114 root ,
130115 ) ;
131116}
117+
118+ /**
119+ * @param {Environment } environment
120+ */
121+ async function getStrings ( environment ) {
122+ return environment . locale === 'en'
123+ ? enStrings
124+ : await fetch ( `./locales/${ environment . locale } /new-tab.json` )
125+ . then ( ( x ) => x . json ( ) )
126+ . catch ( ( e ) => {
127+ console . error ( 'Could not load locale' , environment . locale , e ) ;
128+ return enStrings ;
129+ } ) ;
130+ }
131+
132+ /**
133+ * @param {Environment } environment
134+ * @param {Settings } settings
135+ */
136+ function installGlobalSideEffects ( environment , settings ) {
137+ document . body . dataset . platformName = settings . platform . name ;
138+ document . body . dataset . display = environment . display ;
139+ }
140+
141+ /**
142+ *
143+ * @param {import('../../../types/new-tab.js').InitialSetupResponse['widgets'] } widgets
144+ * @param {(e: {message:string}) => void } didCatch
145+ * @return {Promise<{[p: string]: any}|{}> }
146+ */
147+ async function resolveEntryPoints ( widgets , didCatch ) {
148+ try {
149+ const loaders = widgets . map ( ( widget ) => {
150+ return (
151+ widgetEntryPoint ( widget . id )
152+ // eslint-disable-next-line promise/prefer-await-to-then
153+ . then ( ( mod ) => [ widget . id , mod ] )
154+ ) ;
155+ } ) ;
156+ const entryPoints = await Promise . all ( loaders ) ;
157+ return Object . fromEntries ( entryPoints ) ;
158+ } catch ( e ) {
159+ const error = new Error ( 'Error loading widget entry points:' + e . message ) ;
160+ didCatch ( error ) ;
161+ console . error ( error ) ;
162+ return { } ;
163+ }
164+ }
165+
166+ /**
167+ * @param {Element } root
168+ * @param {Environment } environment
169+ * @param {Settings } settings
170+ * @param {Record<string, any> } strings
171+ */
172+ function renderComponents ( root , environment , settings , strings ) {
173+ render (
174+ < EnvironmentProvider debugState = { environment . debugState } injectName = { environment . injectName } willThrow = { environment . willThrow } >
175+ < SettingsProvider settings = { settings } >
176+ < TranslationProvider translationObject = { strings } fallback = { strings } textLength = { environment . textLength } >
177+ < Components />
178+ </ TranslationProvider >
179+ </ SettingsProvider >
180+ </ EnvironmentProvider > ,
181+ root ,
182+ ) ;
183+ }
0 commit comments