使用構建工具以前我以爲前端好蠢,css沒有變量,不能寫循環,爲了兼容要寫好多前綴,hmtl寫多頁面中有同一個header,我就粘貼複製,而後修改的時候每一個都要改。css
我還不會壓縮和合並,每次都要按F5刷新。其實這些問題也是網頁優化的問題。html
構建工具正是解決這些問題的集合。雖然網上gulp和webpack的教程不少,我仍是根據本身的需求整理了一下。前端
gulp安裝: https://markgoodyear.com/2014/01/getting-started-with-gulp/node
webpack安裝: http://webpack.github.io/docs/installation.htmljquery
基本的需求:android
css:要能編譯sass,要壓縮,要能本身補前綴webpack
js:要壓縮,要醜化(就是把變量名換成簡單的字母,即省空間又不容易被看懂),要合併ios
img: 要壓縮git
html:能夠引入文件(就解決一開始說的問題,多頁面下共同的組件)es6
gulp中的watch功能能夠監聽文件,經過livereload和gulp的監聽來實現保存後自動構建並刷新頁面十分帶感。
在給gulpfile以前,先看一下個人目錄結構:
src是生產目錄,就是代碼都是在這了面編寫的
dist是發佈目錄,裏面裝的就是通過壓縮合並等,構建好的文件目錄
我把html也放在src目錄裏了(可能有些人寫在dist中),而後構建的時候在移到dist目錄中,這樣生產和發佈的目錄就分離的比較好,你上傳到git上的時候能夠只上傳src中的東西
.jshintrc是一個叫gulp-jshint插件對應的配置文件,這個插件是用來檢查你的js的書寫規範和錯誤的,配置是配置它的規則
.babelrc是配置es6的,這個後面再說。
gulpfile
// 載入外掛 var gulp = require('gulp'), sass = require('gulp-ruby-sass'), autoprefixer = require('gulp-autoprefixer'), minifycss = require('gulp-minify-css'), jshint = require('gulp-jshint'), uglify = require('gulp-uglify'), imagemin = require('gulp-imagemin'), rename = require('gulp-rename'), clean = require('gulp-clean'), order = require("gulp-order"), concat = require('gulp-concat'), notify = require('gulp-notify'), cache = require('gulp-cache'), livereload = require('gulp-livereload'), fileinclude = require('gulp-file-include') ; // 樣式 gulp.task('styles', function() { return sass('src/css/*.scss') .pipe(autoprefixer('last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4')) .pipe(gulp.dest('dist/css')) .pipe(rename({ suffix: '.min' })) .pipe(minifycss()) .pipe(gulp.dest('dist/css')) .pipe(notify({ message: 'Styles task complete' })); }); // 腳本 gulp.task('scripts', function() { return gulp.src(['src/**/*.js']) .pipe(order([ "lib/jquery-2.0.3.min.js", "lib/*.js", "js/*.js" ])) .pipe(jshint('.jshintrc')) .pipe(jshint.reporter('default')) .pipe(concat('main.js')) .pipe(gulp.dest('dist/js')) .pipe(rename({ suffix: '.min' })) .pipe(uglify()) .pipe(gulp.dest('dist/js')) .pipe(notify({ message: 'Scripts task complete' })); }); // 圖片 gulp.task('images', function() { return gulp.src('src/images/**/*') .pipe(cache(imagemin({ optimizationLevel: 3, progressive: true, interlaced: true }))) .pipe(gulp.dest('dist/images')) .pipe(notify({ message: 'Images task complete' })); }); //html gulp.task('html', function() { return gulp.src('src/**/*.html') .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(gulp.dest('dist/')) .pipe(notify({ message: 'html task complete' })); }); // 清理 gulp.task('clean', function() { return gulp.src(['dist/css', 'dist/js', 'dist/images'], {read: false}) .pipe(clean()); }); // 預設任務 gulp.task('default', ['clean'], function() { gulp.start('styles', 'scripts', 'images', 'html'); }); gulp.task('watch', function() { // 看守全部.scss檔 gulp.watch('src/css/**/*.scss', ['styles']); // 看守全部.js檔 gulp.watch('src/js/**/*.js', ['scripts']); // 看守全部圖片檔 gulp.watch('src/images/**/*', ['images']); //看守html gulp.watch('src/**/*.html', ['html']) ; livereload.listen(); gulp.watch(['dist/**']).on('change', livereload.changed); });
有幾個插件說明一下:
1.gulp-notify這個插件是用來完成任務後給你一個提示音的,由於若是項目大第一次構建會很慢。
2.gulp-concat插件合併js的時候是沒有順序的,因此我用了gulp-order來解決依賴的問題,好比好多文件依賴jquery
3.gulp-cache插件是緩存img,由於img壓縮很費時間,因此這個插件就是指構建有變動的img
4.gulp-livereload這個插件須要chrome中的插件支持,在chrome瀏覽器中右上角,設置->擴展程序->獲取更多擴展程序 在這裏搜索livereload,並下載安裝
安裝完成後會有這樣的圖標,在要用的時候點一下,讓中間的方形變成實心的就行了
編譯sass遇到的坑:
編譯sass使用的是插件是gulp-ruby-sass,以前常常報錯是編碼的問題,後面將項目路徑的中文名改爲英文名就解決了問題。
網上還有最終方案是在SASS 項目中 config.rb
配置文件 指定SASS的字符集
encoding = 「utf-8」
出處: http://wuyixiang.sinaapp.com/sass-compass-compile-error/
感受gulp這些功能都蠻不錯,但我其實還有一些需求沒說,是關於js的
1.模塊化(避免命名衝突)
2.要用es6(跟上潮流嘛)
3.js能不能按需加載?好比說我有頁面A和頁面B,他們都依賴一個base.js,而後又分別各自依賴a.js和b.js,這種狀況我用剛纔的gulpfile打包之後合併出來的一個公共的js是將三個js都包括了,但顯然頁面B不須要a.js,因此當用戶單獨訪問頁面B的時候加載的js就顯得多餘了,就多費了流量啊,速度也會慢。
上述的前兩個gulp仍是能解決,可是第三個問題好像並很差解決。。。在查找各方資料後我決定用webpack,因此就是其餘css,html的部分仍是gulp來處理,可是把js交給webpack來處理
webpack登場!!
其實使用了es6後就能夠用新特性export和import寫模塊化的東西了,因此前兩個需求算是合併了。
import和export舉例:
export class animal{ constructor(name){ this.name = name; } sayhi(){ //console.log(`hi ${this.name} !`); alert(this.name); } } export var myname = "mtjs " ;
import {animal,myname} from './animal' ;
第三個需求使用webpack中的CommonsChunkPlugin這個插件實現的
這個插件能夠把多個html中公共依賴的部分打包成一個和多個公共依賴包(chunk),這樣每一個頁面只須要引入這個公共chunk和本身單獨的js就能夠了。
webpack和gulp同樣,都是用配置文件的:
const webpack = require('webpack'); var CommonsChunkPlugin = require("webpack/lib/optimize/CommonsChunkPlugin"); module.exports = { entry: { index:'./src/js/index.js', main:'./src/js/main.js' }, output: { filename: '[name].js' }, module: { loaders: [{ test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader', }] }, plugins: [ new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false, }, output: { comments: false, }, }),//壓縮和醜化 new webpack.ProvidePlugin({ $: 'jquery' }),//直接定義第三方庫 new CommonsChunkPlugin({ name: "commons", // (the commons chunk name) filename: "commons.js", // (the filename of the commons chunk) minChunks: 2, // (Modules must be shared between 2 entries) chunks: ["index", "main"] // (Only use these entries) })//定義公共chunk ] };
在webpack中每一個頁面都要有一個entry,這裏index和main就是兩個頁面的entry,在這個entry中定義依賴就行了,output中原本還能夠指定生成文件的路徑,但咱們將路徑放在gulpfile中統一處理
配置中咱們用了babel的loader來編譯用es6標準寫的js文件,這個loader須要前面說到的.babelrc文件來配置
CommonsChunkPlugin的參數:
name:chunk名
filename:生成的文件名
minChunks:最小引用次數,一個依賴最少被引入這個次數纔會被加到公共的chunk中
chunks:指定這個chunk是由哪些頁面構成的
好了js處理完了,如今將gulp和webpack結合起來就行了
在gulpfile中把原來的處理js的task刪掉,添加下面的代碼
var webpack = require('gulp-webpack'); gulp.task('scripts', function(callback) { return gulp.src('src/entry.js') .pipe(webpack( require('./webpack.config.js') )) .pipe(gulp.dest('dist/js')); });
這樣就大功告成了,鍵入gulp和gulp watch來感覺一下吧
項目github地址:https://github.com/jokermask/gulp_webpack_demo