GRUNT Front-end Workflow
GRUNTFront-end Workflow
About Pagepro:
• Internet Software House from Poland • Operating since 2010 • Clients from Western Europe and U.S. • 176 projects done in 2014 • 1758 PSDs converted into
HTML5 in 2014
Common Front-end tasks• Compile SASS / LESS
• Minify
• Uglyfi
• Test
• Optimize
• Analyze
• Modules & Dependencies
node.js
• Server-side JavaScript
• V8 (Google Chrome Browser)
• Command Line Tool
• 40% JS 60 % C++
node.js
• EVENT DRIVEN, non-blocking I/O model
• event-loops
• no DOM implementation
• single-thread
mkdir grunt; cd grunt;
git https://github.com/Pagepro/training-grunt.git .
Clone repository
node.js
node -v;// check version if installed
https://nodejs.org/download/
brew install node
node.js
• process (node)
• document (JavaScript)
node.js
Traditional I/O
var result = db.query('select x from table_Y'); doSomethingWith(result); //wait for result! doSomethingWithOutResult(); //execution is blocked
node.js
Non-blocking I/O
db.query('select x from table_Y', function (result) { doSomethingWith(result); //wait for result! }); doSomethingWithOutResult(); //executes without any delay!
node.js
• Access File
• Listen to network traffic
• HTTP requests
• DB Access
node.js• Utilites
• Gulp
• Grunt
• Yeoman
• Live Reload
• Web servers
node.js
console.log('helo world');
node hello
node hello.js (.js is optional)
node.js
var age = 23, person = { name: 'Chris', location: 'Poland' } console.log(age); console.log(person);
node hello-extended
node.js
var requiredModule = require('./example-module'); console.log(requiredModule);
node modules
module.exports.a = 55; module.exports.b = [1, 3, 4, 5];
node.js
node server var http = require('http'); http.createServer(function (req, res) { console.log(req); res.write('hello!'); res.end(); }).listen(5000, "127.0.0.1");
node.js
node watch
var fs = require('fs');fs.watch('./server.js', { persistent: true}, function(event, filename) { console.log(event + " event occurred on " + filename);});
npm
npm init;
package.json{ "name": "libsasserplate", "version": "1.0.1", "description": "Libsass starter", "author": "Pagepro <[email protected]>", "devDependencies": { "grunt": "^0.4.2", "time-grunt": "latest", "grunt-sass": "latest", "grunt-autoprefixer": "latest", "grunt-spritesmith": "latest", "grunt-contrib-uglify": "~0.2.4", "grunt-contrib-watch": "^0.5.3", "grunt-contrib-copy": "^0.5.0", "grunt-contrib-kraken": "^0.1.3", "grunt-contrib-connect": "^0.8.0", "matchdep": "^0.3.0", "jquery": "1.11.2" }}
package.json
http://browsenpm.org/package.json
http://semver.org
npm
{ "name": "npm", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "" }, "author": "", "license": "ISC", "devDependencies": { "grunt": "^0.4.5" }}
{ "name": "npm", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "" }, "author": "", "license": "ISC"}
npm install grunt —save-dev
npm
rm -rf node_modules/*
ls
npm install
When not to use node.js?• When you are doing heavy and
CPU intensive calculations on server side, because event-loops are CPU hungry
• Node.js API is still in beta, it keeps on changing a lot from one revision to another and there is a very little backward compatibility. Most of the packages are also unstable. Therefore is not yet production ready.
GRUNT• Lint
• Test
• Compile
• Open browser
• Run browser
• Watch assets
• Recompile
• Reload browser
GRUNTpython -m SimpleHttpServer
open index.html
sass —watch sass:css
js hint main.js
./conquer_the_world.sh
etc.
GRUNT
We can setup long flows and run it with just one task.
We can stop the flow if taks fails.
Everyone in the team can follow same workflow.
GRUNT
• JavaScript task runner
• npm install -g grunt-cli
Gruntfile.js
• Grunt configuration file
• Makefile, Rakefile, etc.
GRUNT• cd grunt/linter;
• npm init;
• npm install grunt —save-dev
• npm install grunt-contrib-jshint —save-dev
• grunt jshint
GRUNT
'use strict';module.exports = function (grunt) { // load jshint plugin grunt.loadNpmTasks('grunt-contrib-jshint');};
GRUNT
>> No "jshint" targets found.
Warning: Task "jshint" failed. Use --force to continue.
Aborted due to warnings.
What’s a target?
GRUNTIt’s a core concept of Grunt. When we create a task, we add targets to it.
Every target represents a set of actions and files the task will be run over.
We can run a task’s target by simply appending it to the task name.
grunt mytask:mytarget
GRUNT
'use strict';module.exports = function (grunt) { // load jshint plugin grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.initConfig({ jshint: { all: [ 'Gruntfile.js' ] } });};
GRUNT
'use strict';module.exports = function (grunt) { // load jshint plugin grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.initConfig({ jshint: { all: [ 'Gruntfile.js', 'app/js/**/*.js' ] } });};
GRUNT
'use strict';module.exports = function (grunt) { // load jshint plugin grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.initConfig({ jshint: { all: [ 'Gruntfile.js', 'app/js/**/*.js', '!app/js/vendor/**/*.js' ] } });};
GRUNT'use strict';module.exports = function (grunt) { // load jshint plugin grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.initConfig({ jshint: { options: { jshintrc: '.jshintrc' }, all: [ 'Gruntfile.js', 'app/js/**/*.js', '!app/js/vendor/**/*.js' ] } });};
GRUNT & SASS
cd sass;
npm install;
grunt sass:dev
GRUNT & SASS
Prepare grunt sass:prod for getting minified css.
GRUNT & SERVER
cd server;
npm install;
grunt connect;
GRUNT & SERVER'use strict';module.exports = function (grunt) { // load plugins grunt.loadNpmTasks('grunt-contrib-connect'); grunt.initConfig({ connect: { server: { options: { port: grunt.option('port') || 8080, hostname: 'localhost', base: '', keepalive: true } } } });};
GRUNT & WATCH
Listen for something.
Do something.
GRUNT & SERVER
cd watch;
npm install;
GRUNT & SERVER
watch: {sass: {
files: ['app/sass/*.scss'], tasks: ['sass:dev'] }}
GRUNT & SERVER
grunt connect:server watch
GRUNT & SERVER
grunt.registerTask('mytask', 'Desc', [ 'connect:server', 'watch',]);
GRUNT & SERVER
grunt.registerTask('default', ['copy:dev', 'compass:dev', 'connect:server', 'watch']);
What is matchdep?
Matchdep
// Load pluginsrequire('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);// Default task(s).grunt.registerTask('default', ['sass', 'connect:server', 'copy:dev', 'watch']);// SASSS compilation onlygrunt.registerTask('compile', ['sass']);// sprite generationgrunt.registerTask('sprites', ['sprite']);grunt.registerTask('krak', ['kraken']);
Other examples
Uglifyuglify: {
lp: { files: { 'dist_lp/js/app.min.js': [ 'node_modules/jquery/dist/jquery.js', 'src/js/plugins.js', 'src/js/main.js' ] } }, thx: { files: { 'dist_thx/js/app.min.js': [ 'node_modules/jquery/dist/jquery.js', 'src/js/plugins.js', 'src/js/main.js' ] } } },
Shell
shell: { lpPackage: { command: 'cd dist_lp && zip -r ../package_lp.zip *' }, thxPackage: { command: 'cd dist_thx && zip -r ../package_thx.zip *' }}
Process
process: function (content, srcpath) { content = content.replace('<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>', '<script src="./js/app.min.js"></script>'); content = content.replace('<script src="static/js/main.js"></script>', ''); content = content.replace('<script src="static/js/plugins.js"></script>', ''); return content.replace(/static\//g, "./");}
Useful links1. https://www.youtube.com/watch?v=pU9Q6oiQNd0
2. http://howtonode.org/introduction-to-npm
3. https://speakerdeck.com/dmosher/frontend-workflows-and-tooling
4. http://gruntjs.com/
5. http://browsenpm.org/package.json
Thank you!Developing the web in the heart of Europe.