Gulp和Webpack對(duì)比

在現(xiàn)在的前端開(kāi)發(fā)中笔呀,前后端分離、模塊化開(kāi)發(fā)捏题、版本控制玻褪、文件合并與壓縮、mock數(shù)據(jù)等等一些原本后端的思想開(kāi)始逐漸滲透到“大前端”的開(kāi)發(fā)中公荧。前端開(kāi)發(fā)過(guò)程越來(lái)越繁瑣带射,當(dāng)今越來(lái)越多的網(wǎng)站已經(jīng)從網(wǎng)頁(yè)模式進(jìn)化到了 Webapp 模式。它們運(yùn)行在現(xiàn)代的高級(jí)瀏覽器里循狰,使用 HTML5庸诱、 CSS3、 ES6 等更新的技術(shù)來(lái)開(kāi)發(fā)豐富的功能晤揣,網(wǎng)頁(yè)已經(jīng)不僅僅是完成瀏覽的基本需求,并且Webapp通常是一個(gè)單頁(yè)面應(yīng)用(SPA)朱灿,每一個(gè)視圖通過(guò)異步的方式加載昧识,這導(dǎo)致頁(yè)面初始化和使用過(guò)程中會(huì)加載越來(lái)越多的 JavaScript 代碼,這給前端開(kāi)發(fā)的流程和資源組織帶來(lái)了巨大的挑戰(zhàn)盗扒。

前端開(kāi)發(fā)和其他開(kāi)發(fā)工作的主要區(qū)別跪楞,首先是前端是基于多語(yǔ)言缀去、多層次的編碼和組織工作,其次前端產(chǎn)品的交付是基于瀏覽器甸祭,這些資源是通過(guò)增量加載的方式運(yùn)行到瀏覽器端缕碎,如何在開(kāi)發(fā)環(huán)境組織好這些碎片化的代碼和資源,并且保證他們?cè)跒g覽器端快速池户、優(yōu)雅的加載和更新咏雌,就需要一個(gè)模塊化系統(tǒng),這個(gè)理想中的模塊化系統(tǒng)是前端工程師多年來(lái)一直探索的難題校焦。

webpack2.x 中文文檔
++++++++++++++2017.8.25++++++++++++++

本文需要有一定的GulpWebpack的基本概念赊抖,對(duì)Gulp和Webpack的使用有一定的了解。
同時(shí)還需要對(duì)npm或者cnpm有一定的的了解寨典,對(duì)ComonJS氛雪、AMD規(guī)范有一定的的了解。

Gulp

Gulp就是為了規(guī)范前端開(kāi)發(fā)流程耸成,實(shí)現(xiàn)前后端分離报亩、模塊化開(kāi)發(fā)、版本控制井氢、文件合并與壓縮弦追、mock數(shù)據(jù)等功能的一個(gè)前端自動(dòng)化構(gòu)建工具。說(shuō)的形象點(diǎn)毙沾,“Gulp就像是一個(gè)產(chǎn)品的流水線骗卜,整個(gè)產(chǎn)品從無(wú)到有,都要受流水線的控制左胞,在流水線上我們可以對(duì)產(chǎn)品進(jìn)行管理坏为◎炯罚”

另外,Gulp是通過(guò)task對(duì)整個(gè)開(kāi)發(fā)過(guò)程進(jìn)行構(gòu)建。

Webpack

Webpack 是當(dāng)下最熱門的前端資源模塊化管理和打包工具菇肃。它可以將許多松散的模塊按照依賴和規(guī)則打包成符合生產(chǎn)環(huán)境部署的前端資源。還可以將按需加載的模塊進(jìn)行代碼分隔苏遥,等到實(shí)際需要的時(shí)候再異步加載氓栈。通過(guò) loader的轉(zhuǎn)換,任何形式的資源都可以視作模塊拐云,比如 CommonJs 模塊罢猪、AMD 模塊、ES6 模塊叉瘩、CSS膳帕、圖片、JSON薇缅、Coffeescript危彩、LESS 等攒磨。

Gulp和Webpack功能實(shí)現(xiàn)對(duì)比

簡(jiǎn)單介紹了一下Gulp和Webpack的概念性的問(wèn)題和大環(huán)境,接下來(lái)進(jìn)入本文的主題汤徽,對(duì)比一下Gulp和Webpack的優(yōu)缺點(diǎn)娩缰。將從基本概念、啟動(dòng)本地Server谒府、sass/less預(yù)編譯拼坎、模塊化開(kāi)發(fā)、文件合并與壓縮狱掂、mock數(shù)據(jù)演痒、版本控制、組件控制八個(gè)方面對(duì)Gulp和Webpack進(jìn)行對(duì)比趋惨。

基本概念

首先從概念上鸟顺,我們可以清楚的看出,Gulp和Webpack的側(cè)重點(diǎn)是不同的器虾。

Gulp側(cè)重于前端開(kāi)發(fā)的整個(gè)過(guò)程的控制管理(像是流水線)讯嫂,我們可以通過(guò)給gulp配置不通的task(通過(guò)Gulp中的gulp.task()方法配置,比如啟動(dòng)server兆沙、sass/less預(yù)編譯欧芽、文件的合并壓縮等等)來(lái)讓gulp實(shí)現(xiàn)不同的功能,從而構(gòu)建整個(gè)前端開(kāi)發(fā)流程葛圃。

Webpack有人也稱之為模塊打包機(jī)千扔,由此也可以看出Webpack更側(cè)重于模塊打包,當(dāng)然我們可以把開(kāi)發(fā)中的所有資源(圖片库正、js文件曲楚、css文件等)都可以看成模塊,最初Webpack本身就是為前端JS代碼打包而設(shè)計(jì)的褥符,后來(lái)被擴(kuò)展到其他資源的打包處理龙誊。Webpack是通過(guò)loader(加載器)和plugins(插件)對(duì)資源進(jìn)行處理的。

另外我們知道Gulp是對(duì)整個(gè)過(guò)程進(jìn)行控制喷楣,所以在其配置文件(gulpfile.js)中配置的每一個(gè)task對(duì)項(xiàng)目中該task配置路徑下所有的資源都可以管理趟大。
比如,對(duì)sass文件進(jìn)行預(yù)編譯的task可以對(duì)其配置路徑下的所有sass文件進(jìn)行預(yù)編譯處理:

    gulp.task('sass',function(){
        gulp.src('src/styles/*.scss')
        .pipe(sass().on('error',sass.logError))
        .pipe(gulp.dest('./build/prd/styles/'));//編譯后的輸出路徑
    });

