PHP template engines● Smarty (2002)
● Twig (Symfony)
● Mustache (Logic-less templates)
● Blade (Laravel 4)
● Volt (Phalcon)
Designers’ hell at 2000s● CSS
○ Cascading Style Sheet
○ Browser compatibility
○ Huge single file or external HTTP imports
○ Selector Priority (a#a-02 is more specific than a[id=”a-02”]?)
○ Cascading.
Assets file tree
assets/├── css│ ├── bootstrap.min.css│ ├── magnific-popup.min.css│ ├── videojs.min.css│ └── main.css├── fonts/└── images/
The birth of preprocessorsLESS and SASS were born to solve the bad things of CSS inspired by software
development.
● local imports
● variables
● functions
● reusable code
Assets file tree with less
assets/├── less│ ├── global.less│ ├── main.less│ ├── utils│ │ ├── animations.less│ │ ├── device-label.less│ │ ├── generators.less│ │ ├── helpers.less│ │ ├── media-queries.less│ │ ├── positions.less│ │ ├── shadows.less│ │ └── sizes.less│ └── webfonts.less├── css│ ├── bootstrap.min.css│ ├── magnific-popup.min.css│ ├── videojs.min.css│ └── main.min.css├── fonts/└── images/
Why reinvent the wheel?● jQuery
● Bootstrap
● Foundation
● Magnific Popup
● JWPlayer
● jQuery Mobile
● Video.js
● Sencha Touch
● Backbone
● jQuery UI
● D3.js
● Chosen
● Handlebars
● Underscore
● JQuery-File-Upload
● Prototype
● Dojo
● jquery-select
● jquery-gallery
● jquery-pokemon-go
Bower● Package Manager by Twitter
● Bower.json: single configuration file with all frontend dependencies
● Automatic download
● Flat dependencies tree
● Dependency upgrade with one command
MORE TOOLS
● bower init
● bower install <package> --save
● bower install
Assets file tree with bower
assets/├── bower_components│ ├── bootstrap/│ ├── magnific-popup/│ └── videojs/├── less│ ├── global.less│ ├── main.less│ ├── utils/│ └── webfonts.less├── css│ └── main.min.css├── fonts/└── images/
CommonJS● NodeJS love
● Explosion of packages and tools written for node.js
● Modularization as hell (require(‘left-pad’))
● Encapsulated code with specific exports (module.exports = PokemonGo)
● No more self-invoking functions!
● Small files
Front-end developers’ problem● Code complexity grows as the site gets bigger
● Assembly gets harder
● Developer wants discrete JS files/modules
● Deployment wants optimized code in just one or a few HTTP calls
Browserify● Small wrapper for the require function
● Build process that keeps track of dependencies
● Bundle to one file
More tools
browserify index.js > bundle.js
Assets file tree with browserify
assets/├── bower_components/├── node_modules/├── less/├── dist│ ├── bundle.js│ └── main.min.css├── js│ ├── Components│ │ ├── Modals.js│ │ └── Slideshow.js│ ├── Models│ │ ├── User.js│ │ └── Product.js│ └── main.js├── fonts/└── images/
*choose-a-language* to JavaScript ● Coffeescript to JavaScript - coffeescript.org
● TypeScript to JavaScript - typescriptlang.org
● Dart to JavaScript - dartlang.org
● C/C++ to JavaScript - Emscripten
● ES6 to ES5 - babel
● JavaScript to JavaScript - js2js
A new frontend environement● Single page application
● Web App
● Front-end frameworks:
○ Backbone + jQuery
○ Angular
○ Ember
○ Meteor
○ React.js
● The V of MVC is moved to browsers
● Front-end designers became Front-end developers
● Backend developers and Front-end developers meet together only in one way...
Recap tools● less / sass
● browserify / webpack / rollup
● uglify
● transpilers
● imagemin
● watch
● livereload
● ...
But before I need to node and npm// package.json - created with '$ npm init'{ "name": "my-awesome-project", "version": "0.1.0", "description": "My Awesome Project", "scripts": { "build": "node_modules/grunt-cli/bin/grunt dist", "start": "node_modules/grunt-cli/bin/grunt dev" }, "devDependencies": { "grunt": "~0.4.5", "grunt-cli": "~1.2.0", "grunt-contrib-sass": "~1.0.0" } "author": "RomaJS"}
Gruntmodule.exports = function(grunt) {
grunt.initConfig({sass: {
dist: {files: {
'style/style.css': 'sass/style.scss'}
}},watch: {
css: {files: '**/*.scss',tasks: ['sass']
}}
});grunt.loadNpmTasks('grunt-contrib-sass');grunt.loadNpmTasks('grunt-contrib-watch');grunt.registerTask('start',['sass', 'watch']);grunt.registerTask('build',['sass']);
}
● grunt-contrib-cssmin● grunt-contrib-less● grunt-contrib-concat● grunt-contrib-uglify● grunt-contrib-imagemin● grunt-contrib-copy● grunt-contrib-clean● grunt-contrib-livereload● grunt-contrib-jshint● grunt-eslint● grunt-pokemon-go● ...
// gruntfile.js
Gulpvar gulp = require('gulp'), sass = require('gulp-sass');
gulp.task('scripts', function() { return gulp.src(['bower_components/jquery/jquery-1.11.1.js', 'src/**/*.js']) .pipe(concat('main.js')) .pipe(uglify()) .pipe(gulp.dest('dist/build'));});gulp.task('styles', function() { gulp.src('sass/**/*.scss') .pipe(sass().on('error', sass.logError)) .pipe(gulp.dest('./css/'))});//Watch taskgulp.task('default', ['scripts', 'styles'], function() { gulp.watch('sass/**/*.scss',['styles']); gulp.watch(['js/**/*.js'], ['scripts'])});
● gulp-cssmin● gulp-less● gulp-concat● gulp-uglify● gulp-imagemin● gulp-copy● gulp-clean● gulp-livereload● gulp-jshint● gulp-eslint
// gulpfile.js
Webpackmodule.exports = { entry: './src/js/main.js', module: { loaders: [{ test: /\.js$/, loader: 'babel', query: { presets: ['es2015', 'react', 'stage-0'] } }, { test: /\.less$/, loader: ExtractTextPlugin.extract('style-loader', 'css!less') }] }, output: { filename: 'bundle.js', path: __dirname + '/../web/assets' }};
● creates one or many bundles
● allow commonjs and es6● webpack-dev-server
○ watch○ livereload
● loaders +150○ sass○ less
● plugins +30○ uglifyJs○ imagemin○ commonsChunk
// webpack.config.js