Most efficient way to Grunt concat directories files? - javascript

I apologize for the very awkward question title, if anyone can think of a better way to phrase this question I'll change it immediately.
I'm building an app with Angular and RequireJS and to try to optimize performance, dependencies and lazy-loading I'm looking to build a file structure like this:
/app
----/regisitration
--------_registration.module.js
--------registration.ctrl.js
--------registration.svc.js
--------registration.directive.js
----/courses
--------_courses.module.js
--------courses.directive.js
--------courses.controller.js
--------courses.service.js
--------/course
------------course.controller.js
----/admin
--------_admin.module.js
--------admin.controller.js
Where I set up my routing, I want to be able to have a user who goes to any /registration/ view load the entirety of _registration.module.js which would be the concatenation of all the other .js files within the /registraion directory (and any sub directories) so that my team isn't bogged down by needing to include several and possibly duplicate dependencies as well as serve the entirety of the site "section" to the user in one shot. Hopefully the sample above shows why I wouldn't want to just front-load all the files, because most users will never hit the admin section of the site. I'm trying to figure out the most efficient way to achieve this with grunt, but so far I'm working very manually with code like this:
grunt.initConfig({
concat: {
app: {
files: [
{
src: ['..app/registration/*.js', '!..app/registraion/*.module.js'],
dest: '..app/registration/_registration.module.js'
},
{
src: ['..app/courses/*.js', '!..app/courses/*.module.js'],
dest: '..app/courses/_courses.module.js'
},
{
src: ['..app/admin/*.js', '!..app/admin/*.module.js'],
dest: '..app/admin/_admin.module.js'
}
],
}
},
});
I think there must be a more efficient and less manual way to do what I'm trying to achieve. Does anyone have any suggestions?

Remember that you can still execute JavaScript within your Gruntfile.
grunt.initConfig({
concat: {
app: {
files: grunt.file.expand({ cwd: 'app', filter: 'isDirectory' }, '*')
.map(function(ngModule) {
return {
src: ['app/' + ngModule + '/*.js', '!app/' + ngModule + '/*.module.js'],
dest: 'app/' + ngModule + '/_' + ngModule + '.module.js'
};
})
}
},
});
With this, you should be able to create new modules without needing to remember to update a config entry for them.

Related

What is the conventional way to manage frontend dependencies with Sails.js?

I'm currently using bower inside a Sails.js project, I found the grunt-bower library very complete and useful. However, you still need sometimes to pick or exclude files manually.
So I'm wondering if it exist another more conventional way to manage frontend dependencies inside a Sails.js project ?
Thanks
EDIT:
For those who are wondering, here is my grunt task:
module.exports = function(grunt) {
grunt.config.set('bower', {
dev: {
dest: '.tmp/public',
js_dest: '.tmp/public/js/dependencies',
css_dest: '.tmp/public/styles',
fonts_dest: '.tmp/public/fonts',
less_dest: '.tmp/dontpublish',
scss_dest: '.tmp/dontpublish',
options: {
keepExpandedHierarchy: false,
stripGlobBase: false,
packageSpecific: {
'bootstrap': {
files: [
'fonts/glyphicons-halflings-regular.eot',
'fonts/glyphicons-halflings-regular.svg',
'fonts/glyphicons-halflings-regular.ttf',
'fonts/glyphicons-halflings-regular.woff',
'fonts/glyphicons-halflings-regular.woff2',
'dist/js/bootstrap.js'
]
}
}
}
}
});
grunt.loadNpmTasks('grunt-bower');
};
As you see, I had to include some files manually for bootstrap and I placed less and scss files in a "not published" folder to exclude them. It's no big deal, but I was just wondering if something better exist, or if I have a bad config.

Add "active" classes to menu items using Grunt

I am using Grunt to build a set of static pages that operate together as a site/application. In the interest of sticking to DRY practices, I am using a package called grunt-processhtml to do "includes".
However, my "included" navigation does not have the appropriate classes to indicate the current page in the navigation. I can pull it off with JavaScript if I need to (set the active class after the menu is created, based on either a variable or the URL). However, I also stumbled across this:
grunt-autonav
Which post-processes my assembled static files and adds the appropriate class. However, I can't for the life of me figure out how to configure it for "process all of the .html files and add the appropriate classes to each of them."
My last failed attempt looks like this:
autonav: {
options: {
parent: '.nav'
},
dev: {
src: '<%= dirs.purgatory %>/html/**/*.html',
dest: '<%= dirs.dev %>'
}
}
However, the plugin doesn't seem to want to use this kind of input for the source:
Warning: Unable to read
"purgatory/html/download.html,purgatory/html/upload.html" file (error
code: ENOENT). Use --force to continue.
It sees my two HTML files but doesn't know how to take it from there. I can't tell if I have a configuration error or if the plugin just doesn't work this way. The sample given in their documentation seems to require specifying every single page that needs its nav customized. But it might be a reading comprehension issue.
Does anybody know how to accomplish my goal in Grunt (not in JS) using the above or any other tools? I don't mind adding a new tool, but I've come up short.
To use dynamic file lists in grunt and all its plugins, you need to wrap your src/dest in a files object and set expand to true:
autonav: {
options: {
parent: '.nav'
},
dev: {
files: {
expand: true,
src: '<%= dirs.purgatory %>/html/**/*.html',
dest: '<%= dirs.dev %>'
}
}
}
Xavier Priour set me on the right path, but I had to scratch my head a bit before I arrived at the final solution:
autonav: {
options: {
parent: '.nav'
},
dev: {
files: [
{
expand: true,
cwd: '<%= dirs.purgatory %>/html',
src: '**/*.html',
dest: '<%= dirs.dev %>'
}
]
}
}
First, I had to look into expand, which provided samples that used the files property Xavier mentioned. However, the examples show that files is an array of objects. Not sure if it "has" to be, but I followed that pattern and wrapped it up as an array.
Next was realizing it wasn't the input string that was wrong, it was that I was configuring the copy incorrectly. When expanded, the destination is a recreation of the source path. To get around this, you issue a CWD. This means that your input path is essentially "null"-ish and it doesn't create a "purgatory" directory in the destination.
The final task now works as expected!

Use angular template cache with browserify

I am building a small angular app with browserify and ui-router. As I don't want to use a server, I want to store all my templates using angular's $templateCache like this:
exports.templateCache = ["$templateCache", function($templateCache) {
'use strict';
$templateCache.put('partials/someState.html',
"myHtmlCode"
);
}];
To populate the cache, I use grunt to look into my partials folder, grab all the html and load it into the cache with grunt-angular-templates:
ngtemplates: {
myApp: {
cwd: 'dist/',
src: 'partials/**.html',
dest: 'src/js/templates/templates.js',
options: {
bootstrap: function(module, script) {
return 'exports.templateCache = ["$templateCache", function($templateCache) {\n' +
script +
'}];'
}
}
}
},
I then use browersify to combine all my js together:
browserify: {
dist: {
files: {
'dist/js/app.js': [
'src/js/templates/**',
'src/app.js'
],
}
}
},
This is working so far but this workflow looks very unwieldy to me: I have an intermediary step where I create the templates.js file in my src directory and I have hard-coded code in my grunt file.
Is there any way to do this more elegantly? Does browserify come with built in solutions to tackle this problem?
browserify-ng-html2js has been designed to resolve this problem.
Simply add in package.json :
"browserify": {
"transform": ["browserify-ng-html2js"]
}
And you'll see if it walks the talks :)
Try transform for browserify that give you possibility to require html file (eg. Stringify). Then you can require('yourPartial.html') as string:
$templateCache.put('yourPartialId', require('./partials/yourPartial.html'));
// html file
<div ng-include=" 'yourPartialId' "></div>

Development mode for AngularJS using GruntJS

