Have gulp to update references to angular views - angularjs

I have an angular application which I am using gulp to build.
To keep my app code organized, I like to keep my directory structure grouped together by modules:
app
-> modules
-> sample
- sample.js
- sample.html
app.js
So, in my angular app/modules/sample.js I reference the template
templateUrl: 'modules/sample/sample.html
I would like to keep this structure, but in my distribution, I would like my html moved to a views folder. I have a gulp task which does this
gulp.task('views', function () {
return gulp.src('app/modules/**/*.html')
.pipe(gulp.dest('dist/views'))
.pipe($.size());
});
However, this obviously breaks the references inside my javascript code. How would I use gulp to update the reference to 'views/sample/sample.html' in the javascript for distribution?

You could use gulp-replace to change the path in your JS files once you've compiled them for production. Pretty simple to use:
.pipe($.replace('app/modules/', 'dist/views/modules/'))

Related

Webpack with angular 1.x and ES5

After reading hundreds of lines about browserify vs webpack and several how to of both I decided to go for webpack. The main reason it's because I liked the idea of bundling everything into a js file.
I have an angular project already working and I want to refactor it for webpack. The problem? My project is using angular 1.4.7, ng-animate and plain javascript (ES5) and all the tutorials and manuals are for ES6. I don't want to refactor my project so much. What's the way to go? I would like an example of each angular module : factory, directive, controller and so on. Many thanks
I typically have a feature.module.js file which has my module definition and requires all of the directives / services contained within the module. Also has the external dependancies.
/* module.js */
angular.module('my.module',['dependancy1', 'dependancy2']);
//External libraries
require('./dependancy1.module.js');
require('./dependancy2.module.js');
//Internal components
require('./thing.directive');
require('./thing.service';
/* service.js */
angular.module('my.module')
.directive('yourDir', function myDir(){...});
I'm dealing with the same problem now. And I found something that works (work in progress, but at least I can see progress). My steps:
Install yeoman
Run this angular-webpack generator. Select 'ES5' when asked (the other option is 'ES2015', which I guess is the same that 'ES6')
Start modifying the automatically generated boilerplate with your Angular code
Yes, you still need to learn about gulp and sass, but at least you can run a simple AngularJS app using the old ES5 syntax, and start modifying it.
I'm probably blogging about this. So, I'll update this answer then.
I tend to do this:
app.js:
require('/any/angular/deps');
var subModule = require('/some/sub/module');
var app = angular.module('myApp', []);
// pass the app module in sub modules to allow them to define their own config
subModule.configure(app);
/subModule/module.js:
var someSubDirective = require('./subDir/directive');
export function configure(app) {
someSubDirective.configure(app);
}
/subModule/subDir/directive.js:
export function configure(app) {
app.directive('myDir', myDir);
}
function myDir() {
}
My idea is to let all sub modules handle their own configuration, so declaring config or constant, factories or providers. Letting this then bubble up to the app.js. This means its really easy to delete a folder from your structure, because it is one line removal from it's parent module.
This also makes relevant file paths a lot shorter and easier to handle.

How can I pre load a template in Angular UI router?

I am using Angular UI router. I have many template calls like this:
var access = {
name: 'access',
templateUrl: 'app/access/partials/a1.html',
};
The page served by Access depends on the :content.
Is there a way that I could combine all these HTML files into one and pre-load the files so every action didn't involve another request? I realized I can put my HTML directly inside the template but can I combine the HTML from multiple templates into one file and have it all pre-loaded so it's ready when needed?
Is there a way that I could combine all these HTML files into one and pre-load the files so every action didn't involve another request?
Yes, by using html2js;
or, to be exact, a grunt/gulp plugin called, respectively, grunt-html2js / gulp-html2js
HOW IT WORKS
According to this grunt-html2js tutorial:
" html2js is a plugin (...) that parses all template files in your application and creates a javascript file that populates the $templateCache.
This is very useful trick to reduce the number of request your app needs to make to start the application.
It can also minify the html snippets saving some bandwitdh as well."
----------
According to the grunt-html2s Github repository:
"html2js converts a group of templates to JavaScript and assembles them into an Angular module that primes the cache directly when the module is loaded.
You can concatenate this module with your main application code so that Angular does not need to make any additional server requests to initialize the application."
----------
And according to me :)
What I like about html2js is that you don't need to change any of your angular code, but just configure gruntfile.js / gulpfile.js.
Your templateUrl files will then automagically be available in $templateCache.
So it does exactly what you wished for:
Combine all your templates into a module;
Write the JavaScript source for the module;
All you need to do is to specify the module as a dependency in your code.
Once the module is loaded, all your templates are available in the cache: no request needed!
EXAMPLES OF GRUNT / GULP CONFIG
grunt.initConfig({
html2js: {
options: {
base: 'app',
module: 'templates',
htmlmin: {
... many available options: see GitHub repo ...
}
},
main: {
src: ['app/**/*.html'],
dest: 'templates.js'
},
},
})
then just use the templates module as a dependency:
angular.module('myApp', [ 'templates']);
----------
Here is an example from the gulp-html2js GitHub repository:
gulp.task('scripts', function() {
gulp.src('fixtures/*.html')
.pipe(html2js({
outputModuleName: 'template-test',
useStrict: true
}))
.pipe(concat('template.js'))
.pipe(gulp.dest('./'))
})
TESTING
What's more, html2js is also a very good tool to test directives that use the templateUrl property.
FOR MORE INFORMATION
I came accross html2js after reading Joel Hooks' (Egghead instructor) book about automation, which I strongly recommend.
Watch a dedicated video about html2js in the pro section of the EggHead website.
Testing directives using the templateUrl property with Karma and karma-ng-html2js-preprocessor
NOTE
Technically, you could just use ng-html2js, without using Gulp or Grub; you could then use a command line like the following:
ng-html2js inputFile [outputFile] [-m moduleName] [--module-var ngModule]
However, as you would need to run the above command for each templateUrl file, Gulp/Grub automation seems to be a more efficient way to go.
DISCLAIMER
I have no particular interest or shares in the book/websites/tools I mentioned.
Note: I should also add, you also add this file to your html page:
<script src="path/to/templates.js"></script>
Why not use ng-include in your main html file to load all html's at once.
Something like this...
<div ng-repeat="template in templates">
<ng-include src="template.url"></ng-include>
</div>
So here templates is an array of objects which contains all the url's the other templates which you want to load at once in your main.html file.
Easy. Create them all as ng-template blocks:
<script type="text/ng-template" id="app/access/partials/a1.html">
Content of the template.
</script>
There is already a grunt-angular-templates grunt plugin specific to this angular task only. i have been using it for a while now. this plugin automatically caches your HTML templates using $templateCache in one file which you can add in your application.
grunt-angular-templates - https://www.npmjs.com/package/grunt-angular-templates
Use,
yourApp.run(['$templateCache', function($templateCache) {
$templateCache.removeAll();
}])
Your problem pointed in this site too,
http://javahow.net/questions/27321315/using-angulars-ui-router-how-can-we-make-sure-the-new-version-of-the-html-part

