DEV Community

Cover image for Build Microsoft-Webchat Locally For Performance Improvement
dlmohan
dlmohan

Posted on

Build Microsoft-Webchat Locally For Performance Improvement

Microsoft Bot framework is a popular framework used for creating bots.It provides a webchat interface to use as a user interface for web and mobile users.
It is developed in react,it comes with packages to be used directly in a webpage.But if you want to do some real customization,you have to use it in a react application.
This makes the package size of the deployed application bigger than usual.Which can be an issue if you are looking for better performance.

In this blog i will show you how we can build the webchat locally and do some modifications,so it can give us better performance

Assumptions

  • I did not need the webchat speech ,so i have removed it,to make the package smaller
  • I am using next js for my custom webchat application

First we will see with the default setup

to run webchat with react setup,we need to install botframework-webchat

npm install botframework-webchat
Enter fullscreen mode Exit fullscreen mode
//import as a dynamic module so this will load only when it is needed
const ReactWebChat = dynamic(
    () => {
        return import('botframework-webchat');
    },
    { ssr: false }
);

//the directline
 let directLine = useMemo(() => createDirectLine({
        secret: 'Mytoken',
        domain: 'http://directline endpoint',
        webSocket: true,
        conversationId: 'conversationId',
        pollingInterval: 2000
    }), []);
//redux store
let store=useMemo(() => createStore({}, ({ dispatch }) => next => action => {
     if (action.type === 'DIRECT_LINE/POST_ACTIVITY') {
         //your code here
     }
}), []);
<ReactWebChat directLine={directLine}
                    userID={userId}
                    username={userName}
                    locale='en-us'
                    sendTypingIndicator={true}
                    resize="detect"
                    bot={bot}
                    styleOptions={styleOptionsState}
                    store={store}
                />

With this setup we can run the chat app,for details you can check an example from Microsoft-Webchat 

Enter fullscreen mode Exit fullscreen mode

Next configuration

Install Dev Dependencies

  • @next/bundle-analyzer - this we will use to analyse the bundles
  • duplicate-package-checker-webpack-plugin - this we use to find out duplicate packages
  • next-transpile-modules - transpile modules for IE11 support
  • cross-env - to be used in windows

Analyse the app

to analyse the package footprint,we will use following in scripts of package.json

"analyse": "cross-env ANALYZE=true next build"
Enter fullscreen mode Exit fullscreen mode

inside next.config

const withBundleAnalyzer = require('@next/bundle-analyzer')({
  enabled: process.env.ANALYZE === 'true',
})

const config={
     future: {
        webpack5: true,
     },
}
Enter fullscreen mode Exit fullscreen mode

then run

npm run-script analyse
Enter fullscreen mode Exit fullscreen mode

For my setup this is what i get

Alt Text

Alt Text

Check how botframework-webchat-api/lib is taking a lot of space for localisations.
and also how big the microsoft-cognitiveservices-speech-sdk distribution is taking,if we don't need speech then we can remove it too,so lets clean them up

Lets Make it small

Minimize botframework-webchat-api

  • First we will copy the botframework-webchat-api folder from node_modules to our local directory
  • Remove the locale references we dont need

from botframework-webchat-api\src\localization\getAllLocalizedStrings.ts ,remove all languages except what you need ,in my case only i need en_US

// Strings commented out are pending official translations


import enUS from './en-US.json';

import bundledOverrides from './overrides.json';
import LocalizedStrings from '../types/LocalizedStrings';
import mergeLocalizedStrings from './mergeLocalizedStrings';

let localizedStrings;

function getAllLocalizedStrings(): { [language: string]: LocalizedStrings } {
  return (
    localizedStrings ||
    (localizedStrings = mergeLocalizedStrings(
      {
        'en-US': enUS,
      },
      bundledOverrides
    ))
  );
}

export default getAllLocalizedStrings;

Enter fullscreen mode Exit fullscreen mode
  • Then from botframework-webchat-api\src\localization\overrides.json,just keep what you need,in my case it is en_US
{
  "en-US": {
    "COGNITIVE_SERVICES_SPEECH_TO_TEXT": true,
    "COGNITIVE_SERVICES_TEXT_TO_SPEECH": "neural",
    "GLOBALIZE_LANGUAGE": "en",
    "SPEECH_LANGUAGE": "en-US"
  }
}

Enter fullscreen mode Exit fullscreen mode
  • Build
npm i
npm run-script build
Enter fullscreen mode Exit fullscreen mode

Remove microsoft-cognitiveservices-speech-sdk

  • Copy the botframework-webchat folder from node_modules
  • from webpack config remove
react: resolve(__dirname, '../isomorphic-react/dist/react.js'),  
   react-dom': resolve(__dirname, '../isomorphic-react-dom/dist/react-dom.js')
