Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typing resolutions #102

Closed
guybedford opened this issue Feb 3, 2016 · 55 comments
Closed

Typing resolutions #102

guybedford opened this issue Feb 3, 2016 · 55 comments

Comments

@guybedford
Copy link
Contributor

It sounds like the resolution problems tackled in typings/typings#123 are critical to this plugin's type checking feature. I'd be really interested to see what can be done to make this work, if you don't mind helping me understand this area a little better.

Firstly, jspm-npm will handle conversion of npm packages converting the Node resolution algorithm into the SystemJS resolution algorithm.

Are you saying that typings themselves are written assuming the Node resolution algorithm? Which assumptions are these usually based on? For example, are extensions usually used? Do directory requires or json requires get used? How exactly does SystemJS's naive import not work with this resolution currently?

@frankwallis
Copy link
Owner

A little bit of background on TypeScript typings - originally .d.ts files were included using /// reference path="./typings/angular.d.ts" comments in the source files which needed them. These ambient declaration files contain module definitions like this:

declare module "angular" {
   function bootstrap(modules: Module[]);
}

When you do import angular from "angular" TypeScript then finds the "angular' module declaration and uses that for type-checking. This is quite straightforward for the plugin as it knows all the files which it needs to load to type-check a source file.

Recently there has been change so that you can deliver external declaration files, these are a little different to the one above because the file itself is the module, so the one above would look like:

export function bootstrap(modules: Module[]);

and when you do import angular from "angular" TypeScript will see that the "angular" package has a typings file and use that when type-checking the file. So how does it know whether the angular package has a typings file? Well the algorithm goes something like:

a) Look in package.json for "typings" field. If found use that.
b) Resolve the imported .js file using node.js resolution and see if there is a .d.ts file of the same name

Rule (b) also applies when doing import router from "angular/router". The exact algorithm is described here

So this is the difficulty when loading tin the browser, because the plugin doesn't know which packages have typings files. SystemJS resolution can't be used because that needs to resolve to the .js file.

Angular2 delivers multiple typings files in the npm package and this makes it impossible to type-check in the browser unless you switch back to using one of the old-style ambient declaration files. Solving the angular2 problem ought to be the priority here I think.

If jspm could record any .d.ts files it finds when installing packages so that they were available somewhere in the runtime config then that might work, could jspm-npm do that? Otherwise the typings project may be able to provide this information but its not quite clear how that is going to pan out right now.

I hope this is clearer and we can find a way forward.

edit: updated the terminology to be in line with the rest of the thread.

@robwormald
Copy link

bit more info for background - there are two types of typings files now - "ambient" and "external" - angular2 uses the externals (they are basically es6 modules, more or less) and effectively its a reasonable guarantee that there's 1 .d.ts file per .js file - this is how typescript outputs them.

its unlikely we'll switch back to the old style (ambient) any time soon / ever, and ideally we'd like to not have to tell consumers of NG2 to do the same.

the typings project is for ambient modules only (afaik) and thus we won't be delivering the typings to it's registry for angular2.

@guybedford @frankwallis happy to have a pow-wow if you guys want to work through this.

@robwormald
Copy link

see also microsoft/TypeScript#6012 - and as of TS 1.8 there's a new (configurable) resolution strategy which is ~mostly JSPM style.

@frankwallis
Copy link
Owner

@robwormald yes maybe I am using wrong terminology so the first example above is "ambient" and the second one "external".

In the angular2 case, then, a simple boolean flag to say the package does have external typings would be enough. The plugin would always resolve and fetch external typings for files inside that package. That flag could go in:

  • angular2 package.json typings: true (probably illegal)
  • jspm section of angular2 package.json
  • jspm registry
  • typescriptOptions of consumers
  • package config of consumers

So to account for most common scenarios, jspm could retrieve the value of typings from package,json and make it available to the plugin in runtime configuration. This field (or some other flag) would also be settable in the jspm registry and setting it to true would mean resolve external typings for all modules. Does this sound possible?

