I've started a new project with the Angular CLI tool. After that I follow this official guide to import Underscore and I do exactly as it says.
But still my project crashes in the browser when I try to use Underscore in my app.component with the error message:
ORIGINAL EXCEPTION: ReferenceError: _ is not defined
Underscore is added to the dist/vendor folder so my guess would be that the problem is in the Systemjs configuration.
Here is my angular-cli-build:
var Angular2App = require('angular-cli/lib/broccoli/angular2-app');
module.exports = function(defaults) {
return new Angular2App(defaults, {
sassCompiler: {
includePaths: [
'src/styles'
]
},
vendorNpmFiles: [
'systemjs/dist/system-polyfills.js',
'systemjs/dist/system.src.js',
'zone.js/dist/**/*.+(js|js.map)',
'es6-shim/es6-shim.js',
'reflect-metadata/**/*.+(ts|js|js.map)',
'rxjs/**/*.+(js|js.map)',
'underscore/underscore.js',
'#angular/**/*.+(js|js.map)'
]
});
};
Here is my system-config:
"use strict";
// SystemJS configuration file, see links for more information
// https://github.com/systemjs/systemjs
// https://github.com/systemjs/systemjs/blob/master/docs/config-api.md
/***********************************************************************************************
* User Configuration.
**********************************************************************************************/
/** Map relative paths to URLs. */
const map: any = {
'underscore': 'vendor/underscore/',
};
/** User packages configuration. */
const packages: any = {
'underscore': { main: 'underscore.js', format: 'cjs' },
};
////////////////////////////////////////////////////////////////////////////////////////////////
/***********************************************************************************************
* Everything underneath this line is managed by the CLI.
**********************************************************************************************/
const barrels: string[] = [
// Angular specific barrels.
'#angular/core',
'#angular/common',
'#angular/compiler',
'#angular/forms',
'#angular/http',
'#angular/router',
'#angular/platform-browser',
'#angular/platform-browser-dynamic',
// Thirdparty barrels.
'rxjs',
// App specific barrels.
'app',
'app/shared',
/** #cli-barrel */
];
const cliSystemConfigPackages: any = {};
barrels.forEach((barrelName: string) => {
cliSystemConfigPackages[barrelName] = { main: 'index' };
});
/** Type declaration for ambient System. */
declare var System: any;
// Apply the CLI SystemJS configuration.
System.config({
map: {
'#angular': 'vendor/#angular',
'rxjs': 'vendor/rxjs',
'main': 'main.js'
},
packages: cliSystemConfigPackages
});
// Apply the user's configuration.
System.config({ map, packages });
My app.component:
/// <reference path="../../typings/globals/underscore/index.d.ts" />
import { Component } from '#angular/core';
declare var _;
#Component({
moduleId: module.id,
selector: 'app-root',
template: `<h1>{{title}}</h1>`
})
export class AppComponent {
title = _.version;
}
Where do I go wrong?
And WHY is this so complicated? Will the community accept it being this cumbersome to just add a simple third party library?
Your configuration basically sets up underscore so SystemJS can find it when needed.
When you changed system-config.ts, you told SystemJS: if anyone asks for underscore, it is a file underscore.js that can be found at the vendor/underscore/ folder -- and its module format is CommonJS (cjs).
The changes at angular-cli-build.js are for telling angular-cli what files it should pick and throw into the vendor folder. (So, if you told SystemJS it'd find underscore there, this is what makes it be there.)
But that alone does not import/add underscore into the global scope of your app.
You have to import it at each .ts file so SystemJS adds it to the transpiled .js of that module.
Instead of these two lines:
/// <reference path="../../typings/globals/underscore/index.d.ts" />
declare var _;
Add this to your file:
import * as _ from 'underscore';
If you have problems, try to inspect the generated .js source being executed at the browser. In your case, you'll probably find that there is no require() method importing the underscore.
The doco adding 3rd party lib is misleading.
I have been banging my head for over an hour!
declare var _; // this won't work.
What you need is
/// <reference path="../../../typings/globals/underscore/index.d.ts" />
import * as _ from 'underscore';
Related
I am using angular 2 CLI for my application.
I installed ng2-bootstrap, and I am wondering how I can use the systemJS tool to automatically include that in my application instead of having to manually put in:
<script src="node_modules/ng2-bootstrap/bundles/ng2-bootstrap.min.js"></script>
Does this go into the system-config.ts? If so, what do I have to do? I tried putting ng2-bootstrap into the third party barrels section, but it didn't seem to do anything.
I ask because I see this in the index.html for the app:
{{#each scripts.polyfills}}
<script src="{{.}}"></script>
{{/each}}
<script>
System.import('system-config.js').then(function () {
System.import('main');
}).catch(console.error.bind(console));
</script>
Thanks
my system-config.js
"use strict";
// SystemJS configuration file, see links for more information
// https://github.com/systemjs/systemjs
// https://github.com/systemjs/systemjs/blob/master/docs/config-api.md
/***********************************************************************************************
* User Configuration.
**********************************************************************************************/
/** Map relative paths to URLs. */
const map: any = {
'ng2-bootstrap': 'vendor/ng2-bootstrap'
};
/** User packages configuration. */
const packages: any = {
'ng2-bootstrap': {
format: 'cjs',
defaultExtension: 'js',
main: 'ng2-bootstrap.js'
}
};
////////////////////////////////////////////////////////////////////////////////////////////////
/***********************************************************************************************
* Everything underneath this line is managed by the CLI.
**********************************************************************************************/
const barrels: string[] = [
// Angular specific barrels.
'#angular/core',
'#angular/common',
'#angular/compiler',
'#angular/forms',
'#angular/http',
'#angular/router',
'#angular/platform-browser',
'#angular/platform-browser-dynamic',
// Thirdparty barrels.
'rxjs',
// App specific barrels.
'app',
'app/shared',
'app/browse',
/** #cli-barrel */
];
const cliSystemConfigPackages: any = {};
barrels.forEach((barrelName: string) => {
cliSystemConfigPackages[barrelName] = { main: 'index' };
});
/** Type declaration for ambient System. */
declare var System: any;
// Apply the CLI SystemJS configuration.
System.config({
map: {
'#angular': 'vendor/#angular',
'rxjs': 'vendor/rxjs',
'main': 'main.js'
},
packages: cliSystemConfigPackages
});
// Apply the user's configuration.
System.config({ map, packages });
I am currently working on an Angular 2 project that uses the Angular 2 CLI structure. I am able to add moment, ng-material2, ng2-bootstrap those are fine, but if I attempt to add a package like JsonWebToken then I am unable to properly setup my files.
Note: jsonwebtoken is not built for Angular 2 or Angular 2 CLI. It is just a npm package that I am attempting to use.
I have tried following the setup described in the angular2-cli 3rd party libs and it still does not work.
Here is how I am setting it up:
Angular-cli-build.js:
/* global require, module */
var Angular2App = require('angular-cli/lib/broccoli/angular2-app');
module.exports = function (defaults) {
return new Angular2App(defaults, {
vendorNpmFiles: [
/* more code here */
'jsonwebtoken/**/*',
]
});
};
System-config.js:
/** Map relative paths to URLs. */
const map: any = {
/* more code here */
jsonwebtoken: 'vendor/jsonwebtoken',
};
/** User packages configuration. */
const packages: any = {
/* more code here */
jsonwebtoken:{
defaultExtension: 'js',
main: 'index.js'
}
};
App Component:
import { Component } from '#angular/core';
#Component({
moduleId: module.id,
selector: 'app-selector',
templateUrl: 'app.component.html',
styleUrls: ['app.component.css']
})
export class AppComponent {
constructor() {
}
doSomething() {
/*
How do I use jsonwebtoken here
*/
}
}
Why don't you try angular2-jwt:
https://github.com/auth0/angular2-jwt
npm install angular2-jwt --save
Trying to add angular materials to angular-cli but angular-materials never show up in vendor files. I added materials files to system-config.ts as shown below:
const barrels: string[] = [
// Angular specific barrels.
'#angular/core',
'#angular/common',
'#angular/compiler',
'#angular/http',
'#angular/router',
'#angular/platform-browser',
'#angular/platform-browser-dynamic',
// Thirdparty barrels.
'rxjs',
'./button/button.js',
'./card/card.js',
'./checkbox/checkbox.js',
'./input/input.js',
'./progress-circle/progress-circle.js',
'./sidenav/sidenav.js',
'./toolbar/toolbar.js',
// App specific barrels.
'app',
'app/shared',
/** #cli-barrel */
];
const _cliSystemConfig = {};
barrels.forEach((barrelName: string) => {
_cliSystemConfig[barrelName] = { main: 'index' };
});
/** Type declaration for ambient System. */
declare var System: any;
// Apply the CLI SystemJS configuration.
System.config({
map: {
'#angular': 'vendor/#angular',
'rxjs': 'vendor/rxjs',
'main': 'main.js',
' #angular2-material':'vendor/ #angular2-material'
},
packages: _cliSystemConfig
});
// Apply the user's configuration.
System.config({ map, packages });
Also I added to vedornpmfiles array in angular-cli-build.js as shown below:
vendorNpmFiles: [
'systemjs/dist/system-polyfills.js',
'systemjs/dist/system.src.js',
'zone.js/dist/*.js',
'es6-shim/es6-shim.js',
'reflect-metadata/*.js',
'rxjs/**/*.js',
'#angular/**/*.js',
'#angular2-material/**/*.js'
]
I am getting error that they cant find angular materials files.
If anyone has got a clue. What I am doing wrong?
Your system-config.ts should look like this:
/***********************************************************************************************
* User Configuration.
**********************************************************************************************/
/** Map relative paths to URLs. */
const map: any = {
'#angular2-material': 'vendor/#angular2-material',
};
/** User packages configuration. */
const packages: any = {
'#angular2-material/core': {
format: 'cjs',
defaultExtension: 'js',
main: 'core.js'
},
'#angular2-material/sidenav': {
format: 'cjs',
defaultExtension: 'js',
main: 'sidenav.js'
},
'#angular2-material/toolbar': {
format: 'cjs',
defaultExtension: 'js',
main: 'toolbar.js'
},
'#angular2-material/card': {
format: 'cjs',
defaultExtension: 'js',
main: 'card.js'
},
// add missing material elements as desired
};
////////////////////////////////////////////////////////////////////////////////////////////////
/***********************************************************************************************
* Everything underneath this line is managed by the CLI.
**********************************************************************************************/
const barrels: string[] = [
// Angular specific barrels.
'#angular/core',
'#angular/common',
'#angular/compiler',
'#angular/http',
'#angular/router',
'#angular/router-deprecated',
'#angular/platform-browser',
'#angular/platform-browser-dynamic',
// Thirdparty barrels.
'rxjs',
// App specific barrels.
'app',
'app/shared',
'app/imagecard-component',
'app/search-component',
/** #cli-barrel */
];
const cliSystemConfigPackages: any = {};
barrels.forEach((barrelName: string) => {
cliSystemConfigPackages[barrelName] = { main: 'index' };
});
/** Type declaration for ambient System. */
declare var System: any;
// Apply the CLI SystemJS configuration.
System.config({
map: {
'#angular': 'vendor/#angular',
'rxjs': 'vendor/rxjs',
'main': 'main.js'
},
packages: cliSystemConfigPackages
});
// Apply the user's configuration.
System.config({ map, packages });
Note the map and packages entries.
For reference, see this sample app from one the angular2-material developers.
All these solutions have too much going on. First thing you should do is remove those barells that belong to Angular2-material.
'./button/button.js',
'./card/card.js',
'./checkbox/checkbox.js',
'./input/input.js',
'./progress-circle/progress-circle.js',
'./sidenav/sidenav.js',
'./toolbar/toolbar.js',
in your system-config.ts add the angular 2 vendor path to the map object:
const map: any = {
'#angular2-material': 'vendor/#angular2-material'
};
Then here's the tricky bit, the Packages object is empty const packages: any {}; (unless you have already installed some third party packages and added them, yours will be too). So we have to declare the material packages we want to use, we do this by creating a array of the package names
const materialPkgs[]: string[]= [
'core',
'button'
];
In this case I'm only importing button and core for simplicity's sake. Core must always be imported the other modules depend on it.
Next we loop through these materialPkgs and add them to packages using a forEach function
materialPkgs.forEach((pkg) =>{
packages[`#angular2-material/${pkg}`] = {main: `${pkg}.js`}
});
we're almost done in system-config.ts, last thing we need to add the main vendor package to the map object of the system.config so it can be applied...
System.config({
map: {
'#angular': 'vendor/#angular',
'rxjs': 'vendor/rxjs',
'main': 'main.js',
'#angular2-material': 'vendor/#angular2-material'
},
packages: cliSystemConfigPackages
});
Your angular-cli-build.js file is fine, if you configured the default extension to be 'js' like i did, and probably you did too, you don't need to add it to the vendorNpmFiles. You could just as simply have '#angular2-material/**/*'
And we're done with the configuration.
import the directives in your component
import { MD_BUTTON_DIRECTIVES } from '#angular2-material/button';
add them to your directives array
directives: [ MD_BUTTON_DIRECTIVES ]
and use them in your markup
<h1>
{{title}}
</h1>
<button md-button>FLAT</button>
<button md-raised-button>RAISED</button>
<button md-fab>add</button>
<button md-mini-fab>add</button>
<button md-raised-button color="primary">PRIMARY</button>
<button md-raised-button color="accent">ACCENT</button>
<button md-raised-button color="warn">WARN</button>
They should work.
Screenshot of app working:
I had the same problem with "#angular/http" . So The way I fixed the problem ,it might help you too -
Open your package.json and add this line under the dependencies -
'#angular2-material': "your version"
Then open your terminal on that folder and type -
npm install
It will update your system-config.ts with
const barrels: string[] = [
// Angular specific barrels.
'#angular/core',
'#angular/common',
'#angular2-material',
'#angular/compiler',
'#angular/http',
'#angular/router',
'#angular/platform-browser',
'#angular/platform-browser-dynamic',
// Thirdparty barrels.
'rxjs',
'./button/button.js',
'./card/card.js',
'./checkbox/checkbox.js',
'./input/input.js',
'./progress-circle/progress-circle.js',
'./sidenav/sidenav.js',
'./toolbar/toolbar.js',
'app',
'app/shared',
/** #cli-barrel */
];
I try to use angular-cli with D3.
After
typings install d3 --save
npm install d3
I have in node_modules
and in typings folder
angular-cli-build.js
module.exports = function(defaults) {
var app = new Angular2App(defaults, {
vendorNpmFiles: ['d3/d3.js']
});
return app.toTree();
};
index.html
System.config({
packages: {
app: {
format: 'register',
defaultExtension: 'js'
}
},
d3: {
'd3': 'vendor/d3/d3.js'
}
});
In bar-chart directive I try to import d3
import {Directive} from 'angular2/core';
import d3 from 'd3';
#Directive({
selector: 'bar-graph',
providers: [],
host: {},
})
export class BarGraph {
constructor() {
console.log(d3);
}
}
But the app never loads, and console.log says that it tries to get localhost:4200/d3.
Here is an answer that works!
npm install d3 --save
angular-cli-build.js
module.exports = function(defaults) {
return new Angular2App(defaults, {
vendorNpmFiles: [
...,
'd3/build/*.js'
]
});
};
system-config.js
map['d3'] = 'vendor/d3/build';
packages['d3'] = {
main: 'd3',
format: 'global'
};
app.component.ts
import * as d3 from 'd3';
I have the same issue, i found this example with an old version of Angular (2.0.0-alpha.27) but maybe can help.
https://github.com/gdi2290/ng-vegas-angular2-d3
I think that you need to add the d3 entry in the map block:
System.config({
packages: {
app: {
format: 'register',
defaultExtension: 'js'
}
},
map: { // <-----
'd3': 'vendor/d3/d3.js'
}
});
I got i working following the next steps.
first install:
npm install d3 --save
Then add d3 to angular-cli-build.js like this:
// Angular-CLI build configuration
// This file lists all the node_modules files that will be used in a build
// Also see https://github.com/angular/angular-cli/wiki/3rd-party-libs
/* global require, module */
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/**/*.+(ts|js|js.map)',
'rxjs/**/*.+(js|js.map)',
'#angular/**/*.+(js|js.map)',
'd3/build/d3.js'
]
});
};
And modify your system-config.ts:
/***********************************************************************************************
* User Configuration.
**********************************************************************************************/
/** Map relative paths to URLs. */
const map: any = {
'moment': 'vendor/moment/moment.js',
"d3" : "vendor/d3/build/d3.js",
'jquery': 'vendor/jquery/dist/jquery.js'
};
/** User packages configuration. */
const packages: any = {
'moment': { format: 'cjs'},
'jquery': { format: 'global'},
"d3": { format: 'global'},
};
To make sure that systemJS loads your module add an import to your index.ts and delcare the d3 variable where it's used to avoid compilation problems:
import 'd3'
declare var d3;
I use requireJs to load my javascript files.
I import the lib pixi.js and pixi_extends.js, but pixi_extends generate an error because PIXI is undefined... I don't understand because pixi_extends should wait that pixi.js is uploaded before run.
It's the same with the Bundle, same error about pixi.
I don't understant, I did the "deps" correctly I assume!
loader-index.ts: (I use TypeScript!)
/// <reference path="../def/require.d.ts" />
/// <reference path="Init.class.ts" />
/**
* paths List of the files to load. (Cannot contains references TS classes)
* key: New reference name of the file.
* path: Relative path to /public/js/ of the file.
*
* shim Config about the libraries (dependencies and more).
* See http://requirejs.org/docs/api.html#config-shim
*/
require.config({
//urlArgs: "t=" + (new Date()).getTime(),
//baseUrl: "../",
paths: {
/*
******** Load libraries ********
*/
// Lib - jQuery
'jquery': '../generated/lib/jquery-1.10.2.min',
'jqueryUiCore': '../generated/lib/jquery.ui.core.min',
'jqueryUiEffect': '../generated/lib/jquery.ui.effect.min',
// Lib - Javascript extends
'class': '../generated/lib/class.min',
// Lib - Pixi
'pixi': '../generated/lib/pixi.min',
'pixiExtends': '../generated/lib/pixi_extends.min',
// Lib - Socket
'socketIo': '../generated/lib/socket.io.min',
// Lib - Pomelo
'pomeloclient': '../generated/lib/pomeloclient.min',
// Lib - Path finder
'aStar': '../generated/lib/AStar.min',
/*
******** Load shared source code ********
*/
'Message': '../generated/shared/Message.min',
'ValidatorMessage': '../generated/shared/ValidatorMessage.min',
/*
******** Load other scripts ********
*/
'bundle': '../generated/bundle.min'
},
shim: {
'jquery': {
exports: '$'
},
'jqueryUiCore': {
deps: ["jquery"],
exports: '$'
},
'jqueryUiEffect': {
deps: ["jquery"],
exports: "$"
},
'pixiExtends': {
deps: ["jquery", "pixi"]
},
'pomeloclient': {
deps: ["socketIo"]
},
'ValidatorMessage': {
deps: ["Message"]
},
'bundle': {
deps: ["pixi", "pixiExtends", "pomeloclient"]
}
}
});
/**
* [] Array of name that should be the same than those defined in the config.paths. Exception for the TS classes with reference in this file.
*/
require(
[
'Init.class',
'jquery', 'jqueryUiCore', 'jqueryUiEffect',
'class',
'pixi', 'pixiExtends',
'socketIo', 'pomeloclient',
'aStar',
'Message', 'ValidatorMessage',
'bundle'
],
(
_init,
$, jqueryUiCore, jqueryUiEffect,
_class,
_pixi, pixiExtends,
_socketIo, _pomeloclient,
_aStar,
_message, _validatorMessage,
_bundle
)
=> {
// Initialization.
var init = new _init.Init();
// Make shared source classes public, to help.
_exports([
_message.Message,
_validatorMessage.ValidatorMessage
]);
/**
* Export an array of object to made them public on the browser.
* #param objects - Array of objects. Class of function basically.
* #private
*/
function _exports(objects){
for(var i in objects){
_export(objects[i]);
}
}
/**
*Export an object to the browser to make it public.
* #param o Object to export.
* #param name Customise the name. Optional.
* #private
*/
function _export(o: any, name: any = ''){
if(!name){
name = o.name;
}
window[name] = o;
}
}
);
It should be enough to add the following entry to the shim section:
'pixi': {
exports: 'PIXI'
}
This turns this library into an AMD-compatibile module which can be used as a standalone dependency, also in the deps section of other shims.
Edit:
Reading your comments seems that this "pixi_extends" module is your own code; you're not supposed to shim your own modules, it's only meant to be used for legacy non-AMD libraries. If you want to augment Pixi with your customisations, do something like this:
define(['pixi'], function (ThePixiObject) {
ThePixiObject.customFunction = function () {
console.log('Pixi now has customFunction()');
}
// no need to return anything - we're only interested in the side-effect above
});
Recommended: official documentation regarding shim
NB. Also, there's no need to configure shim for jQuery, it's already AMD compatibile.
I fixed it with using the require() function in the pixi_extends and removing my changes from the official pixi.js lib. Now that works.
But the exports with requirejs doesn't have any effect, I don't get it. That should export in global the PIXI value, it's what that should do and that doesn't work.
I can export it manually once everything is loaded, it's a solution if I wanted to have PIXI as global. But I don't absolutely need it so I'll keep in this way.
But I would like to understand why the "shim exports" doesn't works.