Tuesday, August 15, 2023


Azure Blob Storage is an essential component for many businesses, offering scalable and secure storage for documents, images, and other types of data. But providing secure access to these blobs can be challenging. That's where Shared Access Signatures (SAS) come into play.

What is a Shared Access Signature (SAS)?

A Shared Access Signature (SAS) is a URI that grants restricted access rights to Azure Storage resources. With SAS, you can provide clients with access to data without sharing your account keys.

Breaking Down the SAS Token Generator:

1. Setting Up:

The function starts by parsing the storage account connection string to get a reference to the storage account. With this, it sets up the blob client and gets a reference to the blob container.

CloudStorageAccount storageAccount = CloudStorageAccount.Parse(storageAccountConnectionString);
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference(containerName);

2. Defining the SAS Token's Time Window and Permissions:

The function then defines a time window for the SAS token's validity. By default, it's set to be valid for 4 hours from the current time. It also specifies the permissions for the SAS token, which include both read and write access.

DateTime startTime = DateTime.UtcNow.AddMinutes(-5);
DateTime expiryTime = startTime.AddHours(1);
SharedAccessBlobPolicy sasPolicy = new SharedAccessBlobPolicy()
{
Permissions = SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.Read,
SharedAccessStartTime = startTime,
SharedAccessExpiryTime = expiryTime
};

3. Generating the SAS Token and URL:

Finally, the function generates the SAS token for the specified blob and constructs the SAS URL.

CloudBlockBlob blob = container.GetBlockBlobReference(blobName);
string sasToken = blob.GetSharedAccessSignature(sasPolicy);
string sasUrl = blob.Uri + sasToken;

Why Use SAS Tokens?

Fine-grained Control: You can define what operations (read, write, delete) a user can perform on the blob.

Time-bound Access: The access you grant using SAS is for a limited duration, ensuring that even if someone gets the SAS token, they can't misuse it indefinitely.

Security: No need to share your Azure storage account keys.

Conclusion:

Managing access to your Azure Blob Storage doesn't have to be daunting. With the power of SAS tokens and the right functions in place, you can ensure security and ease of access for your users. Whether you're a seasoned Azure developer or just starting, understanding and utilizing SAS is a game-changer. Dive in and make the most of Azure Blob Storage!

Complete code:

private static string GetSasUrl(string storageAccountConnectionString, string containerName, string blobName)
{
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(storageAccountConnectionString);
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference(containerName);

// Set the SAS token time window
DateTime startTime = DateTime.UtcNow.AddMinutes(-5);
DateTime expiryTime = startTime.AddHours(4);

// Set the permissions for the SAS token
SharedAccessBlobPolicy sasPolicy = new SharedAccessBlobPolicy()
{
Permissions = SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.Read,
SharedAccessStartTime = startTime,
SharedAccessExpiryTime = expiryTime
};

// Generate the SAS token for the blob
CloudBlockBlob blob = container.GetBlockBlobReference(blobName);
string sasToken = blob.GetSharedAccessSignature(sasPolicy);

// Construct the SAS URL for the blob
string sasUrl = blob.Uri + sasToken;

return sasUrl;
}


Friday, August 4, 2023

Managing Assets in the Restaurant of Mistaken Orders: Creating or Updating Main Files from External URLs

In a software kitchen, like the Restaurant of Mistaken Orders, where unexpected dishes (files) are often served, managing the menu (assets) can be a challenging task. In this article, we'll learn how to create or update an asset's main file from an external URL, using a recipe that even the most distracted waiter can follow.

Ingredients

  • Sitecore Content Hub SDK: A rich library to manage your digital assets.
  • C#: Our programming language to cook the code.
  • HttpClient: To fetch the external URL.
  • MemoryStream: To hold the content of the file.
  • A Mistaken Order (External URL): The URL pointing to the new main file.

The Recipe

Step 1: Preparing the Mistaken Order

First, we need a method to fetch the content from the mistaken order (external URL). Think of it as a waiter running to grab a dish from a neighboring restaurant.

public class MemoryStreamHelper
{
public static async Task<MemoryStream> GetMemoryStreamFromUrlAsync(Uri uri, CancellationToken cancellationToken)
{
using (var httpClient = new HttpClient())
using (var response = await httpClient.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead, cancellationToken))
{
response.EnsureSuccessStatusCode();
var memoryStream = new MemoryStream();
await response.Content.CopyToAsync(memoryStream);
memoryStream.Position = 0;
return memoryStream;
}
}
}