@frankwallis
Copy link
Owner

@robwormald I don't think I am able to use the new algorithm in the browser, because it needs to search for files. It solves the issue of missing intellisense and being able to use tsc with jspm and external typings though, which is progress.

@robwormald
Copy link

@frankwallis let me see what we can do about your first question, we should be able to make one of those options work.

The second though - assuming you know that there are typings, no search should be needed, as they are 1 to 1 for the actual source files. (that is, foo.ts becomes foo.js and foo.d.ts on npm) - or am i misunderstanding you?

@frankwallis
Copy link
Owner

@robwormald thanks, I'm really keen to get this working.

I need to have a look at the how this new paths compiler option is implemented and how it interacts with moduleResolution: node, but yes I suppose my point is more about implementing moduleResolution: node without doing nodejs file-system calls.

@alj1s
Copy link

alj1s commented Feb 6, 2016

@robwormald my understanding is that typings is for external modules. See here and here. So then Angular2 could be added to the registry. Or have I missed something?

@guybedford
Copy link
Contributor Author

@frankwallis @robwormald thanks for the clear descriptions here. It does sound like Angular would be the nice case to crack here to set the precedent.

@robwormald did you say we really can assume the convention then that the typing file for a fully-resolved .../full/path/to/module.js is located at .../full/path/to/module.d.ts? Or would such a convention have edge case limitations when scaling over npm?

@frankwallis
Copy link
Owner

@ximenean as I understand it the aim of the typings project is to allow ambient modules to co-exist with external modules until everything has been moved to external modules. It's all rather confusing though...

Some new docs have just arrived on the subject: https://github.com/typings/typings/blob/master/docs/how-typings-makes-external-modules-first-class.md

@frankwallis
Copy link
Owner

@guybedford that is only true for the angular2 package.

