I'm trying to use Grunt as a build tool for my webapp.
I want to have at least two setups:
I. Development setup - load scripts from separate files, without concatenation,
so my index.html would look something like:
<!DOCTYPE html>
<html>
<head>
<script src="js/module1.js" />
<script src="js/module2.js" />
<script src="js/module3.js" />
...
</head>
<body></body>
</html>
II. Production setup - load my scripts minified & concatenated in one file,
with index.html accordingly:
<!DOCTYPE html>
<html>
<head>
<script src="js/MyApp-all.min.js" />
</head>
<body></body>
</html>
The question is, how can I make grunt make these index.html's depending on the configuration when I run grunt dev or grunt prod?
Or maybe I'm digging in the wrong direction and it would be easier to always generate MyApp-all.min.js but put inside it either all my scripts (concatenated) or a loader script that asynchronously loads those scripts from separate files?
How do you do it, guys?
I recently discovered these Grunt v0.4.0 compatible tasks:
grunt-preprocess
Grunt task around preprocess npm module.
grunt-env
Grunt task to automate environment configuration for future tasks.
Below are snippets from my Gruntfile.js.
ENV setup:
env : {
options : {
/* Shared Options Hash */
//globalOption : 'foo'
},
dev: {
NODE_ENV : 'DEVELOPMENT'
},
prod : {
NODE_ENV : 'PRODUCTION'
}
},
Preprocess:
preprocess : {
dev : {
src : './src/tmpl/index.html',
dest : './dev/index.html'
},
prod : {
src : './src/tmpl/index.html',
dest : '../<%= pkg.version %>/<%= now %>/<%= ver %>/index.html',
options : {
context : {
name : '<%= pkg.name %>',
version : '<%= pkg.version %>',
now : '<%= now %>',
ver : '<%= ver %>'
}
}
}
}
Tasks:
grunt.registerTask('default', ['jshint']);
grunt.registerTask('dev', ['jshint', 'env:dev', 'clean:dev', 'preprocess:dev']);
grunt.registerTask('prod', ['jshint', 'env:prod', 'clean:prod', 'uglify:prod', 'cssmin:prod', 'copy:prod', 'preprocess:prod']);
And in the /src/tmpl/index.html template file (for example):
<!-- #if NODE_ENV == 'DEVELOPMENT' -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.js"></script>
<script src="../src/js/foo1.js"></script>
<script src="../src/js/foo2.js"></script>
<script src="../src/js/jquery.blah.js"></script>
<script src="../src/js/jquery.billy.js"></script>
<script src="../src/js/jquery.jenkins.js"></script>
<!-- #endif -->
<!-- #if NODE_ENV == 'PRODUCTION' -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="http://cdn.foo.com/<!-- #echo name -->/<!-- #echo version -->/<!-- #echo now -->/<!-- #echo ver -->/js/<!-- #echo name -->.min.js"></script>
<!-- #endif -->
I'm sure my setup is different than most people, and the usefulness of the above will depend on your situation. For me, while it's an awesome bit of code, the Yeoman grunt-usemin is a more robust than I personally need.
NOTE: I just discovered the above listed tasks today, so I might be missing a feature and/or my process may change down the road. For now, I'm loving the simplicity and features that grunt-preprocess and grunt-env have to offer. :)
I'm not sure if it will be of any help to anyone, but I've created this demo repository on GitHub that shows a complete (and more complex setup) using the technique(s) I've outlined above.
I've come up with my own solution. Not polished yet but I think I'm going to move in that direction.
In essense, I'm using grunt.template.process() to generate my index.html from a template that analyzes current configuration and produces either a list of my original source files or links to a single file with minified code. The below example is for js files but the same approach can be extended to css and any other possible text files.
grunt.js:
/*global module:false*/
module.exports = function(grunt) {
var // js files
jsFiles = [
'src/module1.js',
'src/module2.js',
'src/module3.js',
'src/awesome.js'
];
// Import custom tasks (see index task below)
grunt.loadTasks( "build/tasks" );
// Project configuration.
grunt.initConfig({
pkg: '<json:package.json>',
meta: {
banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - ' +
'<%= grunt.template.today("yyyy-mm-dd") %> */'
},
jsFiles: jsFiles,
// file name for concatenated js
concatJsFile: '<%= pkg.name %>-all.js',
// file name for concatenated & minified js
concatJsMinFile: '<%= pkg.name %>-all.min.js',
concat: {
dist: {
src: ['<banner:meta.banner>'].concat(jsFiles),
dest: 'dist/<%= concatJsFile %>'
}
},
min: {
dist: {
src: ['<banner:meta.banner>', '<config:concat.dist.dest>'],
dest: 'dist/<%= concatJsMinFile %>'
}
},
lint: {
files: ['grunt.js'].concat(jsFiles)
},
// options for index.html builder task
index: {
src: 'index.tmpl', // source template file
dest: 'index.html' // destination file (usually index.html)
}
});
// Development setup
grunt.registerTask('dev', 'Development build', function() {
// set some global flags that all tasks can access
grunt.config('isDebug', true);
grunt.config('isConcat', false);
grunt.config('isMin', false);
// run tasks
grunt.task.run('lint index');
});
// Production setup
grunt.registerTask('prod', 'Production build', function() {
// set some global flags that all tasks can access
grunt.config('isDebug', false);
grunt.config('isConcat', true);
grunt.config('isMin', true);
// run tasks
grunt.task.run('lint concat min index');
});
// Default task
grunt.registerTask('default', 'dev');
};
index.js (the index task):
module.exports = function( grunt ) {
grunt.registerTask( "index", "Generate index.html depending on configuration", function() {
var conf = grunt.config('index'),
tmpl = grunt.file.read(conf.src);
grunt.file.write(conf.dest, grunt.template.process(tmpl));
grunt.log.writeln('Generated \'' + conf.dest + '\' from \'' + conf.src + '\'');
});
}
Finally, index.tmpl, with generation logic baked in:
<doctype html>
<head>
<%
var jsFiles = grunt.config('jsFiles'),
isConcat = grunt.config('isConcat');
if(isConcat) {
print('<script type="text/javascript" src="' + grunt.config('concat.dist.dest') + '"></script>\n');
} else {
for(var i = 0, len = jsFiles.length; i < len; i++) {
print('<script type="text/javascript" src="' + jsFiles[i] + '"></script>\n');
}
}
%>
</head>
<html>
</html>
UPD. Found out that Yeoman, which is based on grunt, has a built-in usemin task that integrates with Yeoman's build system. It generates a production version of index.html from information in development version of index.html as well as other environment settings. A bit sophisticated but interesting to look at.
I dislike the solutions here (including the one I previously gave) and here's why:
The problem with the highest voted answer is that you have to manually sync the list of script tags when you add/rename/delete a JS file.
The problem with the accepted answer is that your list of JS files can't have pattern matching. This means you've got to update it by hand in the Gruntfile.
I've figured out how to solve both of these issues. I've set up my grunt task so that every time a file is added or deleted, the script tags automatically get generated to reflect that. This way, you don't need to modify your html file or your grunt file when you add/remove/rename your JS files.
To summarize how that works, I have a html template with a variable for the script tags. I use https://github.com/alanshaw/grunt-include-replace to populate that variable. In dev mode, that variable comes from a globbing pattern of all my JS files. The watch task recalculates this value when a JS file is added or removed.
Now, to get different results in dev or prod mode, you simply populate that variable with a different value. Here's some code:
var jsSrcFileArray = [
'src/main/scripts/app/js/Constants.js',
'src/main/scripts/app/js/Random.js',
'src/main/scripts/app/js/Vector.js',
'src/main/scripts/app/js/scripts.js',
'src/main/scripts/app/js/StatsData.js',
'src/main/scripts/app/js/Dialog.js',
'src/main/scripts/app/**/*.js',
'!src/main/scripts/app/js/AuditingReport.js'
];
var jsScriptTags = function (srcPattern, destPath) {
if (srcPattern === undefined) {
throw new Error("srcPattern undefined");
}
if (destPath === undefined) {
throw new Error("destPath undefined");
}
return grunt.util._.reduce(
grunt.file.expandMapping(srcPattern, destPath, {
filter: 'isFile',
flatten: true,
expand: true,
cwd: '.'
}),
function (sum, file) {
return sum + '\n<script src="' + file.dest + '" type="text/javascript"></script>';
},
''
);
};
...
grunt.initConfig({
includereplace: {
dev: {
options: {
globals: {
scriptsTags: '<%= jsScriptTags(jsSrcFileArray, "../../main/scripts/app/js")%>'
}
},
src: [
'src/**/html-template.html'
],
dest: 'src/main/generated/',
flatten: true,
cwd: '.',
expand: true
},
prod: {
options: {
globals: {
scriptsTags: '<script src="app.min.js" type="text/javascript"></script>'
}
},
src: [
'src/**/html-template.html'
],
dest: 'src/main/generatedprod/',
flatten: true,
cwd: '.',
expand: true
}
...
jsScriptTags: jsScriptTags
jsSrcFileArray is your typical grunt file-globbing pattern. jsScriptTags takes the jsSrcFileArray and concatenates them together with script tags on both sides. destPath is the prefix I want on each file.
And here's what the HTML looks like:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>Example</title>
</head>
<body>
##scriptsTags
</body>
</html>
Now, as you can see in the config, I generate the value of that variable as a hard coded script tag when it's run in prod mode. In dev mode, this variable will expand to a value like this:
<script src="../../main/scripts/app/js/Constants.js" type="text/javascript"></script>
<script src="../../main/scripts/app/js/Random.js" type="text/javascript"></script>
<script src="../../main/scripts/app/js/Vector.js" type="text/javascript"></script>
<script src="../../main/scripts/app/js/StatsData.js" type="text/javascript"></script>
<script src="../../main/scripts/app/js/Dialog.js" type="text/javascript"></script>
Let me know if you have any questions.
PS: This is a crazy amount of code for something I'd want to do in every client-side JS app. I hope someone can turn this into a reusable plugin. Maybe I will some day.
I have been asking myself the same question for a while, and I think this grunt plugin could be configured to do what you want: https://npmjs.org/package/grunt-targethtml. It implements conditional html tags, that depend on the grunt target.
I was looking for a more simple, straight forward solution so I combined the answer from this question:
How to place if else block in gruntfile.js
and came up with following simple steps:
Keep two versions of your index files as you listed and name them index-development.html and index-prodoction.html.
Use the following logic in your Gruntfile.js's concat/copy block for your index.html file:
concat: {
index: {
src : [ (function() {
if (grunt.option('Release')) {
return 'views/index-production.html';
} else {
return 'views/index-development.html';
}
}()) ],
dest: '<%= distdir %>/index.html',
...
},
...
},
run 'grunt --Release' to choose the index-production.html file and leave off the flag to have the development version.
No new plugins to add or configure and no new grunt tasks.
This grunt task named scriptlinker looks like an easy way to add the scripts in dev mode. You could probably run a concat task first and then point it to your concatenated file in prod mode.
grunt-dom-munger reads and manipulates HTML with CSS selectors. Ex. read tags from your html. Remove nodes, add nodes, and more.
You can use grunt-dom-munger to read all your JS files that are linked by your index.html, uglify them and then use grunt-dom-munger again to modify your index.html to only link the minified JS
I found a grunt plugin called grunt-dev-prod-switch. All it does is comment out certain blocks it looks for based on an --env option you pass to grunt (although it limits you to dev, prod, and test).
Once you set it up as it explains here, you can run for example:
grunt serve --env=dev, and all it does is comment out the blocks which are wrapped by
<!-- env:test/prod -->
your code here
<!-- env:test/prod:end -->
and it will uncomment out blocks which are wrapped by
<!-- env:dev -->
your code here
<!-- env:dev:end -->
It also works on javascript, I use it for setting up the right IP address to connect to for my backend API. The blocks just change to
/* env:dev */
your code here
/* env:dev:end */
In your case, it would be as simple as this:
<!DOCTYPE html>
<html>
<head>
<!-- env:dev -->
<script src="js/module1.js" />
<script src="js/module2.js" />
<script src="js/module3.js" />
...
<!-- env:dev:end -->
<!-- env:prod -->
<script src="js/MyApp-all.min.js" />
...
<!-- env:prod:end -->
</head>
<body></body>
</html>
grunt-bake is a fantastic grunt script that would work great here. I use it in my JQM auto build script.
https://github.com/imaginethepoet/autojqmphonegap
Take a look at my grunt.coffee file:
bake:
resources:
files: "index.html":"resources/custom/components/base.html"
This looks at all the files in base.html and sucks them in to create index.html works fantastic for multipage apps (phonegap). This allows for easier development as all devs are not working on one long single page app (preventing lots of conflict checkins). Instead you can break up the pages and work on smaller chunks of code and compile to the full page using a watch command.
Bake reads the template from base.html and injects the component html pages on watch.
<!DOCTYPE html>
jQuery Mobile Demos
app.initialize();
<body>
<!--(bake /resources/custom/components/page1.html)-->
<!--(bake /resources/custom/components/page2.html)-->
<!--(bake /resources/custom/components/page3.html)-->
</body>
You can take this a step further and add injections in your pages for "menus" "popups" etc so you can really break pages into smaller manageable components.
Use a combination of wiredep https://github.com/taptapship/wiredep and usemin https://github.com/yeoman/grunt-usemin in order to have grunt take care of these tasks. Wiredep will add your dependencies one script file at a time, and usemin will concatenate them all into a single file for production. This can then be accomplished with just some html comments. For instance, my bower packages are automatically included and added to the html when I run bower install && grunt bowerInstall:
<!-- build:js /scripts/vendor.js -->
<!-- bower:js -->
<!-- endbower -->
<!-- endbuild -->
This answer is not for noobs!
Use Jade templating ... passing variables to a Jade template is a bog standard use case
I am using grunt (grunt-contrib-jade) but you don't have to use grunt. Just use the standard npm jade module.
If using grunt then your gruntfile would like something like ...
jade: {
options: {
// TODO - Define options here
},
dev: {
options: {
data: {
pageTitle: '<%= grunt.file.name %>',
homePage: '/app',
liveReloadServer: liveReloadServer,
cssGruntClassesForHtmlHead: 'grunt-' + '<%= grunt.task.current.target %>'
},
pretty: true
},
files: [
{
expand: true,
cwd: "src/app",
src: ["index.jade", "404.jade"],
dest: "lib/app",
ext: ".html"
},
{
expand: true,
flatten: true,
cwd: "src/app",
src: ["directives/partials/*.jade"],
dest: "lib/app/directives/partials",
ext: ".html"
}
]
}
},
We can now easily access the data passed by grunt in the Jade template.
Much like the approach used by Modernizr, I set a CSS class on the HTML tag according to the value of the variable passed and can use JavaScript logic from there based on whether the CSS class is present or not.
This is great if using Angular since you can do ng-if's to include elements in the page based on whether the class is present.
For example, I might include a script if the class is present ...
(For example, I might include the live reload script in dev but not in production)
<script ng-if="controller.isClassPresent()" src="//localhost:35729/livereload.js"></script>
Consider processhtml. It allows definition of multiple "targets" for builds. Comments are used to conditionally include or exclude material from the HTML:
<!-- build:js:production js/app.js -->
...
<!-- /build -->
becomes
<script src="js/app.js"></script>
It even purports to do nifty stuff like this (see the README):
<!-- build:[class]:dist production -->
<html class="debug_mode">
<!-- /build -->
<!-- class is changed to 'production' only when the 'dist' build is executed -->
<html class="production">
Related
Currently I am working on a JavaScript application and I am trying to build it as modular as possible. What I'm planning to do is to get a folder structure like
js
|__ controllers
|__ services
|__ directives
index.html
I am using angularjs and i want to split all the controllers and services into seperate files.
I am a Java-Developper and I want to use maven to build this project and deploying it on a tomcat.
In production mode i want to a compressor/obfuscator to pack all files into one single application.js. Normally when I build my projects i only got one file for all controllers and one for all services and so on. So what I am doing is have one profile for dev and one for live and with filtering I append .min.js in my index.html to include all the files ( minimized on live, non-minimized on dev )
Finally my question:
What is the best way to do that with multiple files?
In development mode i want
<script type="text/javascript" src="MyFirstController.js">
<script type="text/javascript" src="MySecondController.js">
<script type="text/javascript" src="MyThirdController.js">
<script type="text/javascript" src="MyFirstService.js">
/* ... */
And in production mode i only want one file included in my index.html
<script type="text/javascript" src="myapp.js">
The first solution but clearly a not very pretty solution would be to have a multiline property in my maven file where i got all the script tags which i then replace with filtering.
I hope someone can tell me a good solution for my problem. Thanks in advance!
Take a look at the frontend-maven-plugin. This is useful if you want to bundle scripts with a maven artefact.
I haven't needed to use this because my javascript code has been an entirely separate deployable (decoupling and all that). So this is a good use case for gulp. Take a look at the gulpfile.js from hottowel.
First take a look at the build task and its dependencies:
/**
* Build everything
* This is separate so we can run tests on
* optimize before handling image or fonts
*/
gulp.task('build', ['optimize', 'images', 'fonts', 'test-server'], function() {
log('Building everything');
var msg = {
title: 'gulp build',
subtitle: 'Deployed to the build folder',
message: 'Running `gulp serve-build`'
};
del(config.temp);
log(msg);
notify(msg);
});
These should do most of the things you want. There are also environment specific gulp tasks:
gulp serve-dev
gulp build
There are a lot more in there so take a read through.
I've also worked on java + angular projects and it was handy for deployment and consistent with the java/maven approach to create artefacts for the javascript code that can be stored on nexus and fetched for deployment when needed.
The artefact for the javascript code is just a zip file which I create with the following gulp task (ignoring directories and files with ! in front of the directory name):
/**
* Create a versioned artefact
*/
gulp.task('generate-artifact', function() {
var filename = getFilename();
return gulp
.src([
'./**/*.*',
'!artifacts/',
'!artifacts/**',
'!build/',
'!build/**',
'!node_modules/',
'!node_modules/**',
'!bower_components/',
'!bower_components/**'
])
.pipe($.tar(filename + '.tar'))
.pipe($.gzip())
.pipe(gulp.dest('./artifacts/'));
});
Then to deploy to nexus using the nexus-deployer plugin:
/**
* Deploy release to nexus
*/
gulp.task('deploy-release', ['clean-pomdir'], function(cb) {
var deployer = require('nexus-deployer');
var filename = getFilename();
var pkg = require('./package.json');
log('Retrieving artifact ' + filename + '.tar.gz' + 'from artifacts dir');
log('Deploying version ' + pkg.version + ' of ' + pkg.name);
var release = {
groupId: 'my.group.id',
artifactId: 'my-artefact',
version: pkg.version,
packaging: 'tar.gz',
auth: {
username: args.username,
password: args.password
},
pomDir: config.pomDirReleases,
url: 'http://path-to-nexus.repo',
artifact: './artifacts/' + filename + '.tar.gz',
noproxy: '',
cwd: ''
};
deployer.deploy(release, cb);
});
There are a few custom methods and config things in there too: the great yargs module to pass in username and password as command line arguments; convenience method in gulpfile.js to get the filename:
function getFilename() {
var pkg = require('./package.json');
var filename = pkg.name + '_' + pkg.version;
return filename;
}
I have two questions.
I am trying to learn RequireJS and use it along with ASP.NET MVC bundling & minification. I am using a separate config file for RequireJS which holds the bundling information. My first problem is how do I pass on the bundle path generated by MVC to the require.config.js file. A clean way to do that will be as below:
index.cshtml
<script id="requirescript" type="text/javascript" src="~/Scripts/require.config.js"
data-baseurl="#Url.Content("~/Scripts")"
data-bundlepath="#System.Web.Optimization.Scripts.Url("~/bundles/scripts").ToString()"></script>
require.config.js
var reqScript = document.getElementById('requirescript');
var baseUrl = reqScript.getAttribute('data-baseurl');
var bundlePath = reqScript.getAttribute('data-bundlepath');
var require = {
baseUrl: baseUrl,
bundles: {
bundlePath : ['jquery','jqueryui','mymodule']
}
}
};
When I do the above, RequireJS tries to load a non-existing script named bundlePath.js, instead what I want is to load the bundled script which is '/bundles/scripts?v=GZ0QWPB4G0soItEmlsPC6Yp3zftCRVleVTcH3LseMWo1' which contains my modules. So first, my question is how do I pass the bundle URL, as generated by the server, to RequireJS in the require.config.js file without hard-coding the bundle path?
Secondly, the jqueryui module seems to be not loading. I have added the module name in the AMD code in jquery ui min file. How do I make jquery ui work with RequireJS and ASP.NET bundling?
There is a NuGet package RequireJs.NET https://www.nuget.org/packages/RequireJsNet/ which is an implementation of RequireJs for .NET MVC.
RequireJS is an implementation of Asynchronous Module Definition (AMD) that provides all the tools you need to write modular JavaScript. If you are working on a large project with a lot of JavaScript code, many external components and frameworks, RequireJS will help you manage the complexity of dependencies.
You will have access to a configuration file (json) which will look like this:
{
"paths": {
"jquery": "jquery-1.10.2",
"jquery-validate": "jquery.validate",
"jquery-validate-unobtrusive": "jquery.validate.unobtrusive",
"bootstrap": "bootstrap",
"respond": "respond",
"i18n": "Components/RequireJS/i18n",
"text": "Components/RequireJS/text",
"menu-module" : "Controllers/Common/menu-module"
},
"shim": {
"jquery-validate": {
"deps": [ "jquery" ]
},
"jquery-validate-unobtrusive": {
"deps": [ "jquery", "jquery-validate" ]
},
"bootstrap": {
"deps": ["jquery"]
}
},
"autoBundles": {
"main-app": {
"outputPath": "Scripts/Bundles/",
"include": [
{
"directory": "Controllers/Root"
}
]
},
"require-plugins": {
"outputPath": "Scripts/Bundles/",
"include": [
{
"file": "Components/RequireJS/i18n"
},
{
"file": "Components/RequireJS/text"
}
]
}
}
}
And after that you will render RequireJs config into your layout.
#using RequireJsNet
<!DOCTYPE html>
<html>
<head>
<!-- head content -->
</head>
<body>
<!-- body content -->
#Html.RenderRequireJsSetup(new RequireRendererConfiguration
{
// the url from where require.js will be loaded
RequireJsUrl = Url.Content("~/Scripts/Components/RequireJS/require.js"),
// baseUrl to be passed to require.js, will be used when composing urls for scripts
BaseUrl = Url.Content("~/Scripts/"),
// a list of all the configuration files you want to load
ConfigurationFiles = new[] { "~/RequireJS.json" },
// root folder for your js controllers, will be used for composing paths to entrypoint
EntryPointRoot = "~/Scripts/",
// whether we should load overrides or not, used for autoBundles, disabled on debug mode
LoadOverrides = !HttpContext.Current.IsDebuggingEnabled,
// compute the value you want locale to have, used for i18n
LocaleSelector = html => System.Threading.Thread.CurrentThread.CurrentUICulture.Name.Split('-')[0],
// instance of IRequireJsLogger
Logger = null,
// extensability point for the config object
ProcessConfig = config => { },
// extensability point for the options object
ProcessOptions = options => { },
// value for urlArgs to be passed to require.js, used for versioning
UrlArgs = RenderHelper.RenderAppVersion()
})
</body>
</html>
For further reading you can access the documentation page: http://requirejsnet.veritech.io/ .
Or the github project (for issues and questions) : https://github.com/vtfuture/RequireJSDotNet
In this package exists a compressor too for bundling and minification (based on YUI compressor).
Instead of bundlePath use the bundle path "/Scripts/bundles/scripts" . it'll work.
An old question but you can use #Scripts.RenderFormat() to get MVC to output the filename of the bundle on it's own. e.g.
Bundle
bundles.Add(new ScriptBundle("~/bundles/bundleName").Include(
"~/Scripts/filename1.js",
"~/Scripts/filename2.js",
"~/Scripts/filename3.js"
));
View
<script type="javascript">
var arrayOfFiles = [#Scripts.RenderFormat("\"{0}\",","~/bundles/bundlename")];
</script>
This sets arrayOfFiles to
["/Scripts/filename1.js","/Scripts/filename2.js","/Scripts/filename3.js"]
or if the bundling is enabled you just get
["/bundles/bundleName?v=13232424"]
You can then pass this array to other javascript libraries.
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>
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.
In my Sencha application I have a Config.js file containing some service URLs:
Ext.define('MyApp.utils.Config', {
singleton : true,
config : {
authBaseUrl : '...',
serviceBaseUrl : '...',
reportsBaseUrl : '...',
imagesUrl : '...'
},
constructor : function (config) {
this.initConfig(config);
}
});
Before deployment I use the
sencha app build
command from the Sencha Touch SDK to minify and concatenate files etc.
My problem is that the build process will also add config.js to the minified app.js file, although it would be very useful if I could edit it without the need of rebuilding / redeploying the whole application. I haven't found any means to change the behaviour of the build process.
So after building the application I would like to have these three js files:
sdk/sencha-touch.js (concatenated, minified, cached in localstorage after the first download)
app.js (concatenated, minified, cached in localstorage after the first download)
config.js (left untouched, without caching it in the localstorage)
Break it out from the app so that it isn't bundled, then put a reference to it in app.json, this has worked well for me in similar cases.
I also have a config.js that is repeatedly modified during my development, so in my app.json it would look like this:
"js": [
{
"path": "sdk/sencha-touch-all.js"
},
{
"path": "config.js"
},
{
"path": "app.js",
"bundle": true,
"update": "full"
}
],
This makes sure that your config.js file is included in the build.
Then you need to add the script to your app.html file, just make sure that it is loaded before your main app.js. Mine looks like this (autogenerated from Sencha Architect):
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>llm</title>
<link rel="stylesheet" href="resources/css/llm.css">
<script src="http://maps.google.com/maps/api/js?sensor=true"></script>
<script src="sdk/sencha-touch-all.js"></script>
<script src="config.js"></script>
<script src="cordova-2.0.0.js"></script>
<script type="text/javascript" src="app.js"></script>
</head>
<body></body>
</html>
Hope that this helps you!