0
votes

While writing a Typescripts application where I am using RequireJS for loading the modules (I use Visual Studio 2015).

I can easily load almost all of the modules either from .ts classes I wrote myself for from external libraries using their typing .d.ts files.

But my problem begins where I want to load a plugin for jquery.

I am using the typing file for the library but logically there is no module definitions in the .d.ts file because it's just a plugin for jquery.

I have followed the recommendations for shim library loading from RequireJS website like this:

requirejs.config({
baseUrl: "Scripts",
paths: {
    "jquery": "jquery-2.2.3",
    "jquery.pjax": "jquery.pjax"
},
shim:
{
    "jquery.pjax":
    {
        deps: ["jquery"],
        exports: "jQuery.fn.pjax"
    }
}
});
require(["app"]);

And according to the RequireJS website:

The shim config only sets up code relationships. To load modules that are part of or use shim config, a normal require/define call is needed. Setting shim by itself does not trigger code to load.

Now, neither of the following work for loading the plugin (even after moving the jquery.pjax.d.t next to the jquery.pjax.js):

import * as pjax from "jquery.pjax";

import pjax = require("jquery.pjax");

import pjax = require("./jquery.pjax");

import pjax = require("jquery.pjax.js");

import pjax = require("./jquery.pjax.js");

Compiler complains with the error Cannot find module "jquery.pjax" or File C:/foo/bar/jquery.pjax.d.ts is not a module.

The app.ts does not get compiled as long as any of the codes above exists and when I remove them, the plugin does not get loaded.

Regarding that I am using several imports in my app.ts file and there will be more, I prefer to use import Foo = require("foo") or import * as Foo from "foo" module loading style in opposition to writing the AMD define function manually.

Also I am using Nuget package management and I prefer not to edit/move external .d.ts or .js files manually.

Can anyone help me figure this out please?

1

1 Answers

1
votes

If you want to be able to call require("jquery.pjax") then either there needs to be a real TypeScript module defined and findable with that name, or there needs to be a declaration of it somewhere: declare module "jquery.pjax".

I think your options are:

  • Load jQuery totally outside RequireJ (e.g. include both jQuery and jQuery.pjax with plain script tags in your page, and just use them globally). This is what the .d.ts file you have is expecting you to do, becaues jQuery.pjax isn't actually a RequireJS module at all (which is why you're having to use your shim config)
  • Add a module declaration into your codebase and persuade TypeScript that it's a real RequireJS module. This can either be inside your existing .d.ts definition for jquery.pjax, or standalone in a separate file if that's easier for you. You can then require this. Note that if you require it and don't reference it TypeScript won't actually output the dependency, so you'll need a fake reference to it.
  • Use RequireJS manually to load it, outside TypeScript's module system. For plugin ecosystems like this, I normally give the real library the name 'raw-libraryname' in my RequireJS paths, and then create a new 'libraryname.ts' myself, which pulls in the raw library and the plugins, does any setup required, and returns the result (which everybody else can depend on normally). E.g:

    // Require config:
    requirejs.config({
        baseUrl: "Scripts",
        paths: {
            "raw-jquery": "jquery-2.2.3", // only plugins depend on this
            "jquery.pjax": "jquery.pjax",
            "jquery": "lib-wrappers/jquery" // everything else uses this which
                                            // includes all your plugins
        },
        shim:
        {
            "jquery.pjax":
            {
                deps: ["raw-jquery"]
                // I don't think you need an exports here.
                // Anybody who wants this should be using it from jQuery.
            }
        }
    });   
    
    
    
    // in lib-wrappers/jquery.ts
    define(["raw-jquery", "jquery.pjax"], function ($) {
        // RequireJS guarantees that this line is run before anything that
        // depends on jQuery, and after both jQuery & any plugins above are loaded
        return $;
    });
    

    This ensures that everything else can continue using jQuery through RequireJS as normally, while still guaranteeing that the non-requirejs module (jquery.pjax) will be ready and loaded before they try to use it from jQuery.