上面這個(gè)task可以對(duì)'src/styles/*.scss'目錄下的所有以.scss結(jié)尾的文件進(jìn)行預(yù)處理铣焊。

Webpack則不是這樣管理資源的逊朽,它是根據(jù)模塊的依賴關(guān)系進(jìn)行靜態(tài)分析,然后將這些模塊按照指定的規(guī)則生成對(duì)應(yīng)的靜態(tài)資源(如下圖)曲伊。

webpack通過(guò)依賴關(guān)系靜態(tài)分析

通俗的說(shuō)惋耙,Webpack就是需要通過(guò)其配置文件(webpack.config.js)中entry配置的一個(gè)入口文件(JS文件),如下圖

  entry: {
      app:__dirname + "/src/scripts/app.js",
}

然后Webpack進(jìn)入該app.js文件進(jìn)行解析,app.js文件如下圖:

   //引入scss文件
   import '../style/app.scss';
    
   //引入依賴模塊
   var greeter = require('./Greeter.js');
   document.getElementById('root').appendChild(greeter());

解析過(guò)程中,發(fā)現(xiàn)一個(gè)app.scss文件绽榛,然后根據(jù)webpack.config.js配置文件中的module.loaders屬性去查找處理.scss文件的loader進(jìn)行處理,處理app.scss文件過(guò)程中婿屹,如果發(fā)現(xiàn)該文件還有其他依賴文件灭美,則繼續(xù)處理app.scss文件的依賴文件,直至處理完成該“鏈路”上的依賴文件昂利,然后又遇到一個(gè)Greeter.js模塊届腐,于是像之前一樣繼續(xù)去查找對(duì)應(yīng)的loader去處理...
所以,Webpack中對(duì)資源文件的處理是通過(guò)入口文件產(chǎn)生的依賴形成的蜂奸,不會(huì)像Gulp那樣犁苏,配置好路徑后,該路徑下所有規(guī)定的文件都會(huì)受影響扩所。

模塊化開(kāi)發(fā)

所謂的前端模塊化開(kāi)發(fā)围详,我的理解就是,在開(kāi)發(fā)的時(shí)候祖屏,把不通的資源文件按照他的具體用途進(jìn)行分類管理助赞,在使用的時(shí)候利用CommonJS、AMD袁勺、CMD等規(guī)范將這些資源文件引入到當(dāng)前文件中雹食。然后在測(cè)試或者最后上線的時(shí)候,將這些資源文件按照一定的要求進(jìn)行壓縮合并再加上版本控制處理期丰。
可能這樣的理解或者說(shuō)法值得商榷群叶,但是個(gè)人還是覺(jué)得模塊化就是對(duì)內(nèi)容的管理,是為了解耦合钝荡。

首先從Gulp入手街立,看看在項(xiàng)目中,怎樣利用模塊化的思想進(jìn)行開(kāi)發(fā)化撕。下面是一個(gè)gulp項(xiàng)目的目錄結(jié)構(gòu):


gulp項(xiàng)目目錄結(jié)構(gòu)
  Gulp
   |——build:  項(xiàng)目輸出路徑
   |    |——prd:  css几晤、js文件輸出路徑
   |        |——scripts: js文件的輸出路徑
   |        |——styles: css文件的輸出路徑
   |    |——ver: 版本號(hào)相關(guān)文件
   |    |——index.html: 編譯后的index.html
   |——images: 圖片文件夾
   |——mock: mock數(shù)據(jù)文件夾
   |——node_modules: npm包管理文件夾
   |——src: 工作目錄
   |    |——scripts
   |        |——libs: 第三方依賴庫(kù)(jQuery等)
   |        |——tpls: 模板文件
   |        |——utils: 工具類文件夾
   |        |——views: 頁(yè)面自定義js文件
   |        |——app.js: index.html文件的入口js
   |    |——styles:文件和scripts文件夾下基本一致(本例中我引用了第三方框架,目錄更深植阴,不在展示)
   |——gulpfile.js: gulp的配置文件
   |——index.html: 主頁(yè)html文件
   |——package.json: npm包管理配置文件     

在實(shí)際開(kāi)發(fā)過(guò)程中蟹瘾,在src目錄下工作,html掠手、js和css等文件通過(guò)gulp的task配置憾朴,執(zhí)行合并和壓縮后輸出到build目錄下(下面會(huì)詳細(xì)介紹合并壓縮的實(shí)現(xiàn))。在詳細(xì)一點(diǎn)就是:

  1. 創(chuàng)建主頁(yè)html文件
  2. 創(chuàng)建與之對(duì)應(yīng)的app.js入口文件和app.scss入口文件喷鸽。這兩個(gè)文件只通過(guò)CommonJS規(guī)范引入各自views文件中自定義的js(或scss)文件众雷,具體邏輯不寫(xiě)此文件中。
  3. 在views目錄下編寫(xiě)js(或css)文件的邏輯代碼,其中如果多個(gè)文件需要公共邏輯或者工具方法砾省,就可以抽離出來(lái)在util文件夾下創(chuàng)建對(duì)應(yīng)的公共方法鸡岗,然后在views中需要的js(或css)文件中通過(guò)CommonJS規(guī)范引入使用。libs目錄下的第三方庫(kù)或框架也是這個(gè)思想去引用编兄。
  4. scripts目錄下的tpls文件是用來(lái)放置html模板的轩性,引用方式和引用libs相同。

大體介紹了一下我理解的模塊化的思想狠鸳,但是需要指出的是Gulp對(duì)js文件的模塊化工作是通過(guò)Webpack實(shí)現(xiàn)的揣苏,具體來(lái)說(shuō)是通過(guò)安裝gulp-webpack模塊和相關(guān)的loader模塊進(jìn)行js模塊化管理的。具體步驟如下:

  1. 在項(xiàng)目中通過(guò)npm安裝一個(gè)gulp-webpack件舵、vinyl-named卸察、imports-loaderstring-loader模塊(壓縮合并模塊后面再介紹)
   $ npm install gulp-webpack vinyl-named -D
  1. 然后在Gulp的配置文件gulpfile.js中通過(guò)CommonJs規(guī)范引入gulp-webpack 模塊,并進(jìn)行簡(jiǎn)單配置
     //1.引入 gulp-webpack和vinyl-named模塊
    var webpack= require('gulp-webpack');
    var webpack= require('vinyl-named');

     //2.js 模塊化配置
    var jsFiles = [
      './src/scripts/*.js',
    ];
    gulp.task('packjs',function(){
      gulp.src(jsFiles)
      .pipe(uglify().on('error',function(err){
         console.log('\x07',err.lineNumber,err.message);
         return this.end();
       }))
      
      //Webpack 對(duì)js模塊化部分 start
      .pipe(webpack({
          output:{
            filename:'[name].js'
          },
          module:{
              loaders:[{
                test: /\.js$/,
                loader:'imports?define=>false'
              },
              {
                test:/\.string$/,
                loader:'string'
              }
            ]
          }
        }));
        //Webpack 對(duì)js模塊化部分 end
      .pipe(concat('all.js'))
      .pipe(gulp.dest('./build/prd/scripts/'));
  });

