{"id":42998,"date":"2020-08-13T20:03:00","date_gmt":"2020-08-13T20:03:00","guid":{"rendered":"http:\/\/sticky-highjinx.flywheelsites.com\/?p=42998"},"modified":"2025-03-03T08:40:24","modified_gmt":"2025-03-03T13:40:24","slug":"lazy-load-components-and-services-in-spfx-part-one","status":"publish","type":"post","link":"https:\/\/envistacorp.com\/en-au\/2020\/08\/13\/lazy-load-components-and-services-in-spfx-part-one\/","title":{"rendered":"Lazy Load Components and Services in SPFX: Part One"},"content":{"rendered":"<span class=\"span-reading-time rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">Reading Time: <\/span> <span class=\"rt-time\"> 5<\/span> <span class=\"rt-label rt-postfix\">minutes<\/span><\/span>\n<h2 class=\"wp-block-heading\" id=\"h-load-react-components-and-services-on-demand-to-optimise-your-sharepoint-framework-web-parts-and-site-extensions\">Load React components and services on demand to optimise your SharePoint Framework web parts and site extensions.<\/h2>\n\n\n\n<p>When you build collaboration tools that can be reused and configured for different needs, chances are there are going to be bells and whistles that are&nbsp;not&nbsp;used in every instance. Along a similar line, resources may be required in an editing context, but not in a reading context. Does it make sense for end users to wait for code to load that they never get a chance to use? Intelligent&nbsp;lazy loading provides a mechanism to load-in components or services on demand and only when necessary.&nbsp;<\/p>\n\n\n\n<p>Not unique to SharePoint \u2014 in the greater sphere of modern JS development,\u00a0on-demand loading is called\u00a0<a href=\"https:\/\/webpack.js.org\/guides\/code-splitting\" target=\"_blank\" rel=\"noreferrer noopener\">code splitting<\/a>. The technique we utilize is called a\u00a0<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Statements\/import#Dynamic_Imports\" target=\"_blank\" rel=\"noreferrer noopener\">dynamic import<\/a>.\u00a0<\/p>\n\n\n\n<p>This last link to MDN docs on dynamic imports is really the gist of the technique. Read on for real-life examples of lazy loading React components and services. With any luck,&nbsp;this will inspire you to implement the feature in your apps, improving the quality of products you ship to your clients.&nbsp;<\/p>\n\n\n\t\t<div data-elementor-type=\"page\" data-elementor-id=\"53361\" class=\"elementor elementor-53361\" data-elementor-post-type=\"elementor_library\">\n\t\t\t\t\t\t<section class=\"has_eae_slider elementor-section elementor-top-section elementor-element elementor-element-b20eed2 elementor-section-stretched elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-eae-slider=\"77040\" data-id=\"b20eed2\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;stretch_section&quot;:&quot;section-stretched&quot;}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"aux-parallax-section has_eae_slider elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-a4da46b\" data-eae-slider=\"22140\" data-id=\"a4da46b\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<section class=\"has_eae_slider elementor-section elementor-inner-section elementor-element elementor-element-af85717 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-eae-slider=\"35755\" data-id=\"af85717\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"aux-parallax-section has_eae_slider elementor-column elementor-col-50 elementor-inner-column elementor-element elementor-element-94591d3\" data-eae-slider=\"30504\" data-id=\"94591d3\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-b3da8d1 elementor-grid-1 elementor-posts--align-left elementor-grid-tablet-1 elementor-grid-mobile-1 elementor-posts--thumbnail-top elementor-posts__hover-gradient elementor-widget elementor-widget-posts\" data-id=\"b3da8d1\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;cards_columns&quot;:&quot;1&quot;,&quot;cards_row_gap&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:0,&quot;sizes&quot;:[]},&quot;cards_columns_tablet&quot;:&quot;1&quot;,&quot;cards_columns_mobile&quot;:&quot;1&quot;,&quot;cards_row_gap_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;cards_row_gap_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}\" data-widget_type=\"posts.cards\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-posts-container elementor-posts elementor-posts--skin-cards elementor-grid\" role=\"list\">\n\t\t\t\t<article class=\"elementor-post elementor-grid-item post-100095 post type-post status-publish format-standard has-post-thumbnail hentry category-white-paper tag-dynamics-365 tag-microsoft\" role=\"listitem\">\n\t\t\t<div class=\"elementor-post__card\">\n\t\t\t\t<a class=\"elementor-post__thumbnail__link\" href=\"https:\/\/web.envistacorp.com\/hidden-treasures-advanced-warehousing\" tabindex=\"-1\" ><div class=\"elementor-post__thumbnail\"><img fetchpriority=\"high\" decoding=\"async\" width=\"768\" height=\"582\" src=\"https:\/\/envistacorp.com\/en-au\/wp-content\/uploads\/sites\/4\/2022\/10\/image-2025-04-09T153950.688-768x582.jpg\" class=\"attachment-medium_large size-medium_large wp-image-117516\" alt=\"A man in a white shirt stands in a warehouse, holding and reviewing a clipboard. Shelves filled with boxes line the space, and another person in a yellow vest is visible in the background.\" \/><\/div><\/a>\n\t\t\t\t<div class=\"elementor-post__text\">\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/article>\n\t\t\t\t<\/div>\n\t\t\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t<div class=\"aux-parallax-section has_eae_slider elementor-column elementor-col-50 elementor-inner-column elementor-element elementor-element-860af14\" data-eae-slider=\"30376\" data-id=\"860af14\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-32bfd00 elementor-grid-1 elementor-grid-tablet-1 elementor-grid-mobile-1 elementor-posts--thumbnail-top elementor-posts__hover-gradient elementor-widget elementor-widget-posts\" data-id=\"32bfd00\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;cards_columns&quot;:&quot;1&quot;,&quot;cards_row_gap&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:0,&quot;sizes&quot;:[]},&quot;cards_columns_tablet&quot;:&quot;1&quot;,&quot;cards_columns_mobile&quot;:&quot;1&quot;,&quot;cards_row_gap_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;cards_row_gap_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}\" data-widget_type=\"posts.cards\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-posts-container elementor-posts elementor-posts--skin-cards elementor-grid\" role=\"list\">\n\t\t\t\t<article class=\"elementor-post elementor-grid-item post-100095 post type-post status-publish format-standard has-post-thumbnail hentry category-white-paper tag-dynamics-365 tag-microsoft\" role=\"listitem\">\n\t\t\t<div class=\"elementor-post__card\">\n\t\t\t\t<a class=\"elementor-post__thumbnail__link\" href=\"https:\/\/web.envistacorp.com\/hidden-treasures-advanced-warehousing\" tabindex=\"-1\" target=\"_blank\"><div class=\"elementor-post__thumbnail\"><img decoding=\"async\" width=\"300\" height=\"300\" src=\"https:\/\/envistacorp.com\/en-au\/wp-content\/uploads\/sites\/4\/2022\/10\/image-2025-04-09T153950.688-300x300.jpg\" class=\"attachment-medium size-medium wp-image-117516\" alt=\"A man in a white shirt stands in a warehouse, holding and reviewing a clipboard. Shelves filled with boxes line the space, and another person in a yellow vest is visible in the background.\" srcset=\"https:\/\/envistacorp.com\/en-au\/wp-content\/uploads\/sites\/4\/2022\/10\/image-2025-04-09T153950.688-300x300.jpg 300w, https:\/\/envistacorp.com\/en-au\/wp-content\/uploads\/sites\/4\/2022\/10\/image-2025-04-09T153950.688-150x150.jpg 150w, https:\/\/envistacorp.com\/en-au\/wp-content\/uploads\/sites\/4\/2022\/10\/image-2025-04-09T153950.688-60x60.jpg 60w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/div><\/a>\n\t\t\t\t<div class=\"elementor-post__badge\">White Paper<\/div>\n\t\t\t\t<div class=\"elementor-post__text\">\n\t\t\t\t<h3 class=\"elementor-post__title\">\n\t\t\t<a href=\"https:\/\/web.envistacorp.com\/hidden-treasures-advanced-warehousing\" target=&quot;_blank&quot;>\n\t\t\t\tHidden Treasures of Advanced Warehousing\t\t\t<\/a>\n\t\t<\/h3>\n\t\t\t\t<div class=\"elementor-post__excerpt\">\n\t\t\t<p>Make the most of Microsoft Dynamics 365\u2019s Advanced Warehousing module and gain insight into the hidden treasures to unlock value.<\/p>\n\t\t<\/div>\n\t\t\n\t\t<a class=\"elementor-post__read-more\" href=\"https:\/\/web.envistacorp.com\/hidden-treasures-advanced-warehousing\" aria-label=\"Read more about Hidden Treasures of Advanced Warehousing\" tabindex=\"-1\" target=\"_blank\">\n\t\t\tDownload\t\t<\/a>\n\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/article>\n\t\t\t\t<\/div>\n\t\t\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>\n\t\t\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-laying-the-groundwork\">Laying the&nbsp;Groundwork&nbsp;<\/h2>\n\n\n\n<p>Normally, there would be tooling prerequisites (webpack\/babel\u00a0configuration, etc.) to consider. Thankfully, SharePoint manages the build-stack for us, so we can jump right to the code. Also, if you\u00a0are\u00a0reading this, chances are you already know how to spin up a new SharePoint Web Part or Site Extension with the\u00a0<a href=\"https:\/\/pnp.github.io\/generator-spfx\/\" target=\"_blank\" rel=\"noreferrer noopener\">SPFX yeoman generator<\/a>. Therefore,\u00a0we\u00a0will\u00a0omit that boilerplate and jump straight to a scenario involving React components.\u00a0<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-define-widget-interfaces\">Define&nbsp;Widget&nbsp;Interfaces&nbsp;<\/h2>\n\n\n\n<p>For our demo purposes, our web part displays rows of widgets. A basic widget shows text content and a link. Our web part, however, allows a content editor to add additional widget types such as &#8216;current weather&#8217; and &#8216;bot chat.&#8217;&nbsp;<\/p>\n\n\n\n<p>First, we&#8217;ll define interfaces to represent the required properties of each widget. A type&nbsp;enum&nbsp;will simplify type-checking&nbsp;later.&nbsp;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-iwidgets-ts\">IWidgets.ts:<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>export enum WidgetType { \n  text, \n  weather, \n  botChat \n}; \nexport interface IWidget { \n  heading: string; \n  type: WidgetType; \n} \nexport interface ITextWidget extends IWidget { \n  content: string; \n  url: string; \n} \nexport interface IWeatherWidget extends IWidget { \n   apiKey: string; \n} \nexport interface IBotChatWidget extends IWidget { \n  odataConfiguration: any; \n} <\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-provide-widgets-directly-to-react-component\">Provide&nbsp;Widgets&nbsp;Directly to React&nbsp;Component<\/h2>\n\n\n\n<p>An example set of widgets:&nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>const textWidget:ITextWidget { \n  heading: 'Get Involved', \n  type: WidgetType.text, \n  content: 'Discover how you can become more engaged with WidgetCo.', \n  url: '\/\/#get-involved', \n}; \nconst weatherWidget:IWeatherWidget = { \n  heading: 'Current Weather', \n  type: WidgetType.weather, \n  apiKey: '1234-abcd', \n}; \nconst chatBotWidget:IChatBotWidget = { \n  heading: 'Chat', \n  type: WidgetType.botChat,  \n  odataConfiguration: { \n    address: 'bot.chat\/endpoint', \n    \/\/ &#091;...] \n  } \n}; \nconst widgets:IWidget&#091;] = &#091; \n  textWidget, \n  weatherWidget, \n  chatBotWidget \n];  \n<\/code><\/pre>\n\n\n\n<p>Our example would be applicable when widgets are loaded in from a list, but for brevity&#8217;s sake, we&nbsp;will&nbsp;show widgets passed directly to the main React component as if defined in the property pane. The render function shows a beginning which we&nbsp;will&nbsp;update later to display each type of widget uniquely.&nbsp;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-widgetsdisplay-tsx\">WidgetsDisplay.tsx:&nbsp;<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>import * as React from 'react'; \nimport { IWidget } from '.\/IWidgets.ts'; \nexport interface IWidgetsDisplayProps { \n  widgets: IWidget&#091;]; \n} \nexport default class WidgetsDisplay extends React.Component&lt;IWidgetsDisplayProps, {}&gt; { \n  public render(): React.ReactElement&lt;IWidgetsDisplayProps&gt; { \n    const { widgets } = this.props; \n    return ( \n      &lt;div&gt; \n        {\/* show each widget *\/} \n        {widgets.map(item =&gt; ( \n          &lt;div&gt;\n            &lt;h3&gt;{widget.heading}&lt;\/h3&gt; \n          &lt;\/div&gt; \n        )} \n      &lt;\/div&gt; \n    ); \n  } \n} \n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-defining-widget-components\">Defining&nbsp;Widget&nbsp;Components&nbsp;<\/h2>\n\n\n\n<p>It&nbsp;is&nbsp;a standard convention to use separate files for different components, but it&nbsp;is especially important here since we plan to dynamically import these&nbsp;later. Additionally, any interfaces that describe the component properties should be separated from the component files. That way, a client can use&nbsp;strongly typed&nbsp;properties without loading the components themselves.&nbsp;<\/p>\n\n\n\n<p>Our text widget is a standard functional or state-less component.&nbsp;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-textwidget-tsx\"><strong>TextWidget.tsx<\/strong>:&nbsp;<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>import * as React from 'react';\nimport { ITextWidget } from '.\/IWidgets.ts';\nexport const TextWidget = ({\n  heading,\n  content,\n  url,\n}) =&gt; {\n  return (\n    &lt;div&gt;\n        &lt;h3&gt;{heading}&lt;\/h3&gt;\n        &lt;p&gt;{content}&lt;\/p&gt;\n        &lt;a href={url}&gt;Read more&lt;\/a&gt;\n    &lt;\/div&gt;\n  );\n};\nexport default TextWidget;\n<\/code><\/pre>\n\n\n\n<p>Our weather widget will load in weather data when mounted. It&#8217;s important to note that so far we&nbsp;have&nbsp;avoided external libraries;&nbsp;however, in&nbsp;WeatherWidget,&nbsp;we import a component from&nbsp;<a href=\"https:\/\/developer.microsoft.com\/en-us\/fluentui#\/\" target=\"_blank\" rel=\"noreferrer noopener\">fluent&nbsp;ui<\/a>. Without asynchronous loading, code we import into a component (i.e.,&nbsp;a fluent&nbsp;ui&nbsp;package) would be included in the code bundle which is loaded by the end user.&nbsp;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-weatherwidget-tsx\">WeatherWidget.tsx:&nbsp;<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>import * as React from 'react';\nimport { Icon } from '@fluentui\/react\/lib\/Icon';\nimport { IWeatherWidget }  from '.\/IWidgets.ts';\nexport interface IWeatherWidgetState {\n  isLoading?: boolean;\n  weatherData?: {\n    temp: number;\n    icon: string;\n  }\n}\nexport default class WeatherWidget extends React.Component&lt;IWeatherWidget, IWeatherWidgetState&gt; {\n  constructor(props) {\n    super(props);\n    this.state = {\n      isLoading: false,\n      weatherData: null\n    };\n  }\n  public componentDidMount() {\n    this.setState({ isLoading: true });\n    \/\/ load data from weather api\n    const { apiKey } = this.props;\n    setTimeout(() =&gt; {\n      this.setState({\n        isLoading: false,\n        weatherData: {\n          temp: 77,\n          icon: cloudy-sun\n        }\n      });\n    }, 2000);\n  }\n\n  public render(): React.ReactElement&lt;IWeatherWidget&gt; {\n    const {\n        heading,\n      } = this.props,\n      {\n        weatherData,\n        isLoading\n      } = this.state;\n    return (\n      &lt;div&gt;\n         &lt;h3&gt;{heading}&lt;\/h3&gt;\n         {isLoading &amp;&amp; &lt;p&gt;Loading...&lt;\/p&gt;}\n         {!!weatherData &amp;&amp; (\n           &lt;div&gt;\n             &lt;Icon iconName={icon} \/&gt;\n             &lt;strong&gt;{temp}\u00b0&lt;\/strong&gt;\n           &lt;\/div&gt;\n        )}\n      &lt;\/div&gt;\n    );\n  }\n}\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-lazy-loading-a-service-into-a-component\">Lazy&nbsp;Loading a&nbsp;Service into a&nbsp;Component&nbsp;<\/h2>\n\n\n\n<p>Our chat bot will incorporate a slightly different scenario. We&#8217;ll imagine that the service that powers our chat bot is rather bulky. Since we do&nbsp;not technically need it until the user interacts with the widget, we&nbsp;will&nbsp;wait&nbsp;until&nbsp;then to asynchronously load the service.&nbsp;<\/p>\n\n\n\n<p>Defining an interface for our&nbsp;service&nbsp;allows us to programme to an interface instead of an instance \u2014 crucial for maintaining strongly-typed code when using dynamic imports.&nbsp;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-ichatbotservice-ts\">IChatBotService.ts:&nbsp;<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>export default interface IChatBotService {\n  odataConfiguration: any;\n  postMessage(message:string) =&gt; Promise&lt;string&gt;;\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-chatbotservice-ts\">ChatBotService.ts:&nbsp;<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>Import iChatBotService from '.\/IChatBotService';\nexport class ChatBotService implements IChatBotService {\n  constructor(public odataConfiguration: any) {}\n  postMessage(message:string): Promise&lt;string&gt; {\n    return new Promise((resolve)=&gt; {\n      setTimeout(() =&gt; {\n        resolve('Ask again later.');\n      }, 2000);\n    });\n  }\n}\n<\/code><\/pre>\n\n\n\n<p>A true bot chat implementation would be&nbsp;lengthier, but this gets the idea across.&nbsp;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-chatbotwidget-tsx\">ChatBotWidget.tsx:&nbsp;<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>import * as React from 'react';\nimport { IChatBotWidget } from '.\/IChatBotWidget.ts';\nimport { DefaultButton } from '@fluentui\/react\/lib\/Button';\nexport interface IChatBotWidgetState {\n  isLoading?: boolean;\n  message?: string;\n  visible?: boolean;\n}\nexport default class ChatBotWidget extends React.Component&lt;IChatBotWidget, IChatBotWidgetState&gt; {\n  private ChatBotService:IChatBotService;\n  constructor(props) {\n    super(props);\n    this.state = {\n      isLoading: false,\n      message: '',\n      visible: false,\n    };\n  }\n\n  public render(): React.ReactElement&lt;IChatBotWidget&gt; {\n    const {\n      isLoading,\n      message,\n      visible,\n    } = this.state;\n    return (\n      &lt;div&gt;\n        &lt;h3&gt;{heading}&lt;\/h3&gt;\n        &lt;DefaultButton onClick={this.toggleDialog}&gt;{!visible ? 'Ask a question' : 'Cancel'}&lt;\/DefaultButton&gt;\n        {isLoading &amp;&amp; &lt;p&gt;...&lt;\/p&gt;}\n        {visible &amp;&amp; (\n          &lt;div&gt;\n            &lt;TextField\n              onChange={(ev, newValue) =&gt; { this.setState({ message: newValue }); }\n              value={message}\n            \/&gt;\n            &lt;DefaultButton onClick={this.postMessage} \/&gt;\n          &lt;\/div&gt;\n        })\n      &lt;\/div&gt;\n    );\n  }\n\n  private toggleDialog = async () =&gt; {\n    if (!this.ChatBotService) {\n      const { odataConfiguration } = this.props;\n      const imported = await import('.\/ChatBotService.ts');\n      this.ChatBotService = new imported.default(odataConfiguration);\n    }\n    this.setState({ visible: !this.state.visible });\n  }\n\n  private postMessage = async () =&gt; {\n    const response = await this.ChatBotService.postMessage(this.state.message);\n    alert(response);\n  }\n}\n<\/code><\/pre>\n\n\n\n<p>You may have missed the dynamic import as it&nbsp;is only a few lines of code. We waited until the appropriate interaction, aka clicking the &#8216;Ask a question&#8217; button. At that point,&nbsp;we checked for the presence for our service (useful if the user may repeat this interaction). If not initialized, we use the `await import(&#8216;name&#8217;)`&nbsp;syntax to&nbsp;lazy load&nbsp;our service. It&nbsp;is important to refer to `.default` of our imported results \u2014 this shape will be consistent for any dynamically imported module.&nbsp;<\/p>\n\n\n\n<p>A service that&nbsp;is only required after user interaction is a great candidate for&nbsp;lazy loading. By importing our&nbsp;ChatBotService&nbsp;dynamically,&nbsp;we&nbsp;have split our code into separate bundle files: one for the&nbsp;ChatBotService&nbsp;and one for everything else. When we publish our&nbsp;sppkg&nbsp;file to SharePoint,&nbsp;each bundle file will be uploaded;&nbsp;however,&nbsp;the bundle associated with our service will be loaded on demand.&nbsp;<\/p>\n\n\n\n<p>In our next blog, we will&nbsp;implement&nbsp;lazy loading for React components.&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Load React components and services on demand to optimise your SharePoint Framework web parts and site extensions.<\/p>\n","protected":false},"author":22,"featured_media":46178,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"content-type":"","_searchwp_excluded":"","footnotes":"","_links_to":"","_links_to_target":""},"categories":[3475],"tags":[3746,3561,3938],"class_list":["post-42998","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog","tag-dynamics-365","tag-microsoft","tag-project-operations"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.2 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Lazy Load Components in SPFx \u2013 Part 1 | enVista<\/title>\n<meta name=\"description\" content=\"Load React components and services on demand to optimise your SharePoint Framework web parts and site extensions.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/envistacorp.com\/en-au\/2020\/08\/13\/lazy-load-components-and-services-in-spfx-part-one\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Lazy Load Components in SPFx \u2013 Part 1 | enVista\" \/>\n<meta property=\"og:description\" content=\"Load React components and services on demand to optimise your SharePoint Framework web parts and site extensions.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/envistacorp.com\/en-au\/2020\/08\/13\/lazy-load-components-and-services-in-spfx-part-one\/\" \/>\n<meta property=\"og:site_name\" content=\"enVista Australia\" \/>\n<meta property=\"article:published_time\" content=\"2020-08-13T20:03:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-03-03T13:40:24+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/envistacorp.com\/en-au\/wp-content\/uploads\/sites\/4\/2020\/08\/shutterstock_357486680-scaled.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"2560\" \/>\n\t<meta property=\"og:image:height\" content=\"1707\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"enVista Marketing\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"enVista Marketing\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"4 minutes\" \/>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Lazy Load Components in SPFx \u2013 Part 1 | enVista","description":"Load React components and services on demand to optimise your SharePoint Framework web parts and site extensions.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/envistacorp.com\/en-au\/2020\/08\/13\/lazy-load-components-and-services-in-spfx-part-one\/","og_locale":"en_US","og_type":"article","og_title":"Lazy Load Components in SPFx \u2013 Part 1 | enVista","og_description":"Load React components and services on demand to optimise your SharePoint Framework web parts and site extensions.","og_url":"https:\/\/envistacorp.com\/en-au\/2020\/08\/13\/lazy-load-components-and-services-in-spfx-part-one\/","og_site_name":"enVista Australia","article_published_time":"2020-08-13T20:03:00+00:00","article_modified_time":"2025-03-03T13:40:24+00:00","og_image":[{"width":2560,"height":1707,"url":"https:\/\/envistacorp.com\/en-au\/wp-content\/uploads\/sites\/4\/2020\/08\/shutterstock_357486680-scaled.jpg","type":"image\/jpeg"}],"author":"enVista Marketing","twitter_card":"summary_large_image","twitter_misc":{"Written by":"enVista Marketing","Est. reading time":"4 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/envistacorp.com\/en-au\/2020\/08\/13\/lazy-load-components-and-services-in-spfx-part-one\/#article","isPartOf":{"@id":"https:\/\/envistacorp.com\/en-au\/2020\/08\/13\/lazy-load-components-and-services-in-spfx-part-one\/"},"author":{"name":"enVista Marketing","@id":"https:\/\/envistacorp.com\/en-au\/#\/schema\/person\/c938d19b1c760a4e1c353086018cb894"},"headline":"Lazy Load Components and Services in SPFX: Part One","datePublished":"2020-08-13T20:03:00+00:00","dateModified":"2025-03-03T13:40:24+00:00","mainEntityOfPage":{"@id":"https:\/\/envistacorp.com\/en-au\/2020\/08\/13\/lazy-load-components-and-services-in-spfx-part-one\/"},"wordCount":886,"commentCount":0,"publisher":{"@id":"https:\/\/envistacorp.com\/en-au\/#organization"},"image":{"@id":"https:\/\/envistacorp.com\/en-au\/2020\/08\/13\/lazy-load-components-and-services-in-spfx-part-one\/#primaryimage"},"thumbnailUrl":"https:\/\/envistacorp.com\/en-au\/wp-content\/uploads\/sites\/4\/2020\/08\/shutterstock_357486680-scaled.jpg","keywords":["Dynamics 365","Microsoft","Project Operations"],"articleSection":["Blog"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/envistacorp.com\/en-au\/2020\/08\/13\/lazy-load-components-and-services-in-spfx-part-one\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/envistacorp.com\/en-au\/2020\/08\/13\/lazy-load-components-and-services-in-spfx-part-one\/","url":"https:\/\/envistacorp.com\/en-au\/2020\/08\/13\/lazy-load-components-and-services-in-spfx-part-one\/","name":"Lazy Load Components in SPFx \u2013 Part 1 | enVista","isPartOf":{"@id":"https:\/\/envistacorp.com\/en-au\/#website"},"primaryImageOfPage":{"@id":"https:\/\/envistacorp.com\/en-au\/2020\/08\/13\/lazy-load-components-and-services-in-spfx-part-one\/#primaryimage"},"image":{"@id":"https:\/\/envistacorp.com\/en-au\/2020\/08\/13\/lazy-load-components-and-services-in-spfx-part-one\/#primaryimage"},"thumbnailUrl":"https:\/\/envistacorp.com\/en-au\/wp-content\/uploads\/sites\/4\/2020\/08\/shutterstock_357486680-scaled.jpg","datePublished":"2020-08-13T20:03:00+00:00","dateModified":"2025-03-03T13:40:24+00:00","description":"Load React components and services on demand to optimise your SharePoint Framework web parts and site extensions.","breadcrumb":{"@id":"https:\/\/envistacorp.com\/en-au\/2020\/08\/13\/lazy-load-components-and-services-in-spfx-part-one\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/envistacorp.com\/en-au\/2020\/08\/13\/lazy-load-components-and-services-in-spfx-part-one\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/envistacorp.com\/en-au\/2020\/08\/13\/lazy-load-components-and-services-in-spfx-part-one\/#primaryimage","url":"https:\/\/envistacorp.com\/en-au\/wp-content\/uploads\/sites\/4\/2020\/08\/shutterstock_357486680-scaled.jpg","contentUrl":"https:\/\/envistacorp.com\/en-au\/wp-content\/uploads\/sites\/4\/2020\/08\/shutterstock_357486680-scaled.jpg","width":2560,"height":1707,"caption":"A person types on a laptop at a wooden desk, with data charts and graphs digitally overlaid above the screen, suggesting analysis or business activity. Sunlight shines on the right side of the workspace."},{"@type":"BreadcrumbList","@id":"https:\/\/envistacorp.com\/en-au\/2020\/08\/13\/lazy-load-components-and-services-in-spfx-part-one\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/envistacorp.com\/en-au\/"},{"@type":"ListItem","position":2,"name":"Lazy Load Components and Services in SPFX: Part One"}]},{"@type":"WebSite","@id":"https:\/\/envistacorp.com\/en-au\/#website","url":"https:\/\/envistacorp.com\/en-au\/","name":"enVista Australia","description":"Enabling Enterprise Commerce","publisher":{"@id":"https:\/\/envistacorp.com\/en-au\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/envistacorp.com\/en-au\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/envistacorp.com\/en-au\/#organization","name":"enVista Australia","url":"https:\/\/envistacorp.com\/en-au\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/envistacorp.com\/en-au\/#\/schema\/logo\/image\/","url":"https:\/\/envistacorp.com\/en-au\/wp-content\/uploads\/sites\/4\/2021\/10\/enVista_Logo_White-1.png","contentUrl":"https:\/\/envistacorp.com\/en-au\/wp-content\/uploads\/sites\/4\/2021\/10\/enVista_Logo_White-1.png","width":348,"height":152,"caption":"enVista Australia"},"image":{"@id":"https:\/\/envistacorp.com\/en-au\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/envistacorp.com\/en-au\/#\/schema\/person\/c938d19b1c760a4e1c353086018cb894","name":"enVista Marketing","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/908735372279b00297ea13e45a4947cdb05e2ee7244abfcfb3ea9d263679fa53?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/908735372279b00297ea13e45a4947cdb05e2ee7244abfcfb3ea9d263679fa53?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/908735372279b00297ea13e45a4947cdb05e2ee7244abfcfb3ea9d263679fa53?s=96&d=mm&r=g","caption":"enVista Marketing"},"description":"enVista was founded by supply chain and technology experts in response to market demand for skilled consulting services. Read posts by our Thought Leaders.","url":"https:\/\/envistacorp.com\/en-au\/author\/envistamarketing\/"}]}},"_links":{"self":[{"href":"https:\/\/envistacorp.com\/en-au\/wp-json\/wp\/v2\/posts\/42998","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/envistacorp.com\/en-au\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/envistacorp.com\/en-au\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/envistacorp.com\/en-au\/wp-json\/wp\/v2\/users\/22"}],"replies":[{"embeddable":true,"href":"https:\/\/envistacorp.com\/en-au\/wp-json\/wp\/v2\/comments?post=42998"}],"version-history":[{"count":0,"href":"https:\/\/envistacorp.com\/en-au\/wp-json\/wp\/v2\/posts\/42998\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/envistacorp.com\/en-au\/wp-json\/wp\/v2\/media\/46178"}],"wp:attachment":[{"href":"https:\/\/envistacorp.com\/en-au\/wp-json\/wp\/v2\/media?parent=42998"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/envistacorp.com\/en-au\/wp-json\/wp\/v2\/categories?post=42998"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/envistacorp.com\/en-au\/wp-json\/wp\/v2\/tags?post=42998"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}