microsoft / BotFramework-WebChat

A highly-customizable web-based client for Azure Bot Services.
https://www.botframework.com/
MIT License
1.59k stars 1.54k forks source link

ReactWebChat error in SPFx and IE11 with Polyfills #3161

Open c-eiser13 opened 4 years ago

c-eiser13 commented 4 years ago

Version

4.4.2 of botframework-webchat 1.10 (latest) of SPFx

Describe the bug

First off, thanks for a solution that is very easy to integrate with React and directline, component works great everywhere except IE11. I've reviewed the other posts in the issues list related to IE11 and SPFx, most notably #2030, where the list of polyfills is pointed out. I've installed core-js and imported the same polyfills listed here: packages/bundle/src/index-es5.ts into my component and it still does not function in IE11. Occasionally, I will get an "Out of stack space" exception, but mostly the chat window will load, but does not show any messages. The out of stack space exception has a lengthy discussion on the SP Dev Docs repo here and I've tinkered with commenting out certain polyfills, but have not been able to get this thing working. Below is my component that my web part is loading: image image

IE: image

Chrome/edge: image

In IE console: image

Note: in screenshot, I have set commented out since that is one that causes the out of stack space exception. I've also tried including the polyfills in the webpart.ts file and even importing an external polyfills.ts file, but none will work properly. If I am not importing something correctly, missing something, or there is any other advice, i'd greatly appreciate it. I'm hoping someone who has successfully implemented the React component in SPFx and has it working in IE can provide some insight. If there are further details needed, please let me know.

Steps to reproduce

  1. yo '@microsoft/sharepoint' to create new SPFx project
  2. Install botframework-webchat and directline.
  3. gulp serve and view in IE11.

Expected behavior

Working web part in IE11.

Additional context

[Bug]

MaximCoppieters commented 4 years ago

Hello, I've also struggled with making BotFramework-Webchat work with SPFX for IE11. After trying out a lot of configurations, I've finally found one that works for me.

I'll start out with the versions I'm using. This is what my package.json file looks like (minus irrelevant packages and information):

{
  "dependencies": {
    "@microsoft/sp-core-library": "1.10.0",
    "@microsoft/sp-lodash-subset": "1.10.0",
    "@microsoft/sp-office-ui-fabric-core": "1.10.0",
    "@microsoft/sp-property-pane": "1.10.0",
    "@microsoft/sp-webpart-base": "1.10.0",
    "@types/react": "16.8.8",
    "@types/react-dom": "16.8.3",
    "@types/webpack-env": "1.15.2",
    "botframework-webchat": "^4.4.2",
    "core-js": "^3.6.5",
    "react": "16.8.5",
    "react-dom": "16.8.5",
    "url-search-params-polyfill": "^8.1.0",
    "whatwg-fetch": "^3.0.0"
  },
  "resolutions": {
    "@types/react": "16.8.8"
  },
  "devDependencies": {
    "@babel/preset-env": "^7.9.6",
    "@babel/preset-react": "^7.9.4",
    "@babel/preset-typescript": "^7.9.0",
    "@microsoft/rush-stack-compiler-3.3": "0.5.11",
    "@microsoft/sp-build-web": "1.10.0",
    "@microsoft/sp-module-interfaces": "1.10.0",
    "@microsoft/sp-tslint-rules": "1.10.0",
    "@microsoft/sp-webpart-workbench": "1.10.0",
    "@types/core-js": "^2.5.0",
    "@types/node": "^14.0.1",
    "babel-loader": "^8.1.0",
    "gulp": "~3.9.1",
    "gulp-env": "^0.4.0"
  },
  "browserslist": [
    "> 0.25%",
    "ie 11"
  ],
  "targets": {
    "chrome": "58",
    "ie": "11"
  }
}

Besides adopting these versions, I'd also add the target and browserlist fields if they are not yet present in your package.json.

The next step is to add the babel loader with the presets to your webpack config. This is done in gulpfile.js. The way the configuration is loaded is similar to a .babel.rc file. At the top of the file I added the following line:

build.addSuppression(/Warning/gi); // Still allow the build to pass when warnings are printed

The babel configuration looks as follows:

build.configureWebpack.mergeConfig({
  additionalConfiguration: (generatedConfiguration) => {
    /* Babel polyfills to make the bot work on IE11 */
    generatedConfiguration.module.rules.push({
      test: /\.m?js$/,
      exclude: /node_modules/,
      use: {
        loader: "babel-loader",
        options: {
          presets: [
            [
              "@babel/preset-env",
              {
                targets: {
                  ie: "11",
                },
                corejs: { version: 3 },
                useBuiltIns: "entry",
              },
            ],
            [
              "@babel/preset-typescript",
              {
                targets: {
                  ie: "11",
                },
                corejs: { version: 3 },
                useBuiltIns: "entry",
              },
            ],
            [
              "@babel/preset-react",
              {
                targets: {
                  ie: "11",
                },
                corejs: { version: 3 },
                useBuiltIns: "entry",
              },
            ],
          ],
        },
      },
    });
});

The "entry" flag tells babel you will partially supply your own polyfills in the entrypoint of the application, which for me are fairly similar to the ones you have. In my experience, the symbol and promise polyfill imports crashed the webpart for me. Here are the corejs imports in my WebPart entry point:

import "core-js/features/math/sign";
import "core-js/features/object/values";
import "core-js/features/object/assign";
import "core-js/features/object/entries";
import "core-js/features/object/from-entries";
import "core-js/features/object/is";
import "core-js/features/number/is-finite";
import "core-js/features/string/ends-with";
import "core-js/features/string/starts-with";
import "core-js/features/array/find-index";
import "core-js/features/array/find";
import "core-js/features/array/includes";
import "core-js/features/array/iterator";
import "core-js/features/dom-collections";
import "url-search-params-polyfill";
import "whatwg-fetch";

Now comes the tricky part, it took me quite a while to do find out about this. The framework allows you to load external libraries (eg. from CDN) in the config/config.json file. I did this to load the botframework library. This will replace the version from npm_modules at runtime, but keep its typings. The property to set is called externals. My config.json file looks like this:

{
  "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json",
  "version": "2.0",
  "bundles": {
        ...
    }
  },
  "externals": {
    "botframework-webchat": "https://cdn.botframework.com/botframework-webchat/4.4.2/webchat.js"
  },
  "localizedResources": {
    "WebchatO365WebPartStrings": "lib/webparts/webchatO365/loc/{locale}.js"
  }
}

That's it, if there are no other libraries installed in your project that cause polyfill conflicts, this setup should work for you. Hope it helps!

compulim commented 4 years ago

Thanks @c-eiser13 for super details and investigations.

For the externals in config/config.json, can you point it to https://cdn.botframework.com/botframework-webchat/4.4.2/webchat-es5.js? This one will contains polyfills required for IE11.

Also, in the F12 console of the web part, can you type [].includes in the console to see if it is being polyfilled correctly?

BTW, I am new to SPFx app. To host it for testing, do I require to host it on SharePoint Online?

MaximCoppieters commented 4 years ago

@compulim Logically spoken, it does indeed make sense to include the es5 bundle. I tried this with multiple versions of the botframework. This breaks the web part with the following error:

Cannot redefine non-configurable property 'startsWith'

This also occurs when the corejs polyfills are removed from the webpart entrypoint (this is needed because the es5 bundle applies its own polyfills)

I'm not sure about running it locally. In our workflow, gulp serve pushes the webpart to the workbench, which is hosted on Sharepoint. Making changes and saving them then let's webpack rebuild and update the page.

c-eiser13 commented 4 years ago

@MaximCoppieters thanks a ton for your information, I will review this and give it a try. @compulim I also tried including the webchat-es5.js CDN reference in the externals section of a basic (non-react based) SPFx web part, thinking this would be the solution I would use for IE11 support, but this also crashed the web part. I was getting the "Out of stack space" error when just including the es5 bundle in externals section and trying to load the web chat that way. I was also seeing the "object does not contain property or method includes" so it sounds like [].includes may not be polyfilled correctly.

You are not required to host in SPO, but to use the latest version (1.10) will require SPO, and I'd recommend using SPO. To use SPFx on-prem, you will be tied to v1.4 of SPFx.

For the time being, I've created an Azure site and added the webchat to a page in this site and I display this in an iFrame in SPFx if IE is detected. Its certainly not how I want to use this, but i'm unfortunately stuck supporting IE11 for a few customers. I'm going to test out the suggestions above, but if I can assist or test something further, I'm happy to help.

c-eiser13 commented 4 years ago

@compulim I still had my sample project with basic web part and es5 bundle in externals section, and here is the code and results: image

image

IE console: botes5-1

And in Chrome, works properly: image

Ideally, i'd like to use the React component and have it load correctly in IE11 via an SPFx web part. It appears something in SPFx or native SharePoint also breaks the usage of the es5 bundle in a basic, non-react based web part. If I can provide further information, please let me know.

MaximCoppieters commented 4 years ago

@c-eiser13 I didn't find a way to make the es5 bundle work for our web part, and I tried a lot of things. The normal version at https://cdn.botframework.com/botframework-webchat/4.4.2/webchat.js together with the corejs imports I stated in my initial post did it for me, alongside the babel-loader configuration in gulpfile.js.

compulim commented 4 years ago

As Set is already supported in IE11, I think we can take it out from index-es5.ts so we don't get "out of stack space" error in SPO.

image

@MaximCoppieters I compared my list and your list. Your list doesn't have: promise, promise/finally, and symbol. And probably SPO polyfilled them.

If I read your solution correctly:

  1. Set useBuiltIns to "entry" will turn import 'core-js/es/array' into import 'core-js/es/array/map' (plus other polyfills that IE11 don't have, e.g. array/lastIndexOf, etc)

I believe, SPO has some internal polyfills and it conflict with core-js. And we need to find out that list and suggest people who use Web Chat in IE11 + SPO should bring in a smaller set of polyfills, instead of webchat-es5.js.

I would prefer someone (or me) to work on this from scratch to make the solution as lean as possible. I.e. I prefer not to run babel-loader and webpack as Web Chat is already Babel-ed. And we should find a solution that we don't "double Babel it".

Action items (for whoever have time to take up this one):

The ideal solution, SPO developers can use import ReactWebChat from 'botframework-webchat' to import Web Chat:

corinagum commented 3 years ago

Needs priority confirmation