對(duì)css文件我們也采用同js文件一樣的模塊化思想铅祸,利用sass進(jìn)行模塊化開(kāi)發(fā)坑质,至于對(duì)scss文件的合并壓縮配置,下面還會(huì)詳細(xì)介紹个少。

接下來(lái)應(yīng)該介紹一下Webpack的模塊化實(shí)現(xiàn)了洪乍,其實(shí)也就沒(méi)什么可以說(shuō)的了,文件目錄和Gulp的基本相同夜焦,只不過(guò)實(shí)現(xiàn)過(guò)程中使用到的插件或者說(shuō)模塊不同壳澳,配置不同而已。另外需要注意的是茫经,Webpack對(duì)于資源文件的模塊化打包處理都是按js文件的處理方式處理的巷波,例如還是上一小節(jié)中,你可能發(fā)現(xiàn)了卸伞,我在app.js入口文件中有這樣一行代碼

  import '../style/app.scss';

你當(dāng)時(shí)可能產(chǎn)生疑問(wèn)抹镊,為什么在js文件中引入scss文件呢?
這是因?yàn)閃ebpack是通過(guò)依賴關(guān)系進(jìn)行文件管理的荤傲,所以垮耳,想要對(duì)樣式文件進(jìn)行模塊化管理則必須與app.js入口文件建立依賴關(guān)系,因此我們將樣式文件的入口app.scss文件引入到了app.js中(其他資源想要被管理遂黍,也需要這樣與app.js入口文件建立依賴關(guān)系)终佛。
但是這樣做很明顯的就是樣式文件通過(guò)app.js入口文件全部都合并壓縮到j(luò)s文件中了,這很顯然不是我們想要的結(jié)果雾家,所以我們需要將樣式文件從js文件中剝離出來(lái)铃彰。

  1. 在項(xiàng)目中通過(guò)npm安裝一個(gè)extract-text-webpack-plugin的模塊
   $ npm install  extract-text-webpack-plugin -D
  1. 然后在Webpack的配置文件webpack.config.js中進(jìn)行簡(jiǎn)單配置
    //1.引入extract-text-webpack-plugin模塊
    var Et = require('extract-text-webpack-plugin');

    module.exports = {
      //source-map調(diào)試
      devtool: 'eval-source-map',
      //webpack入口文件配置
      entry: {
         app:__dirname + "/src/scripts/app.js",
      },
      //webpack出口文件配置
      output: {
          path: __dirname + "/prd/scripts/",//輸出文件路徑配置
          filename: "bundle.js"http://輸出文件名配置
      },
      module:{
          loaders:[
            {
                test: /\.scss$/,
                loader: Et.extract('style','css!sass')//從js中抽離scss文件
            }
          ]
       },
      plugins: [
          new Et('./styles/bundle.css'),//從js中抽離scss文件輸出目錄設(shè)置
      ],
      //本地server配置
      devServer: {
        contentBase:  __dirname + '/prd/',//本地服務(wù)器所加載的頁(yè)面所在的目錄
        port:8089,//本地服務(wù)端口配置
        colors: true,//終端中輸出結(jié)果為彩色
        historyApiFallback: true,//不跳轉(zhuǎn)
        inline: true//實(shí)時(shí)刷新
      }
   }

上面有些配置信息并不完全,下面的小節(jié)中會(huì)逐漸介紹到芯咧。這樣我們就實(shí)現(xiàn)了將css文件從js文件中剝離出來(lái)的目的牙捉。Webpack不但可以對(duì)css文件可以進(jìn)行模塊化管理竹揍,還可以對(duì)圖片進(jìn)行模塊管理,有興趣的可以自己去嘗試一下邪铲。

文件合并與壓縮

上面的模塊化中芬位,我們提到了模塊化其實(shí)很大一部分是在做文件的合并與壓縮操作,所以我們馬上來(lái)看看Gulp和Webpack是怎樣是想文件的合并和壓縮的霜浴。

先來(lái)看看大背景晶衷,由于現(xiàn)在前端越來(lái)越龐大,頁(yè)面文件依賴也越來(lái)越多阴孟,所以對(duì)這些文件進(jìn)行合理的合并和壓縮就志在必得。根據(jù)前面的了解税迷,Webpack應(yīng)該比Gulp更擅長(zhǎng)文件合并和壓縮永丝,畢竟人家被稱為模塊打包機(jī)嗎。
結(jié)論是正確的箭养,Gulp可以對(duì)css文件以及js文件進(jìn)行合并壓縮處理慕嚷,而Webpack可以實(shí)現(xiàn)對(duì)css文件,js文件毕泌,html文件等進(jìn)行合并壓縮和圖片的壓縮喝检,還可以對(duì)js文件進(jìn)行編譯(如es6-->es5,react jsx)等等撼泛,這些都是通過(guò)Webpack的loader實(shí)現(xiàn)的挠说,當(dāng)然這些也可以加入到Gulp中,畢竟Gulp把Webpack當(dāng)做一個(gè)模塊愿题,通過(guò)gulp-webpack都引入了损俭。

Gulp合并壓縮文件

css的壓縮

要想實(shí)現(xiàn)Gulp對(duì)css文件的壓縮只需要安裝一個(gè)gulp-minify-css模塊即可。

  1. 在項(xiàng)目中通過(guò)npm安裝一個(gè)gulp-minify-css的模塊
   $ npm install gulp-minify-css -D
  1. 然后在Gulp的配置文件gulpfile.js中通過(guò)CommonJs規(guī)范引入gulp-minify-css模塊潘酗,并進(jìn)行簡(jiǎn)單配置
     //1.引入 gulp-minify-css模塊
    var minifyCSS = require('gulp-minify-css');

    //2.css 預(yù)處理
    var cssFiles = [
      './src/styles/usage/page/index.scss'
    ]
    gulp.task('sass',function(){
        gulp.src(cssFiles)
        .pipe(sass().on('error',sass.logError))
        .pipe(minifyCSS())//執(zhí)行壓縮處理在一行
        .pipe(gulp.dest('./build/prd/styles/'));
    });