As an example of another sort of package angular/zone.js contains a typings field in package.json (https://github.com/angular/zone.js/blob/master/package.json#L6)

{
  "name": "zone.js",
  "version": "0.5.13",
  "description": "Zones for JavaScript",
  "main": "build/lib/zone.js",
  "typings": "build/lib/core.d.ts",

This file (build/lib/core.d.ts) will contain bundled typings for the whole package.

@guybedford
Copy link
Contributor Author

@frankwallis as far as I can tell zone.js does use the same convention within in its file structure. It does seem a very sensible convention that would be easily compatible with SystemJS if this is the way things are moving.

@frankwallis
Copy link
Owner

@guybedford yes and in fact the core.d.ts typings entry in package.json looks incorrect to me, it should point to zone.d.ts. Another example is RxJS, which in 5.0.0-beta also follows the same convention.

I think it is quite likely that packages which are developed in TypeScript will follow this convention, but packages which are developed in JavaScript may choose to have a single bundled typings file.

@frankwallis
Copy link
Owner

I have managed to get the angular2 example type-checking by telling the plugin which packages have typings files, the configuration looks like this currently:

typingsMap: {
   angular2: true,
   rxjs: true
}

This works because all imports from these packages specify the module name to be imported (ie import {bootstrap} from "angular2/boostrap". I don't know how to find out the main of a package within SystemJS, so import {bootstrap} from "angular2" would not currently work.

@guybedford
Copy link
Contributor Author

In jspm 0.17, the main entry point problem here goes away because the main is resolved as part of the normalize step instead of fetched through a pointer module. In cases where you don't have a true value for the typingsMap, perhaps you can just infer from the fact that the plugin fetch hook is being called for a source and load the typing file in parallel at that point (even if it is a 404)?

@frankwallis
Copy link
Owner

@guybedford that's good news about the main entry point issue in 0.17, and I was hoping you would say that! Unfortunately I don't think the plugin fetch hook will always be called in this situation, as the actual file will resolve to a .js file, but TBH I don't think it's a big deal if it can't be fully supported until 0.17, as long as angular2 works.

What are your thoughts about putting this configuration into the package config? I am happy to do a PR if you point me in the right direction.

I would propose that:

  • The typings field would be loaded package.json when availble
  • It could be overridden in jspm registry, where it can also be set to true
  • It could be overridden in user package config or overrides, where it can also be set to true

Does this sound ok?

@guybedford
Copy link
Contributor Author

@frankwallis I'd strongly suggest moving on the 0.17 upgrade path and encouraging users here to as well. I would have published it as stable already, but am going slowly on the stable branch rather to give users time, but individual projects should push forward.

The only way to handle a custom field through the package configuration is through meta exactly as in #96 -

{
  "meta": {
    "*.ts": {
      "loader": "typescript",
      "typescriptOptions": {
        "typings": {...}
      }
    }
  }
}

Would you still consider that if a TypeScript file is run through the fetch hook, the loader would request the typing by default? If the fetch hook is not run for that specific file (eg for 0.16 mains), then a field like this makes sense certainly. It could potentially also act as an opt-out for the automatic typing loading if that is implemented.

My biggest concern is what normalization space this field is acting in? Multiple plain names can refer to the same module, so you'd need to run that name through System.normalizeSync or System.decanonicalize to get into URL space for name comparison (the only space in which comparison is unique). normalizeSync probably gives the most naming flexibility handling all the many-to-one options.

@guybedford
Copy link
Contributor Author

The other thing is even if using normalizeSync, it should probably be a contextual normalization as well to get all the contextual package maps. It's not completely clear though which contextual parent is intended for such an unnormalized typing (with System.normalizeSync(typingName, whichParentName?))

@frankwallis
Copy link
Owner

If it's a typescript file we don't need any typings, the typings files are only needed for packages delivered as .js files.

The plugin needs to know:
a) the value of the typings field in package.json if there is one
b) a flag to tell it that a package provides typings files alongside all of its js files

So the typings field in package config would either be a string for situation (a) or true for situation (b). The plugin handles all the normalization stuff already I think.

I have put in the typingsMap field into typescriptOptions so that I could see if this was going to work, but it is really meant as a stopgap until this configuration can come from the packages themselves.

@guybedford
Copy link
Contributor Author

Ahh, right, thanks for bearing with - sorry it's my distance from these workflows showing in these simple errors. I'm really so grateful you are working all of this out!

So the '.js' file has matching '.d.ts' typings usually when it was compiled from TypeScript as separate files then? And thats what Angular and Rxjs do? Is there any indication in the source code of those .js files that these typings files exist? You mentioned the comment method previously?

Would a TypeScript package ever have a typings field for its dependencies? Or is the point here that we associate all typings through overrides to the underlying files?

So in jspm 0.17 "meta" can be provided as a field in the package.json (along with all other SystemJS package config options). The code example in my previous comment could be the package.json file itself or the override.

Thinking further, could you not just do something like:

{
  "meta": {
    "*.js": {
      typings: true
    }
  }
}

So that we use the individual metadata per-module to indicate which files have associated typings?

@robwormald
Copy link

might be better with "external" vs "ambient" to denote parallel typings (external)?

@frankwallis
Copy link
Owner

hey no problem, I just want to make sure we get to the right place.

So, yes, angular2 and rxjs provide .d.ts files alongside their .js files, but there is no way to figure this out without looking at the files which are in the package.

Some other packages can populate a typings field in package.json which will point to a single .d.ts fie which corresponds to their main file. It remains to be seen how much this will be used.

I'm not quite clear on your question, but I think the answer is that a TypeScript package would not have typings for it's dependencies - the plugin should automatically locate those typings in the dependency package if they exist, and feed them into the compiler. This is why it is important for the plugin to know what typings are present.

Providing this information in the meta might work, if I can access it at the right time. As an example:

somefile.ts:

import {boostrap} from "angular/bootstrap"
...

At this point I normalize "angular/bootstrap" -> "http://jspm_packages/.../bootstrap.js" and I then need to get the meta for that file. I'm not quite sure how to do that?

I will have a play around with this and report back. If it works then I think we will have a solution as this meta can be added into the jspm registry presumably, or put in the angular2 package.json file?

@guybedford
Copy link
Contributor Author

There's a hack that can be used to get the metadata for a package, but it won't work in future versions when the locate hook is deprecated. We can make sure the use case sticks around somehow though.

Basically you can do:

var metadata = {};
System.locate({ name: 'http://jspm_packages/.../bootstrap.js', metadata: metadata })
.then(function(address) {
  // metadata.typings, metadata.typescriptOptions etc should all now be populated correctly,
  // respecting the composition of all global metadata, wildcard metadata and package metadata correctly
});

Yes meta can be in the original package.json or the jspm registry. I hate to be introducing "another" way of doing this stuff, but we do just need to let these metadata conventions all fight it out in the wild for a bit I think.

@frankwallis
Copy link
Owner

ok I'll give that a try and report back. I also think that this stuff is likely to change on the typescript side (see microsoft/TypeScript#6950 for example), so I agree it's good not to be over committed at this time.

@frankwallis
Copy link
Owner

@robwormald I don't understand - can you clarify?

@frankwallis
Copy link
Owner

I have added support for specifying typings configuration in metadata and it is released in 4.0.0. The angular2 project now type-checks as I have added packages configuration here:

    "angular2": {
      "meta": {
        "*.js": {
          "typings": true
        }
      }
    },
    "rxjs": {
      "meta": {
        "*.js": {
          "typings": true
        }
      }
    }

@frederikschubert
Copy link

Would it be possible to add this meta information to the packages overrides in the jspm registry? So that the consumer of the library doesn't have to set this in his jspm.config.js.

@frankwallis
Copy link
Owner

@frederikschubert yes that is the plan, I just need to get it working with a manual override first to verify.

@rolandjitsu
Copy link

That gives me:

Chrome 49.0.2623 (Mac OS X 10.11.3) ERROR: 'TypeScript', Error{originalErr: Error{}}
Chrome 49.0.2623 (Mac OS X 10.11.3) ERROR: 'Potentially unhandled rejection [4] Error: http://localhost:9876/jspm_packages/npm/reflect-metadata@0.1.3/typings.d.ts!http://localhost:9876/jspm_packages/github/frankwallis/plugin-typescript@4.0.2/plugin.js detected as esm but didn't execute.
            at tryCatchReject (http://localhost:9876/base/jspm_packages/system-polyfills.src.js?3aa57969dce4ecea4c51aab540f372d15cc886b6:1252:30)
            at runContinuation1 (http://localhost:9876/base/jspm_packages/system-polyfills.src.js?3aa57969dce4ecea4c51aab540f372d15cc886b6:1211:4)
            at Fulfilled.when (http://localhost:9876/base/jspm_packages/system-polyfills.src.js?3aa57969dce4ecea4c51aab540f372d15cc886b6:999:4)
            at Pending.run (http://localhost:9876/base/jspm_packages/system-polyfills.src.js?3aa57969dce4ecea4c51aab540f372d15cc886b6:890:13)
        Error loading http://localhost:9876/jspm_packages/npm/reflect-metadata@0.1.3/typings.d.ts!http://localhost:9876/jspm_packages/github/frankwallis/plugin-typescript@4.0.2/plugin.js'

And the reflect-metadata@1.3.0.json generated by JSPM looks like:

{
  "main": "Reflect.js",
  "map": {
    "crypto": "@empty"
  },
  "format": "cjs",
  "meta": {
    "*": {
      "globals": {
        "process": "process"
      }
    },
    "*.json": {
      "format": "json"
    },
    "typings.d.ts": {
      "format": "esm"
    }
  }
}

So maybe that is not the right config?

@rolandjitsu
Copy link

Yeah, so the right way for this is:

"npm:reflect-metadata@0.1.3": {
    "meta": {
        "Reflect.js": {
            "typings": "Reflect.ts"
        }
    }
}

Maybe this should be reported as Reflect.ts should probably be Reflect.d.ts.

@svi3c
Copy link
Contributor

svi3c commented May 10, 2016

What is the current status of this issue?
As far as I tested, typeCheck works on server side compilation, but not yet on client side.
At least when using external dependencies I get errors:

logger.js:17 TypeScript http://localhost:9987/jspm_packages/npm/@ngrx/store@1.5.0/interfaces.d.ts:1:28Logger.error @ logger.js:17(anonymous function) @ format-errors.js:13formatErrors @ format-errors.js:7(anonymous function) @ plugin.js:39
logger.js:17 TypeScript Cannot find module 'rxjs/Observable'. (TS2307)Logger.error @ logger.js:17(anonymous function) @ format-errors.js:20formatErrors @ format-errors.js:7(anonymous function) @ plugin.js:39
logger.js:17 TypeScript http://localhost:9987/jspm_packages/npm/@ngrx/store@1.5.0/store.d.ts:1:28Logger.error @ logger.js:17(anonymous function) @ format-errors.js:13formatErrors @ format-errors.js:7(anonymous function) @ plugin.js:39
logger.js:17 TypeScript Cannot find module 'rxjs/Observable'. (TS2307)Logger.error @ logger.js:17(anonymous function) @ format-errors.js:20formatErrors @ format-errors.js:7(anonymous function) @ plugin.js:39
logger.js:17 TypeScript http://localhost:9987/jspm_packages/npm/@ngrx/store@1.5.0/store.d.ts:2:33Logger.error @ logger.js:17(anonymous function) @ format-errors.js:13formatErrors @ format-errors.js:7(anonymous function) @ plugin.js:39
logger.js:17 TypeScript Cannot find module 'rxjs/BehaviorSubject'. (TS2307)Logger.error @ logger.js:17(anonymous function) @ format-errors.js:20formatErrors @ format-errors.js:7(anonymous function) @ plugin.js:39
logger.js:17 TypeScript http://localhost:9987/jspm_packages/npm/@ngrx/store@1.5.0/dispatcher.d.ts:1:25Logger.error @ logger.js:17(anonymous function) @ format-errors.js:13formatErrors @ format-errors.js:7(anonymous function) @ plugin.js:39
logger.js:17 TypeScript Cannot find module 'rxjs/Subject'. (TS2307)Logger.error @ logger.js:17(anonymous function) @ format-errors.js:20formatErrors @ format-errors.js:7(anonymous function) @ plugin.js:39
logger.js:17 TypeScript http://localhost:9987/jspm_packages/npm/@ngrx/store@1.5.0/ng2.d.ts:1:39Logger.error @ logger.js:17(anonymous function) @ format-errors.js:13formatErrors @ format-errors.js:7(anonymous function) @ plugin.js:39
logger.js:17 TypeScript Cannot find module '@angular/core'. (TS2307)Logger.error @ logger.js:17(anonymous function) @ format-errors.js:20formatErrors @ format-errors.js:7(anonymous function) @ plugin.js:39
logger.js:17 TypeScript http://localhost:9987/src/app/pages/test1.component.ts:1:25Logger.error @ logger.js:17(anonymous function) @ format-errors.js:13formatErrors @ format-errors.js:7(anonymous function) @ plugin.js:39
logger.js:17 TypeScript Cannot find module '@angular/core'. (TS2307)Logger.error @ logger.js:17(anonymous function) @ format-errors.js:20formatErrors @ format-errors.js:7(anonymous function) @ plugin.js:39
logger.js:17 TypeScript http://localhost:9987/src/app/pages/test1.component.ts:2:31Logger.error @ logger.js:17(anonymous function) @ format-errors.js:13formatErrors @ format-errors.js:7(anonymous function) @ plugin.js:39
logger.js:17 TypeScript Cannot find module '@angular/common'. (TS2307)Logger.error @ logger.js:17(anonymous function) @ format-errors.js:20formatErrors @ format-errors.js:7(anonymous function) @ plugin.js:39
logger.js:17 TypeScript http://localhost:9987/src/dev/main.dev.ts:7:25Logger.error @ logger.js:17(anonymous function) @ format-errors.js:13formatErrors @ format-errors.js:7(anonymous function) @ plugin.js:39
logger.js:17 TypeScript Cannot find module '@angular/platform-browser-dynamic'. (TS2307)Logger.error @ logger.js:17(anonymous function) @ format-errors.js:20formatErrors @ format-errors.js:7(anonymous function) @ plugin.js:39
logger.js:17 TypeScript http://localhost:9987/src/dev/main.dev.ts:10:32Logger.error @ logger.js:17(anonymous function) @ format-errors.js:13formatErrors @ format-errors.js:7(anonymous function) @ plugin.js:39
logger.js:17 TypeScript Cannot find module '@angular/router-deprecated'. (TS2307)Logger.error @ logger.js:17(anonymous function) @ format-errors.js:20formatErrors @ format-errors.js:7(anonymous function) @ plugin.js:39
logger.js:17 TypeScript http://localhost:9987/src/app/app.ts:1:25Logger.error @ logger.js:17(anonymous function) @ format-errors.js:13formatErrors @ format-errors.js:7(anonymous function) @ plugin.js:39
logger.js:17 TypeScript Cannot find module '@angular/core'. (TS2307)Logger.error @ logger.js:17(anonymous function) @ format-errors.js:20formatErrors @ format-errors.js:7(anonymous function) @ plugin.js:39
logger.js:17 TypeScript http://localhost:9987/src/app/app.ts:2:46Logger.error @ logger.js:17(anonymous function) @ format-errors.js:13formatErrors @ format-errors.js:7(anonymous function) @ plugin.js:39
logger.js:17 TypeScript Cannot find module '@angular/router-deprecated'. (TS2307)Logger.error @ logger.js:17(anonymous function) @ format-errors.js:20formatErrors @ format-errors.js:7(anonymous function) @ plugin.js:39
logger.js:17 TypeScript http://localhost:9987/src/app/todos/todo.service.ts:4:26Logger.error @ logger.js:17(anonymous function) @ format-errors.js:13formatErrors @ format-errors.js:7(anonymous function) @ plugin.js:39
logger.js:17 TypeScript Cannot find module '@angular/core'. (TS2307)Logger.error @ logger.js:17(anonymous function) @ format-errors.js:20formatErrors @ format-errors.js:7(anonymous function) @ plugin.js:39
logger.js:17 TypeScript http://localhost:9987/src/app/todos/todo.service.ts:5:26Logger.error @ logger.js:17(anonymous function) @ format-errors.js:13formatErrors @ format-errors.js:7(anonymous function) @ plugin.js:39
logger.js:17 TypeScript Cannot find module 'rxjs/Observable'. (TS2307)Logger.error @ logger.js:17(anonymous function) @ format-errors.js:20formatErrors @ format-errors.js:7(anonymous function) @ plugin.js:39
logger.js:17 TypeScript http://localhost:9987/src/app/todos/todo.service.ts:6:20Logger.error @ logger.js:17(anonymous function) @ format-errors.js:13formatErrors @ format-errors.js:7(anonymous function) @ plugin.js:39
logger.js:17 TypeScript Cannot find module 'immutable'. (TS2307)Logger.error @ logger.js:17(anonymous function) @ format-errors.js:20formatErrors @ format-errors.js:7(anonymous function) @ plugin.js:39
logger.js:17 TypeScript http://localhost:9987/src/app/todos/todos.store.ts:2:20Logger.error @ logger.js:17(anonymous function) @ format-errors.js:13formatErrors @ format-errors.js:7(anonymous function) @ plugin.js:39
logger.js:17 TypeScript Cannot find module 'immutable'. (TS2307)Logger.error @ logger.js:17(anonymous function) @ format-errors.js:20formatErrors @ format-errors.js:7(anonymous function) @ plugin.js:39
logger.js:17 TypeScript http://localhost:9987/src/app/pages/test2.component.ts:1:25Logger.error @ logger.js:17(anonymous function) @ format-errors.js:13formatErrors @ format-errors.js:7(anonymous function) @ plugin.js:39
logger.js:17 TypeScript Cannot find module '@angular/core'. (TS2307)Logger.error @ logger.js:17(anonymous function) @ format-errors.js:20formatErrors @ format-errors.js:7(anonymous function) @ plugin.js:39
logger.js:17 TypeScript http://localhost:9987/src/app/pages/test2.component.ts:2:31Logger.error @ logger.js:17(anonymous function) @ format-errors.js:13formatErrors @ format-errors.js:7(anonymous function) @ plugin.js:39
logger.js:17 TypeScript Cannot find module '@angular/common'. (TS2307)

Ambient dependencies seem not to cause problems.
I'm using lodash in the sources and the matching ambient typings are loaded.

What I would like to achieve in my setup is typescript compilation with typeCheck on client side in combination with hot-module-replacement. This is a promising workflow :)

There is another ticket disabling me on this setup. But I'm not totally sure whether this is a problem with the systemjs-hot-reloader or anything else.

@frankwallis
Copy link
Owner

I think this is working, see the angular2 example

What version of jspm are you using?

@svi3c
Copy link
Contributor

svi3c commented May 10, 2016

I'm using "jspm": "^0.17.0-beta.13".
Which version was used for the example? It's not listed in the package.json

@frankwallis
Copy link
Owner

It's the same version, it's listed in the root package.json.

If you can provide a repro I will take a look.

@sokolovstas
Copy link

I have tried example with Angular2 RC and it won't work. Maybe I'm doing something wrong. Please could you update example to Angular2 RC?

@svi3c
Copy link
Contributor

svi3c commented May 15, 2016

Hi @frankwallis, sorry for the late response. I recently published ng2-jspm-template. Here the problem ocurrs when you turn on typeCheck inside jspm.conf.js and trigger TypeScript compilation inside the browser (for example via hot-module-replacement or starting without development bundling).

@frankwallis
Copy link
Owner

frankwallis commented May 15, 2016

@svi3c thanks for sharing your project.

The issue with Cannot find module 'rxjs/Observable' can be resolved by changing the packages configuration in jspm.config.js:

    "rxjs": {
      "meta": {
        "*.js": {
          "typings": true
        }
      }
    }

becomes

    "npm:rxjs@5.0.0-beta.6": {
      "meta": {
        "*.js": {
          "typings": true
        }
      }
    }

It seems that when the packages configuration and map entry for a package happen in different System.config calls then the metadata is not being found. In your case the typings: true metadata is found for @ngrx but not found for rxjs or @angular/*. This could well be related to systemjs/systemjs#1255

Really this configuration should be setup in the jspm registry but that has not happened yet. In the typescript example project I have moved this configuration into package.json which means that jspm writes it to the config file with the map configuration and makes it easier when updating versions.
Update: Moving the typings metadta to package.json does fix this issue, the metadata does not get written to the config file though it gets written to jspm_packages/npm/rxjs@5.0.0-beta3.js (for example)

The error with the hot reloader trying to reload files is happening because the files were originally coming from the bundle and then trying to be reloaded with the file:// extension. I think that plugin-typescript should not be writing the file:/// extension to the bundles, so I need to investigate that. The hot-reloading should work when not using the bundles configuration though?

@frankwallis
Copy link
Owner

@sokolovstas the angular2 example is now using rc1

@svi3c
Copy link
Contributor

svi3c commented May 15, 2016

Thanks for the clarification and support, @frankwallis! Yes, without using bundles, the hmr works in combination with typeCheck.

@tamird
Copy link
Contributor

tamird commented May 29, 2016

@frankwallis I'm having a similar (?) problem in CockroachDB. Two of our dependencies (redux and reselect) now ship with external typings, so we want plugin-typescript to load them rather than using typings to fetch these files. It doesn't work (no attempt is made to load the .d.ts files). I've tried the workaround you describe here to no avail - jspm install removes the overrides. All the work is here cockroachdb/cockroach@master...tamird:ui-next-update

Any ideas?

EDIT: one thing I noticed while debugging this is that metadata (in Resolver.prototype.lookupTyping) is an empty object for these dependencies.

EDIT: both packages specify typings in their package.json files.

@frankwallis
Copy link
Owner

I haven't tried it yet (it's late here) but on quick inspection the override should be:

    "npm:redux@3.4.0": {
        "meta": {
          "dist/redux.js": {
            "typings": "index.d.ts"
          }
        }
      },

Note the version does not have the ^ it is the actual installed version. typings: true means that all js files will have a corresponding .d.ts file with the same name (like angular2), for bundled typings like redux it should contain the path of the bundle.

Hopefully this will fix it, if not I will take another look.

@tamird
Copy link
Contributor

tamird commented May 29, 2016

@frankwallis updated, but that didn't fix it =/

metadata is still an empty object, too.

@frankwallis
Copy link
Owner

Ok, that configuration only works in jspm@0.17, but in 0.16 you can achieve the same thing by adding global meta configuration in config.js:

  transpiler: "ts",
  typescriptOptions: {
    "typeCheck": "strict",
    "tsconfig": true,
    "targetLib": "ES5"
  },
  meta: {
    "reselect": {
      "typings": "src/reselect.d.ts"
    }
  },

Alternatively you can also install them using the typings tool apparently see this comment which would give intellisense support (I haven't actually tried this though...)

@tamird
Copy link
Contributor

tamird commented May 30, 2016

Indeed, both of the solutions you mention work, thanks.

However, why is it that this doesn't "Just Work" given that the information is already in reselect's package.json?

@frankwallis
Copy link
Owner

The plugin does not have access to the package.json, and even if it did there are some packages which contain typings and do not have a typings entry in packages.json. The algorithm TypeScript uses for finding external typings cannot be used from within a browser as it involves trawling the file system, so when external typings exist the plugin needs to know that they do exist and their exact location.

I agree that the configuration is painful, and I am open to better solutions but I just don't see any at the moment. Ideally this configuration will get added into the central jspm registry and then things will "Just Work" for those packages.

@guybedford
Copy link
Contributor Author

The above typings metadata can also be added with a meta override into the jspm registry for 0.17. Let me know if you'd like help with that at all.

@tamird
Copy link
Contributor

tamird commented Jun 1, 2016

@guybedford if this information was in the jspm registry, it'd end up in my generated config.js, correct?

If that's the case, why doesn't (or can't) jspm read package.json and populate the same thing? Seems to me that the jspm registry ought to be for overriding packages' own information as opposed to housing copies thereof.

@bmayen
Copy link

bmayen commented Jun 2, 2016

@frankwallis, you mentioned that "the algorithm TypeScript uses for finding external typings cannot be used from within a browser as it involves trawling the file system". Would it be possible to support this for precompilation builds and only require the additional configuration for the browser?

@frankwallis
Copy link
Owner

@bmayen it would be possible, but I am reluctant to go down that route as it would mean the file resolution worked completely differently in the 2 scenarios and that would be a constant source of issues. It seems to me that if you are using that workflow then you may be better off type-checking with tsc and just transpiling with the plugin?

@frankwallis
Copy link
Owner

I have added a new compiler option typings to enable easier configuration of packages with external typings contained within. See here for more info.

Also plugin-typescript now supports the types option for when you have installed typings from the @types scoped packages. See here for more info.

I am going to close this issue now, if you find issues with either of these features then please raise them separately.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants