TSIFY compatibility with Typescript AngularJS - angularjs

I am trying to build a gulp based process that would use AngularJS from a bower package and a tool called debowerify (which I believe should let me plug in the installed bower components into the TSIFY/Browserify stream). Essentially, I want to build an app.js file for use in my application (with all the JS I need). I cannot for the life of me get AngularJS to work in this process. I am using an index.ts file (see below) to bring in my references for browserify to work with. It has been tricky with angular as the library is optimized out by the compilation process unless you use the import in some way hence the module call I was testing in the index.ts file.
index.ts
//#### Type Definitions ####
/// <reference path="../../typings/angularjs/angular.d.ts" />
/// <reference path="greeter.ts" />
import angular = require('angular');
import greeter = require('./Greeter');
var greet = new greeter();
greet.sayHello();
angular.module('app', []);
Here are my gulp defintions:
gulpfile.js
var gulp = require('gulp');
var source = require('vinyl-source-stream');
var browserify = require('browserify');
var tsify = require('tsify');
var debowerify = require('debowerify');
var exorcist = require('exorcist');
var config = {
publicDir: __dirname + '/app',
path: __dirname + '/src/typescript',
main: 'index.ts',
result: 'app.js'
};
gulp.task('compile-ts', function(){
var bundler = browserify({
basedir: config.path,
debug: true
})
.add(config.path + '/' + config.main)
.plugin(tsify)
.transform(debowerify);
return bundler.bundle()
.pipe(exorcist(config.publicDir + '/app.js.map'))
.pipe(source(config.result))
.pipe(gulp.dest(config.publicDir));
});
The custom TS files I built (ie: greeter.ts) work great. However, when I run my gulp compile-ts task I get no errors in the console only in the browser when it informs me that angular is undefined (on the call to angular.module). I have suspicions that CommonJS may not be supported for angular, but I also found information on the interwebs to the contrary of that. I am trying to avoid AMD if possible but if that is my only option I would certainly re-consider. I have this application working if I link to the angular script in my html rather than attempt to import it into my typescript, but I am just not satisfied with that approach as I know this should work.

Angular doesn't currently support CommonJS, replacing
import angular = require('angular');
with
require('angular');
solved it for me. See here.

Related

requirejs and angularjs 1.5 injection of ui.router failing for components

I'm getting this error when using the recommended component loading method (See step 3 )
Error: Module name "angular-ui-router" has not been loaded yet for context: _. Use require([])
app module definition:
<script>
var adminApp = angular.module('adminClientApp', [require('angular-ui-router'), 'ngMaterial', 'ngResource', 'ngMessages', 'ngMdIcons']);
</script>
According to the doco, there isn't a need to include a script tag - it will be loaded via requirejs
Requirejs main.js definition:
require.config({
paths:{
'angular-ui-router': 'vendor/angular-ui-router/release/'
},
shim:{
'angular': {
exports: 'angular'
}
}
});
app layout:
-- root
index.html
main.js
-- js
-- app (angular files here)
app.js
-- vendor (3rd party libs)
requirejs main.js setting in index.html
<script data-main="main.js" src="vendor/requirejs/require.js"></script>
The guide you are using is not made for RequireJS. After applying the instructions there, you are doing something like this:
<script>
var myApp = angular.module('myApp', [require('angular-ui-router')]);
</script>
This will generally fail to work with RequireJS because calling require with a single string fails unless the module is already loaded. This call is guaranteed to work only if it is inside a define, like this:
define(function (require) {
var myApp = angular.module('myApp', [require('angular-ui-router')]);
});
This code is a module which should be in a separate .js file and loaded with require(['module name']). (Note that the parameter is an array of strings. This is a different form of require than the one that takes a single string parameter.)
You should use Component, which is what the author of the guide you are using was using when he/she wrote the guide, or a tool that is equivalent to it. Otherwise, you need to convert your code to work with RequireJS.

Using gulp-babel gives Uncaught ReferenceError: require is not defined

