3

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:

enter image description here

This is correct - this is the typehead library.

After pressing F5 in IE this changes to:

enter image description here

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:

  1. adding "jquery.typeahead" to the globalName "jQuery"
  2. 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!):

enter image description here

Then when pressing F5 in IE (not expected at all!):

enter image description here

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:

  1. yo @microsoft/sharepoint
    • (choose knockout, otherwise all defaults)
  2. npm install jquery --save
  3. npm install jquery-typeahead --save
  4. add externals to "config.json" (see below)
  5. add "jquery" and "jquery.typeahead" to view model (see below)
  6. add debug output to view model constructor (see below)
  7. 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).

1

Here's what I got from a member of the team when I posed this to them:


One thing that surprises me is that he is putting both dependencies as ‘jQuery’ global name, which is confusing, and looks like the issue could be somewhere there.

jquery-typeahead modifies the jquery object and returns a different thing. In his code I see he’s using the output of require(), instead of the global object, therefore defining a global object does more harm than good in there.

  • Thanks for checking back. I hope to address these concerns with my edit. The problem still persists. – Heinrich Ulbricht Mar 20 '17 at 14:21
  • I could repro the behavior using a newly created project - the steps are outlined above. Let me know if you need the project, but the repro is quickly done. Thanks for any efforts you guys put into this! – Heinrich Ulbricht Mar 20 '17 at 14:51
1

This solution solves the problem for me:

  • remove everything regarding jquery and "jquery.typeahead" from config.json
  • require "jquery.typehead" from "node_modules" directly

The require looks like this:

require("jquery-typeahead/src/jquery.typeahead");

Webpack will resolve this correctly to the js file located in the node_modules directory of your project.

After this change pressing F5 in IE works as expected. The error is gone.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.