Open c-eiser13 opened 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!
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?
@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.
@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.
@compulim I still had my sample project with basic web part and es5 bundle in externals section, and here is the code and results:
IE console:
And in Chrome, works properly:
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.
@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.
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.
@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:
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)
core-js
import, this should have no effects on index-es5.ts
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):
index-es5.ts
to make it work under SPO
core-js/.../set
because IE11 should already support Set
promise
, promise/finally
, symbol
, string/startsWith
and string/endsWith
externals
in webpack.config.js
to point to the CDN bundle of Web Chat. It doesn't perfectly make sense to me because externals
is for import
. And the CDN bundle is not import-able (it's global on window.WebChat
).The ideal solution, SPO developers can use import ReactWebChat from 'botframework-webchat'
to import Web Chat:
import
should be localized and not globalize Web Chat into window.WebChat
import 'botframework-webchat/polyfill/sharepoint';
Needs priority confirmation
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:
IE:
Chrome/edge:
In IE console:
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
Expected behavior
Working web part in IE11.
Additional context
[Bug]