Try   HackMD

Using LiveChatWidget in react + TypeScript + Webpack 5

This guide is intented to help you getting started with <LiveChatWidget /> in a react application using Webpack 5, TypeScript.

Explaining features/options used below for react, TypeScript, Webpack, Babel are out of scope of this document. Please refer to these open sources official documents for getting more details.

Steps:

1: Setting up app

Let’s create the following folders in a root folder:

dist: This folder will contain all the artifacts from the build output. This will also hold the HTML page where the React app will be injected to.
src: This will contain source codes.

2: Adding package.json

In the root of the project, add the following package.json. You can also use npm init command to create it.

{
  "name": "my-sample-widget",
  "version": "0.0.1"
}

3. Add index.html

Let’s also add the following index.html file into the dist folder. Note the bundle.js, this JavaScript file will be created after building the react app and will be placed inside dist folder.

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
</head>

<body>
    <div id="root"></div>
    <script src="bundle.js"></script>
</body>

</html>

4. Adding React and TypeScript

Run the following commands from a command prompt from root folder:

npm install react react-dom
npm install --save-dev typescript
npm install --save-dev @types/react @types/react-dom

5. Add tsconfig.json

TypeScript is configured with a file called tsconfig.json. Let’s create this file in the root of our project with the following content:

{
    "compilerOptions": {
      "lib": ["dom", "dom.iterable", "esnext"],
      "allowJs": true,
      "allowSyntheticDefaultImports": true,
      "skipLibCheck": true,
      "esModuleInterop": true,
      "strict": true,
      "forceConsistentCasingInFileNames": true,
      "moduleResolution": "node",
      "resolveJsonModule": true,
      "isolatedModules": true,
      "noEmit": true,
      "jsx": "react"
    },
    "include": ["src"]
  }

6. Add a root component

Create a simple React component in a index.tsx file in the src folder. This will eventually be displayed in index.html.

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

const App = () => (
  <h1>My Sample app!</h1>
);

ReactDOM.render(
  <App />,
  document.getElementById("root")
);

7. Add Babel

npm install --save-dev @babel/core @babel/preset-env @babel/preset-react @babel/preset-typescript @babel/plugin-transform-runtime @babel/runtime

8. Configuring Babel

We'll configure the babel in .babelrc file. Create this file under root directory.

{
    "presets": [
      "@babel/preset-env",
      "@babel/preset-react",
      "@babel/preset-typescript"
    ],
    "plugins": [
      [
        "@babel/plugin-transform-runtime",
        {
          "regenerator": true
        }
      ]
    ]
  }

9. Add Webpack and tools

Webpack is a bundler tool that can be use to bundle all JavaScript code into the bundle.js file that is used in index.html.

Install webpack and webpack command line tools:

npm install --save-dev webpack webpack-cli @types/webpack

Webpack also have a web server that can be used during development. To install:

npm install --save-dev webpack-dev-server @types/webpack-dev-server

babel-loader will help to transpile react + TypeScript code to JavaScript. To install:

npm install --save-dev babel-loader

Webpack configuration file is JavaScript based as standard, however we can TypeScript as well. To do this use ts-node.

npm install --save-dev ts-node

10. webpack.config.ts

Webpack is configured through a configuration file. Create this file in root directory

import path from "path";
import { Configuration } from "webpack";
import * as webpack from 'webpack';
import * as webpackDevServer from 'webpack-dev-server';

const fileLoader = {
    test: /\.(jpe?g|png|gif|svg|mp3)$/i,
    loader: "file-loader",
    options: {
        name: "public/assets/[name].[ext]"
    }
};

const disableFullyQualifiedNameResolutions = {
    test: /\.m?js/,
    resolve: {
        fullySpecified: false,
    },
};

const babelLoaderConfiguration = {
    test: /\.(ts|js)x?$/,
    exclude: /node_modules/,
    use: {
        loader: "babel-loader",
        options: {
            presets: [
                "@babel/preset-env",
                "@babel/preset-react",
                "@babel/preset-typescript",
            ],
        },
    }
};

const config: Configuration = {
    entry: "./src/index.tsx",
    mode: "development",
    module: {
        rules: [
            babelLoaderConfiguration,
            fileLoader,
            disableFullyQualifiedNameResolutions
        ],
    },
    resolve: {
        extensions: [".tsx", ".ts", ".js"],
    },
    output: {
        path: path.resolve(__dirname, "dist"),
        filename: "bundle.js",
    },
    devServer: {
        static: path.join(__dirname, "dist"),
        compress: true,
        port: 4000,
        client: {
            overlay: {
                warnings: false,
                errors: true
            }
        }
    },
};

export default config;

11. Add npm scripts

To build and run add below scripts to package.json

...,
  "scripts": {
    "start": "webpack serve --open",
    "build": "webpack --mode development", //Adjust mode(development/production) as needed
  },
  ...

12. Verify the sample app

Verify the below folder structure after npm run build

Try running the app using npm run start, you should see a sample page opened in your default browser

After this step, we'll proceed for adding Omnichannel LCW packages

13. Omnichannel Live Chat Widget UI Components installation

npm i @microsoft/omnichannel-chat-sdk
npm i @microsoft/omnichannel-chat-widget --legacy-peer-deps

14. Adding <LiveChatWidget /> to index.tsx

import { OmnichannelChatSDK } from "@microsoft/omnichannel-chat-sdk";
import { LiveChatWidget } from "@microsoft/omnichannel-chat-widget";
import React, { useEffect, useState } from "react";
import ReactDOM from "react-dom";

const getOmnichannelChatConfig = () => {
    // add your own OC setting, hard-coded just for sample, should be replaced with a better handling
    const omnichannelConfig = { 
        orgId: "",
        orgUrl: "",
        widgetId: ""
    };
    return omnichannelConfig;
}

const App = () => {
    const [liveChatWidgetProps, setLiveChatWidgetProps] = useState<any>();

    useEffect(() => {
        const init = async () => {
            const omnichannelConfig = getOmnichannelChatConfig();

            const chatSDK = new OmnichannelChatSDK(omnichannelConfig);
            await chatSDK.initialize();
            const chatConfig = await chatSDK.getLiveChatConfig();

            const liveChatWidgetProps = {
                styleProps: {
                    generalStyles: {
                        width: "400px",
                        height: "600px",
                        bottom: "30px",
                        right: "30px"
                    }
                },
                chatSDK,
                chatConfig
            };

            setLiveChatWidgetProps(liveChatWidgetProps);
        }

        init();
    }, []);

    return (
        <div>
            {liveChatWidgetProps && <LiveChatWidget {...liveChatWidgetProps} />}
        </div>
    );
};

ReactDOM.render(
    <App />,
    document.getElementById("root")
);

That's all!!!