I'm having serious problems getting gulp-angular-templatecache to work nicely within my app. I'm using the HotTowel yeomen generator and I modified it a little bit, but I can't seem to get my template cache to use a different module name. Here's the relevant gulpfile code:
gulp.task('templatecache', ['clean-code'], function() {
log('Creating an AngularJS $templateCache');
return gulp
.src(config.htmltemplates)
.pipe($.if(args.verbose, $.bytediff.start()))
.pipe($.minifyHtml({empty: true}))
.pipe($.if(args.verbose, $.bytediff.stop(bytediffFormatter)))
.pipe($.angularTemplatecache(
'templates.js',
{
module: 'app.templates',
standalone: true,
root: 'app/',
moduleSystem: 'IIFE'
}
))
.pipe(gulp.dest(config.temp));
});
The original HotTowel gulpfile had {module: 'app.core', standalone: false, root: 'app/'} as the options. Every time I run the build process, my stupid templates.js file looks like this:
angular.module("app.core").run(["$templateCache"....
I've tried so many things to change it, but it never goes to app.templates. Any ideas?
Related
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.
Context
I have a few grunt tasks that I've already written, and I'd like to use them with a new project I'm writing in Sails.js.
With Sails.js, you can add additional grunt tasks by adding a JS file to the /tasks/register folder. Before we get to the file I've added, let's talk about the problem.
The Problem
Sails won't lift. Debugger shows:
debug: --------------------------------------------------------
error: ** Grunt :: An error occurred. **
error:
------------------------------------------------------------------------
ERROR
>> Unable to process task.
Warning: Required config property "clean.dev" missing.
The issue in question is obviously with grunt, so then I try grunt build (which automatically runs with sails lift):
Running "clean:dev" (clean) task
Verifying property clean.dev exists in config...ERROR
>> Unable to process task.
Warning: Required config property "clean.dev" missing. Use --force to continue.
From this, I've garnered that this is a path issue. Let's take a look at the file I've added.
/tasks/register/customTask.js
The task here loads load-grunt-config, which is the source of my problems:
module.exports = function(grunt) {
// measures the time each task takes
require('time-grunt')(grunt);
// This require statement below causes my issue
require('load-grunt-config')(grunt, {
config: '../../package.json',
scope: 'devDependencies',
overridePath: require('path').join(process.cwd(), '/asset-library/grunt')
});
grunt.registerTask('customTask', [
'newer:jshint',
'newer:qunit',
'newer:concat',
'newer:cssmin',
'newer:uglify'
]);
};
I had assumed that using overridePath instead of configPath would solve my issue, but alas, it's not quite that simple. Is there some way to make it so that I can use my own custom tasks folder with load-grunt-config like I've done in other projects, or is there some magic conditional I can wrap the require statement around?
I only need it to run with grunt customTask, and not run with grunt * (anything else).
Okay, this was actually pretty easy. All I had to do was change the grunt.registerTask call in my customTask.js file from this:
grunt.registerTask('customTask', [
'newer:jshint',
'newer:qunit',
'newer:concat',
'newer:cssmin',
'newer:uglify'
]);
to this:
grunt.registerTask('customTask', 'My custom tasks', function() {
// The require statement is only run with "grunt customTask" now!
require('load-grunt-config')(grunt, {
config: '../../package.json',
scope: 'devDependencies',
overridePath: require('path').join(process.cwd(), '/asset-library/grunt')
});
grunt.task.run([
'newer:jshint',
'newer:qunit',
'newer:concat',
'newer:cssmin',
'newer:uglify'
]);
});
In case it's not clear, I did have to move the require('load-grunt-config') call, so if you're copy + pasting, make sure to remove the require statement that's outside the grunt.registerTask call.
You can find more information about custom Grunt tasks here.
I am setting up a project with Gulp to run unit tests with Mocha, including Angular tests. I have the basic set up working (indexOf, etc.), however when I include angular-mocks I get this error or a node-module error:
ReferenceError in 'gulp-mocha': "Window is not defined"
I've tried including angular-module-mocks, using gulp-mocha-phantomjs... but the result is the same. (With mocha-phantomjs my error was 'Init timeout'.) I've seen many examples of configurations with Mocha and Angular or Gulp and Karma but have not yet found a solution for Gulp, Mocha and Angular alone.
I'm thinking of something similar to this Karma solution to correctly load angular-mocks by specifying it in a config file and forcing Gulp to load it (Angular testing with Karma: "module is not defined"). However, even if this would work, it seems like gulp-mocha does not support loading a configuration file (mocha.opts - https://github.com/sindresorhus/gulp-mocha/issues/26). I would be happy to hear a more straightforward solution.
I am using angular-mocks 1.2.22 and gulp-mocha 1.1.0.
Code snippets:
var mocha = require('gulp-mocha');
gulp.task('test', function () {
return gulp.src('test/*.js', {read: false})
.pipe(mocha({reporter: 'nyan', timeout: 400}));
});
test/test.js
var assert = require('assert');
var angular_mocks = require('angular-mocks'); //Fails only when this line is present
//tests
What finally worked for me with Gulp/Browserify/Mocha was using Karma and Mocha combined.
Specifically, I used gulp-karma, and defined the configuration at karma.config.js and used a dummy file for gulp.src as others have done:
gulp.task('test', function () {
return gulp.src('./foobar.js').pipe(karma({
configFile:'karma.config.js',
action: 'run'
}))
.on('error', handleErrors);
});
Then I used this karma.config.js file. I needed the npm modules karma-mocha, karma-chai, and karma-bro. (With only the first two, I was getting 'require is not defined'. Then of course I tried including karma-requirejs, but that does not work with Browserify. Then I tried karma-commonjs, which still didn't work. Then I tried karma-browserify, and got a strange error involving bundle() that no one seems to have solved (https://github.com/xdissent/karma-browserify/issues/46). Karma-bro did the trick.)
I also needed to preprocess each file referenced in the tests as well as the tests themselves. (For using phantomJS also include karma-phantomjs-launcher. And I am using the bower version of angular-mocks simply because it is more recent: v1.2.25 compared to 1.2.22 for npm - but the npm version might work.)
module.exports = function(config) {
config.set({
basePath: '',
// frameworks to use
frameworks: ['browserify', 'mocha', 'chai'],
// list of files / patterns to load in the browser
files: [
'node_modules/angular/lib/angular.min.js',
'bower_components/angular-mocks/angular-mocks.js',
'source/javascript/controllers/*.js',
'source/javascript/*.js',
'test/*.js'
],
reporters: ['progress'],
port: 9876,
colors: true,
autoWatch: true,
browsers: ['PhantomJS'],
preprocessors: {
'source/javascript/controllers/*.js': ['browserify'],
'source/javascript/*.js': ['browserify'],
'test/*.js': ['browserify']
}
});
};
And finally this test passes. At the end I needed to make sure the names of my modules and controllers were consistent (capitals etc.) to resolve 'Module not defined' errors. For debugging I replaced node_modules/angular/lib/angular.min.js with node_modules/angular/lib/angular.js in the files.
describe('Angular', function() {
describe('App Controllers', function() {
beforeEach(angular.mock.module('App'));
describe('MessageCtrl', function() {
it('should retrieve the correct amount of messsages', angular.mock.inject(function($controller) {
var scope = {},
ctrl = $controller('MessageCtrl', {$scope:scope});
assert.equal(scope.messages.length, 2);
}));
});
});
});
I do get this: 'WARNING: Tried to load angular more than once.' I can live with it.
So here is my hypothetical config object for a hypothetical fooTask that does something (not relevant to question) to a bunch of JS files
grunt.initConfig({
fooTask: {
app1: 'app1/*.js',
app2: 'app2/*.js',
app3: 'app3/*.js'
}
});
As you can see, with this approach, I have to run fooTask 3 times with each app specified as a target:
grunt fooTask:app1
grunt fooTask:app2
grunt fooTask:app3
Needless to say this does not scale as either the number of apps increase or the number of such foo tasks increase as one has to C&P the same code over and over for each app.
So ideally what I would like to define is just one target with the name of the app passed in as a config variable
grunt.initConfig({
fooTask: {
dist: '<%=appName%>/*.js'
}
});
I would then like to call fooTask 3 times, one for each app, with the right app set as appName
var apps = ['app1', 'app2', 'app3'];
apps.forEach(function(app) {
var currAppName = app;
// Run fooTask but how do I specify the new currAppName config?
grunt.task.run('fooTask');
});
As from code above, I know I can run my fooTask using grunt.task.run but how do I set the appName config for my task?
Note that this question is similar to this other one that also does not have the right answer yet - Pass Grunt config options from task.run
Thanks a lot.
EDIT 2:
So nevermind the garbage below the first edit, leaving as example of what doesn't work. In my case it was really important to be able to set the value within a task at run-time so I settled on the file system. Perhaps it suits your needs.
grunt.initConfig({
someTask: {
someKey: fs.readFileSync('file.txt', { encoding: 'utf8' })
}
});
of course you can do the readFile outside of the task if you need a bunch of different app names.
EDIT:
Hmmm. I swear I had this working when I wrote this...but now it is not. Grunt just sees the extra arguments as additional unfound tasks.
I was trying to figure this out myself, finally a "duh" just moment happened - why not parse process.argv before grunt.initConfig?
module.exports = function(grunt) {
var sourcefile = process.argv[2] || 'default.js'; // <- this
grunt.initConfig({
uglify: {
main: {
src: sourcefile, // <- voila :)
dest: sourcefile.substring(0, sourcefile.length-3) + '.min.js'
}
}
});
grunt.loadNpmTasks('uglify');
grunt.registerTask('default', ['uglify']);
};
and use from command line:
grunt mykillerscript.js
I didn't even try to use grunt.option for the same reason that all the examples only showed directing which task is run, but I wouldn't be surprised if there is a more "grunt" way to do this.
I've been working with RequireJS for a bit lately but I am brand new to the optimizer and I am trying to add it into my build steps but I am running into an issue. After it runs and merges my JS files into one, the body of my "main" no longer executes (worked fine prior to optimizing). All of the dependency JS loads correctly but the actual code inside of my main define() does not (even though I can see it in the final output file. Here is what I mean:
Assuming simplified version of my main.js:
console.log("This statement outputs to console");
define(["jquery", "modernizr", "jquery.joyride"], function($) {
console.log("This statement does not");
}
As I mentioned I will see jquery, modernizer, joyride and both console.log() statements in inline in the output file so I believe it is getting generated correctly. My guess is that it has to do with my require config:
This is simplified version of my app.js:
requirejs.config({
"baseUrl": "/assets/js",
"paths": {
"jquery": "jquery"
},
"shim": {
"jquery.joyride": ["jquery"]
}
});
requirejs(["app/main"]);
My assumption is that the second requirejs() call is not getting executed. Is that possible? What would cause that to happen and what is the proper fix?
Essentially my optimized version of main.js looks something like the following:
(function(e,t){ ..jquery code.. };
define("jquery.joyride", function(){});
(function(a){ ...code here... });
console.log("This statement outputs to console");
define('main',["jquery", "modernizr", "jquery.joyride"], function($) {
console.log("This statement does not");
};
Here is by build config:
({
appDir: '../../',
baseUrl: "assets/js",
mainConfigFile: '../../assets/js/app.js',
dir: '../../../BUILD/',
optimizeCss: 'default',
modules: [
{
name: "main"
}
],
removeCombined: true,
preserveLicenseComments: false,
optimize: 'none' // I Disabled this to help me try and debug
})
Also it it helps, this is the line I'm using to include my JS (same exact line boht before and after I optimize the file):
<script data-main="/assets/js/app" src="/assets/js/require.js"></script>
so by looking closer at the code you've shared above... the issue is that the optimized version of main.js is not adding the proper module name (define("main"[ should be define("app/main"[. I suspect this has to do with one of 2 things:
wrong module name in the r.js config file
improper module reference in your app.js
first, to test/prove my assumption: manualy edit the optimized version of main.js to match what I mentioned above ("app/main" in place of just "main"). if that works, then try these things (one at a time, not at the same time):
for addressing #1, in your r.js config file... change name:"main" to name:"app/main"
for #2, in your app.js, change requirejs(["app/main"]); to requirejs(["main"]);