26
votes

I am trying to start using angular 2 cli.
I want to use momentjs in my project so here is what I have done:
1. created project using angular cli.
2. run npm install --save moment
3. from src folder run typings init + typings install --save moment.
4. added moment to system modules:

System.config({
  packages: {
    app: {
      format: 'register',
      defaultExtension: 'js'
    },
    moment: {
      map: 'node_modules/moment/moment.js',
      type: 'cjs',
      defaultExtension: 'js'
    }
  }
});
  1. added import * as moment from 'moment'; to my desired component.
  2. running ng serve and getting:

[DiffingTSCompiler]: Typescript found the following errors: app/angular-day-picker.ts (2, 25): Cannot find module 'moment'. Error: [DiffingTSCompiler]: Typescript found the following errors: app/angular-day-picker.ts (2, 25): Cannot find module 'moment'. at DiffingTSCompiler.doFullBuild (/Users/vioffe/personal/angular-day-picker/node_modules/angular-cli/lib/broccoli/broccoli-typescript.js:202:29) at DiffingTSCompiler.rebuild (/Users/vioffe/personal/angular-day-picker/node_modules/angular-cli/lib/broccoli/broccoli-typescript.js:101:18) at DiffingPluginWrapper.rebuild (/Users/vioffe/personal/angular-day-picker/node_modules/angular-cli/lib/broccoli/diffing-broccoli-plugin.js:87:45) at /Users/vioffe/personal/angular-day-picker/node_modules/angular-cli/node_modules/angular-cli/node_modules/broccoli/lib/api_compat.js:42:21 at lib$rsvp$$internal$$tryCatch (/Users/vioffe/personal/angular-day-picker/node_modules/angular-cli/node_modules/angular-cli/node_modules/rsvp/dist/rsvp.js:1036:16) at lib$rsvp$$internal$$invokeCallback (/Users/vioffe/personal/angular-day-picker/node_modules/angular-cli/node_modules/angular-cli/node_modules/rsvp/dist/rsvp.js:1048:17) at /Users/vioffe/personal/angular-day-picker/node_modules/angular-cli/node_modules/angular-cli/node_modules/rsvp/dist/rsvp.js:331:11 at lib$rsvp$asap$$flush (/Users/vioffe/personal/angular-day-picker/node_modules/angular-cli/node_modules/angular-cli/node_modules/rsvp/dist/rsvp.js:1198:9) at doNTCallback0 (node.js:430:9) at process._tickCallback (node.js:359:13)

Here is my tsconfig.json file:

{
  "compilerOptions": {
    "declaration": false,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "mapRoot": "",
    "module": "system",
    "moduleResolution": "node",
    "noEmitOnError": true,
    "noImplicitAny": false,
    "rootDir": ".",
    "sourceMap": true,
    "sourceRoot": "/",
    "target": "es5"
  },
  "files": [
    "typings/main.d.ts"
  ],
  "exclude": [
    "typings/browser.d.ts",
    "typings/browser"
  ]
}

What did I do wrong? I can't find in the docs a guide to add 3rd party libs.

8

8 Answers

40
votes

When including 3rd party libraries, there are two parts... the javascript code you want to execute, and the definition files to give the IDE all it's strongly-typed goodness.

