简体   繁体   中英

RequireJS/AMD external module resolution

In any module I create for my app, I can put the following:

import ko = require("knockout");

I then have a ko object I can use.

If I write my own module, say /app/services/I18n.js , I have to import it using the path:

import i18m = require("services/I18n");

I'd like to know what the Knockout module has done to make that possible so I can do the same. I'm expecting it to be something about the Knockout.d.ts that comes with Knockout.TypeScript.DefinitelyTyped , I just don't know what.

I've tried adding a configuration item to my RequireJS config in my main.ts :

requirejs.config({
    baseUrl          : "/app",
    urlArgs          : "bust=" + (new Date()).getTime(),
    paths            : {
        "text"       : "lib/requirejs-text/text",
        "durandal"   : "lib/durandal/js",
        "plugins"    : "lib/durandal/js/plugins",
        "transitions": "lib/durandal/js/transitions",
        "knockout"   : "lib/knockout.js/knockout",
        "jquery"     : "lib/jquery/jquery",
        "uuid"       : "lib/node-uuid/uuid",
        "bootstrap"  : "lib/bootstrap-sass-official/javascript/bootstrap",
        "I18n"       : "services/I18n"
    }
});

But that isn't "noticed" by Visual Studio or ReSharper, so has no effect (I'm unclear whether it work at runtime).

The long and the short of it is that I'm unclear how modules are found. Is it always by filename? Does the path mean anything? Are there special rules for *.d.ts ? It feels like there's magic going on.

The TypeScript module resolution is a bit fishy. Brocco is right in his answer regarding to local modules in *.ts files. TS doesn't read the require config - there is a new tsconfig.json file (as of v1.5 I think) where you can provide configuration for the compiler. If you want your i18n module to be recognized like eg the knockout module by say Visual Studio you need to declare these in a *.d.ts file - in TS lingo this is an ambient declaration. The declaration files are special in that you have to take care not to export anything from the top-level within these files or else TS will bombard you with nonsense error messages - so no top-level export s are allowed but instead you just declare what TS should take for granted. This is an example file for this use case:

// i18n.d.ts
interface I18n {
    // Your module's TS interface
    translate(key: string): string;
}

declare var i18n: I18n;

declare module "i18n" {
    export = i18n;
}

This will tell the TS compiler that there is a top-level module called i18n that will be present after compilation with the specified interface. After compilation to AMD modules you need to provide the information where to find this module at runtime in the configuration:

// require.config.js
requirejs.config({
    // ...
    paths            : {
        // ...
        // Tell require.js where to find your module
        "I18n"       : "services/I18n"
    }
});

This is the setup I'm working with, hope it helps.

It isn't really something special that has been done by ko itself, it is more related to how packages are resolved/found. When you reference a local/internal module you should preface it with a ./ so the module resolution knows where to look.

As for ko (and other npm packages) it will traverse up the folder structure until a package.json file is found, and from there it will traverse through the dependencies. And within each dependency it will look in its package.json main field/property to determine which file/module is loaded.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM