9

I always get a message saying:

$.hubConnection is not a function

Error: jQuery was not found. Please ensure jQuery is referenced before the SignalR client JavaScript file. consoling out "$" and "jquery" is undefined.

What do I need to do, to get signalr working using webpack?

hannes neukermans
  • 12,017
  • 7
  • 37
  • 56

3 Answers3

15

Clean solution: use expose-loader !!

npm install expose-loader --save-dev

inside your vendor.ts

import 'expose-loader?jQuery!jquery';
import '../node_modules/signalr/jquery.signalR.js';

inside your webpack.config.ts

new ProvidePlugin({ jQuery: 'jquery', $: 'jquery', jquery: 'jquery' })

Explanation: The jquery.signalR.js script is indeed not written as a umd module. Which makes it by default, not to be loadable by webpack. It doesn't require jquery, but assumes that Jquery lives on the global variable window.jQuery. We can make this work in webpack by importing the jquery module with the expose-loader. This loader will make sure that the exported value of jquery, is exposed to the jQuery global var. Thus allowing to load the signalr.js script as the next module.

Also if you want to later use signalr by using $, you also will have to use the provideplugin for the jquery module. inside webpack.config.js

dasch88
  • 999
  • 10
  • 13
hannes neukermans
  • 12,017
  • 7
  • 37
  • 56
  • this works to load jQuery and signalR, but I am sttill unable to call `$.connection.myHub` since the hub proxies are not loaded. How can I achieve this with webpack? – marsop Oct 28 '16 at 08:55
  • Using the dynamically generated signalr/hubs script is optional. Currently I don't use it, inside my webpack environment. – hannes neukermans Oct 28 '16 at 09:37
  • 1
    Using the dynamically generated signalr/hubs script is optional. I use **$.hubConnection(this.url)** & **connection.createHubProxy(this.hubName)** and it works. – hannes neukermans Oct 28 '16 at 09:44
  • Thanks, indeed import **import 'expose-loader?jQuery!jquery'** is the solution for using signalR with Webpack. I had no problem calling server methods $.connection['myHub'].server.chat( message ), or client methods $.connection['myHub'].client.chat = ( message : string ) => { ... }. – Anthony Brenelière May 22 '17 at 15:16
6

Thanks to hannes and this guide from Microsoft I managed to get SignalR working with Webpack and TypeScript using the ES6 syntax.

Before:

///<reference path="./vendor/typings/signalr/signalr.d.ts"/>

interface SignalR {
    myHub: Some.Stuff.IMyHubProxy;
}

namespace MyWebsite.Stuff {
    export class SignalRConnectionService {
        ...
        public start() {
            var myHubProxy = $.connection.myHub;

            myHubProxy.client.onSomethingChanged = (eventArgs) => {
                // do stuff
            };

            $.connection.hub.start();
        }
    }
}

After:

import "signalR";

export class SignalRConnectionService {
    public start() {
        ...
        const hubConnection = $.hubConnection();
        const myHubProxy = hubConnection.createHubProxy('myHub');

        myHubProxy.on('onSomethingChanged', (summary) => {
            // do stuff
        });

        hubConnection.start();
    }
}

webpack.config.js:

plugins: [
    new webpack.ProvidePlugin({
        $: "jquery",
        'window.jQuery': 'jquery',
        jQuery: "jquery"
    })
]

packages.json:

"dependencies": {
  "jquery": "~2.1.4",
  "signalr": "~2.2.3"
}

NB: You will also need to remove loading of <script src="/signalR/hubs"/> as it's no longer needed.

Vedran
  • 10,369
  • 5
  • 50
  • 57
1

Extedning Hannes Neukermans's answer:

Using webpack.ProvidePlugin makes jQuery available globaly, but it also let jQuery getting into middle where it shouldn't. For instance, it wrapps some events with jQuery-specific object (KeyboardEvent => jQuery.Event).

So better is not to use webpack.ProvidePlugin at all, and use the expose-loader only instead.

In your webpack.config.js:

module: {
    rules: [
        {
            test: require.resolve('jquery'),
            use: [
                {
                    loader: 'expose-loader',
                    options: 'jQuery'
                },
                {
                    loader: 'expose-loader',
                    options: '$'
                }
            ]
        }
    ]
}

You still have to import signalR and jQuery in your vendor.ts:

import 'jquery';
import 'signalR';