Step 2: Cooking the New MainFile (Asset Creation)

If the order is new and the asset doesn't exist yet, we'll create a new dish.

public async Task<long> CreateNewAsset(string videoBlobUrl)
{
var uri = new Uri(videoBlobUrl, UriKind.Absolute);
var memoryStream = await MemoryStreamHelper.GetMemoryStreamFromUrlAsync(uri, CancellationToken.None);
var request = new UploadRequest(new StreamUploadSource(memoryStream, "video/mp4", "video.mp4"), "AssetUploadConfiguration", "NewAsset")
{
// Add any additional parameters as needed
};

var response = await mClient.Uploads.UploadAsync(request, CancellationToken.None);
return (long)await mClient.LinkHelper.IdFromEntityAsync(response.Headers.Location);
}

Step 3: Updating the MainFile (Asset Update)

If the asset already exists, and we want to replace the main file, we'll need to follow a different recipe.

public async Task UpdateAssetMainFile(long assetId, string videoBlobUrl)
{
var uri = new Uri(videoBlobUrl, UriKind.Absolute);
var memoryStream = await MemoryStreamHelper.GetMemoryStreamFromUrlAsync(uri, CancellationToken.None);

var request = new UploadRequest(new StreamUploadSource(memoryStream, "video/mp4", "video.mp4"), "AssetUploadConfiguration", "NewMainFile")
{
ActionParameters = new Dictionary<string, object>
{
{ "AssetId", assetId }, // Specify the asset ID to update
}
};

await mClient.Uploads.UploadAsync(request, CancellationToken.None);
}

Conclusion

In the Restaurant of Mistaken Orders, managing assets and main files can be as delightful as tasting a new dish. Whether it's creating a new asset or updating an existing one, the ingredients and steps outlined in this article provide a nourishing recipe for success.

So the next time a customer (user) comes in with a mistaken order (external URL), you'll know exactly how to cook up the perfect solution. Bon appétit! 🍽️

Tuesday, July 4, 2023

Azure to the Rescue: How The Restaurant of Mistaken Orders Served Up Flawless Video Content


Picture this: In a bustling corner of Tokyo, there is a unique eatery known as The Restaurant of Mistaken Orders. What sets this establishment apart is its endearing waitstaff, who all have dementia. It's a place where you never know what you’ll get, but whatever arrives at your table is served with love and joy. The owners wanted to share this special experience with the world by creating videos that showcase the warmth, understanding, and acceptance that defines their restaurant. There was just one catch: they needed a way to process and upload these videos efficiently and on a budget. The Azure cloud provided just the solution!

Cooking Up A Solution with Azure Batch

Azure Batch is like the kitchen of a restaurant. In the kitchen, there are multiple chefs (nodes) working together to prepare different dishes (tasks) that make up the complete meal (job). The Restaurant of Mistaken Orders decided to use Azure Batch to process their video content, much like how their chefs work together to whip up delightful dishes.

In the provided C# code, an Azure Function called H_AzureBatchVideoProcessing is defined. Azure Functions are serverless, meaning they don’t require you to manage any infrastructure. This is like having an automatic dishwasher that takes care of the dishes while the chefs focus on cooking.

The Ingredients

To start, the Restaurant of Mistaken Orders needs to gather all the necessary ingredients (configurations and credentials) for Azure Batch and Blob Storage.

string batchAccountUrl = _videoBatchConfig.BatchAccountUrl;
string batchAccountName = _videoBatchConfig.BatchAccountName;
string batchAccountKey = _videoBatchConfig.BatchAccountKey;
string storageAccountConnectionString = _blobStorageConfig.ConnectionString;

Much like preparing the perfect broth, setting up the credentials is an essential first step.

Preparing The Kitchen

Just like how the kitchen must be ready before cooking can start, Azure Batch requires a pool of compute nodes. In the code, the CreatePool method sets up a pool in the Batch account.

string poolId = "ffmpeg-pool";
CreatePool(batchClient, poolId, log);

Think of the poolId as the name of the kitchen. The code ensures there’s a kitchen ready with all the tools required, like knives and cutting boards (compute nodes).

Chefs, Ready Your Stations!

Now that the kitchen is ready, it’s time to define the job. A job in Azure Batch is like a complete meal consisting of several dishes.

string jobId = CreateJob(batchClient, poolId, log);

This sets up a job that will use the kitchen (pool) we previously set up. It’s like telling the chefs to start prepping!

The Main Course - Processing The Videos