I have a couple of products that started off with the yeoman angular generator, and it has been a pretty good dev setup. One thing I haven't been able to find a good solution for is setting a development/production mode flag.
Naturally we use a few tools that we only want on in production so having prod/dev variable that we can use both inline JavaScript and/or HTML files would be quite useful. I searched for solutions online before but haven't found anything useful.
Ultimately, I'm looking for a good solution to use in an AngularJS setting, ideally set via grunt serve and/or build run. What are other teams doing here?
I'm using ng-constant. It creates a .js file which contains some angular constants of your choice.
grunt.initConfig({
...
ngconstant: {
options: {
name: 'config',
dest: '<%= yeoman.app %>/scripts/config.js'
},
development: {
constants: {
myVariable: 'it is development'
}
},
production: {
constants: {
myVariable: 'it is production'
}
}
}
});
And then just add it to your tasks:
grunt.registerTask('serve', [
...
'ngconstant:development',
...
]);
And don't forget to include this /scripts/config.js file in your html and inject 'config' into your app.
var app = angular.module('myApp', [
'config',
...
]);

grunt replace all less files into css files

I use grunt to convert all my less files into css files,using this:
less: {
development: {
files: {
"css/*.css": "less/*.less"
}
}
}
This worked on version 0.3.0, but now that I have upgraded to v0.4.0 it doesn't work anymore.
The following code (not using * in the destination) works on both versions, so the problem is with the star on the destination file.
less: {
development: {
files: {
"css/test.css": "less/*.less"
}
}
}
Any idea ?
This isn't a bug. Grunt no longer supports globbing in dest using that configuration. However, you can use the "files array" format, like this:
files: [
{
expand: true,
cwd: 'src',
src: ['*.less'],
dest: 'assets/css/',
ext: '.css'
}
]
Also, if you use a library like Bootstrap and you want to build each LESS file (component) into a separate, individual CSS file, it's not very easy to accomplish "out of the box". The reason is that each LESS file would need to have its own #import statements for variables.less and mixins.less (and a couple of others like forms.less and navbar.less, since they are referenced in other files).
To make this really easy, try the Grunt plugin, assemble-less (disclaimer: I'm one of the maintainers of the project, and I'm also on the core team for less.js). assemble-less is a fork of grunt-contrib-less by Tyler Kellen, but it adds some experimental features that will accomplish what you need (if you want stability, please stick with grunt-contrib-less). For example:
// Project configuration.
grunt.initConfig({
less: {
// Compile all targeted LESS files individually
components: {
options: {
imports: {
// Use the new "reference" directive, e.g.
// #import (reference) "variables.less";
reference: [
"bootstrap/mixins.less",
"bootstrap/variables.less"
]
}
},
files: [
{
expand: true,
cwd: 'bootstrap/less',
// Compile each LESS component excluding "bootstrap.less",
// "mixins.less" and "variables.less"
src: ['*.less', '!{boot,var,mix}*.less'],
dest: 'assets/css/',
ext: '.css'
}
]
}
}
...
}
The imports feature essentially prepends the specified #import statements onto the source files. The reference option allows you to "reference" other less files while only outputting styles that are specifically referenced via mixins or :extend. You might need to reference a few more files than shown here, since Bootstrap cross-references styles from other components, like forms.less, buttons.less, etc. (See the Gruntfile in assemble-less for examples.)
So after running the assemble-less task with the configuration in the example above, the assets/css folder would have:
alerts.css
badges.css
breadcrumbs.css
button-groups.css
buttons.css
carousel.css
close.css
code.css
component-animations.css
dropdowns.css
forms.css
glyphicons.css
grid.css
input-groups.css
jumbotron.css
labels.css
list-group.css
media.css
modals.css
navbar.css
navs.css
normalize.css
pager.css
pagination.css
panels.css
popovers.css
print.css
progress-bars.css
responsive-utilities.css
scaffolding.css
tables.css
theme.css
thumbnails.css
tooltip.css
type.css
utilities.css
wells.css
There are other features that should help you with this, but the imports feature is super powerful since it allows you to add directives directly to the Gruntfile.

Categories