Obviously, the first must be present if the app is to function. The easiest way to get that is to include the 3rd party library with a <script src="thirdLib.js"> tag in the html page that hosts your Angular 2 app. That will not get you definitions, so you will not have IDE goodness, but the app will function. (to stop the IDE from complaining that it doesn't know about variable 'thirdLib', add declare var thirdLib:any to your ts file. Because it is of type any the IDE will not offer code-completion for thirdLib, but it will also not throw IDE errors.)

To get executing code and definitions, if the lib was written in Typescript, you can add a reference to that ts file from your code with import {thirdLib} from 'thirdLibfolder/thirdLib'. The lib's ts file by its nature has both the executing code and the typescript definitions.

If the lib is not written in Typescript, but some good soul wrote a thirdLib.d.ts definition file for it, you can reference the d.ts file with /// <reference path="thirdLibfolder/thirdLib.d.ts" /> in your ts file. And then still include the actual executing javascript with the script reference as mentioned above.

The location of these files, and whether you include extensions in the reference, are specific to your project setup and the bundler and build tool you are using. Webpack will search node_modules folder for libraries referenced in the import {... and will accept a reference with .ts extension and without. Meteor will throw an error if you include the .ts extension.

5
votes

Example.. First we need to install ChartJS from npm.

npm install chart.js --save

Now that we have installed ChartJS we need to tell the CLI in the angular-cli-build.js file where the new JavaScript file is located so it can be bundled.

var Angular2App = require('angular-cli/lib/broccoli/angular2-app');

module.exports = function(defaults) {
  return new Angular2App(defaults, {
    vendorNpmFiles: [
      'systemjs/dist/system-polyfills.js',
      'systemjs/dist/system.src.js',
      'zone.js/dist/**/*.+(js|js.map)',
      'es6-shim/es6-shim.js',
      'reflect-metadata/**/*.+(js|js.map)',
      'rxjs/**/*.+(js|js.map)',
      '@angular/**/*.+(js|js.map)',
      'chart.js/Chart.min.js',
    ]
  });
};


const map: any = {
  'chartjs': 'vendor/chart.js/'
};


const packages: any = {
  chartjs: { defaultExtension: 'js', main: 'Chart.min.js' }
};
2
votes

support for 3rd party lib via command is still not supported.

Do the following for the moment :

  1. npm install moment
  2. copy moment.js from node_modules/moment to src/assets/js/moment.js
  3. include assets/js/moment.js in your index.html
  4. install the typings and import lib to your .ts file where you need it
  5. run ng serve and enjoy using moment :)

This wiki page gives a more detailed explanation :

https://github.com/angular/angular-cli/wiki/3rd-party-libs

2
votes

Still Angular-cli has some problem with the 3rd party library integration. Until They fix it properly, I can give you a hack around. Lets say you want to use _ of lodash in your code. So I will give you my working code scenario-

To install lodash

npm install lodash --save
typings install lodash --ambient --save

before that make sure you install typings globally

npm install typings -g

Then in your angular-cli-build.json , make sure it remains like this way

module.exports = function(defaults) {
  return new Angular2App(defaults, {
    vendorNpmFiles: [
      ...
      'lodash/**/*.js'
    ]
  });
};

and in your system-config.ts:

/** Map relative paths to URLs. */
 const map: any = {
   'lodash': 'vendor/lodash/lodash.js'
 };

 /** User packages configuration. */
 const packages: any = {
   'lodash': {
     format: 'cjs'
   }
 };

in your src/index.html add this line(This is the weird fix)

<script src="/vendor/lodash/lodash.js" type="text/javascript"></script>

now in your component where you want to use lodash , write this way

declare var _:any;

@Component({
})
export class YourComponent {
  ngOnInit() {
     console.log(_.chunk(['a', 'b', 'c', 'd'], 2));
  }
}

it worked for me :). I have used enormous 3rd party libraries in my angular2 project through angular-cli. Hope it will help you too

Edit:

If you dont get any npm for your third-party libraries. Make an assets folder under your src folder. Then you can add separate folders for js,css and images. Put your third-party js inside the js folder. Then you have to reference js file in your index.html like this way:

<script src="assets/js/your_js.js"></script>

Now, when you do ng serve or ng build it will automatically update the public folder with your assets/js. Hope you understand the whole scenario :)

1
votes

If library you want to include is not in typings you have two ways to include it in an angular 2 application:

  1. using npm: step a. install library using package manager

    step b. add path of the library to the map object in systemjs.config.js file.

example:

'jquery' : 'npm:jquery/dist/jquery.js', 'd3' : 'npm:d3/build/d3.js'

step c. import it in app.module.ts example:

import 'jquery'; import 'd3';

step d. declare it

example: declare var $: any;

declare var d3: any;

  1. simply you can include that in script tag in index.html and declare it.
0
votes

I’m not currently using moment.js myself right now. So I’m not sure, but it seems to me that you are trying to use moment.js as a typescript module and maybe it is not a typescript module. I suggest another approach. Do not use moment.js as module to import but use a d.ts file instead. To accomplish this I’m use tsd: Open a cmd:

  • npm install tsd -g
  • Global install of tsd

  • cd [your project dir]
  • Change to your project root

  • tsd init
  • Among another things, Creates a tsd.json file to keep track of your installed d.ts files

  • tsd install moment -save

After this I did get code completion in typescript after: moment.

Did not test further...

I'm now using typings, instead of tds, as manager for TypeScript definitions. Tds is now deprecated.

You probably can install moment.d.ts like this: typings install moment --ambient --save

0
votes