The AddTask method adds a task to the job, which is like assigning a chef to prepare a dish. The Restaurant of Mistaken Orders is preparing a video, so this is the main course!

AddTask(batchClient, jobId, inputVideoUrl, inputVideoName, outputVideoName, curlBlobSasUrl, ffmpegBlobSasUrl, azcopyBlobSasUrl, storageAccountConnectionString, "video-storage", log);

In this line, a task is added to the job to download a video, process it, and upload the output to Azure Blob Storage.

Patiently Waiting For The Dish To Cook

Just as you have to wait for a dish to cook properly, you have to wait for the video processing task to complete.

log.LogInformation("Task added to job. Waiting for completion...");

var monitor = batchClient.Utilities.CreateTaskStateMonitor();
var cloudTask = await batchClient.JobOperations.GetTaskAsync(jobId, "ffmpegTask");

await monitor.WhenAll(
new List<CloudTask> { cloudTask },
TaskState.Completed,
TimeSpan.FromMinutes(30)
);

This part of the code monitors the task until it’s completed, like watching the oven to make sure the dish doesn’t burn!

Serving The Dish

Once the video is processed, the function cleans up the task and returns a success message, akin to a chef serving the dish to an eagerly awaiting customer.

log.LogInformation("Task Completed");
await batchClient.JobOperations.DeleteTaskAsync(jobId, "ffmpegTask");
return new OkObjectResult("Video processed successfully.");

Voilà! A Delicious Video is Served

The Restaurant of Mistaken Orders now has a powerful Azure solution to process and share their heartwarming videos with the world. Through Azure Batch and Blob Storage, they can focus on what they do best - serving love and acceptance, one mistaken order at a time.

Exciting News! This post is part of a series on integrating Sitecore Content Hub with Azure for video editing! Sitecore Content Hub is an integrated content management solution that enables organizations to manage and deliver content efficiently across various channels. By leveraging Azure’s powerful processing capabilities, this series will take you through how you can edit and optimize videos directly within Sitecore Content Hub. Stay tuned for more mouth-watering tips and tricks in upcoming posts! 🌟

Whether you are a restaurant owner, a marketer, or a developer, the combination of Azure and Sitecore Content Hub opens up endless possibilities for content creation and delivery. Grab your chef's hat and join us on this culinary tech adventure! 🍽️


Tuesday, June 27, 2023

Serving Up Cut-Out Text Like a Master Chef: A Delectable CSS & React Recipe


Greetings to all connoisseurs of the code, patrons of programming, and gastronomes of the grid! Chef Gourmet here, and today I have a special treat on the menu. We are going to learn how to cook up an exquisite web dish – Cut-Out Text with a CSS & React sauce.

Imagine you’re dining in the mystique ambiance of the *Restaurant of Mistaken Orders*, and a plate is placed before you with text that looks like it has been delicately carved out, revealing a succulent video playing right underneath. That, my dear friends, is the deliciousness we are about to create.

Ingredients:

  • Fresh React app
  • Ripe Rnd component for draggable and resizable delights
  • A pinch of CSS properties
  • A dash of creativity

Preparation:

First, let’s prepare the base. We have an application where users can overlay text boxes on videos. These text boxes are resizable and draggable, much like the flexibility of our menu where patrons never know what they’re going to get.

Our guests have made a peculiar request - they want to see through the letters as if the text itself were made of windows to the video underneath. It's called a cut-out text effect.

Method:

Step 1: The Div Layering Technique

In our kitchen, stacking is an art. It’s like the fine layering of a Ratatouille, but for this dish, we are stacking `div` elements. The `video` layer needs to be directly underneath the `div` which is responsible for the cut-out text effect. We don’t want the cheese (video) too far from the pasta (div) - they must melt together.

Step 2: Marinate with CSS

Now, let’s marinate our `div` with the right blend of CSS to achieve that melt-in-your-mouth cut-out effect. Here’s our secret sauce:

{
background-color: white; /* The color you want around your text */
-webkit-background-clip: text;
background-clip: text;
color: transparent; /* This makes the text transparent, while the background stays */
}

This is the alchemy that transforms plain text into cut-out text!

Step 3: Mix with React

In React, we have this sumptuous component that uses the `Rnd` library, allowing text boxes to be draggable and resizable like the ever-changing dishes in our restaurant.

Here’s how you mix it:


<Rnd { /* ...all your Rnd props... */ }>
<div style={{ /* ...background styles... */ }}>
<div style={{
WebkitBackgroundClip: 'text',
backgroundClip: 'text',
color: 'transparent'
}}
dangerouslySetInnerHTML={{ __html: content }}
/>
</div>
</Rnd>

This structure lets the `Rnd` component do its magic, while the inner `div` reveals the delectable video underneath.

Step 4: Serve Immediately

Now that we’ve cooked up our dish, serve it hot and fresh! Invite your guests to interact with the text boxes, dragging them across the screen to savor different parts of the video through the cut-out text.

Closing Notes:

In the *Restaurant of Mistaken Orders*, our dishes are as unpredictable as they are delicious. Today, you learned how to create a Cut-Out Text delicacy with CSS and React, and like a true master chef, you’ve seen how important it is to layer your ingredients properly. Keep your video close to your

Sunday, June 18, 2023

Debugging React Components in Vite for Sitecore Content Hub: The Secret Sauce

Welcome back, chefs! Having prepared our first dish in the previous blog post, now it's time to add some secret sauce: Debugging. Debugging is the taste test of the digital kitchen. It helps ensure the quality of our dish, i.e., our React components, before we serve them up to our diners.

So, grab your apron, and let's add this flavor booster to our dish!

The Culinary Twist: Debugging

In our previous blog post, we learned how to set up a Vite project for Sitecore Content Hub and create our first React component. Now, let's understand how to debug these components.

The twist in our digital kitchen? We'll be using the source TypeScript (*.ts/*.tsx) files instead of the transpiled JavaScript (*.js) files for debugging.

Why Use TypeScript Files for Debugging?

  1. Readability: TypeScript files are easier to read and understand than their transpiled JavaScript counterparts. This makes it easier to identify and resolve issues in your code.
  2. Superior Development Tools Support: Development tools such as VS Code offer excellent support for TypeScript, including advanced features like IntelliSense, which provides code suggestions, type checking, and autocompletion. This makes the development and debugging process a lot smoother. To further enhance your debugging experience, you might want to consider installing VS Code extensions like:
    • TypeScript Hero: TypeScript Hero provides advanced TypeScript functionality, including the ability to automatically import required modules and organize your imports.

    • Debugger for Chrome: This extension lets you launch a development server and debug your React apps directly in the VS Code editor. You can set breakpoints, step through your code, inspect variables, and navigate the call stack.

    • ESLint: ESLint is a pluggable and configurable linter tool for identifying and reporting on patterns in JavaScript. Its TypeScript support helps to enforce code style, catch bugs, and generally maintain a consistent code quality. If you're using TypeScript with React, you'll likely want to use the typescript-eslint parser.

    • Prettier - Code formatter: Prettier is an opinionated code formatter that supports many languages, including TypeScript. It helps to maintain a consistent style in your code by automatically formatting it on save.

    • Code Spell Checker: This extension is particularly helpful when you're new to a language like TypeScript. It can help to catch common spelling errors in variable declarations and comments.

    • Visual Studio IntelliCode: IntelliCode enhances your software development efforts by providing AI-assisted IntelliSense. The suggestions you get are based on your own coding practices and those of thousands of other TypeScript developers.

    • GitLens: GitLens supercharges the Git capabilities built into VS Code. It helps you to visualize code authorship at a glance via Git blame annotations and code lens, seamlessly navigate and explore Git repositories, and much more.

Getting Ready for Debugging

Remember the component we cooked up in the previous blog post? Let's consider its code for debugging. In the index.html file where we attached our component to the DOM, instead of pointing to the compiled JavaScript file in the dist folder, we point to the TypeScript source file directly:

<script type="module">
import createExternalRoot from '/src/components/example-component/index.tsx';
const rootElement = document.querySelector("#app");
const component = createExternalRoot(rootElement);
const mockContext = {
theme: {
palette: {
primary: {
main: "#000000"
}
}
}
};
component.render(mockContext);
</script>

In the TypeScript file index.tsx, we include console log statements, which will output valuable information to the browser console while debugging.

export default function createExternalRoot(container) {
return {
render(context) {
console.log('Rendering with context:', context); // Added for debugging
ReactDOM.render(
<OptionsContext.Provider value={context.options}>
<OptionsContext.Consumer>
{options => (
<>
<h2 style={{ color: context.theme.palette.primary.main }}>
Example Component
</h2>
<p>
Example Component, Sitecore Content Hub
</p>
</>
)}
</OptionsContext.Consumer>
</OptionsContext.Provider>,
container
);
},
unmount() {
console.log('Unmounting the component'); // Added for debugging
ReactDOM.unmountComponentAtNode(container);
},
};
}

Taste Test (Debugging)

Open the index.html in a browser to see the component in action. One of the powerful tools at our disposal here are the browser's developer tools. These tools not only allow us to observe logs and catch any bugs in the component, but they also provide capabilities like setting breakpoints, a critical part of the debugging process.

Breakpoints are markers that you can set at specific lines in your code. When your browser executes your code and encounters a breakpoint, it'll pause execution. This pause allows you to examine the current state of your code, including the values of variables, the call stack, and more.

To use breakpoints:

Open the Developer Tools (For instance, in Chrome, you can press F12 or Ctrl + Shift + I).

Navigate to the 'Source' tab (this might be named differently in browsers other than Chrome).

Locate your TypeScript file in the file navigator. It should be under the 'localhost' section.

Click on the line number beside the code where you want to set a breakpoint. A marker will appear, indicating that a breakpoint has been set.

When you reload your page, execution will pause at your breakpoint, allowing you to examine the state of your code at that point.

Setting breakpoints in our TypeScript files gives us the advantage of being able to debug our code in the same form that we write it. We don't need to navigate through minified or transpiled JavaScript, making our debugging process much more straightforward and efficient.

In the Network tab, ensure 'Disable cache' is selected. This forces the browser to get the latest versions of all files from the server, helping you avoid potential confusion caused by caching.

Summary

We've added a robust flavor to our dish - debugging. It's an integral part of the cooking process in our digital kitchen. Just like in a culinary kitchen where chefs taste their dishes before serving, in our digital kitchen, we debug our code before deploying. This helps us catch and rectify any bugs, ensuring that we're delivering a high-quality, delicious dish to our diners.


That's it for today's culinary-tech adventure! In the next blog post, we'll dive deeper into converting an Existing Sitecore Content Hub 4.1 external component to a React component. Until then, keep cooking and debugging!




Tuesday, May 30, 2023

Cooking Up a Vite Project for Sitecore Content Hub: A Recipe Inspired by the Restaurant of Mistaken Orders


Have you ever been to the Restaurant of Mistaken Orders? It's a place where you're served delicious dishes that you didn't order, but you end up loving them anyway! Imagine we're in the kitchen of that restaurant, cooking up a new Vite project for Sitecore Content Hub. Let's get started with this culinary-tech journey.

Setting Up a Vite Project for Sitecore Content Hub

1. Create a Vite Project

First, open up Visual Studio Code. Next, you'll need to create a Vite project.

To do this, use the npm command create Vite as follows:

npm create vite@latest

During the setup process, name your project appropriately. In this example, we're naming it "Sitecore.CH.ExternalComponents.React".

2. Choose Your Framework and Language

During the setup process, you will be asked to choose a framework and a variant. Select React for your framework and TypeScript as your variant.

3. Install Dependencies

Once your project setup is complete, change your directory to the root directory of your new project and install the necessary packages using the npm install command.

npm install

4. Verify Your Installation

With everything set up, you should now see the default files that are automatically built, including index.html. You'll also have your tsconfig.json pre-configured. Run the command npm run dev to verify that your installation is working properly.

npm run dev

5. Configure SSL

To configure your project for SSL, you should use certificates! we can create them using a command prompt as follow:

cd "C:\Program Files\Git\usr\bin"

.\openssl.exe req -x509 -newkey rsa:4096 -keyout c:\certs\key.pem -out c:\certs\cert.pem -days 365 -nodes -subj "/CN=localhost"

host: 'localhost',
port: 5000,
https: {
key: fs.readFileSync('certs/key.pem'),
cert: fs.readFileSync('certs/cert.pem'),
},

copy the certs folder to your project folder, and add the certs folder to .gitignore

.gitignor (example)

# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

# Project Specific files
.env

# Project-Specific Directories
certs


in order to use fs "filesystem" in the vite.config file you need to add the following at the top of the vite.config file.

Example vite.config

import { defineConfig, loadEnv } from 'vite'
import react from '@vitejs/plugin-react'
import fs from 'fs'