這樣一個(gè)簡(jiǎn)單的css壓縮就實(shí)現(xiàn)了杆兵。

js合并壓縮

要想實(shí)現(xiàn)Gulp對(duì)js文件的合并壓縮需要安裝一個(gè)gulp-uglifygulp-concat兩個(gè)模塊,前者是用于壓縮的模塊仔夺,后者是一個(gè)合并的模塊琐脏。

  1. 在項(xiàng)目中通過(guò)npm安裝gulp-uglifygulp-concat模塊
   $ npm install gulp-uglify gulp-concat -D
  1. 然后在Gulp的配置文件gulpfile.js中通過(guò)CommonJs規(guī)范引入gulp-uglifygulp-concat模塊,并進(jìn)行簡(jiǎn)單配置
   //1.引入**gulp-uglify**和**gulp-concat**模塊
   var uglify = require('gulp-uglify');
   var concat = require('gulp-concat');

  //js 合并壓縮
   var jsFiles = [
      './src/scripts/*.js',
    ];
    gulp.task('packjs',function(){
      gulp.src(jsFiles)
      //js文件的壓縮
      .pipe(uglify().on('error',function(err){
         console.log('\x07',err.lineNumber,err.message);
         return this.end();
       }))
      .pipe(webpack({
          output:{
            filename:'[name].js'
          },
          module:{
              loaders:[{
                test: /\.js$/,
                loader:'imports?define=>false'
              },
              {
                test:/\.string$/,
                loader:'string'
              }
            ]
          }
        }));
      //js文件的合并
      .pipe(concat('all.js'))
      .pipe(gulp.dest('./build/prd/scripts/'));
  });

js的文件合并壓縮也完成了缸兔。我們?cè)賮?lái)看一下Webpack的合并壓縮日裙。

Webpack的合并壓縮

壓縮js和css

針對(duì)js和css文件的壓縮,Webpack已經(jīng)內(nèi)嵌了uglifyJS來(lái)完成對(duì)js與css的壓縮混淆灶体,無(wú)需引用額外的插件阅签。我們只需要在Webpack配置文件中的plugins屬性中做如下配置:

  plugins: [
    new webpack.optimize.UglifyJsPlugin({ //壓縮代碼
      compress: {
        warnings: false
      },
      except: ['$super', '$', 'exports', 'require'] //排除關(guān)鍵字
  })
]

需要注意的是:壓縮的時(shí)候需要排除一些關(guān)鍵字,不能混淆蝎抽,比如$或者require政钟,如果混淆的話就會(huì)影響到代碼的正常運(yùn)行路克。

html的壓縮

想要對(duì)html進(jìn)行壓縮,同樣也是需要配置Webpack的配置文件养交,并且需要下載兩個(gè)插件HtmlWebpackPluginhtml-minifier插件:
1.在項(xiàng)目中通過(guò)npm安裝HtmlWebpackPluginhtml-minifier模塊

  $ npm install HtmlWebpackPlugin -D
  $ npm install html-minifier -D
```
2.然后在Webpack的配置文件webpack.config.js進(jìn)行如下配置:
```js
  plugins: [
     new HtmlWebpackPlugin({ //根據(jù)模板插入css/js等生成最終HTML
         favicon:'./src/img/favicon.ico', //favicon路徑
         filename:'/view/index.html', //生成的html存放路徑
         template:'./src/view/index.html', //html模板路徑
         inject:true, //允許插件修改哪些內(nèi)容精算,包括head與body
        hash:true, //為靜態(tài)資源生成hash值
        minify:{ //壓縮HTML文件
            removeComments:true, //移除HTML中的注釋
             collapseWhitespace:true //刪除空白符與換行符
         }
    })
   ]
```
HtmlWebpackPlugin插件在生成HTML時(shí)調(diào)用了 html-minifier 插件來(lái)完成對(duì)HTML的壓縮,這里我們使用兩個(gè)配置完成來(lái)移除HTML中的注釋以及空白符達(dá)到壓縮的效果碎连。

## sass/less預(yù)編譯
我們?cè)賮?lái)看看sass/less預(yù)編譯灰羽,其實(shí)就sass/less的預(yù)編譯來(lái)說(shuō),兩者區(qū)別不是很大鱼辙。Gulp是通過(guò)``gulp-sass``廉嚼、``gulp-less``模塊進(jìn)行預(yù)處理;而Webpack是通過(guò)``scss-loader``倒戏、``less-loader``加載器(loader)進(jìn)行預(yù)處理怠噪。我們還是分別來(lái)看一下兩者對(duì)此的實(shí)現(xiàn)。

### Gulp預(yù)編譯sass/less
以sass為例子:
1. 在項(xiàng)目中通過(guò)npm安裝一個(gè)**gulp-sass**的模塊
 ```js
    $ npm install gulp-sass -D
```
2. 然后在Gulp的配置文件gulpfile.js中通過(guò)CommonJs規(guī)范引入gulp-sass模塊杜跷,并進(jìn)行簡(jiǎn)單配置
```js
     //1.引入 gulp-sass模塊
    var sass= require('gulp-sass');

    //2.css 預(yù)處理
    var cssFiles = [
      './src/styles/usage/page/**/*'
      //./src/styles/usage/page目錄下的所有文件
    ];
    gulp.task('sass',function(){
        gulp.src(cssFiles)
        .pipe(sass().on('error',sass.logError))
        .pipe(minifyCSS())
        .pipe(gulp.dest('./build/prd/styles/'));//編譯后的輸出路徑
    });
  
    //3.對(duì)sass文件的修改添加監(jiān)聽(tīng)事件
    gulp.task('watch',function(){
       gulp.watch('./src/styles/**/*',['sass']);
    });

    gulp.task('default',['watch','webserver'],function(){
        console.log('所有任務(wù)隊(duì)列執(zhí)行完畢');
    });
