Configure Restangular.baseUrl using Gruntjs - angularjs

I'm using Restangular in a project built using Gruntjs. Here is a snippet:
// scripts/app.js
angular.module('myApp', ['restangular'])])
.config(['RestangularProvider', function(RestangularProvider) {
/* this is different on dev, test, prod environments */
var baseUrl = 'http://localhost:8080/sms-api/rest/management/';
RestangularProvider.setBaseUrl(baseUrl);
}])
I would like to have a different value for baseUrl if specified at cli or a default if not specified:
$ grunt server
Using default value for 'baseUrl'
$ grunt build --rest.baseUrl='http://my.domain.com/rest/management/'
Using 'http://my.domain.com/rest/management/' for 'baseUrl'
How can I do that?

It's possible with the aid of Grunt preprocess which is useful for replacing (and other things) templates inside files.
First add this to your .js code:
/* Begin insertion of baseUrl by GruntJs */
/* #ifdef baseUrl
var baseUrl = /* #echo baseUrl */ // #echo ";"
// #endif */
/* #ifndef baseUrl
var baseUrl = 'http://www.fallback.url';
// #endif */
/* End of baseUrl insertion */
Then in your grunt file, after installing grunt preprocess (i.e npm install grunt-preprocess --save-dev you add the following configuration:
preprocess: {
options: {
context: {
}
},
js: {
src: 'public/js/services.js',
dest: 'services.js'
}
},
obviously, you need to update the js file list accordingly to which ever files you use. important notice - if you are planning on updating the same file (and not to a new destination) you need to use the inline option
At last, in order to work with a command line config variable, add the following custom task to your grunt file as well:
grunt.registerTask('baseUrl', function () {
var target = grunt.option('rest.baseUrl') || undefined;
grunt.log.ok('baseUrl is set to', target);
grunt.config('preprocess.options.context.baseUrl', target);
grunt.task.run('preprocess');
});
Finally, run the baseUrl task like so:
grunt baseUrl --rest.baseUrl='http://some.domain.net/public/whatever'
Notice I put in a fallback url so you can also run grunt baseUrl and grunt will set your baseUrl to your defined one.

Related

How to make an angular application take arguments from command line?

I have an AngularJS application in which my code looks something like this:
myApp = angular.module('myApp',
[
'ui.router',
'ngMaterial',
'ngMessages'
]
);
myApp.constant('CONSTANTS', (function() {
// Define your variable
return {
backend: {
baseURL: 'http://mybackend.com:3026'
}
};
})());
I run this application using http-server on port number 8000 like this:
% http-server -p 8000
I want to pass in a command-line argument for the backend.baseURL such that it over-rides the value specified in the code. How can I do it??
What you need is at least required http-server that supported dynamic content. while your http-server is supported only static content.
And in the comment you asking which server should you use. There are thousands of web-server that support dynamic content out there. but sinc you are currently using http-server I assumed you just want a small server for local-dev.
Unfortunately, I cannot find any server that support your need without modifying their code. So I suggest you to create your own server base on a library on npm.
This is and example server using live-server.
var liveServer = require("live-server");
var fs = require("fs")
var root = process.argv[2] || "."
var port = process.argv[3] || 8000
var replaceTextMiddleWare = function(req, res, next){
var file = process.argv[4]
var find = process.argv[5]
var replace = process.argv[6]
if(file && find){
if(req.url === file) {
fs.readFile( root + file, "utf-8", function(e, content){
res.end( content.replace(find, replace))
} )
return;
}
}
next();
}
var params = {
port: port, // Set the server port. Defaults to 8080.
host: "0.0.0.0", // Set the address to bind to. Defaults to 0.0.0.0 or process.env.IP.
root: root, // Set root directory that's being server. Defaults to cwd.
open: false, // When false, it won't load your browser by default.
ignore: 'scss,my/templates', // comma-separated string for paths to ignore
file: "index.html", // When set, serve this file for every 404 (useful for single-page applications)
wait: 1000, // Waits for all changes, before reloading. Defaults to 0 sec.
mount: [['/components', './node_modules']], // Mount a directory to a route.
logLevel: 2, // 0 = errors only, 1 = some, 2 = lots
middleware: [ replaceTextMiddleWare ] // Takes an array of Connect-compatible middleware that are injected into the server middleware stack
};
liveServer.start(params);
Then you can run your server by
nodejs myserver.js /mydocument/myproject/ 8000 config.js "http://mybackend.com:3026" "http://mydevserver.com:80"
The command accept parameters:
Path to serve content
Port
File name
Text to find
Text to replace
This server support only one dynamic file with simple find/replace.
From this point, I guess you can modify middleware to do whatever you want.
when Ive done this in production I use the build process for this, using gulp in this case,
var knownOptions = {
string: 'env',
default: { env: process.env.NODE_ENV || 'default' }
};
var options = minimist(process.argv.slice(2), knownOptions);
console.log("using config : " + chalk.blue(options.env));
we get an environment variable defaulting to default using minimist we can pass -env 'string'
then further in the code pushing a dynamic file onto app.js
//now we use options.env
appJS.push("env/"+options.env+".js");
env/[options.env].js here is an angular module that exports environment specific constants
looks like you are not using gulp but you are using node script from package.json. if you are using gulp then this should not be a problem you you use http-server via gulp.
one thing you can do in your current case is as part of your run command, set process.env.baseUrl="dynamic" and then roughly speaking, use this in your code like this
return {
backend: {
baseURL:process.env.baseUrl || 'http://fallbackurl'
}
Basically what I understand is that you want to customize http-server package for your won custom handling.
Here is small solution I found for you....
Go to node installation folder(In my case its local one)...
So path of file which we going to edit is like this...
../node_modules/http-server/lib/http-server.js
Import one package which serve you to get command line arguments...you don't need to install it, its already there.
var argv = require('optimist').boolean('cors').argv; // add this line at top after line number 7
Now
At line 60 and after code before.push(function (req, res) { add following code..
if( req.url === '/backend-url' ) {
return res.end(JSON.stringify(argv.x));
}
So before push function will look like::
before.push(function (req, res) {
if( req.url === '/backend-url' ) {
return res.end(JSON.stringify(argv.x));
}
if (options.logFn) {
options.logFn(req, res);
}
res.emit('next');
});
now we have configured our new command line argument x for http-server which will be return for url "/backend-url"
Now at front end
myApp.constant('CONSTANTS', ('$http', function($http) {
// Define your variable
**var backendURL = (function() {
return $http.get('/backend-url', function(bUrl) {
return bUrl;
})
})();**
return {
backend: {
baseURL: backendURL
}
};
})());
Done, now you add url like this: **http-server -p 8080 -x http://example.com**
I choose this approch as replacing file content i dont think good in you case
If you use only one instance of your app, you can start it with script, that accepts all necessary command line arguments, replaces appropriate placeholders (string between specific comments, for example) in your application js files and then launches http-server on necessary port.

Using different domain for development and production in angularjs

I'm working on AngularJS single page application that consume REST services. The front-end application is developed separately from the back-end and therefore during development we've to hardcode the domain name in the URLs for AJAX calls (we've enabled CORS). But in the case of production everything is running in the same domain and hence hardcoding the domain name looks little bad. Is there we can use the domain name in urls for ajax calls during development and in production don't hardcode the domain name? I'm using gulp.
An example of using gulp-ng-constant with an $http interceptor:
The following task in gulpfile.js will generate the file target/build/scripts/_config.js with the contents angular.module('globals', []).constant('apiContextPath', '...');:
gulp.task('app.ngconstant', [], function() {
var ngConstant = require('gulp-ng-constant'),
var rename = require('gulp-rename');
return
ngConstant({
constants: {
apiContextPath: '.' // TODO Devise a way to set per environment; eg command line
},
name: 'globals',
stream: true
})
.pipe(rename('_config.js'))
.pipe(gulp.dest('target/build/scripts'));
});
Obviously you need to include the generated file in your (packed/minified) code.
Something along the following code will configure the $httpProvider to prepend the apiContextPath to all requests that start with '/api/' (i.e. our REST endpoints):
angular.module(...).config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push(['globals', function(globals) {
return {
'request': function(config) {
if( config.url.indexOf('/api/') === 0 ) {
config.url = globals.apiContextPath + config.url;
}
return config;
}
};
}]);
}]);
(There are quite a few other configuration options, so this is just an example from an older project I worked on.)
If you don't already, you could pass your gulp build a parameter to build in production or development mode.
Based on that flag you can set a baseUrl property in your gulpfile that is used to include a script (using gulp-insert) into your javascript build before all of your angular scripts:
'window.baseUrl = ' + baseUrl
Then you could have a constant in your application that your services use to get the baseUrl:
angular.module('YourModule').constant('baseUrl', window.baseUrl);

How to create a bundle using gulp without using "require" everywhere

Thanks for reading. I am new to gulp, so apologizing if its a dumb question. I have an AngularJS project with the following folder structure:
app/
app.js
modules/
mod1/
index.js
mod1.js
another.js
mod2/
... same structure as mod1
To create a bundle using browserify I am using this:
gulp.task('bundle', function() {
return browserify('app/app.js')
.bundle()
.pipe(vinylSource('bundle.js'))
.pipe(gulp.dest('public/js'));
});
To make this work, I have include require('mod1') ..require('another') and so on.
I always have to make sure that I am requiring the script that I need to use.
My goal is to create a bundle that includes all javascript file inside my app folder starting from app.js without getting into dependency conflicts and without me writing require('somefile').
You can get that by just using the gulp-concat plugin.
You just specify the paths to search. Because you're using angular and need the modules defined before everything else, I'd add the app first, then all the module definitions, then remaining directives and controllers etc after.
var gulp = require('gulp');
var concat = require('gulp-concat');
gulp.task('app-js', function() {
return gulp.src([
'./app/app.js',
'./app/**/mod*.js',
'./app/**/*.js',
])
.pipe(concat('bundle.js'))
.pipe(gulp.dest('public/js'))
});

Wanting To Optionally Add JavaScript code using Gulp

I've got a gulpfile.js that bundles using browserify and I want to be able to optionally add one line to one of my javascript files based on a variable like useMock. Below is my GulpFile.js build step
function bundle (bundler) {
return bundler
.bundle()
.pipe(source('app.js'))
.pipe(gulp.dest('./dist'))
.pipe(browserSync.stream());
}
The last line of the file below is the one I want to optionally include.
module.exports = require('angular')
.module('AngularUApp', [
require('angular-ui-router'),
require('angular-sanitize'),
require('../../base'),
require('./home'),
require('./speaker'),
require('./author')
])
.config(enableHtml5Mode)
.name;
enableHtml5Mode.$inject = ['$locationProvider'];
function enableHtml5Mode($locationProvider) {
console.log('enableHtml5Mode');
$locationProvider.html5Mode(true);
}
// I want to optionally include this from my gulpfile.js
require('../mock');
I want to be able to have a production and dev build where the dev includes the extra line and production does not. If there is a better more recommended way to do this, please suggest.
I found the answer myself. Using the browserify api itself from this link:
https://github.com/substack/node-browserify#usage
var combinedArgs = merge(watchify.args, { debug: true });
var b = browserify(baseDir,combinedArgs);
b.add('angu/mock');
var watcher = watchify(b);
I had a problem earlier because I forgot the relative directory from gulp is different than from inside the JavaScript itself.

Load JavaScript and CSS files in folders in AngularJS

I have an AngularJS application and in the future, some developers in other teams will develop modules that will be installed as parts of it. So I defined the folder structure as below.
www/
index.html
app.js
modules/
modulesA/ -- will be copied when module A was installed
moduleA.js
moduleA.css
moduleA.partial.html
modulesB/ -- will be copied when module B was installed
moduleB.js
moduleB.css
moduleB.partial.html
Now I have a problem. When user installed module A, how to let AngularJS (and the application) load JS and CSS under its folder? Is there any library can load JS and CSS by folder so that I can put the code in index.html likes
<script src="/modules/**/*.js"></script>
<link src="/modules/**/*.css"/>
Otherwise, I have to add some placesholders in index.html and change the content when user installed a module, something like
<script src="/app.js"></script>
<!-- $$_JS_$$ -->
<link src="/app.css"/>
<!-- $$_CSS_$$ -->
AngularJS doesn't support what you want, but you could take a look at build tools such as Grunt or Gulp that let you "build" your application for you. In your case, these tools can look for CSS files and concatenate them into one single file. This way your index.html does not have to change if you ever add new modules.
GruntJS: http://gruntjs.com/
GulpJS: http://gulpjs.com/
Personally I use GulpJS, since it seems to be much faster & I found it easier to configure:
Included my configuration file below.
For example, the task "styles" will compile every css file it finds in the folders I specified, concatenate them, and drop them in the distribution folder.
Since there is an initial learning curve on how to use these tools, you can always integrate gulp or grunt at your own pace. For now you could let it build your css files & later expand it by concatenating JS as well and do various other tasks. In my opinion, its worth learning as it saves you so much time & effort.
var gulp = require("gulp");
var concat = require("gulp-concat");
var html2js = require("gulp-ng-html2js");
var sass = require("gulp-sass");
var clean = require("gulp-clean");
var streamqueue = require("streamqueue");
var ngDepOrder = require("gulp-ng-deporder");
var paths = {
"dist": "../server/staffing/static/",
"vendor": ['vendor/underscore/underscore.js',
'vendor/angular/angular.min.js',
'vendor/angular-route/angular-route.min.js',
'vendor/restangular/dist/restangular.min.js',
'vendor/angular-animate/angular-animate.min.js',
'vendor/angular-bootstrap/ui-bootstrap-0.7.0.min.js',
'vendor/angular-bootstrap/ui-bootstrap-tpls-0.7.0.min.js',
'vendor/angular-ui-router/release/angular-ui-router.min.js',
'vendor/angular-bootstrap-colorpicker/js/bootstrap-colorpicker-module.js',
'vendor/momentjs/min/moment.min.js'],
"scripts": ['app/**/*.js'],
"fonts": ['app-data/fonts/*.*'],
"templates": ['app/**/*.html'],
"styles": ['app/**/*.scss','vendor/angular-bootstrap-colorpicker/css/*.css']
}
gulp.task("watch", function () {
gulp.watch('app/**/*.js', ['scripts']);
gulp.watch('app/**/*.html', ['scripts'])
gulp.watch('app/**/*.scss', ['styles']);
})
gulp.task("default", ["clean"], function () {
gulp.start("scripts", "vendor", "styles", "fonts");
})
gulp.task("clean", function () {
return gulp.src(paths.dist, {read: false})
.pipe(clean({force: true}));
})
gulp.task("vendor", function () {
gulp.src(paths.vendor)
.pipe(concat("vendor.js"))
.pipe(gulp.dest(paths.dist + "js/"));
});
gulp.task("scripts", function () {
var stream = streamqueue({objectMode: true});
stream.queue(gulp.src(paths.scripts)
.pipe(ngDepOrder()));
stream.queue(gulp.src(paths.templates)
.pipe(html2js({moduleName: "templates"})));
return stream.done()
.pipe(concat("app.js"))
.pipe(gulp.dest(paths.dist + "js/"))
});
gulp.task("styles", function () {
gulp.src(paths.styles)
.pipe(sass())
.pipe(concat("staffing.css"))
.pipe(gulp.dest(paths.dist + "css/"))
})
gulp.task("fonts", function () {
gulp.src(paths.fonts).
pipe(gulp.dest(paths.dist + "fonts/"))
})
Check out the angular generator for Slush, it does what I think you want using gulp-bower-files and gulp-inject. You specify your app dependencies using bower, and these are collected and injected by gulp using gulp-inject, which then injects in your index.html the proper link/src/style tags that look very much like your own examples above. Modules' JS and CSS is also collected, minimized, concatenated and injected as well. It also compiles partials and injects those into $templateCache.
I have used it to automatically include dependencies from sub-folder modules/views using a project layout similar to yours.
Note that all your vendor dependencies will need to be bower packages that specify their dist files using the 'main' attribute in bower.json. Some packages do not do this properly, but it's easy to fork the package and add them yourself then point bower at your updated repo.

Resources