Can Grunt tasks navigate "up" from the folder they are run in? - gruntjs

I am trying to structure my assets so that multiple projects can share a "phase" of the build script. For example, if I have 3 web-based products that all use Bootstrap and jQuery, I want to only source the libraries from a shared "library".
The folders are proposed to be structured like this:
shared
-sharedGrunt.js (file)
-lib (folder)
-bootstrap (folder)
-jQuery.js (file)
app1
-Gruntfile.js (file)
-src (folder)
-images (folder)
-js (folder)
-etc
app2
-Gruntfile.js (file)
-src (folder)
-images (folder)
-js (folder)
-etc
I want Gruntfile.js in each "app" folder to be able to "import" or otherwise execute sharedGrunt.js. I haven't crossed that bridge yet because I'm stuck at the very first proof of concept test: a simple copy.
So, in one of the app's Gruntfile.js files, I have a copy task that looks like this:
copy: {
externalTest: {
expand: true,
src: '../shared/lib/jQuery.js',
dest: 'dev/js/jQuery.js',
flatten: true
}
}
As you can see, I try to go UP one level from the Gruntfile. Which is the directory containing "shared", "app1", and "app2". And then navigate back down into the shared lib folder in order to grab jQuery.
The task is "successful" (no actual error is thrown), but no files are copied.
How can I accomplish my goal? Will I need to put a "catch-all" gruntFile into a "parent" folder that contains all of the projects? I don't want developers to require checking out the whole parent. I want developers to be able to check out "app1" and "shared" and run with it.

It's weird - Grunt has no problem with going up any level, and on my machine your code indeed copies 1 file.
However, your use of expand cause grunt to use the dest property as a directory, so your file ends up being dev/js/jQuery.js/jQuery.js (note the repetition).
Fixed by doing:
copy: {
externalTest: {
expand: true,
src: '../shared/lib/*.js',
dest: 'dev/js',
flatten: true
}
}

Prompted by observations in Xavier's answer, I forged ahead and determined that I had two flaws:
I should simply provide the destination directory. If I try to provide a filename, it will make an additional directory with the name of what I thought would be the filename; this is per Xavier's observation.
If you don't issue a "cwd" for the copy, it reproduces the entire directory tree from the source side.
So, the following:
share: {
expand: true,
src: '../common/lib/jquery.js',
dest: 'dev/js/'
}
results in a file found in the destination as '"dev/common/lib/jquery.js"'. This is not intended behaviour.
SOLUTION:
Supply the destination as a directory, not a filename. It will use the original filename.
Issue a CWD before the copy so that the source path is not merged into the destination path.
Working task:
share: {
expand: true,
cwd: '../common/lib',
src: 'jquery.js',
dest: 'dev/js/'
}
Results in a file sourced at "../common/lib/jquery.js" and ending up at destination "dev/js/jquery.js" as intended.

Related

GruntJS and imagemin, Is it ok to overwrite 'src'?

I have a grunt script (written by someone else) which is minify'ing images, but the the source and destination are the same folder, which to my mind appears to be overwriting the source with the minified images.
Here is a section from the gruntfile.js
imagemin: {
options: {
compress: true
},
dist : {
files: [
{
expand: true,
cwd : 'templates',
src : ['**/*.{png,jpg,gif}'],
dest : 'templates'
}
]
}
}
There is also a 'watch' task and 'newer' is in use so files are not reprocessed.
Is this ok? Or should the source and destination always be different? I don't think 'jpg' and 'gif' come in a 'lossless' flavour. I've been told that because the script is using 'newer', it keeps a cache of what it's done that survives a restart.
That sounds like a horrible idea. (I mean that it's written to overwrite the same directory, that's insane!)
You can definitely change src to src: ['large/**/*.{png,jpg,gif}'], and drop the original images there.
newer will still keep track of which files have already been compressed, but you'll still have access to the original high-res images in a separate large folder.
MORE:
Though in my own projects, I have a src folder at the top-level directory for the project, so src/img/**/* is compressed and output to just img. It's a complete split between the source files that all go in a top-level src directory, and production ready is everything but src at the top for static sites, or in a dest/build/whatever directory for more involved projects at the top.

ASP .NET 5 - grunt task to copy files from node modules to wwwroot