Add new library

I'm trying to figure out the right way to add any eventual new library (for example I need angularJS ui-router) in an onsen app.
I installed bower and then downloaded ui-router.
Since I do not know exactly the way Gulp is used, I got confused on what I'm suppose to do.
At the moment, I have the following folders:
bower_components, hooks, merges, node, modules, platforms, plugins, www
The index.html has the following reference:
What I suppose to do, now?
manually copy the ui-router js files in /www/lib/
configure gulp to copy the files automatically
change the script tag src and make the reference to the bower_component folder
change the Bower default folder
could you please guide me on sort it out?
tnx
At the end I chose the option 2.
I edited the file gulpfile.js adding a new custom task supposed to copy the missing bower libraries.
var mainBowerFiles = require('main-bower-files');
gulp.task('copy-bower-libs', function() {
return gulp.src(mainBowerFiles())
.pipe(gulp.dest(__dirname + "/www/lib/bower/js"))
});

How to dynamically include all template partials when using a module in AngularJS

I have several modules that require some template partials to be loaded whenever the module is used. I am storing these files in a folder called partials inside each module subfolder. My starting point for my app is meanjs, and I am storing partials file are in public/modules//partials/*.html.
I have seen several ng-include and directive examples, but being new to AngularJS each sample I read confuses me further as to what is best practice / most AngularJS appropriate way to do this.
Store your partials whenever you wants.
To load them all use angular template cache.
Use Grunt or gulp to generate automatically. Personally I use gulp.
Here is my working example of one of my project.
install nodejs and npm
npm intall gulp -g
npm install gulp-angular-templatecache
create gulpfile.js
var templateCache = require('gulp-angular-templatecache'),
watch = require('gulp-watch');
gulp.task('generate', function () {
gulp.src('public/*/partials/*.html')
.pipe(templateCache('templates.js', {module: 'YOURMODULENAME', standalone: false}))
.pipe(gulp.dest('public/js'));
});
gulp.task('watch-partials', function () {
gulp.watch('public/*/partials/*.html', ['generate']);
});
then use it like this:
gulp generate - to regenerate partials
gulp watch-partials - watch file changes, if partials are changed it automatically run generate task for you. :)
One more thing, dont forget to include template.js in your html file
<script src="public/js/template.js"></script>
Every time you change your partial dont forget to regenerate your template cache.
You should take advantage of $templateCache. In your partials folder define the templates like this:
angular.module('yourTemplateModule', []).run('$templateCache', function ($templateCache) {
$templateCache.put('yourTemplate', '<div>...some HTML here...</div>');
}
Then create a module, named for example 'app.tpls', which has as dependencies all your template modules. Inject it as dependency to your main app module, probably located in meanjs and now you have your templates ready whenever you need them in your application. You retrieve them by calling:
$templateCache.get('yourTemplate');

Backbone.Marionette - Grunt Browserify - "require is not defined"

I'm using grunt-browserify and running into two issues in particular. The task is up and running successfully with the following config options. The variable jsFilesToConcat represents all of the javascript files for a Backbone.js + Marionette.js application, the main application defintion, the front-end utility assets (e.g. Bootstrap plugins), and all JS associated with the project. Is this the wrong approach? The thought was to load the entire 250k JS application (and all it's dependencies) at one time.
I want to offer the disclaimer that this is new territory for me, so I think my intended use case is available with the options already available with the plugin, but I'm confused by two errors:
1) Backbone not defined - which means that the script is in fact loading, however, when I inspect the call stack in Chrome Dev Tools it shows only the anonymous self-invoking function. So I'm not clear on how to pass the Backbone object to Marionette in order for it to be extended at load time.
2) require is not defined - error on the line where I'm declaring var SampleApp = require('SampleApp'). Do I need to do something special within my grunt config, or node.js server.js config to expose the require function?
3) Is the javascript executing asynchronously within itself, is this part of the browserify intended behavior that I'm not properly handling? I think since I'm wrapping alot of JS utilities in a global wrapper to protect namespacing, that's the reason some functions are not available, but I'm not clear on why that would affect require.
// uses grunt-browserify task
browserify: {
developmentJs: {
options: {
debug: true,
alias: ["./js/app.dev.js:SampleApp"],
},
src: [
'<%= pkg.jsFilesToConcat %>'
],
dest: 'public-dev/js/app.dev.js'
}
}
and then in the index.html of my single-page Marionette app, I have.
(function ($) {
$(document).ready( function() {
var sampleApp = require('SampleApp');
console.log( SampleApp );
});
})(jQuery);
Well for starters, the src attribute in your grunt file doesn't need to reference all of the files in your application. It only needs an entry point. So normally I have something similar to your anonymous self executing function in an index.js file, and set my src configuration option to ["./index.js"]. When browserify looks at that file, it will check for calls to require and grab all of the required dependencies.
That said, browserify will generate a file with an internal definition of require. The require function is not globally available on the page, nor are the dependencies that you include with require. You can use them in your application, but that doesn't make them available in the page. So if you are getting a Backbone is not defined error, the first thing I would check is that you have installed backbone via npm (npm install backbone --save).
Once everything is set up you should just have to include your compiled script on the page, and let your anonymous self executing function (which should now be in a file that grunt-browserify is processing) do the work to kick off your application.

Resources