<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sam Kirkpatrick</title>
    <description>The latest articles on DEV Community by Sam Kirkpatrick (@iamsamk).</description>
    <link>https://dev.to/iamsamk</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F736524%2Fee47ef2e-0f23-4ede-8c73-35d89609a739.jpeg</url>
      <title>DEV Community: Sam Kirkpatrick</title>
      <link>https://dev.to/iamsamk</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/iamsamk"/>
    <language>en</language>
    <item>
      <title>Azure DevOps Pipeline Caching</title>
      <dc:creator>Sam Kirkpatrick</dc:creator>
      <pubDate>Tue, 01 Mar 2022 22:32:23 +0000</pubDate>
      <link>https://dev.to/iamsamk/azure-devops-pipeline-caching-50oc</link>
      <guid>https://dev.to/iamsamk/azure-devops-pipeline-caching-50oc</guid>
      <description>&lt;p&gt;If you're an Azure-DevOps-using organisation, pipelines are obviously key to an effective CI/CD strategy. And there's a skill to getting the steps right for your context. Some tasks you still need to do every single time, even though the contents might not change (much) between builds.&lt;/p&gt;

&lt;p&gt;We build .NET solutions which often have framework-based front-ends (or at least some form of front-end packaging process). So we've always got NuGet references and &lt;code&gt;node_modules&lt;/code&gt; folders. It's a rare thing that these change between runs of a pipeline, but it can happen, so we need to fetch updates or run &lt;code&gt;npm install&lt;/code&gt; each time. &lt;/p&gt;

&lt;p&gt;Within pipelines, these steps can occasionally take quite some time - possibly several minutes depending on the agent count and capability, size of the payloads or the number of packages/references you have. And it really starts to be come a factor if you're running multiple pipelines for multiple projects simultaneously throughout the day.&lt;/p&gt;

&lt;p&gt;Alas, "Cache" tasks to the rescue... &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv1ehv6hkv34jq5tsl7id.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv1ehv6hkv34jq5tsl7id.png" alt="Screenshot of the Cache task in a pipeline set-up wizard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cache tasks allow you to store blobs based on a key. Adding a cache step to your pipeline will check against the key and set a variable indicating whether there has been a hit or not. If there is a cache hit, the blob will be downloaded to the pipeline working directory and the value of the hit variable can be used a condition on running later steps in the pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Worked Example - &lt;code&gt;node_modules&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Let's work through how exactly we use Cache steps for a NodeJS build (which would ordinarily create a &lt;code&gt;node_modules&lt;/code&gt; folder). Since, during the development of our application, we may add new dependencies, we do need to run the &lt;code&gt;npm install&lt;/code&gt; command on each execution of the pipeline.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Take a pipeline with a traditional "npm install" step. 
&lt;/li&gt;
&lt;li&gt;Add a new "Cache" task above that step, and fill it in something like this:

&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyzq3ytd6cfx91uz6wjkf.png" alt="A completed sample Cache step"&gt;

This initialises a compound cache key containing the static string "npm", the Agent OS name and the unique hash of the "package-lock.json" file and tells Azure to store the contents of the specified "node_modules" folder as the blob attached to the cache key.

&lt;/li&gt;
&lt;li&gt;Modify the "Control Options" of the "npm install" task to use the cache hit variable value defined above.

&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy21ap01qw4tebuydast6.png" alt="npm install step conditions"&gt; 

This tells Azure to only run this step if the "NodeJsApp" cache hit variable is not equal to 'true' (i.e. a cache miss).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And, um, that's it.&lt;/p&gt;

&lt;p&gt;On first run, the pipeline logs will get a cache miss and run the "npm install". &lt;strong&gt;&lt;em&gt;At the end of the pipeline&lt;/em&gt;&lt;/strong&gt;, the referenced cache blobs will be automatically uploaded to storage. On subsequent runs of the pipeline (provided the scope criteria match), the matching blob will be downloaded and the "npm install" step will be skipped entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some Points of Note
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Azure uses generalised and self-managed blob storage for cache entries. You have no control nor ability to configure where exactly your cache goes, nor to easily access it manually.&lt;/li&gt;
&lt;li&gt;Cache blobs are stored in a scope - essentially mapping to a branch. So if you're working on a development branch which triggers the pipeline with each commit, your first run will create the cache blob and all subsequent runs (provided they don't alter the key) will re-use that blob.&lt;/li&gt;
&lt;li&gt;The size of your blob can be a factor in whether or not caching is actually useful. If it takes as long (or potentially longer) to download the cached blob to your build agent as it does to run the command, you've a dilemma. Well, not really - you choose whichever option is faster in a given content.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Cache Effectiveness
&lt;/h2&gt;