I have a simple ASP .NET 5 empty project - with npm and grunt installed.
I've used npm to install a few client-side libraries, at present located in the node_modules directory directly under my ASP .NET project.
I want to copy the relevant files (for example, jquery.min.js) from the node_modules folder into the wwwroot folder.
It's unclear to me how to use grunt to do this - as each node module has it's own dependency tree, and there doesn't seem to be any consistency in the file structure from package to package.
I could write a grunt task explicitly for each client side library I use, but in that case I may as well download everything manually and place the files where I need them manually, avoiding npm all together.
I know I could use bower, which has a flat dependency tree - which is probably the root I should go down - but I've read a few articles saying "there's no need for bower - npm can do it all" and therefore I would like to know if there's a way to do this purely with npm.
Is there a way? Or is the "npm can do it all" statement aimed at projects that will require the components directly from the node_modules?
TL DR; Is bower a better fit than npm for ASP .NET 5 projects with separation of source and build files, and if not, what's the recommended way of doing it purely with npm?
I don't fill me professional in grunt, but I use it myself and I think that I can explain you how one can use it corresponds to your requirements.
First of all you should add "New Item" to your project, choose "Client-Side" and "NPM Configuration file" to add package.json to the the project (in the same directory where you have project.json). I suppose you have already created the file, but the existence of the file is important for grunt too. Then you adds some dependencies, which you need on the client-side to "dependencies" part of package.json and add at least grunt and grunt-contrib-copy to "devDependencies" part. An example of the file you will see below
{
"version": "1.0.0",
"name": "ASP.NET",
"private": true,
"dependencies": {
"font-awesome": "^4.5.0",
"jquery": "^1.11.3"
},
"devDependencies": {
"grunt": "^0.4.5",
"grunt-contrib-clean": "^0.7.0",
"grunt-contrib-copy": "^0.8.2"
}
}
Now you should add "Grunt Configuration File" in the same way like you added "NPM Configuration file". You will create gruntfile.js (in the same directory where you have project.json). Finally you should fill gruntfile.js with more helpful code. For example the code
module.exports = function(grunt) {
grunt.initConfig({
clean: ["wwwroot/font-awesome/", "wwwroot/jquery*.*"],
copy: {
main: {
files: [
{
src: "node_modules/font-awesome/css/*",
dest: "wwwroot/font-awesome/css/",
expand: true,
filter: "isFile",
flatten: true
},
{
src: "node_modules/font-awesome/fonts/*",
dest: "wwwroot/font-awesome/fonts/",
expand: true,
filter: "isFile",
flatten: true
},
{
src: "node_modules/jquery/dist/*",
dest: "wwwroot/",
expand: true,
filter: "isFile",
flatten: true
}
]
}
}
});
grunt.loadNpmTasks("grunt-contrib-clean");
grunt.loadNpmTasks("grunt-contrib-copy");
grunt.registerTask("all", ["clean", "copy"]);
grunt.registerTask("default", "all");
};
registers two tasks: clean and copy and the aliases all and default. You can select gruntfile.js file in the solution explorer, open context menu and choose "Task Runner Explorer". You will see all defined tasks. The task with the name "default" will be executed if you execute grunt without parameters (without the task name) in the command line.
Now you can choose some task and run it. You can choose some task, click right mouse button to open context menu and check "After Build" in "Bindings":
Now the task will be executed every time when you build the project. You can click optionally "V" button on the left side to see verbose information from the executed tasks.
I hope it's already the main information which you need. Many other helpful information about plugins grunt-contrib-clean, grunt-contrib-copy, grunt-contrib-jshint, grunt-jscs, grunt-newer and many other you will find yourself. One official place of ASP.NET 5 documentation should be mentioned. It's the place.
P.S. You asked additionally about the usage of bower. I find both npm and bower not perfect, but still very practical. I would prefer to hold full control over the dependencies and especially about the data, which will be copied under wwwroot. Thus I change the content of .bowerrc file from { "directory": "wwwroot/lib" } to { "directory": "bower_components" } and I use grunt to copy the required data from bower_components in the same way like I do this with files from node_modules. See the article for more details. In other words I use packages published only in bower repository in the same way like I use npm packages.

How does my project find files in Grunt's .tmp directory?

I currently am using a Yeoman seed project which comes with a Gruntfile and I'm having some trouble understanding parts of it. One particularly confusing thing is that during the development phase my SASS files are compiled into CSS and placed into a .tmp directory. My project however looks for main.css under app/styles yet the only thing there is my scss file. How is my project able to find main.css when it's not where it's looking?
./myApp
--Gruntfile.js
--.tmp
----main.css
--./app
----styles
------main.scss
When I create the dist folder the main.css file is placed correctly where it should be.
I think it may have to do with the compass or live-reload plugin.
I believe that you are talking about the situation when you ran grunt serve.
In the situation, the built-in server provides files under both .tmp and app directories by default which is specified for grunt-contrib-connect in Gruntfile like followings.
// The actual grunt server settings
connect: {
...
livereload: {
options: {
open: true,
base: [
'.tmp',
'<%= config.app %>'
]
}
},
This is why "styles/main.css" in index.html file goes to .tmp/styles/main.css.

Chaining Grunt tasks

Is it possible to chain Grunt tasks so the output of one task is fed into another task without being written to the disk first? For example, could I compile Stylus files into CSS, prefix them with Autoprefixer and then compress them using grunt-contrib-cssmin without writing intermediate files to the disk? I ask because it's a pain to store and reference files between my source and build directories.
I don't believe there is, but I have another way for you. Store the path in a configuration object in your initConfig. By using grunt's built in underscore templates you can have the file path defined once (so it's easier to manage).
module.exports = function(grunt){
grunt.initConfig({
pathTo: {
css: 'dist/css/master.css'
},
cssmin: {
dist: {
files: {
'<%= pathTo.css %>': ['<%= pathTo.css %>']
}
}
},
clean: {
dist: ['dist']
}
});
}
I also recommend using grunt-contrib-clean to erase your dist folder before it is built. This way all of the files that end up in there have been generated by Grunt, so if you change your mind about a file path or item in there you don't have to manually clean it up. Hope this helps. :-)

gruntfile.js config using grunt-jekyll

I am trying to configure jekyll with grunt.js.
Here is my directory structure:
.
.._layouts
.._includes
..other
Here is my code for the gruntfile:
jekyll: {
dev: {
src: '',
dest: ['_layouts', '_includes']
},
},
This dumps the entire site in one folder named _layouts,_includes
I want to to source .html files from both the _includes and _layouts folders. I know the easy way to do this is to put them in "templates" and then have jekyll watch that, but I was wondering if I can keep to this alternative structure somehow?
I'm not entirely positive this will work as the dest only accepts a string. You might consider using 2 sub tasks that put the site in both _layouts and _includes directories

Resources