Handle resource versioning with require.js - versioning

We are planning on versioning our key resources at build time by appending a version to the filename (e.g. main-v1_1.js)
We are learning how to use require.js to manage our resource loading. I would like to be able to specify a postfix in the require.js configuration that will be appended to the resources being loaded.
var version = "1_1"; //inserted at build time
requirejs.config(
{
postfix: "_" + version //is there something like this?
}
);
require([main]...); //would load main_1_1.js
Suggestions? Thoughts? Better ways to handle this situation?
Thank you.

Sounds like this would be suited to the map configuration option.
requirejs.config({
map: {
'some/newmodule': {
'foo': 'foo1.2'
},
'some/oldmodule': {
'foo': 'foo1.0'
}
}
});
When 'some/newmodule' does require('foo') it will get the foo1.2.js
file, and when 'some/oldmodule' does require('foo') it will get the
foo1.0.js file. This feature only works well for scripts that are real
AMD modules that call define() and register as anonymous modules.

We ended up using the urlArgs parameter to append a version querystring.
http://requirejs.org/docs/api.html#config-urlArgs

Related

How to configure jsLoader in angular ocLazyLoad latest version.

Earlier versions of angular oclazyload had an option to configure asyncLoader to use webpack bundle loader as its script loader.
app.config(['$ocLazyLoadProvider', function ($ocLazyLoadProvider) {
$ocLazyLoadProvider.config({
asyncLoader: function (expr, callback) {
var load = require('bundle?lazy!oclazyDir/out/' + expr + '.js');
load(function (file) {
callback(null, file);
});
}
});
}
]);
How to achieve the same with the latest version of angular oclazyload. Replacing asyncLoader with jsLoader also didn't work out.
This may not answer your question completely, but I discovered that there is a separate flavor of oclazyload that is tailored for RequireJS (https://github.com/ocombe/ocLazyLoad/blob/1.0.9/dist/ocLazyLoad.require.js). This wasn't mentioned in the documentation, so it took a while for me to find it..
There is also this helpful answer from the author of oclazyload outlining why RequireJS is unnecessary if you're using oclazyload: https://stackoverflow.com/a/28961833/2449100
I hope this helps!

Using VS 2015/gulp for versioning js files

I'm using VS 2015, ASP.NET 5 (MVC 6) and Gulp to write a SPA with angularjs and supplementary modules. My target framework is dnx451. I've read several best practices which state that the response from Index should have a strict no cache policy set, and all other resources (e.g. js, css, img) should all be heavily cached. In doing so, the browser always downloads the lightweight page and caches the scripts. When publishing, I am trying to have a gulp task which concats/uglifys all my JS files and outputs a single app.min.{version}.js (also for the less -> css file). This gives the benefit of always downloading the latest file version, but keeping them in cache while it is the latest and greatest.
Is there a way to get the Version (from project.json) and the build (from the * portion of project.json) from my gulp task? I am looking for a way to have the file {version} portion of the name match the version/build of the website.
I have seen examples of using process.env in gulp for VS environment variables, but am having trouble putting the pieces together to achieve the desired Version.Build format.
I have tried:
var project = require('./project.json');
gulp.task('js-publish', function(){
project.version; //this give 1.0.0-* (makes sense since its a string)
});
and
gulp.task('js-publish', function(){
process.env.BUILD_VERSION; //which is undefined
});
You want to use the gulp-rename NPM package to rename the file. Add gulp-rename to your package.json file. Here is an example of how it can then be used in your gulpfile.js:
var rename = require("gulp-rename");
// rename via string
gulp.src("./src/main/text/hello.txt")
.pipe(rename("main/text/ciao/goodbye.md"))
.pipe(gulp.dest("./dist")); // ./dist/main/text/ciao/goodbye.md
// rename via function
gulp.src("./src/**/hello.txt")
.pipe(rename(function (path) {
path.dirname += "/ciao";
path.basename += "-goodbye";
path.extname = ".md"
}))
.pipe(gulp.dest("./dist")); // ./dist/main/text/ciao/hello-goodbye.md
// rename via hash
gulp.src("./src/main/text/hello.txt", { base: process.cwd() })
.pipe(rename({
dirname: "main/text/ciao",
basename: "aloha",
prefix: "bonjour-",
suffix: "-hola",
extname: ".md"
}))
.pipe(gulp.dest("./dist")); // ./dist/main/text/ciao/bonjour-aloha-hola.md

Gulp - How do I control processing order with gulp-concat

I'm trying to generate combined JavaScript and CSS resources into a single file using gulp-concat using something like this:
var concatjs = gulp
.src(['app/js/app.js','app/js/*Controller.js', 'app/js/*Service.js'])
.pipe(concat('app.js'))
.pipe(gulp.dest('build'));
I get a concatted file with this, but the order of the javascript files embedded in the combined output file is random - in this case the controllers are showing up before the initial app.js file, which causes problems when trying to load the Angular app that expects app.js before any of the related resources are loaded. Likewise for CSS resources that get combined end up in random order, and again the order is somewhat important - ie. bootstrap needs to load before the theme and any custom style sheets.
How can I set up the concatenation process so that the order remains intact?
Update
So it turns out the ordering above DOES actually work by explicitly specifying the file order in the array of file specs. So in this case the crucial thing is to list app/js/app.js first, then let the rest of the scripts where order doesn't matter in in any order.
The reason I failed to see this behavior (Duh!) is that Gulp Watch was running and the gulpfile.js update wasn't actually reflected in the output. Restarting gulp did update the script. Neophyte error...
Other Thoughts:
Still wondering though - is this the right place to specify build order? It seems you're now stuffing application logic (load order) into the build script, which doesn't feel right. Are there other approaches to address this?
For an angular application like the one in your example (and it's dependency management), I normally use this kind of syntax: gulp.src(['app\js\app.js', 'app\js\**\*.js']).
You can also use just gulp.src('app\js\**\*.js') if your app.js file is the first one in alphabetic order.
I see your point about moving the load file order into the build script: I had the same feeling till I started using gulp-inject for injecting the unminified files references in my index.html at development time and injecting the bundled, minified and versioned ones in the production index file. Using that glob ordering solution across all my development cycle made so sense to me that i don't think to it anymore.
Finally, a possible solution for this 'ordering smell' can be using browserify but to me it is just complicating the architecture for an angular application: in the end, as you said, you just need that one specific file is called before all the other ones.
For my js i use a particular structure/naming convention which helps. I split it up into directories by feature, where each 'feature' is then treated as a separate encapsulated module.
So for my projects i have,
app/js/
- app.js
- app.routes.js
- app.config.js
/core/
- core.js
- core.controllers.js
- core.services.js
/test/
- .spec.js test files for module here
/feature1/
- feature1.js
- feature1.controllers.js
/feature2/
- feature2.js
- feature2.controllers.js
...
So each directory has a file of the same name that simply has the initial module definition in it, which is all that app.js has in it for the whole app. So for feature1.js
angular.module('feature1', [])
and then subsequent files in the module retrieve the module and add things (controllers/services/factories etc) to it.
angular.module('feature1')
.controller(....)
Anyway, i'll get to the point...
As i have a predefined structure and know that a specific file has to go first for each module, i'm able to use the function below to sort everything into order before it gets processed by gulp.
This function depends on npm install file and npm install path
function getModules(src, app, ignore) {
var modules = [];
file.walkSync(src, function(dirPath, dirs, files) {
if(files.length < 1)
return;
var dir = path.basename(dirPath)
module;
if(ignore.indexOf(dir) === -1) {
module = dirPath === src ? app : dir;
files = files.sort(function(a, b) {
return path.basename(a, '.js') === module ? -1 : 1;
})
.filter(function(value) {
return value.indexOf('.') !== 0;
})
.map(function(value) {
return path.join(dirPath, value);
})
modules = modules.concat(files);
}
})
return modules;
}
It walks the directory structure passed to it, takes the files from each directory (or module) and sorts them into the correct order, ensuring that the module definition file is always first. It also ignores any directories that appear in the 'ignore' array and removes any hidden files that begin with '.'
Usage would be,
getModules(src, appName, ignoreDirs);
src is the dir you want to recurse from
appName is the name of your app.js file - so 'app'
ignoreDirs is an array of directory names you'd like to ignore
so
getModules('app/js', 'app', ['test']);
And it returns an array of all the files in your app in the correct order, which you could then use like:
gulp.task('scripts', function() {
var modules = getModules('app/js', 'app', ['test']);
return gulp.src(modules)
.pipe(concat('app.js'))
.pipe(gulp.dest('build'));
});

Loading relative templateUrl

I've been trying to find the best way to create a modular, scalable angular application. I really like the structure of projects like angular-boilerplate, angular-app, where all the related files are grouped together by feature for partials and directives.
project
|-- partial
| |-- partial.js
| |-- partial.html
| |-- partial.css
| |-- partial.spec.js
However, in all these examples, the template URL is loaded relative to the base url, not relative to the current file:
angular.module('account', [])
.config(function($stateProvider) {
$stateProvider.state('account', {
url: '/account',
templateUrl: 'main/account/account.tpl.html', // this is not very modular
controller: 'AccountCtrl',
});
})
This is not very modular, and could become difficult to maintain in large projects. I would need to remember to change the templateUrl path every time I moved any of these modules. It would be nice if there was some way to load the template relative to the current file like:
templateUrl: './account.tpl.html'
Is there any way to do something like this in angular?
The best way to do this now is using a module loader like browserify, webpack, or typescript. There are plenty of others as well. Since requires can be made from the relative location of the file, and the added bonus of being able to import templates via transforms or loaders like partialify, you don't even have to use template urls anymore. Just simply inline the Template via a require.
My old answered is still available below:
I wrote a post on exactly this subject and spoke on it at our local Angular Meetup. Most of us are now using it in production.
It is quite simple as long as your file structure is represented effectively in your modules. Here is a quick preview of the solution. Full article link follows.
var module = angular.module('myApp.things', []);
var all = angular.module('myApp.things.all', [
'myApp.things',
'things.someThing',
'things.someOtherThing',
'things.someOtherOtherThing',
]);
module.paths = {
root: '/path/to/this/thing/',
partials: '/path/to/this/thing/partials/',
sub: '/path/to/this/thing/sub/',
};
module.constant('THINGS_ROOT', module.paths.root);
module.constant('THINGS_PARTIALS', module.paths.partials);
module.constant('THINGS_SUB', module.paths.sub);
module.config(function(stateHelperProvider, THINGS_PARTIALS) {
stateHelperProvider.setNestedState({
name: 'things',
url: '/things',
templateUrl: THINGS_PARTIALS + 'things.html',
});
});
And then any sub modules or "relative" modules look like this:
var module = angular.module('things.someThing', ['myApp.things']);
var parent = angular.module('myApp.things');
module.paths = {
root: parent.paths.sub + '/someThing/',
sub: parent.paths.sub + '/someThing/sub/',
partials: parent.paths.sub + '/someThing/module/partials/',
};
module.constant('SOMETHING_ROOT', module.paths.root);
module.constant('SOMETHING_PARTIALS', module.paths.partials);
module.constant('SOMETHING_SUB', module.paths.sub);
module.config(function(stateHelperProvider, SOMETHING_PARTIALS) {
stateHelperProvider.setNestedState({
name: 'things.someThing',
url: "/someThing",
templateUrl: SOMETHING_PARTIALS + 'someThing.html',
});
});
Hope this helps!
Full Article: Relative AngularJS Modules
Cheers!
I think you'll eventually find that maintaining the paths relative to the js file will be harder, if even possible. When it comes time to ship, you are most likely going to want to concatenate all of your javascript files to one file, in which case you are going to want the templates to be relative to the baseUrl. Also, if you are fetching the templates via ajax, which Angular does by default unless you pre-package them in the $templateCache, you are definitely going to want them relative to the baseUrl, so the server knows where to find them once your js file has already been sent to the browser.
Perhaps the reason that you don't like having them relative to the baseUrl in development is because you aren't running a server locally? If that's the case, I would change that. It will make your life much easier, especially if you are going to work with routes. I would check out Grunt, it has a very simple server that you can run locally to mimic a production setup called Grunt Connect. You could also checkout a project like Yeoman, which provides a pre-packaged front end development environment using Grunt, so you don't have to spend a lot of time getting setup. The Angular Seed project is a good example of a Grunt setup for local development as well.
I've been chewing on this issue for a while now. I use gulp to package up my templates for production, but I was struggling to find a solution that I was happy with for development.
This is where I ended up. The snippet below allows any url to be rewired as you see fit.
angular.module('rm').config(function($httpProvider) {
//this map can be defined however you like
//one option is to loop through script tags and create it automatically
var templateMap = {
"relative.tpl.html":"/full/path/to/relative.tpl.html",
etc...
};
//register an http interceptor to transform your template urls
$httpProvider.interceptors.push(function () {
return {
'request': function (config) {
var url = config.url;
config.url = templateMap[url] || url;
return config;
}
};
});
});
Currenly it is possible to do what you want using systemJs modules loader.
import usersTemplate from './users.tpl';
var directive = {
templateUrl: usersTemplate.name
}
You can check good example here https://github.com/swimlane-contrib/angular1-systemjs-seed
I had been using templateUrl: './templateFile.tpl.html but updated something and it broke. So I threw this in there.
I've been using this in my Gruntfile.js html2js object:
html2js: {
/**
* These are the templates from `src/app`.
*/
app: {
options: {
base: '<%= conf.app %>',
rename: function( templateName ) {
return templateName.substr( templateName.lastIndexOf('/') );
}
},
src: [ '<%= conf.app %>/**/{,*/}<%= conf.templatePattern %>' ],
dest: '.tmp/templates/templates-app.js'
}
}
I know this can lead to conflicts, but that is a smaller problem to me than having to edit /path/to/modules/widgets/wigdetName/widgetTemplate.tpl.html in every file, every time, I include it in another project.

Define global values using AMD require.js & backbone.js

I am developing a frontend using the Backbone.js and require.js and everything is going well till i need to create a file named it config.js to store some defaule values to use it in the whole of the application
below is the code of the config.js file
// Filename: config.js
define([''], function(){
var baseUrl = "http://localhost:8888/client/",
apiServer = "http://api-server:8888";
return function(type){
return eval(type);
};
});
in one of my views I would define the config.js then i can access the value of both
var baseUrl = "http://localhost:8888/client/",
apiServer = "http://api-server:8888";
via this line of code below that i put it inside any *.js file on my application
var baseUrl = config('baseUrl');
console.log(baseUrl); //prints out this > http://localhost:8888/client/
the problem here is i am using eval to get the value of what kind of value i need to retrieves, I know it's not safe method to use but could anyone suggest safe solution
RequireJS lets you define objects just like you define more complicated modules. You can have a config module and then use it in whichever other files that require it.
Inside config.js you can do:
define({
baseUrl:"http://localhost:8888/client/",
apiServer:"http://api-server:8888"
});
Then require it in other modules:
//someotherfile.js , defining a module
define(["config"],function(config){
config.baseUrl;// will return the correct value here
//whatever
});
Side note: You can use actual global state (defining the variable on window) but I strongly urge you not to since this will make testing hard, and will make the dependency implicit and not explicit. Explicit dependencies should always be preferred. In the above code and unlike the global it's perfectly clear that the configuration is required by the modules using it.
Note, if you want values that are not valid identifiers you can use bracket syntax too config["baseUrl"] the two (that and config.baseUrl) are identical in JavaScript.
As an alternative solution (and uglier than Benjamin's) you can put both urls into an object:
define([''], function(){
var urls = {
baseUrl: "http://localhost:8888/client/",
apiServer: "http://api-server:8888"
};
return function(type){
return urls[type];
};
});
Still, simply exporting an object is much cleaner.

Resources