I need to load the jquery-typeahead library in my SPFx web part. I register this dependency by adding it to "config\config.json" like this:
"externals": {
"jquery": {
"path": "./node_modules/jquery/dist/jquery.min.js",
"globalName": "jQuery"
},
"jquery.typeahead.min": {
"path": "./node_modules/jquery-typeahead/dist/jquery.typeahead.min.js",
"globalName" : "jQuery",
"globalDependencies": ["jquery"]
}
}
(Note that this works well for other libraries I depend on so I assume this is the correct way to do it. But correct me if I'm wrong.)
I then require
the dependency in TypeScript like this:
require('jquery.typeahead.min');
It transpiles well, loads the module and gives me the $.typehead
as expected - in the following browsers:
- Firefox
- Chrome
- IE on first load
And here is the problem. When reloading the page by pressing F5 (NOT Ctrl+F5) this require
does fail to load the module - ONLY IN IE. When using Ctrl+F5 instead (or opening the developer tools and checking "reload from server") all is well.
Does this ring a bell for somebody? Are there known issues like this? Or is this expected somehow?
Out of curiosity I changed the require to this to output the loaded module:
var t = require('jquery.typeahead.min');
alert(t);
On first load in IE I get:
This is correct - this is the typehead library.
After pressing F5 in IE this changes to:
And know what? This is jQuery! So my require('jquery.typeahead.min')
does not return the required module, but something else.
Afaik SharePoint Framework uses webpack with CommonJS modules, so the require should return the required dependency immediately and synchronously. (My "tsconfig.json" is saying "module": "commonjs"
- so I assume that to be true at least for my project.)
Any ideas what's going on here? Note that the problem is only affecting IE when pressing F5. I'm testing in the local workbench.
====== ADDITION after response from Pat Mill ======
Pat Mills colleagues saw two potential issues:
- adding "jquery.typeahead" to the
globalName
"jQuery" - using the result of
require
I eliminated those points of concern by changing my config.json to:
"externals": {
"jquery": {
"path": "./node_modules/jquery/dist/jquery.min.js",
"globalName": "jQuery"
},
"jquery.typeahead.min": {
"path": "./node_modules/jquery-typeahead/dist/jquery.typeahead.min.js",
"globalName" : "typeahead",
"globalDependencies": ["jquery"]
}
}
Note the changed globalName
for jquery.typeahead.min
.
Also note that I cannot get rid of the globalName
altogether because gulp serve
would give me this:
Error - [copy-assets] External "jquery.typeahead.min" is defined as a Non-AMD script,but is missing a globalName property.
Furthermore I still do require("jquery.typeahead.min")
, but don't use the result of this call (previously I used it only to output the result in a message box). Instead, I output the typehead
extension of jQuery like this (in the view model constructor, and only for demo purposes):
alert(($ as any).typeahead);
The result when pressing Ctrl+F5 in IE (as expected!):
Then when pressing F5 in IE (not expected at all!):
So there is no change in behavior. There are still problems when reloading by pressing F5 only in IE - the module is simply missing.
====== REPRO ======
Ok here is a step by step repro:
- yo @microsoft/sharepoint
- (choose knockout, otherwise all defaults)
- npm install jquery --save
- npm install jquery-typeahead --save
- add externals to "config.json" (see below)
- add "jquery" and "jquery.typeahead" to view model (see below)
- add debug output to view model constructor (see below)
- gulp serve - open in IE, see difference between Ctrl F5 and F5
config.json:
"externals": {
"jquery": {
"path": "./node_modules/jquery/dist/jquery.min.js",
"globalName": "jQuery"
},
"jquery.typeahead.min": {
"path": "./node_modules/jquery-typeahead/dist/jquery.typeahead.min.js",
"globalName": "typeahead",
"globalDependencies": ["jquery"]
}
},
Add to HelloWorldViewModel.ts on top:
import * as $ from 'jquery';
require("jquery.typeahead.min");
Add debug output to constructor:
constructor(bindings: IHelloWorldBindingContext) {
alert(($ as any).typeahead); // <-- THIS
this.description(bindings.description);
Boom (IE 11).