I am using the following gulp.js file
var gulp = require('gulp');
var babel = require('gulp-babel');
gulp.task('bundle', bundle);
function bundle () {
gulp.src('./src/*.jsx')
.pipe(babel())
.pipe(gulp.dest('./dist'));
}
gulp.task('build', ['bundle']);
Before transpile "main.jsx" content
import React from 'react';
After Transpile, "js" files generated in the dist folder, has require('')
var _react = require('react');
while requesting for the page index.html
<body>
<div id="app" ></div>
<script src="main.js"></script>
</body>
Uncaught ReferenceError: require is not defined is shown in the console.
I know there is something wrong in the build task, but i am unable to figure out.
In the browser, you can not use require API, so you need to somehow bundle your code, you have few options:
Browserify
Webpack
Rollup
These module bundlers allow you to specify an 'entry' point and then bundle all the required modules together in a single file.
Similar questions that answer this problem:
Gulp + babelify + browserify issue

Using gulp, browserify and react with addons

I'm trying to learn about gulp, browserify and react and have been knocking up a little test project. This was fine until I decided to implement some animations in there. Specifically this:
var React = require("react");
var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
I'm getting an error because "React.addons" is null.
I also have the issue that my build is taking an age - between 20 secs and a minute. I think the reason is partly because react itself is being included in my bundle, whereas I would ideally like to retrieve it from a CDN (or at least keep it separate).
This is my gulpfile:
var gulp = require('gulp');
var browserify = require('browserify');
var babelify = require('babelify');
var source = require('vinyl-source-stream');
gulp.task('js', function () {
return browserify('./public/js/app.js', {
debug: false, bundleExternal: true
})
.transform(babelify, {"presets": ["es2015", "react"]})
.bundle()
.pipe(source('app.js'))
.pipe(gulp.dest('./build/js/'));
});
If I set "bundleExternal" to false then it does stop react being included in my js - but then nothing works because "react" is not found. I found something about browserify-shims but couldn't get it to work from gulp. And wasn't sure if it was the right way to go?
Apologies for the newbie question!
To include ReactCSSTransitionGroup you need to install it first:
npm install react-addons-css-transition-group
Then just require it:
var ReactCSSTransitionGroup = require('react-addons-css-transition-group');

gulp-ng-annotate - how to use it?

I want to minify my big angular project.
Using angular 1.5.0.
I'm trying to use the module gulp-ng-annotate to do so.
var gulp = require('gulp');
var ngAnnotate = require('gulp-ng-annotate');
gulp.task('default', function () {
return gulp.src('../www-myalcoholist-com-angular/model/app.js')
.pipe(ngAnnotate())
.pipe(gulp.dest('dist'));
});
when I execute this nodejs script, it fails silently. or... welll.. it doesn't do anything.
i gave it only the main app.js file as a parameter. can I some how give it the all project ?
when I run ng-annotate from terminal, it added annotations properly to my project.. well.. i hope :)
so why this script fails?
I'm new to gulp so any information would be greatly appreciated.
gulp-ng-annotate does not try to find other files in your application. You'll need to either concat your application into a single app.js file before piping to gulp-ng-annotate or src all files separately and pass them to`gulp-ng-annotate.
E.g. the concat method:
var gulp = require('gulp');
var ngAnnotate = require('gulp-ng-annotate');
var concat = require('gulp-concat');
gulp.task('default', function () {
return gulp.src('../www-myalcoholist-com-angular/model/**/*.js')
.pipe(concat('app.js'))
.pipe(ngAnnotate())
.pipe(gulp.dest('dist'));
});
A sample configuration -
gulp.task('app', function() {
return gulp.src([
// './bower_components/angular/angular.min.js',
// './bower_components/angular-sanitize/angular-sanitize.min.js',
//'./bower_components/angular-ui-select/dist/select.min.js',
// './bower_components/angular-ui-router/release/angular-ui-router.min.js',
'./components/**/*.js'])
.pipe(plumber())
.pipe(count('## js-files selected'))
.pipe(concat('./app/all.min.js', {newLine: ';'}))
.pipe(ngAnnotate({
// true helps add where #ngInject is not used. It infers.
// Doesn't work with resolve, so we must be explicit there
add: true
}))
.pipe(gulp.dest('./dist'));
});
This will produce a concatenated build js file. I have kept the vendor js files separate but you can have it any way you like.
P.S - Any other task e.g Linting is done separately in conjunction with watch task.