```
這樣傍念,一個(gè)簡(jiǎn)單的sass預(yù)處理的task就配置完成了,然后我們還將該task加到gulp.watch()上實(shí)現(xiàn)了自動(dòng)編譯(即修改sass文件后保存葛闷,則立即執(zhí)行sass預(yù)處理)憋槐,配合Gulp啟動(dòng)的server則可以實(shí)現(xiàn)sass文件修改保存即可在瀏覽器中查看效果的目的,下一小節(jié)會(huì)介紹啟動(dòng)本地server淑趾。

### Webpack預(yù)編譯sass/less
同樣以sass為例子:
1. 在項(xiàng)目中通過(guò)npm安裝一個(gè)**sass-loader**和**node-sass**模塊阳仔,前者是用來(lái)加載sass相關(guān)文件的,后者是用來(lái)編譯sass文件的治笨。另外還需要安裝另外兩個(gè)模塊**css-loader**和**style-loader**驳概,前者是用來(lái)加載css相關(guān)文件的,后者是用來(lái)將css樣式裝填到html中的內(nèi)聯(lián)樣式旷赖。
 ```js
    $ npm install sass-loader node-sass css-loader style-sass -D
```
2. 然后在Webpack的配置文件webpack.config.js中進(jìn)行簡(jiǎn)單配置
```js
     module:{
          loaders:[
          {
              test: /\.css$/,//匹配以.css結(jié)尾的文件顺又,如果你項(xiàng)目不需要刻意不配置
              loader: 'style!css'//這里順序必須這樣  
          },
          {
              test: /\.scss$/,//匹配以.scss結(jié)尾的文件
              loader: 'style!css!sass'
          }
        ]
    }
```
前面提到過(guò),Webpack是通過(guò)文件的依賴關(guān)系進(jìn)行加載分析的等孵,所以當(dāng)程序從主入口(js文件)進(jìn)入后稚照,在依賴的資源文件中發(fā)現(xiàn)有sass文件后,就會(huì)利用我們配置的**sass-loader**去加載俯萌,然后用**node-sass**去解析編譯成普通的css語(yǔ)法的樣式文件果录,在然后就是利用**style-loader**將樣式以內(nèi)聯(lián)樣式的形式配置到html中(這里有一個(gè)問(wèn)題,就是css-loader有什么用?我也沒(méi)搞明白咐熙,但是不添加會(huì)報(bào)錯(cuò)弱恒,有知道的可以留言交流一下)。這樣Webpack就完成了sass的預(yù)處理棋恼。

## 啟動(dòng)server
我們都知道在前端開(kāi)發(fā)中返弹,ajax請(qǐng)求是需要啟動(dòng)一個(gè)server的锈玉。特別是在前后端分離思想中,前端開(kāi)發(fā)不再像以前一樣過(guò)分依賴于后端開(kāi)發(fā)义起,以前的那種前端測(cè)試ajax請(qǐng)求需要裝個(gè)tomcat或者其它服務(wù)器來(lái)啟動(dòng)server的現(xiàn)象已經(jīng)成為過(guò)去式拉背,現(xiàn)在我們可以使用像Gulp這類前端自動(dòng)構(gòu)建工具啟動(dòng)一個(gè)本地server進(jìn)行測(cè)試,再也不收后端程序員鉗制了(開(kāi)個(gè)玩笑默终,和后端好好溝通才能讓前端開(kāi)發(fā)更方便)椅棺。那么,我們來(lái)分別看一下Gulp和Webpack是怎樣實(shí)現(xiàn)這個(gè)功能的齐蔽。

### Gulp啟動(dòng)server
在Gulp中想要啟動(dòng)一個(gè)本地serve两疚,只需要以下幾步:
1. 在項(xiàng)目中通過(guò)npm安裝一個(gè)**gulp-webserver**的模塊
 ```js
    $ npm install gulp-webserver -D
```
2. 然后在Gulp的配置文件gulpfile.js中通過(guò)CommonJs規(guī)范引入gulp-webserver模塊,并進(jìn)行簡(jiǎn)單配置
```js
   //1.引入 gulp-webserver 模塊
  var webserver = require('gulp-webserver');

  //2.配置server task
  gulp.task('webserver',function(){
    gulp.src('./')
    .pipe(webserver({
        host:'localhost',
        port:80,
        //瀏覽器自動(dòng)刷新
        livereload:true,
        //顯示文件目錄
        directoryListing:{
          enable: true,
          path:'./'
        },
      }));
  });

  //3.配置默認(rèn)task
  gulp.task('default',['webserver'],function(){
      console.log('啟動(dòng)任務(wù)隊(duì)列執(zhí)行完畢');
  })
```
3. 在命令行中啟動(dòng)server
```js
  $ gulp
```
啟動(dòng)成功:
![gulp cli 啟動(dòng)成功](http://upload-images.jianshu.io/upload_images/3333422-4e64d02bacb680de.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

4. 在瀏覽器地址欄中輸入**localhost**打開(kāi)頁(yè)面驗(yàn)證含滴。

經(jīng)過(guò)以上這三步鬼雀,我們就在Gulp中啟動(dòng)了一個(gè)server了。在Gulp中啟動(dòng)本地服務(wù)有一個(gè)很方便的配置蛙吏,就是``livereload:true``屬性的設(shè)置,設(shè)置后瀏覽器會(huì)根據(jù)你項(xiàng)目中資源的變化自動(dòng)刷新瀏覽器(如果你的chrome瀏覽器設(shè)置該屬性后在你修改文件并保存時(shí)仍沒(méi)有自動(dòng)刷新鞋吉,可能是你的chrome瀏覽器不支持鸦做,可以chrome擴(kuò)展程序中搜索并安裝LiveReload插件),比如:
我的gulp測(cè)試目錄結(jié)構(gòu):
![gulp測(cè)試目錄結(jié)構(gòu)](http://upload-images.jianshu.io/upload_images/3333422-58ae1decb26ea33f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
index.html
```html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>

      <script src="/src/scripts/app.js"></script>
    </body>
  </html>
```
我在app.js文件中輸入以下內(nèi)容谓着,然后保存泼诱。
```js
    console.log('gulp-webserver livereload');