&lt;p&gt;The original driver for looking into this was an attempt to reduce build times for pipelines with NuGet or Node steps which took significant chunks of time and were run often. On one project we've applied this to, a pipeline with two distinct "npm install" steps has gone from those steps taking an average of over 7mins per run to approximately 2mins per run.&lt;/p&gt;

&lt;p&gt;Given the following legend:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwzdia1db6umcdxor9bns.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwzdia1db6umcdxor9bns.png" alt="Pipeline legend"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;...can you spot when we might have enabled the caching of these 2 steps?&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fneo2vjf4i81on64hltyq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fneo2vjf4i81on64hltyq.png" alt="Pipeline run history"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A thoroughly useful technique for speeding up the execution of pipelines with required but potentially time consuming steps. Just take note to get the cache key correct and don't fall foul of creating a blob larger than the payload required to run the command afresh on each execution.&lt;/p&gt;

</description>
      <category>azure</category>
      <category>devops</category>
      <category>pipelines</category>
    </item>
    <item>
      <title>Adding React to an Optimizely UI - Part 2</title>
      <dc:creator>Sam Kirkpatrick</dc:creator>
      <pubDate>Fri, 19 Nov 2021 13:52:04 +0000</pubDate>
      <link>https://dev.to/iamsamk/adding-react-to-an-optimizely-ui-part-2-n37</link>
      <guid>https://dev.to/iamsamk/adding-react-to-an-optimizely-ui-part-2-n37</guid>
      <description>&lt;p&gt;In &lt;a href="https://dev.to/skmte/adding-react-to-an-optimizely-ui-part-1-31kh"&gt;Part 1 of this series&lt;/a&gt;, I gave a start-to-finish overview of how we at &lt;a href="https://unrvld.com"&gt;UNRVLD&lt;/a&gt; integrated a React application into an Optimizely ASP.NET MVC website.&lt;/p&gt;

&lt;p&gt;I'd like to delve into several aspects of the process in more detail over the next few parts, starting with the choice of React itself and the specifics of how we actually implemented it, given there were (as there always is with anything front-end...) several options.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a Front-End Framework?
&lt;/h2&gt;

&lt;p&gt;JavaScript is easily the most flexible way of implementing a performant, user-centric experience in a browser. Your HTML gives you structure, CSS makes it pretty and JavaScript manipulates it as necessary. &lt;/p&gt;

&lt;p&gt;At some point, the amount of JavaScript code increases and the amount of manipulation required - even with the help of some still very popular libraries... &lt;strong&gt;cough...&lt;small&gt;jQuery&lt;/small&gt;...cough&lt;/strong&gt; - reaches the point of being unmanageable and unsustainable. FE frameworks have, in recent years, really risen to address these limitations. &lt;/p&gt;

&lt;p&gt;Taking on a project to do exactly what these frameworks are designed to do really meant it was a no-brainer to go with one.&lt;/p&gt;

&lt;h2&gt;
  
  
  But which one?
&lt;/h2&gt;

&lt;p&gt;The decision of which front-end framework to build on given a reasonably blank slate is always a challenging one. The stereotype of the front-end development landscape changing every 15 minutes is not entirely undeserved - the choices are, indeed, ever more numerous.&lt;/p&gt;

&lt;p&gt;But the big name players are still &lt;a href="https://reactjs.org/"&gt;React&lt;/a&gt;, &lt;a href="https://angular.io/"&gt;Angular&lt;/a&gt; and &lt;a href="https://vuejs.org/"&gt;Vue&lt;/a&gt;, in my opinion (and I fully confess there was a lot of my opinion in the decision phase here!). Other noteworthy candidates were &lt;a href="https://nextjs.org/"&gt;Next.JS&lt;/a&gt; and &lt;a href="https://svelte.dev/"&gt;Svelte&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;However, for reasons including (but not limited to):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In-house developer experience&lt;/li&gt;
&lt;li&gt;Learning curve&lt;/li&gt;
&lt;li&gt;Community support and documentation&lt;/li&gt;
&lt;li&gt;Training availability&lt;/li&gt;
&lt;li&gt;Package library diversity&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;...we chose React. &lt;/p&gt;

&lt;p&gt;And then we added &lt;a href="https://www.typescriptlang.org"&gt;TypeScript&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;As I mentioned in Part 1, I've been someone who was - despite my years of experience and interest in new development tools - actively resistant to adopting TypeScript. But I'm willing to admit I was mistaken. It has definitely grown on me. &lt;/p&gt;

&lt;p&gt;The supporting tools in IDEs like VS Code are really excellent and the assistance you get when developing actually does help significantly. I can't see us starting any significant piece of JS development in the future without using TypeScript.&lt;/p&gt;

&lt;p&gt;I have no doubt that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;perfectly valid arguments could have been made for using a number of other frameworks&lt;/li&gt;
&lt;li&gt;we would have successfully produced a solution using any one of those number of other frameworks&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But React it would be for us for now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrating with .NET
&lt;/h2&gt;

&lt;p&gt;Since we remain somewhat constrained by a traditional MVC architecture and a UI rendered using Razor views, we needed a way to integrate the React app into the site.&lt;/p&gt;

&lt;p&gt;One potential option would have been to use &lt;a href="https://reactjs.net/"&gt;ReactJS.NET&lt;/a&gt; - a platform almost specifically built to do what we were trying to do. But the coupling of Razor and React required by this tool just felt "wrong", and would have left us inseparably tied to React (&lt;a href="https://world.optimizely.com/forum/developer-forum/Developer-to-developer/Thread-Container/2020/5/using-reactjs-net-is-dxp/#222699"&gt;a view also expressed by the Optimizely team themselves&lt;/a&gt;). Given our "proof of concept" stage, maintaining the ability to swap out one framework for another one in the (unlikely-but-you-just-never-know) event of reaching an insurmountable road block was important.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;create-react-app&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The de-facto standard when starting a new React application is to open a terminal and run &lt;code&gt;npx create-react-app&lt;/code&gt;. Again, we decided against this. Whilst this app does indeed give you absolutely everything you need to create, build and deploy a React application, it includes a bulk load of features that we didn't expect to need and we weren't creating a Single Page Application (SPA) - something &lt;code&gt;create-react-app&lt;/code&gt; is very much angled towards.&lt;/p&gt;

&lt;p&gt;Our app was going to be a fully built-by-hand endeavour. Starting with a brand new working folder and &lt;code&gt;npm init&lt;/code&gt; and a &lt;code&gt;src/index.tsx&lt;/code&gt;, off we went.&lt;/p&gt;

</description>
      <category>react</category>
      <category>optimizely</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Adding React to an Optimizely UI - Part 1</title>
      <dc:creator>Sam Kirkpatrick</dc:creator>
      <pubDate>Fri, 05 Nov 2021 14:19:37 +0000</pubDate>
      <link>https://dev.to/iamsamk/adding-react-to-an-optimizely-ui-part-1-31kh</link>
      <guid>https://dev.to/iamsamk/adding-react-to-an-optimizely-ui-part-1-31kh</guid>
      <description>&lt;p&gt;At &lt;a href="https://unrvld.com"&gt;UNRVLD&lt;/a&gt;, we build solutions on a number of DXP platforms, including the &lt;a href="https://www.optimizely.com"&gt;Optimizely Content and Commerce platforms&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;We have a significant number of clients using Optimizely Content up to v11 and we've been considering how we might be able to deliver some of the more complex and heavily interactive user journeys our clients need by leveraging modern front-end frameworks. In this post, I want to walk you through how we've recently architected the introduction of React to part of the site for one of our largest e-commerce partners.&lt;/p&gt;

&lt;p&gt;This is the first part of a series looking at how we approached this challenge as an organization in which I'll summarize the technologies and solutions. In subsequent parts, I'll break down some of the key aspects in more technical detail - keep an eye out for these over the coming weeks.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's the motivation?
&lt;/h2&gt;

&lt;p&gt;Front-end frameworks are obviously becoming huge in terms of developing web solutions and user interfaces. With Optimizely Cloud being built on a server-based ASP.NET MVC architecture, there's a challenge to leveraging some JavaScript tools.&lt;/p&gt;

&lt;p&gt;But user expectations are growing ever higher. Performance, personalization and quality experiences are essential for any site and significant improvements in these areas can have huge impact on conversions in an e-commerce context. As an agency, we have the design and UX expertise to know what works in these areas and this exercise was about how to implement those ideas technically.&lt;/p&gt;

&lt;h2&gt;
  
  
  What would we need?
&lt;/h2&gt;

&lt;p&gt;So how would we inject a React app with all its dependencies on CMS content and configuration into the existing site and have it render on-screen? &lt;/p&gt;

&lt;p&gt;We would need:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The React application itself&lt;/li&gt;
&lt;li&gt;A placeholder within the Razor views of the MVC site in which to inject the React code&lt;/li&gt;
&lt;li&gt;A mechanism to provide the required data to the React app&lt;/li&gt;
&lt;li&gt;Support for server-side rendering (SSR)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I'll go into the thought processes (e.g., why React?) and structure of these individual items in further posts throughout this series.&lt;/p&gt;

&lt;h2&gt;
  
  
  The React App
&lt;/h2&gt;

&lt;p&gt;Items 1 and 2 were intrinsically tied. We had to have a React app and then confirm that we could get it to render in the context of using Razor views. On the surface, this seems pretty trivial - you just need some JS files declared as a bundle and included in your Razor! But this was key to deciding if the approach would work long-term, so we had to prove it as a concept.&lt;/p&gt;

&lt;p&gt;We also had to decide whether or not to use TypeScript. With 20+ years of writing JavaScript under my belt, I've been a slightly hesitant adopter of TypeScript, but it honestly feels like starting any significant JS development project nowadays without it is churlish. TypeScript it was - more on that in a later post.&lt;/p&gt;

&lt;p&gt;We created a very simple app initially to ensure it could be embedded into the site as we wanted. Since "create-react-app" generally focuses on SPAs and includes a lot of features we didn't expect to need, we decided against it but instead hand-crafted the packages and files we needed.&lt;/p&gt;

&lt;p&gt;For context, our first &lt;code&gt;index.tsx&lt;/code&gt; app looked something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ReactDOM&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;,&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using Webpack, we built this to an existing folder within the .NET web application to make it easily referenceable using the following partial config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/index.tsx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[name].js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../static&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;extensions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.tsx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We quickly reached a point of having a compiled JavaScript file that we could reference in our Optimizely Content site.&lt;/p&gt;

&lt;h2&gt;
  
  
  Razor Placeholder
&lt;/h2&gt;

&lt;p&gt;The next task was to add something to the Razor views to get the app to appear on screen, leading us to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"react-app"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
@Html.VersionedJs("~/static/react-app.js")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With a quick &lt;code&gt;npm run build&lt;/code&gt; of our React app and a spin-up of the Optimizely MVC site, we browsed to the necessary address. Et voilà! A React app rendered inside an Optimizely view.&lt;/p&gt;

&lt;h2&gt;
  
  
  Injecting Data (Populating State)
&lt;/h2&gt;

&lt;p&gt;The most important element of making this work was ensuring that the React app had the required data. This would obviously be built and prepared by the back-end C#, but how best to get it into the app? Really, it comes down to one of two options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Render the data in some way on the page (e.g. hidden field) and consume it within your React start-up.&lt;/li&gt;
&lt;li&gt;Mount the React app and trigger an immediate callback to fetch the data.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The trade offs here are about performance and user perception of speed. We went for the former initially, purely because a lot of the work to build the data was done on page load behind the scenes, so it didn't really make sense to get a blank, placeholder UI on screen before then re-requesting much of the already built data. We may review that over time as our app grows.&lt;/p&gt;

&lt;p&gt;Using &lt;a href="https://redux.js.org/"&gt;Redux&lt;/a&gt; for state management (which will be important in the SSR section below), our app instantiation code expanded to look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ReactDOM&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Provider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-redux&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;initStore&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./redux/store&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dataBlob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;initial-state&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;HTMLElement&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;storeData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dataBlob&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;initStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;storeData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Provider&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Provider&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Server Side Rendering
&lt;/h2&gt;

&lt;p&gt;Given this React app was being included in a major e-commerce solution with significant SEO foundations already in place, it became clear we would need to implement server-side rendering (SSR) of our React app to maintain those high scores and visibility. This was definitely one of the more interesting aspects of the overall project and will be covered in detail in a later post - it turned into a very expansive aspect, too!&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;So, that's the overview - a proof of concept idea to include a significant, standalone React element in a long-established ASP.NET MVC application, with state management and SSR to support continued SEO efforts, taken through to a production-quality implementation.&lt;/p&gt;

&lt;p&gt;In the rest of the series, I'll go into more detail about the different parts of the solution and hopefully be able to share something of how the changes have been received by our client and their customers once released.&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>optimizely</category>
    </item>
  </channel>
</rss>