Is it possible to build a self-contained Angular plugin to be embedded in other angular sites?

I really like Angular.
Having said that, I want to create a plugin in Angular that can be hosted in other websites - no matter what framework they're using. These frameworks can be Angular and it might be something else.
Surely, the latter it easier. I just add my Angular code and violla. It just works. The former is what I'm having troubles with - websites that do use Angular.
A simple setup created locally failed due to:
WARNING: Tried to load angular more than once.
Any suggestions on how I can overcome this issue ?
It sounds almost like you want to create an angular module that you may register on NPM.
In terms of the error you referenced, you may want to tweak your "loader" script. I have created a few public npm modules that use this format also with webpack to create the scripts. This is what my "loader" script looks like. It allows for script tag, commonJS, and AMD module loading.
import mooAccordionDirective from './mooAccordion.js';
import mooRepeatTranscludeModule from 'moo-utility-repeat-transclude';
(function (root, factory) {
if (typeof module !== 'undefined' && module.exports) {
// CommonJS
if (typeof angular === 'undefined') {
var angular = require('angular');
factory(angular);
module.exports = 'mooAngularAccordion';
} else {
factory(angular);
module.exports = 'mooAngularAccordion';
}
} else if (typeof define === 'function' && define.amd) {
// AMD
define(['angular'], factory);
} else {
// Global Variables
factory(root.angular);
}
}(this, function (angular) {
'use strict';
// create your angular module and do stuff
var moduleName = 'mooAngular.accordion';
var mod = angular.module(moduleName, ['mooAngular.utilityRepeatTransclude']);
mooAccordionDirective(mod);
return moduleName; // the name of your module
}));
For more reference on how I built the entire project using Webpack+AngularJS+ES6 you can view my github page for the moo-angular-accordion project.
For you to use this script it would look like:
(function (root, factory) {
if (typeof module !== 'undefined' && module.exports) {
// CommonJS also this prevents your error you are getting.
if (typeof angular === 'undefined') {
var angular = require('angular');
factory(angular);
module.exports = 'myModuleExportString';
} else {
factory(angular);
module.exports = 'myModuleExportString';
}
} else if (typeof define === 'function' && define.amd) {
// AMD
define(['angular'], factory);
} else {
// Global Variables
factory(root.angular);
}
}(this, function (angular) {
'use strict';
// create your angular module and do stuff
var moduleName = 'myModule';
var mod = angular.module(moduleName, ['otherDepModulesIfNeeded']);
mod.directive(/*... defined here ...*/);
return moduleName; // the name of your module
}));
Breakdown:
You define a IIEF which is called with this and your module function (factory) provided as arguments.
The logic checks to see if angular already exists in the global namespace (and if CommonJS support is available.
If angular exists, use it (so that it isn't defined twice), and pass that angular to your module definition (factory)
If not CommonJS, check AMD
If not AMD, load to root as a global (usable as a Script tag)
EDIT: You can also use Grunt, Gulp, or whatever build system you want to bundle your assets instead of Webpack, however the magical script above makes your module exportable in multiple formats (AMD, Script Tag, CommonJS, etc.).
#Sean Larkin's answer is correct, but for those of you using jspm and typescript, here'e what I did there.
1) Write your App module:
/// <reference path="typings/tsd.d.ts" />
import * as angular from "angular";
import modules from "./Modules"; // a simple exported array
// Create our angular module.
angular.module("module.name", modules);
2) Run this command to build a bundle:
jspm bundle-sfx App - angular app.min.js --globals "{ 'angular': 'angular' }" --minify
3) Now app.min.js is an ES5 module library easy to be loaded in a script tag or even another jspm consumer website.

Resources