```
瀏覽器中控制臺(tái)上會(huì)立刻打印出一下信息:
![gulp測(cè)試目錄結(jié)構(gòu)](http://upload-images.jianshu.io/upload_images/3333422-578319e411ede2e6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
說(shuō)明瀏覽器自動(dòng)刷新工程,這個(gè)小功能在我們開(kāi)發(fā)中屢試不爽赊锚。但是治筒,這個(gè)功能是需要結(jié)合上一小節(jié)中的``gulp.watch()``實(shí)時(shí)監(jiān)控文件變化,然后執(zhí)行合并壓縮和sass/less編譯等操作后舷蒲,瀏覽器再刷新時(shí)才能保證是我們修改后的內(nèi)容耸袜。所以,``livereload:true``屬性只是監(jiān)控到我們修改文件后刷新瀏覽器重新請(qǐng)求文件牲平,如果我們不重新編譯修改后的文件堤框,瀏覽器獲取到的還是原文件,并不會(huì)展示變化纵柿。

### Webpack啟動(dòng)server
在Webpack中也可以通過(guò)插件的形式安裝一個(gè)**webpack-dev-server**來(lái)實(shí)現(xiàn)達(dá)到啟動(dòng)本地server的目的蜈抓,具體步驟如下:
1. 在項(xiàng)目中通過(guò)npm安裝一個(gè)**webpack-dev-server**的模塊
 ```js
    $ npm install  -g webpack-dev-server -D
```
2. 然后在Webpack的配置文件webpack.config.js中進(jìn)行簡(jiǎn)單配置
```js
    module.exports = {
      devtool: 'eval-source-map',
      //webpack入口文件配置
      entry: {
         app:__dirname + "/src/scripts/app.js",
      },
      //webpack出口文件配置
      output: {
          path: __dirname + "/prd/scripts/",//輸出文件路徑配置
          filename: "bundle.js"http://輸出文件名配置
      },
      //本地server配置
      devServer: {
        contentBase:  __dirname,//本地服務(wù)器所加載的頁(yè)面所在的目錄
        port:8089,//本地服務(wù)端口配置
        colors: true,//終端中輸出結(jié)果為彩色
        historyApiFallback: true,//不跳轉(zhuǎn)
        inline: true//實(shí)時(shí)刷新
      }
   }
```
3. 在命令行中啟動(dòng)server
```js
  $ webpack-dev-server
```
然后你就會(huì)看見(jiàn)命令行輸出內(nèi)容很多,只要看看保證沒(méi)有Error就說(shuō)明成功了昂儒。
4. 在瀏覽器地址欄中輸入**localhost:8089**測(cè)試一下沟使。

Webpack的啟動(dòng)本地服務(wù)也順利實(shí)現(xiàn)了,是不是也想實(shí)現(xiàn)像Gulp一樣瀏覽器自動(dòng)刷新呀渊跋?那Webpack能不能實(shí)現(xiàn)呢腊嗡?答案是肯定的着倾,Webpack官方提供了一個(gè)輔助開(kāi)發(fā)工具,它可以自動(dòng)監(jiān)控項(xiàng)目下的文件叽唱,一旦有修改保存操作屈呕,開(kāi)發(fā)服務(wù)器就會(huì)自動(dòng)運(yùn)行Webpack 打包命令,幫我們自動(dòng)將開(kāi)發(fā)的代碼重新打包棺亭。而且虎眨,如果需要的話,還能自動(dòng)刷新瀏覽器镶摘,重新加載資源嗽桩。理論上好像是這樣,但是實(shí)現(xiàn)好像有不少限制凄敢,比如碌冶,HTML文件的自動(dòng)刷新問(wèn)題(html-webpack-plugin插件使用老是報(bào)錯(cuò)),當(dāng)本地server啟動(dòng)在非output.path路徑之外時(shí)則不能自動(dòng)刷新等問(wèn)題涝缝,等我再學(xué)習(xí)學(xué)習(xí)再說(shuō)扑庞,或者有知道的可以留言討論。

而這個(gè)輔助工具就是**webpack-dev-server**拒逮,它主要提供兩個(gè)功能:一是為靜態(tài)文件提供server服務(wù)罐氨,二是自動(dòng)刷新和熱替換(HMR)。所以想實(shí)現(xiàn)如Gulp一樣的功能也是可以的滩援,只需要在``$ webpack-dev-server``后面添加``--inline --hot``即可栅隐。需要注意的是``--inline``是自動(dòng)刷新,同時(shí)在第二部中的devServer屬性中有一個(gè)**inline:true**需要配置玩徊;而``--hot``是熱替換([詳細(xì)了解熱替換](https://segmentfault.com/a/1190000003872635)租悄、[了解webpack-dev-server](https://segmentfault.com/a/1190000006964335)、[webpack-dev-server](http://www.07net01.com/2015/12/1004731.html))恩袱。

通過(guò)對(duì)比來(lái)看泣棋,好像Webpack的**webpack-dev-server**比Gulp的**gulp-server**功能要強(qiáng)一些。因?yàn)橥ㄟ^(guò)上面可以看出**webpack-dev-server**有兩個(gè)大功能:一是為靜態(tài)文件提供server服務(wù)憎蛤,二是自動(dòng)刷新(**自動(dòng)刷新其實(shí)需要兩步:1.修改文件后外傅,文件自動(dòng)編譯{包括合并壓縮或者語(yǔ)法編譯等},2.刷新瀏覽器請(qǐng)求最新編譯后的文件**)和熱替換(HMR)俩檬;而**gulp-server**雖然提供了啟動(dòng)本地server的能力和僅自動(dòng)刷新瀏覽器的能力萎胰,缺少一個(gè)文件自動(dòng)編譯的能力,這需要借助其他模塊實(shí)現(xiàn)(上一小節(jié)已介紹棚辽,結(jié)合gulp.watch()實(shí)時(shí)監(jiān)控文件變化技竟,并編譯)。

另外需要注意的是屈藐,實(shí)際開(kāi)發(fā)中發(fā)現(xiàn)**webpack-dev-server**實(shí)現(xiàn)自動(dòng)刷新的時(shí)候榔组,并沒(méi)有執(zhí)行自動(dòng)編譯熙尉,只是將修改的內(nèi)容合并壓縮等處理后發(fā)送給了瀏覽器,并造成了已經(jīng)編譯的現(xiàn)象搓扯,但是通過(guò)build/prd/scripts目錄下的bundle.js(合并壓縮后的輸出文件)文件检痰,可以發(fā)現(xiàn)內(nèi)容并沒(méi)有編譯(對(duì)于Webpack還是不熟悉,好多問(wèn)題等待解決)锨推。

## mock數(shù)據(jù)
在現(xiàn)在前后端分離的思想中铅歼,前端和后端耦合度越來(lái)越小煌张,現(xiàn)在唯一需要前后端密切聯(lián)系的就是借口的定義和數(shù)據(jù)格式的確定玉雾。一般在項(xiàng)目開(kāi)始前,前端和后端將項(xiàng)目中的接口和數(shù)據(jù)格式全部確定下來(lái)(當(dāng)然項(xiàng)目需求變更就需要臨時(shí)確立這些共識(shí)了)蜘澜,然后前端就可以自己mock數(shù)據(jù)了沾鳄。

### Gulp實(shí)現(xiàn)mock數(shù)據(jù)
Gulp中對(duì)mock數(shù)據(jù)的實(shí)現(xiàn)使通過(guò)NodeJS內(nèi)置的fs模塊和url模塊實(shí)現(xiàn)的慨飘,因?yàn)镚ulp本身就是基于NodeJS的。還記得第一小節(jié)“模塊化開(kāi)發(fā)”中目錄結(jié)構(gòu)中的那個(gè)mock目錄嗎译荞?那就是用來(lái)儲(chǔ)存``.json``文件的mock數(shù)據(jù)目錄瓤的。

1. 配置Gulp的gulpfile.js文件

```js
  //1.引入 fs 和 url 模塊
  var fs = require('fs');
  var url = require('url');

  //2.重新配置一下上一小節(jié)的server
  gulp.task('webserver',function(){
     gulp.src('./')
     .pipe(webserver({
        host:'localhost',
        port:80,
        livereload:true,
        directoryListing:{
          enable: true,
          path:'./'
      },

      //mock數(shù)據(jù)配置
      middleware:function(req,res,next){
        var urlObj = url.parse(req.url,true);
        switch (urlObj.pathname) {
            case '/pro/getPro':
              res.setHeader('Content-Type','application/json;charaset=utf-8');
              fs.readFile('./mock/list.json',function(err,data){
                //上面list.json路徑使用相對(duì)路徑,絕對(duì)路徑前臺(tái)無(wú)法獲取數(shù)據(jù)
                res.end(data);
              });
              return;
            case '/web/getUser':
                //....
              return;
          }
          next();
        }
      }));
  });
