I'm writing an angular1 + angular2 hybrid application which uses webpack as package bundler.
In my code I import a library (#angular/upgrade) in this way
import { UpgradeModule } from '#angular/upgrade/static';
Angular upgrade library is sitting in node_module folder with the following tree structure (simplified):
#angular/upgrade
├── bundles
│ ├── upgrade-static.umd.js
│ ├── upgrade-static.umd.min.js
│ ├── upgrade.umd.js
│ └── upgrade.umd.min.js
├── index.d.ts
├── index.js
├── index.js.map
├── index.metadata.json
├── package.json
├── static
│ └── package.json
├── static.d.ts
├── static.js.map
├── static.metadata.json
└── static.js
The problem is that by default webpack resolve my import statement loading #angular/upgrade/static.js, an ES6 file which, once bundled with the rest of the code generate errors.
What I'd like webpack to do instead is loading #angular/upgrade/static/package.json which contains the right main definition pointing to the umd bundle
{"main": "../bundles/upgrade-static.umd.js"}
Is that achievable?
Thanks,
Gab
Although the module resolution described here:
https://webpack.github.io/docs/resolving.html
should be able to do what I've described above by default, in order to achieve that I had to use the resolve.alias property. Here's the configuration that I've used:
resolve: {
extensions: [ '.js', '.ts', '' ],
modulesDirectories: [ path.resolve( __dirname, 'node_modules' ) ],
alias: {
'#angular/upgrade/static$': '../../node_modules/#angular/upgrade/bundles/upgrade-static.umd.js'
}
},
Does import UpgradeModule from '#angular/upgrade/bundles/upgrade-static.umd.js'; work?
Webpack only follows the main in package.json if package.json is at the root level of the npm module, so in this case you'll have to access the file you want directly.
I am using nativescript 2.3.0 with angular. I created a starter project with the following command
tns create projname --ng
I have the following folder structure
├── app
│ ├── app.css
│ ├── app.component.html
│ ├── app.component.ts
│ ├── main.ts
In side the main.ts file i have the following.
import { platformNativeScriptDynamic, NativeScriptModule } from "nativescript-angular/platform";
import { NgModule } from "#angular/core";
import { AppComponent } from "./app.component";
#NgModule({
declarations: [AppComponent],
bootstrap: [AppComponent],
imports: [NativeScriptModule]
})
class AppComponentModule {}
platformNativeScriptDynamic().bootstrapModule(AppComponentModule);
Notice that I am importing the AppComponent on line 3
What I want to do is that I want to organize my code so that i have the app.component file in a separate folder
As shown below
│ ├── pages
│ │ └── app.component.ts
│ │ └── app.component.html
│ ├── app.css
│ ├── main.ts
I have changed the import in main.ts file to follows
import { AppComponent } from "./pages/app.component";
Moving the file app.component.html file give the following error.
Unhandled Exception
com.tns.nativescriptException:
Calling js method onCreateView failed
I am developing a web application using the MEAN framework and gulp for minification of the files. However, the application does not work because there are lots of "is not a function, got undefined" when I inspect the navigator console. When I read the app.min.js file which is generated with gulp, I can't find most of javascripts files (controllers, services and so on).
The folder structure that I am using for the client is the following:
client/
├── app.min.js
├── app.min.js.map
├── controllers
│ ├── auth
│ │ ├── login_controller.js
│ │ └── register_controller.js
│ ├── home
│ │ └── home_controller.js
│ ├── navigation
│ │ └── navigation_controller.js
│ └── profile
│ └── profile_controller.js
├── directives
│ └── navigation.js
├── index.html
├── main.js
├── services
│ ├── authentication.js
│ └── data.js
└── views
├── auth
│ ├── login
│ │ └── login.html
│ └── register
│ └── register.html
├── home
│ └── home.html
├── navigation
│ └── navigation.html
└── profile
└── profile.html
This the the gulp file which I am using:
var gulp = require("gulp");
var concat = require("gulp-concat");
var uglify = require("gulp-uglify");
var watch = require("gulp-watch");
var sourcemaps = require("gulp-sourcemaps");
var ngHtml2Js = require("gulp-ng-html2js");
gulp.task("scripts", function() {
gulp.src([
"./client/**/*.js",
"!./client/app.min.js"
]).pipe(sourcemaps.init())
.pipe(concat("./app.min.js"))
.pipe(uglify({mangle: true}))
.pipe(gulp.dest("client"))
.pipe(sourcemaps.write("./"))
.pipe(gulp.dest("client"));
});
gulp.task("watch", function() {
watch(["./client/**/*.js", "!./client/**/*.test.js", "!./client/app.min.js"], function() {
gulp.start("scripts");
});
});
gulp.task("default", ["scripts", "watch"]);
Thanks in advance.
EDIT:
This is the generated app.min.js file:
!function(){function t(t,e){t.when("/",{templateUrl:"views/home/home.html",controller:"homeCtrl",controllerAs:"vm"}).when("/register",{templateUrl:"views/register/register.html",controller:"registerCtrl",controllerAs:"vm"}).when("/login",{templateUrl:"views/login/login.html",controller:"loginCtrl",controllerAs:"vm"}).when("/profile",{templateUrl:"views/profile/profile.html",controller:"profileCtrl",controllerAs:"vm"}).otherwise({redirectTo:"/"}),e.html5Mode(!0)}function e(t,e,n){t.$on("$routeChangeStart",function(t,o,r){"/profile"!==e.path()||n.isLoggedIn()||e.path("/")})}angular.module("app",["ngRoute"]),angular.module("app").config(["$routeProvider","$locationProvider",t]).run(["$rootScope","$location","authentication",e])}(),function(){function t(){return{restrict:"EA",templateUrl:"/views/navigation/navigation.html",controller:"navigationCtrl as navvm"}}angular.module("app").directive("navigation",t)}(),function(){function t(t,e){var n=function(t){e.localStorage["token"]=t},o=function(){return e.localStorage["token"]},r=function(){var t,n=o();return n?(t=n.split(".")[1],t=e.atob(t),t=JSON.parse(t),t.exp>Date.now()/1e3):!1},i=function(){if(r()){var t=o(),n=t.split(".")[1];return n=e.atob(n),n=JSON.parse(n),{email:n.email,name:n.name}}},l=function(e){return t.post("/api/register",e).success(function(t){n(t.token)})},a=function(e){return t.post("/api/login",e).success(function(t){n(t.token)})},c=function(){e.localStorage.removeItem("token")};return{currentUser:i,saveToken:n,getToken:o,isLoggedIn:r,register:l,login:a,logout:c}}angular.module("app").service("authentication",t),t.$inject=["$http","$window"]}(),function(){function t(t,e){var n=function(){return t.get("/api/profile",{headers:{Authorization:"Bearer "+e.getToken()}})};return{getProfile:n}}angular.module("app").service("appData",t),t.$inject=["$http","authentication"]}(),function(){function t(t,e){var n=this;n.credentials={name:"",email:"",password:""},n.onSubmit=function(){console.log("Submitting registration"),e.register(n.credentials).error(function(t){alert(t)}).then(function(){t.path("profile")})}}angular.module("app").controller("registerCtrl",t),t.$inject=["$location","authentication"]}(),function(){function t(){console.log("Home controller is running")}angular.module("app").controller("homeCtrl",t)}(),function(){function t(t,e){var n=this;n.user={},e.getProfile().success(function(t){n.user=t}).error(function(t){console.log(t)})}angular.module("app").controller("profileCtrl",t),t.$inject=["$location","appData"]}();
//# sourceMappingURL=app.min.js.map
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.
As part of learning angular i’ve decided to create a simple bug tracker app using ng-boilerplate as a starting point as I like their approach to folder structure. I’ve got the auth down and have moved onto the "members area” which lists all the users projects and allows them to create new projects and to eventually add bugs to each project.
I’m having a bit of an analysis paralysis in regards to structuring the code the “angular way”. So far I have :
- member
— add-project
—— add.js
—— add.tpl.html
- member.tpl.html
- member.js
inside member.js I have a memberctrl which lists the users projects and adds a new project, calling a factory called ProjectsService (also sitting in member.js) to do both. The ProjectsService currently has two methods, query() and add() although obviously this would grow to include update, delete etc.
The add.js in the add-project folder seems a bit redundant at the moment, but i’m worried that the member controller is going to grow (editing projects, adding bugs, editing bugs etc) so what would be an ideal structure going forward? Should I have a separate addProjectCtrl inside add.js solely for adding a project? Should I remove add() from ProjectsService and move it into its own factory in add.js as well?
Code for member.js is as follows
.controller('MemberCtrl', function MemberCtrl($scope, $location,ProjectsService) {
$scope.projects = [];
$scope.refresh = function () {
ProjectsService.query()
.then(function (data) {
$scope.projects = data;
});
};
$scope.addProject = function (project) {
ProjectsService.add(project).then(function (data) {
$scope.projects = data;
$location.path("/member");
});
};
//is this just going to get bigger and bigger?
$scope.refresh();
})
.factory('ProjectsService', ['$http', '$q', function ($http, $q) {
return {
query: function () {
var deferred = $q.defer();
$http.get('/api/get-projects')
.success(function (data) {
deferred.resolve(data);
})
.error(function (data) {
deferred.reject(data);
});
return deferred.promise;
},
add: function (project) {
var deferred = $q.defer();
$http.post('/api/create-project', project)
.success(function (data) {
deferred.resolve(data);
})
.error(function (data) {
deferred.reject(data);
});
return deferred.promise;
}
};
}])
and code for add.js
angular.module( 'ngBoilerplate.member.add-project', [
'ui.router',
'placeholders',
'ui.bootstrap',
'ngBoilerplate.config',
'ngBoilerplate.member'
])
.config(function config( $stateProvider,USER_ROLES ) {
$stateProvider.state( 'member.add-project', {
url: '/add-project',
views: {
"main": {
templateUrl: 'member/add-project/add.tpl.html'
}
},
data:{ pageTitle: 'Add Project'
}
});
})
;
Take a look at the official angular-seed project, or Yeoman angular generator which will give you a barebone structure for start your angular projects.
A generally good practice is to split into different files your Controllers / Services / Directives.
For a more detailed code guide, read the popular angular-style-guide.
Extracted from it, here is an example of structure :
.
├── app
│ ├── app.js
│ ├── controllers
│ │ ├── home
│ │ │ ├── FirstCtrl.js
│ │ │ └── SecondCtrl.js
│ │ └── about
│ │ └── ThirdCtrl.js
│ ├── directives
│ │ ├── home
│ │ │ └── directive1.js
│ │ └── about
│ │ ├── directive2.js
│ │ └── directive3.js
│ ├── filters
│ │ ├── home
│ │ └── about
│ └── services
│ ├── CommonService.js
│ ├── cache
│ │ ├── Cache1.js
│ │ └── Cache2.js
│ └── models
│ ├── Model1.js
│ └── Model2.js
├── partials
├── lib
└── test