How can I customize this build script with Node? - javascript

I have a unique directory structure that I need help making a build script for.
Here is the link (slightly different) or directory structure:
client
/extensions
/sandbox
/widgets
/form
/collections
/models
/views
/styles
custom.css
/controllers
main.coffee
server
/views
/layouts
/errors
app.coffee
config.coffee
Couple things I need:
Compile coffeescript with a watch task into a server-dist +
client-dist
Copy over all other files into their nested folders, preferably with a watch task also
Problems:
If I just compile coffeescript it just copies over the .coffee files
to .js into their nested directories but that leaves behind .css /
imgs / etc loaded with require.js. I need a way to bring them as well
into the -dist directories
Main.coffee in the /client folder is a require.config and can be used with requirejs grunt build tool to optimize things.
Anyways the easiest solution is what I am looking for.

I ended up using grunt - with the following tasks:
clean: Clears the server / client build directories
watch: Monitors .coffee files and both build directories
copy: Copies over client / server files to build directories ignoring .coffee files which are managed by the coffee task
coffee: Compiles .coffee files to .js moving them to the build directories
Here is the grunt file in its current iteration:
grunt.initConfig({
clean: {
build: ['client-dist', 'server-dist'],
release: []
},
watch: {
coffee: {
files: ['client/**/*.coffee', 'server/**/*.coffee'],
tasks: 'coffee reload'
},
reload: {
files: ['client/**/*.!(coffee)', 'server/**/*.!(coffee)'],
tasks: 'copy reload'
}
},
copy: {
client: {
files: {
"client-dist/": "client/**/*.!(coffee)"
},
options: {
basePath: "client"
}
},
server: {
files: {
"server-dist/": "server/**/*.!(coffee)"
},
options: {
basePath: "server"
}
}
},
coffee: {
compile: {
files: {
'server-dist/*.js': 'server/**/*.coffee',
'client-dist/*.js': 'client/**/*.coffee'
}
}
}
});
grunt.loadNpmTasks('grunt-contrib');
grunt.loadNpmTasks('grunt-reload');
grunt.registerTask('default', '');
grunt.registerTask('build', 'clean:build copy coffee watch');

Related

Source map to files outside public directory

I have a file structure like this:
/server/
- package.json
- node_modules/
- Gruntfile.js
/public/
- index.html
- assets/
When in /server I run npm install, which downloads things like Angular into /server/node_modules.
I then run the Gruntfile.js which looks like this:
require('load-grunt-tasks')(grunt);
grunt.initConfig({
//concat js
concat: {
options: {
separator: ';',
sourceMap: true
},
lib: {
src: [
'./node_modules/angular/angular.js',
'./node_modules/angular-route/angular-route.js',
'./node_modules/angular-animate/angular-animate.js'
],
dest: '../public/assets/build/lib/lib.min.js'
}
},
//minify js
uglify: {
options: {
mange: true,
compress: true,
sourceMap: true
},
lib: {
src: '<%= concat.lib.dest %>',
dest: '<%= concat.lib.dest %>'
}
}
});
grunt.registerTask('build', ['concat', 'uglify']);
The grunt file works as expected to concat and minify the Angular modules with a source map. The problem is that the domain name points to the public directory, but the source map wants to point to the Angular source code in the server directory, which I don't think will work.
How do I get around this problem? Do I have to have the node_modules in the root of the public directory? I'd rather not have any precompiled code in the public directory if possible, the reason being that when I put the site live, I can simply FTP the public directory and ignore the server, reducing unnecessary bulk.

How to minify all js and css in MEAN.JS for production environment?

I have just developed a simple MEAN.JS application. MEAN.JS provides a command grunt build that helps me to minify the js and css files located at the following folders
css: [
'public/modules/**/css/*.css'
],
js: [
'public/config.js',
'public/application.js',
'public/modules/*/*.js',
'public/modules/*/*[!tests]*/*.js'
]
but how about also minifies the third-party libraries, which is installed with bower and located in public/lib/...? All the needed js and css file paths are already inside the MEAN.JS environment config file.
Meanwhile, the minified js file application.min.js is really just "minified", not "uglified", the variables' names are still the same as the original and very long.
In short, has MEAN.JS already provided any ways or functions that can "uglified" all the js and css files including third-party libraries?
EDIT:
To avoid errors when uglifying 3rd party files, only include non-minified 3rd party .js files in your config/env/all.js file.
Currently, your grunt build task uglifies your application javascript files but not your 3rd party javascript files. It does this via the uglify task in your grunt.js file.
uglify: {
production: {
options: {
mangle: false
},
files: {
'public/dist/application.min.js': 'public/dist/application.js'
}
}
},
If you want to uglify your 3rd party files I suggest taking the following steps:
Add your vendor files to your grunt.js file and the uglify task:
Change the configuration object (around line 170) to include your vendor files:
// A Task for loading the configuration object
grunt.task.registerTask('loadConfig', 'Task that loads the config into a grunt option.', function() {
var init = require('./config/init')();
var config = require('./config/config');
// insert vendor files
grunt.config.set("vendorJavaScriptFiles", config.assets.lib.js);
// note: you can do the same for your css files
grunt.config.set("vendorCSSFiles", config.assets.lib.css);
grunt.config.set('applicationJavaScriptFiles', config.assets.js);
grunt.config.set('applicationCSSFiles', config.assets.css);
});
Add your vendorJavaScriptFiles to your uglify task:
uglify: {
production: {
options: {
mangle: false
},
files: {
'public/dist/application.min.js': 'public/dist/application.js',
'public/dist/vendor.min.js': '<%= vendorJavaScriptFiles %>'
}
}
}
Change your config/env/production.js file to reflect your new vendor.min file:
assets: {
lib: {
css: [
'public/lib/bootstrap/dist/css/bootstrap.min.css',
'public/lib/bootstrap/dist/css/bootstrap-theme.min.css',
// note you can follow a similar process for your css files
],
js: 'public/dist/vendor.min.js'
},
css: 'public/dist/application.min.css',
js: 'public/dist/application.min.js'
}
Now, when you run grunt build you should get both an applicaiton.min.js file and a vendor.min.js file in your public/dist/ folder.
I separated them out for clarity, but you could combine them into one application.min.js file if you prefer.
Here is a much more detailed description of the process: https://blog.dylants.com/2014/11/19/bundling-production-assets-for-mean-js/
Hope this helps.

Configure grunt.js to minify files one by one in bower folder

I have the dependencies of the application in bower_components, some of the dependencies don't have a minified version so I'd like to create a task creates a minified copy of the file version in the same place where the file is located like:
bower_components
lib1
lib1.js
lib1.min.js <- create this file if doesn't exist
lib2
lib2.js
lib2.min.js <- create this file in it's own lib2 folder
lib3
lib3.js
lib3.min.js <- and so on...
This is my grunt Config so far:
uglify: {
dev: {
files:[
{
expand: true,
src: 'bower_components/modernizr/modernizr.js',
dest: '/',
ext:'.min.js'
}, {
expand: true,
src: 'bower_components/angular-facebook/lin/angular-facebook.js',
dest: '/',
ext: '.min.js'
}]
},
main: {
src: 'temp/app.min.js',
dest:'dist/app.min.js'
}
}
the Grunt task says that copied modernizr to it's own folder but when I look at it, the file is not there and after the first file Grunt passes to the next task and ignores the 'second' file in the array.
I was just testing this obviously I'd like to implement a way that grunt scan all the dependencies in bower_components automatically.
btw, I don't mind to change the task to any other library.
the / in your dest-option means the root path (were your gruntfile resides). just delete the dest-option or put an empty string there.
important: this just works with the expand-option set!
{
expand: true,
src: 'bower_components/modernizr/modernizr.js',
ext:'.min.js'
}
Edit:
for scanning all folders an minimizing all js files do it like this (note the second argument in src to not minify files which are already minified):
{
expand: true,
src: ['bower_components/**/*.js', '!bower_components/**/*.min.js'],
ext:'.min.js'
}

grunt copy moving build folder outside of project

Hello I have a file structure that looks like this,
|-App
|------|src
|----------|js
|----------|img
|----------|css
|----------|less
|----------|tpl
|----------|index.php
|- Gruntfile.js (withing parent app folder)
|- package.json (withing parent app folder)
What I am trying to do is move all the contents of the src folder into a build folder, the build folder gets created but outside of the App folder, and I don't really understand why, secondly when it does copy the src folder it copies the actual src folder, I want to copy all its children but no the parent src folder, and thirdly the copy ignores the index.php file why? Below is my current Gruntfile.js
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
copy: {
build: {
cwd: '.',
src: ['src/*/*'],
dest: '../build',
expand: true
}
},
clean: {
build: {
cwd: '.',
src: ['build']
}
}
});
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.registerTask('move', 'Moves the project to the build folder', ['copy', 'clean']);
};
Your paths are wrong. Change the build options to:
build: {
cwd: '.',
src: ['src/**/*'],
dest: './build',
expand: true
}
../build meant the build directory was created in the parent dir (.. is the parent dir)
src/**/* means recursively copy all files and files of descendent folders.

Grunt & requirejs optimizer for a multi app project

I'm having issues getting Grunt to perform requirejs optimization on a project with the following structure:
static/js
|── apps
|── app.js
|── dash.js
|── news.js
... (many more 'app' files)
|── build
|── collections
|── libs
|── models
|── util
|── views
Each of static/js/apps/*.js should be compiled to static/js/build/*.js containing the relevant dependencies (eg. views/view1, libs/query etc).
This is currently being performed by a basic bash script:
JS_ROOT="static/js"
for f in ${JS_ROOT}/apps/*
do
FILE=$(basename -s .js ${f})
pushd .
cd ${JS_ROOT} && r.js -o baseUrl=. name=libs/require-min.js include=apps/${FILE} out=build/${FILE}.js
popd
done
I'm attempting to move to a Grunt-based optimization, with the following in Grunt.js:
requirejs: {
compile: {
options: {
appDir: 'static/js/',
baseUrl: './apps/',
dir: 'static/js/build/',
modules: [
{
name: 'app',
}
]
}
}
}
Running generates the following error:
>> Tracing dependencies for: app
>> Error: ENOENT, no such file or directory
>> 'static/js/build/apps/libs/jquery.js'
>> In module tree:
>> app
I can clearly see what the problem is, but am failing to figure out how to indicate that the dependencies in each static/js/apps/*.js file are in static/js/ not static/js/build
In addition to this, I'm assuming that the modules block containing name: 'app' should be outputting the compiled file static/js/build/app.js from the contents of static/js/apps/app.js.
Without creating an additional module block for each file in static/js/apps, how can I compile each of the files into their relevant static/js/build/*.js file?
Update 1
So the following in my Gruntfile compiles static/js/apps/app.js successfully into static/js/build/app.js:
requirejs: {
compile: {
options: {
baseUrl: 'static/js/',
include: './apps/app.js',
out: 'static/js/build/app.js',
}
}
}
The next step being to compile static/js/apps/*.js into static/js/build/*.js without having to define each individually...
Update 2
Modifying the above to:
requirejs: {
compile: {
options: {
baseUrl: '../',
include: './apps/<%= appFile %>',
out: 'static/js/build/<%= appFile %>',
}
}
}
And creating the task:
grunt.registerTask('buildrjs', function() {
var dir='static/js/apps/';
grunt.file.setBase(dir);
var files = grunt.file.expand(['*.js']);
files.forEach(function(filename) {
grunt.log.write('Compiling '+filename+'\n');
grunt.config.set('appFile', filename);
grunt.task.run('requirejs:compile');
});
});
Almost gets me to the solution. The tasks runs through each file in static/js/apps/ and passes the filename into grunt.config.set('appFile', filename);. The output of the task outputs Compiling app.js Compiling news.js... etc, however afterwards the actual requirejs:compile tasks runs over & over on the last file in the static/js/apps/ directory, rather than each individual file. An async issue?
Solved, by passing multiple sets of options to the requirejs task, thanks to this article for the final pointers I needed:
module.exports = function(grunt) {
var files = grunt.file.expand('static/js/apps/*.js');
var requirejsOptions = {};
files.forEach(function(file) {
var filename = file.split('/').pop();
requirejsOptions[filename] = {
options: {
baseUrl: 'static/js/',
include: './apps/'+filename,
out: 'static/js/build/'+filename
}
};
});
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
requirejs: requirejsOptions,
});
};
Then the ['requirejs'] task can be run as normal and will output the appropriate compiled .js file as per each of the options: {} blocks that were specified in requirejsOptions, eg:
grunt.registerTask('default', ['requirejs']);
You need to change baseUrl to static/js from apps in requirejs build config. As currently baseUrl is pointing to apps directory, require is trying to search dependency files in apps directory. If you change the baseUrl to static/js it will find those dependency files.
requirejs: {
compile: {
options: {
appDir: 'static/js/',
baseUrl: 'static/js',
dir: 'static/js/build/',
modules: [
{
name: 'app',
}
]
}
}
}

Categories