```
具體來(lái)說(shuō)堤瘤,就是通過(guò)NodeJS攔截http請(qǐng)求,根據(jù)請(qǐng)求URL來(lái)模擬后端做出處理后返回不同的數(shù)據(jù)浆熔。

### Webpack實(shí)現(xiàn)mock數(shù)據(jù)
Webpack并沒(méi)有自帶實(shí)現(xiàn)mock數(shù)據(jù)的功能,畢竟Webpack人家本來(lái)就是用來(lái)打包的桥帆,人家并不是流程控制的,我們可以和Gulp對(duì)比實(shí)現(xiàn)其他功能医增,是因?yàn)槠渌δ芏际窃诖虬^(guò)程中實(shí)現(xiàn)的(啟動(dòng)server除外)。雖然Webpack沒(méi)有自帶mock數(shù)據(jù)的功能老虫,但是我們可以借助一些其他手段來(lái)實(shí)現(xiàn)叶骨,比如說(shuō)**[json-server](https://github.com/typicode/json-server)**,它的實(shí)現(xiàn)原理就是祈匙,啟動(dòng)一個(gè)本地3000端口作為mock數(shù)據(jù)的端口忽刽,然后我們?cè)赪ebpack中配置一個(gè)代理,讓所有請(qǐng)求代理到3000端口上去跪帝,就可以獲取到數(shù)據(jù)了。
實(shí)現(xiàn)步驟:
1. 在項(xiàng)目中通過(guò)npm安裝一個(gè)**json-server**的模塊
 ```js
    $ npm install  -g json-server
```
可以將在任何一個(gè)目錄下啟動(dòng)json-server,為了統(tǒng)一些阅,我們建議直接在項(xiàng)目根目錄啟動(dòng)伞剑,將mock數(shù)據(jù)也放在項(xiàng)目根目錄下。
2. 啟動(dòng)json-server
```js
  $ json-server
```
json-server是一個(gè)非常強(qiáng)大的工具市埋,感興趣的可以自行g(shù)oogle黎泣。
3. 然后在Webpack的配置文件webpack.config.js中進(jìn)行簡(jiǎn)單配置
```js
    module.exports = {
      devtool: 'eval-source-map',
      entry: {
       app:__dirname + "/src/scripts/app.js",
      },
      output: {
          path: __dirname + "/prd/scripts/",
          filename: "bundle.js"
      },
      //本地server配置
      devServer: {
        contentBase:  __dirname,
        port:8089,
        colors: true,
        historyApiFallback: true,
        inline: true,
        //重點(diǎn)在這里
        proxy:{
          '/http://chping.website/*':{//為正則表達(dá)式恕刘,匹配以http://chping.website開(kāi)頭的url
            target: 'http://localhost:3000',//代理到本地3000端口
            pathRewrite:{
              '^/http://chping.website':''//將http://chping.website替換為空字符串
            }
          }
        }
      }
   }
```
說(shuō)明:
配置項(xiàng)``'^/http://chping.website':''//將http://chping.website替換為空字符串``的目的,舉例說(shuō)明:
假設(shè)我們項(xiàng)目中訪問(wèn)的是``http://chping.website/userlist``去獲取用戶列表抒倚,經(jīng)過(guò)此配置項(xiàng)后褐着,url為``http://localhost:3000/userlist``,否則為``http://localhost:3000/http://chping.website/userlist/userlist``。
4. 在命令行中重新啟動(dòng)server
```js
  $ webpack-dev-server
```

## 版本控制
對(duì)于版本控制托呕,我們?cè)陂_(kāi)發(fā)過(guò)程中含蓉,也是一個(gè)使用比較頻繁的功能,特別是開(kāi)發(fā)團(tuán)隊(duì)比較大的時(shí)候镣陕,這個(gè)功能就顯得更加重要了谴餐。那么Gulp和Webpack是具體怎樣實(shí)現(xiàn)的呢?

### Gulp實(shí)現(xiàn)版本控制
1. 在項(xiàng)目中通過(guò)npm安裝**gulp-rev**和**gulp-rev-collector**模塊呆抑,前者用于生成文件的MD5碼文件和按MD5碼命名的資源文件岂嗓,后者是利用MD5碼,對(duì)文件名進(jìn)行替換鹊碍。
 ```js
    $ npm install  gulp-rev gulp-rev-collector -D