export default defineConfig(({ command, mode }) => {
const env = loadEnv(mode, process.cwd(), '')
const isDev = mode === 'development';

return {
server: isDev ? {
host: 'localhost',
port: 5000,
https: {
key: fs.readFileSync('certs/key.pem'),
cert: fs.readFileSync('certs/cert.pem'),
},
proxy: {
'^/api/.*': {
target: env.HOST_URL,
changeOrigin: true,
secure:false,
auth: `'${env.USERNAME}:${env.PASSWORD}'`,
rewrite: (path) => path.replace(/^\/api/, '')
},
},
}:{},
build: {
sourcemap: true,
minify: true,
target: 'es2015',
lib: {
formats: ['es'],
fileName: process.env.npm_config_component,
entry: `./src/components/${process.env.npm_config_component}/index.tsx`,
},
},
define: isDev ? {
//'process.env.API_URL': JSON.stringify(apiUrl)
}:{},
}
})

import fs from 'fs'

6. Update Your package.json

The next step is to configure your run script in your package.json file. Make sure to enable hosting and SSL, and also ensure that CORS is enabled. This is necessary to run your script inside Content Hub.

"scripts": {
"watch": "vite build --watch",
"dev": "vite --host -- https --cors",
"build": "tsc && vite build"
},

In some cases you need to add your localhost URL to the CORS settings in Content Hub, you can find this in manage > settings > CORSConfiguration

7. Clean Up Your Project

Before proceeding further, it's a good idea to clean up your project a bit. Delete any unnecessary assets and files, leaving only your Vite configurations and environment variables. You can also delete the public folder.

8. Create Your First Component

Now that your project is all setup, it's time to start building. 

Prepping the Kitchen

Just like in a real kitchen, where you need to prepare your ingredients and tools before starting to cook, we'll have to complete some setup steps. Visit the 'Additional Steps' section for more details.

Step 1: Setting up the Component Structure

Think of this as laying out your ingredients. In our Sitecore Content Hub project, navigate to the "components" directory. Here, create a new folder named "example-component", just like how you'd prepare and lay out your ingredients before cooking.

Step 2: Create the Component File

This is akin to prepping your main ingredient. Inside the "example-component" folder, create a new TypeScript file called index.tsx.

Step 3: Seasoning the Component

Now comes the fun part, seasoning our ingredients. Open the newly created index.tsx file and create an index.html file and add your component's code. Just like seasoning a dish to taste, this code will give our component its unique flavor.

Index.tsx

import React from 'react';
import ReactDOM from 'react-dom';

const OptionsContext = React.createContext(null);

export default function createExternalRoot(container) {
return {
render(context) {
ReactDOM.render(
<OptionsContext.Provider value={context.options}>
<OptionsContext.Consumer>
{options => (
<>
<h2 style={{ color: context.theme.palette.primary.main }}>
Example Component
</h2>
<p>
Example Component, Sitecore Content Hub
</p>
</>
)}
</OptionsContext.Consumer>
</OptionsContext.Provider>,
container
);
},
unmount() {
ReactDOM.unmountComponentAtNode(container);
},
};
}

Index.html

<!DOCTYPE html>
<html>
<head>
<title>Example Component</title>
</head>
<body>
<div id="app"></div>
<div id="myElement">.</div>
<script type="module">
import createExternalRoot from '/src/components/example-component/index.tsx';
const rootElement = document.querySelector("#app");
const component = createExternalRoot(rootElement);
const mockContext = {
theme: {
palette: {
primary: {
main: "#000000"
}
}
}
};
component.render(mockContext);
</script>
</body>
</html>

Step 4: Cooking the Component

With our ingredients prepped and seasoned, it's time to cook. Open your terminal or command line interface, navigate to the "Sitecore.CH.ExternalComponents.React" folder, and start the build process. After the build process completes, just like letting a dish simmer, we'll start our development server.

npm run build

Step 5: Taste Test

Like tasting a dish to ensure it's cooked to perfection, we'll validate our components. Navigate to the development server URL, and you should see the transpiled JavaScript code for your component.

https://localhost:5000/dist/example-component.js

Step 6: Plating the Dish

In the culinary world, presentation is everything. Similarly, in our digital kitchen, we need to upload our beautifully cooked components to the Content Hub. Navigate to the Sitecore Content Hub management interface and select "Portal Assets". Upload the JavaScript file that we cooked up - "example-component.js".

Step 7: Serving the Dish

Finally, it's time to serve our dish. In our case, this means adding the external component to a Content Hub page. Navigate to the page where you want to add the external component, add it, and select the portal asset you just uploaded.

Additional Steps: Taste before you serve

Let's talk about debugging react components in our next blog.
In our next blog, we will convert an Existing Sitecore Content Hub 4.1 external component to a react component. And have a deep dive into how we debug these components.