Enter fullscreen mode Exit fullscreen mode
  • from package.json remove
   "isomorphic-react": "4.13.0",  
    "isomorphic-react-dom": "4.13.0",  
    "microsoft-cognitiveservices-speech-sdk": "1.15.1",  
    "botframework-directlinespeech-sdk": "4.13.0",

Enter fullscreen mode Exit fullscreen mode
  • from src/index.ts

    comment reference for createCognitiveServicesSpeechServicesPonyfillFactory,createDirectLineSpeechAdapters

  • Build

npm i
npm run-script build
Enter fullscreen mode Exit fullscreen mode

remove node_modules from botframework-webchat-api,botframework-webchat

in next config


config.resolve.alias['microsoft-cognitiveservices-speech-sdk/distrib/lib/src/common.browser/Exports']= resolve(
      __dirname,
      'node_modules/microsoft-cognitiveservices-speech-sdk/distrib/lib/src/common.browser/Exports.js'
    ),
    config.resolve.alias['microsoft-cognitiveservices-speech-sdk/distrib/lib/src/common.speech/Exports']= resolve(
      __dirname,
      'node_modules/microsoft-cognitiveservices-speech-sdk/distrib/lib/src/common.speech/Exports.js'
    ),
    config.resolve.alias['microsoft-cognitiveservices-speech-sdk/distrib/lib/src/common/Exports']= resolve(
      __dirname,
      'node_modules/microsoft-cognitiveservices-speech-sdk/distrib/lib/src/common/Exports.js'
    ),
    config.resolve.alias['microsoft-cognitiveservices-speech-sdk/distrib/lib/src/sdk/Audio/AudioStreamFormat']= resolve(
      __dirname,
      'node_modules/microsoft-cognitiveservices-speech-sdk/distrib/lib/src/sdk/Audio/AudioStreamFormat.js'
    ),
    config.resolve.alias['microsoft-cognitiveservices-speech-sdk/distrib/lib/src/sdk/Exports']= resolve(
      __dirname,
      'node_modules/microsoft-cognitiveservices-speech-sdk/distrib/lib/src/sdk/Exports.js'
    ),
    config.resolve.alias['microsoft-cognitiveservices-speech-sdk/distrib/lib/microsoft.cognitiveservices.speech.sdk']= resolve(
      __dirname,
      'node_modules/microsoft-cognitiveservices-speech-sdk/distrib/lib/microsoft.cognitiveservices.speech.sdk.js'
    ),

    // This line must be placed after other specific imports.
    config.resolve.alias['microsoft-cognitiveservices-speech-sdk']= resolve(
      __dirname,
      'node_modules/microsoft-cognitiveservices-speech-sdk/distrib/lib/microsoft.cognitiveservices.speech.sdk.js'
    ),

    config.resolve.alias['botframework-webchat-api'] = resolve(
      __dirname,
      'botframework-webchat-api'
    )

    config.resolve.alias['botframework-webchat'] = resolve(
      __dirname,
      'botframework-webchat'
    )

Enter fullscreen mode Exit fullscreen mode

Now lets run again

npm run-script analyse
Enter fullscreen mode Exit fullscreen mode

This is what i get

Image

Image1

Thats'it

We have decreased the size of our packages,

Bonus

For decreasing packages for lodash or moment you can use following

for moment inside next config

 config.plugins.push(new webpack.IgnorePlugin({
      resourceRegExp: /^\.\/locale$/,
      contextRegExp: /moment$/,
    }))
Enter fullscreen mode Exit fullscreen mode

for lodash,use in your code like

import cloneDeep from 'lodash/cloneDeep';
import isEmpty from 'lodash/isEmpty';

Enter fullscreen mode Exit fullscreen mode

To transpile for IE11


const withTM = require('next-transpile-modules')(['react-markdown', 'react-markdown/node_modules/is-plain-obj',
 'postcss','sanitize-html','sanitize-html/node_modules/escape-string-regexp']);
let withAnalyzer = withBundleAnalyzer(config)
let final = withAnalyzer
if (!process.env.NODE_ENV || process.env.NODE_ENV === 'production') {
  final = withTM(withAnalyzer)
}

Enter fullscreen mode Exit fullscreen mode

To find duplicate packages

 const DuplicatePackageCheckerPlugin = require('duplicate-package-checker-webpack-plugin')
 config.plugins.push(new DuplicatePackageCheckerPlugin())

//  then you can use for duplicate packages,to pickup only from default path
 config.resolve.alias['core-js'] = resolve(
      __dirname,
      'node_modules',
      'core-js'
    )
Enter fullscreen mode Exit fullscreen mode

To see errors in chrome console with proper source code use

config.optimization.minimize = false
Enter fullscreen mode Exit fullscreen mode

Top comments (0)