```
2. 然后在Gulp的配置文件gulpfile.js中進(jìn)行簡(jiǎn)單配置
```js
    //1.引入連個(gè)模塊
    var rev = require('gulp-rev');
    var revCollector = require('gulp-rev-collector');
    // 2.版本號(hào)控制
    gulp.task('ver',function(){
      gulp.src(cssFiles)
      .pipe(rev())//產(chǎn)生MD5碼
      .pipe(gulp.dest('./build/prd/styles/'))//重命名文件
      .pipe(rev.manifest())//產(chǎn)生版本信息的json文件
      .pipe(gulp.dest('./build/ver/styles/'));
    gulp.src(jsFiles)
    .pipe(rev())
    .pipe(gulp.dest('./build/prd/scripts/'))
    .pipe(rev.manifest())
    .pipe(gulp.dest('./build/ver/scripts/'));
   })
   //動(dòng)態(tài)修改html中對(duì)css和js文件的修改
   gulp.task('html',function(){
    gulp.src(['./build/ver/**/*','./build/*.html'])
    .pipe(revCollector())
    .pipe(gulp.dest('./build/'));
  })
```

Gulp實(shí)現(xiàn)版本控制很方便厌殉,將這兩個(gè)task加入gulp.watch()中,即可實(shí)現(xiàn)修改保存文件實(shí)時(shí)自動(dòng)修改版本的功能侈咕。

### Webpack實(shí)現(xiàn)版本控制
Webpack中需要版本控制的有css公罕、js文件,不過(guò)Webpack的版本控制只實(shí)現(xiàn)了將css耀销、js文件添加hash值方式命名的文件方式楼眷,修改引用路徑中的文件名需手動(dòng)實(shí)現(xiàn)。
不過(guò)實(shí)現(xiàn)確實(shí)很簡(jiǎn)單熊尉,只需要將webpack.config.js配置文件中的output.filename和plugins中的輸出文件名稱修改一下即可罐柳。
```js
  module.exports = {
      devtool: 'eval-source-map',
      entry: {
         app:__dirname + "/src/scripts/app.js",
      },
      output: {
          path: __dirname + "/prd/scripts/",
          filename: "[name]-[hash].js"http://修改輸出文件名
      },
      plugins: [
          new Et('./styles/[name]-[hash].css'),//修改輸出文件名
      ]
   }
```
這樣就解決了。

## 組件控制
組件控制原本應(yīng)該放在模塊化小節(jié)或者前后小節(jié)狰住,但是由于實(shí)在不知道該怎樣比較张吉,其實(shí)也沒(méi)啥可比較的,就放在最后了催植。
Gulp和Webpack對(duì)各自組件的管理都是使用的npm進(jìn)行的組件管理肮蛹,想了解更多npm組件的管理的可自行百度,或者看看這篇文章入個(gè)門[《npm介紹》](http://chping.website/2016/09/12/npm/)创南。

## 總結(jié)
通過(guò)以上八個(gè)方面的功能對(duì)比伦忠,Gulp和Webpack基本都能滿足前端自動(dòng)化構(gòu)建工具的任務(wù),但是還是看出兩個(gè)工具的側(cè)重點(diǎn)是不通的稿辙,Gulp側(cè)重整個(gè)過(guò)程的控制缓苛,Webpack在模塊打包方面有特別出眾。所以,Gulp + Webpack 組合使用可能更方便未桥。

很長(zhǎng)的一篇總結(jié)文章笔刹,前前后后花了兩天時(shí)間終于寫(xiě)完了,還有很多測(cè)試沒(méi)做冬耿,并且還有很多疑問(wèn)沒(méi)解決舌菜。慢慢學(xué)習(xí),慢慢在補(bǔ)充修改吧亦镶。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末日月,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子缤骨,更是在濱河造成了極大的恐慌爱咬,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件绊起,死亡現(xiàn)場(chǎng)離奇詭異精拟,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)虱歪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門蜂绎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人笋鄙,你說(shuō)我怎么就攤上這事师枣。” “怎么了萧落?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵践美,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我找岖,道長(zhǎng)拨脉,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任宣增,我火速辦了婚禮,結(jié)果婚禮上矛缨,老公的妹妹穿的比我還像新娘爹脾。我一直安慰自己,他們只是感情好箕昭,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布灵妨。 她就那樣靜靜地躺著,像睡著了一般落竹。 火紅的嫁衣襯著肌膚如雪泌霍。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,036評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音朱转,去河邊找鬼蟹地。 笑死,一個(gè)胖子當(dāng)著我的面吹牛藤为,可吹牛的內(nèi)容都是我干的怪与。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼缅疟,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼分别!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起存淫,我...
    開(kāi)封第一講書(shū)人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤耘斩,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后桅咆,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體括授,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年轧邪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了刽脖。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡忌愚,死狀恐怖曲管,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情硕糊,我是刑警寧澤院水,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站简十,受9級(jí)特大地震影響檬某,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜螟蝙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一恢恼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧胰默,春花似錦场斑、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至奴迅,卻和暖如春青责,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工脖隶, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留扁耐,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓浩村,卻偏偏與公主長(zhǎng)得像做葵,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子心墅,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 在現(xiàn)在的前端開(kāi)發(fā)中酿矢,前后端分離、模塊化開(kāi)發(fā)怎燥、版本控制瘫筐、文件合并與壓縮、mock數(shù)據(jù)等等一些原本后端的思想開(kāi)始...
    Charlot閱讀 5,431評(píng)論 1 32
  • 版權(quán)聲明:本文為博主原創(chuàng)文章之众,未經(jīng)博主允許不得轉(zhuǎn)載。 webpack介紹和使用 一依许、webpack介紹 1棺禾、由來(lái) ...
    it筱竹閱讀 11,028評(píng)論 0 21
  • 無(wú)意中看到zhangwnag大佬分享的webpack教程感覺(jué)受益匪淺,特此分享以備自己日后查看峭跳,也希望更多的人看到...
    小小字符閱讀 8,140評(píng)論 7 35
  • 最近在學(xué)習(xí) Webpack,網(wǎng)上大多數(shù)入門教程都是基于 Webpack 1.x 版本的,我學(xué)習(xí) Webpack 的...
    My_Oh_My閱讀 8,166評(píng)論 40 247
  • 前言 WebPack 是什么膘婶? WebPack 是什么,WebPack 可以看做是模塊打包機(jī):它做的事情是蛀醉,分析你...
    Promise__閱讀 1,121評(píng)論 3 12