進階:構(gòu)建具備版本管理能力的項目

webpack是時下十分流行的編譯和打包工具,它提供一種可擴展的loader的方式,簡單的配置,便可以編譯打包各類型的文件,包括js、css、image、font、html,以及各種預(yù)編譯語言都不在話下。

一、回顧與思考

在上一節(jié)的【入門:十分鐘自動化構(gòu)建】中我們講解了如何用gulp去搭建一個工作流。我們認識到gulp是一個流程管理工具,以單個任務(wù)為基礎(chǔ)單元,組合成為一套完整的工作流,而且gulp還有很多的以gulp-*格式命名的工作模塊,用來處理各種資源文件,如果沒有看過上一節(jié)內(nèi)容的同學(xué),建議先回去看過,再往下閱讀,因為本節(jié)內(nèi)容是跟上一節(jié)的知識點緊密聯(lián)系的。

這一節(jié)我們會講解如何構(gòu)建具備版本管理能力的項目,什么是版本管理能力?不是什么svn或者branch,我們看這樣一個場景來幫助理解:

你用上次搭建的工作流開發(fā)了一個網(wǎng)站,然后上線。
第二天打開發(fā)現(xiàn)有bug,心想尼瑪趕緊趁著老板沒發(fā)現(xiàn)修復(fù)一下。
改完代碼,打包,發(fā)布,一氣呵成,完美。
然而十分鐘以后老板讓你去一趟辦公室,打開頁面跟你說有個bug。
心里一抽,一看!我勒個去,這坑爹的緩存啊。。。

怎么去解決這個緩存?,或者說,怎么保證我上線一個新版本,可以完完全全地替代舊版本?這就是版本管理。

這問題有很多解決方法,包括手動打個戳啊什么的,像src="a.jpg?201608062315",這確實可以解決,但是如果一次更新的東西很多,你壓根改不過來。

gulp能幫我們做這事嗎?可以,麻煩,有興趣的同學(xué)可以自行搜索資料。有沒有簡單點的套路?有的,webpack天然支持這一功能。接下來我們就介紹如何用webpack來搭建這么一套工作流。

二、webpack

webpack的用法,我們簡單介紹一下。跟gulp一樣,webpack也是寫好配置文件才能開始工作。

全局安裝webpack

npm install webpack -g

記得養(yǎng)成好習(xí)慣,也本地安裝一下哦

npm install webpack --save-dev

順帶我們把接下來要用到的幾個loader一起安裝了:

npm install style-loader css-loader sass-loader swig-loader --save-dev

這里的*-loader作用跟gulp-*差不多,就是一些編譯用的模塊。

緊接著我們在根目錄下,新建一個webpack.config.js配置文件,我們直接來看代碼:

var path = require('path')

module.exports = {
  entry: {
    Index: ['./src/js/index.js']
  },
  output: {
    path: path.resolve(__dirname, './dist/static'),
    publicPath: 'static/',
    filename: '[name].js'
  },
  resolve: {
    extensions: ['', '.js', '.scss', '.swig']
  },
  module: {
    loaders: [
      {
        test: /\.css$/,
        loader: 'style!css'
      },
      {
        test: /\.scss$/,
        loader: 'style!css!sass'
      },
      {
        test: /\.swig$/,
        loader: 'swig'
      }
    ]
  }
}

這里大致分為四部分的內(nèi)容:
entry
入口文件,也就是一切工作的起點,你可以將整個web應(yīng)用都最終打包成一個js文件,那你只需要定義一個入口,而如果你希望對多個頁面獨立開來,你需要定義多個入口,最終在不同的頁面引用不同的js。一個entry對應(yīng)生成一個bundle。

output
定義打包輸出的配置:

  • path是打包文件的存放路徑,按上面的配置,意味著我們待會打包的文件是要放在dist/static下的;
  • publicPath是定義文件被打包后的url前綴的,效果是<script src="index.js"></script> => <script src="static/index.js"></script>
  • filename顧名思義,就是定義打包后的名字,你可以按照上面的方式定義,最終文件名與原來的保持一致,也可以在這個基礎(chǔ)上自己再拼接一些名詞,比如[name].min.js,最終打包出來文件名就是index.min.js

resolve
這個配置可有可無,它是定義一些常用的文件拓展名,被定義了的文件格式,在引用的時候可以不加擴展名,比如我配置了.js的拓展名之后,在開發(fā)中我可以直接require('./common'),而不需要require('./common.js')

module
最重要的一個部分,我們在這里定義針對各種類型文件的loader(加載器/編譯器),可以看到我們分別定義了css、scss、swig三種文件對應(yīng)的loader,多個loader之間用!隔開,'-loader'可以省略不寫。注意,編譯的優(yōu)先次序是從右到左的,比如scss文件是先被sass-loader處理,然后再被css-loader處理,最后再被style-loader處理。

除了這幾點,webpack還有個比較重要的配置項plugins,這個我們暫時不介紹,后面會在具體的應(yīng)用場景里引入。除此之外,webpack的其他配置項大家可以去官網(wǎng)了解。

三、源碼

話不多說,我們還是取原來的gulp_base項目源碼來做介紹。

- project
  |- src  // 源文件夾
  | |- tpl
  | | `- index.swig
  | |- sass
  | | `- index.scss
  | |- js
  | | `- index.js
  |- dist  // 打包文件夾
  `- package.json

webpack的模塊化使我們可以很方便地使用commonjs的規(guī)范來組織代碼。有關(guān)commonjs的內(nèi)容,大家可以自行查閱相關(guān)文章,這里不作深入展開;或者關(guān)注我之后的文章,我將會針對模塊化做一些講解。不過這都是后話了。

在這里我們只需要知道,我們通過將頁面劃分成很多的小模塊,每個模塊都是單獨的js文件,我們可以通過require的方式,去引入一個模塊,進而組織成一個大的web應(yīng)用。而webpack更甚,在webpack里,"一切資源皆模塊",不管是圖片還是css,都可以在js文件中直接require,當然前提是你已經(jīng)在webpack.config.js的module項里配置了這類文件的相關(guān)loader。

四、編譯打包

ok,準備就緒,我們來試著編譯一下

webpack

理論上,我們?nèi)绻裫s文件放在一個叫做js的文件夾里,那幾乎百分百確定這貨就是.js結(jié)尾的,擴展名顯得有點多余。當然如果你硬是要在js文件夾里放個.jpg的文件我也拿你沒辦法是吧。

咱們看看dist目錄里面是不是有了個static文件夾?文件夾里是不是有個文件叫做index.js?是不是就成功了?沒成功你找我。

好,我們試著驗證另外一個配置,output.filename,我們改一下:

module.exports = {
  output: {
    path: path.resolve(__dirname, './dist/static'),
    publicPath: 'static/',
    filename: '[name].[chunkhash].js'
  },
  ...
}

命令行里webpack一下:

Hash: 408544aa45e4f298cb49
Version: webpack 1.13.1
Time: 49ms
                        Asset     Size  Chunks             Chunk Names
Index.e167a63b2bcf28077701.js  1.53 kB       0  [emitted]  Index
   [0] multi Index 28 bytes {0} [built]
   [1] ./src/js/index.js 21 bytes {0} [built]

打開dist/static目錄一看,生成了一個Index.e167a63b2bcf28077701.js文件,chunkhash是由webpack對index.js這個文件進行 md5 編碼之后得到的一個戳,這個戳是唯一的,拼接在文件名上,可以表示這個文件的唯一性,只要index.js里面的內(nèi)容被修改一丁點,這個生成的戳就會不一樣。

這不正是我們開頭想要的版本管理嗎?太美好了,沒想到這么容易就解決了這個問題。

有個問題,如果我每修改一點,這個文件名就不一樣了,那我不就要在html中每個引用了這個js的地方再修改一下文件名?這根本就沒有減負嘛!

怎么去解決這個問題?webpack當然提供了解決方案,如果我們用webpack幫我們打包html,并且自動地去注入這些資源,那問題就解決了。

一般來說webpack就只是處理入口文件,也就是從js去入手,這樣的話怎么都輪不到html,那怎么樣才能讓webpack去處理一下html?答案就是我們之前提過的,plugins

我們來修改一下配置:

var path = require('path')
var HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  entry: {
    Index: ['./src/js/index.js']
  },
  output: {
    path: path.resolve(__dirname, './dist/static'),
    publicPath: 'static/',
    filename: '[name].[chunkhash].js'
  },
  resolve: {
    extensions: ['', '.js', '.scss', '.swig']
  },
  module: {
    loaders: [
      {
        test: /\.css$/,
        loader: 'style!css'
      },
      {
        test: /\.scss$/,
        loader: 'style!css!sass'
      },
      {
        test: /\.swig$/,
        loader: 'swig'
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      chunks: ['Index'],
      filename: '../index.html',  // 留意這里,這里的路徑是相對來path配置的
      template: './src/tpl/index',
      inject: true
    })
  ]
}

請留意兩點修改的地方,一個是var HtmlWebpackPlugin = require('html-webpack-plugin'),一個是plugins的配置內(nèi)容。

webpack允許以插件的方式去擴展功能。html-webpack-plugin是webpack提供的一個簡化html處理的插件,其實本意就是為了解決這個引用bundle的問題,順便提供一些像壓縮啊注入、變量啊什么的功能。具體其他功能大家可以去官網(wǎng)看文檔。

使用前記得先install啊!

我們再次編譯一下,然后查看一下dist文件夾,是不是多了個index.html?而且index.js也被編譯后自動注入了頁面
編譯前:

// index.swig
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>index</title>
  </head>
  <body>
    hello, world!
  </body>
</html>

編譯后:

// index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>index</title>
  </head>
  <body>
    hello, world!
  <script type="text/javascript" src="static/Index.e167a63b2bcf28077701.js"></script></body>
</html>

done!

看著這html,有沒有感覺少了點什么?嗯,少了css,我們來看看css怎么注入。

其實css更簡單,我們已經(jīng)說過了:

在webpack里,一切資源皆模塊。

我們只需要在index.js中直接require就可以了:

// index.js
require('../sass/index')
console.log('index')

編譯一下,打開index.html:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>index</title>
  </head>
  <body>
    hello, world!
  <script type="text/javascript" src="static/index.c04c40a250e85ea100ab.js"></script></body>
</html>

沒看到有引入css啊?你個騙紙!

別著急,試著雙擊index.html文件,在瀏覽器打開試試?是不是有樣式了!神奇,樣式是哪里來的?原來css都被打包進js里面了!

雖然說目的是達到了,但是總覺得有點不好,我們還是習(xí)慣外聯(lián)css啦,能不能實現(xiàn)?可以!甩你一個plugin!extract-text-webpack-plugin

var ExtractTextPlugin = require('extract-text-webpack-plugin')

module.exports = {
  module: {
    loaders: [
      {
        test: /\.css$/,
        loader: ExtractTextPlugin.extract('style', ['css'])
      },
      {
        test: /\.scss$/,
        loader: ExtractTextPlugin.extract('style', ['css', 'sass'])
      },
      {
        test: /\.swig$/,
        loader: 'swig'
      }
    ]
  },
  plugins: [
    new ExtractTextPlugin('[name].[chunkhash].css'),
    ...
  ],
  ...
}

看著就能明白吧,這里不再細講,反正也就是這么用而已。

編譯一遍,看看index.html:

// index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>index</title>
  <link href="static/index.d4085060ebf342f7a5a1.css" rel="stylesheet"></head>
  <body>
    hello, world!
  <script type="text/javascript" src="static/index.d4085060ebf342f7a5a1.js"></script></body>
</html>

完美!

到這里,我們的打包工作算是介紹完了,下面我們試著搭建開發(fā)環(huán)境。

五、開發(fā)環(huán)境

我們在使用gulp的時候,搭建開發(fā)環(huán)境是借助browser-sync,而對于webpack來說,我們有更好的選擇:webpack-dev-server

webpack-dev-server是webpack官網(wǎng)提供的一款本地開發(fā)服務(wù)器,可以為我們提供一個適用于在webpack下進行開發(fā)的環(huán)境。

webpack-dev-server的用法其實很簡單,基于webpack的配置,稍稍補充一些內(nèi)容就可以了。webpack-dev-server有兩種使用方式,cli和api,我們分別做介紹。

在開始之前,我們需要針對開發(fā)環(huán)境單獨創(chuàng)建一份配置文件,有印象的同學(xué)可以記得,我們上一節(jié)講過,打包與開發(fā)的配置文件有一個不同點,打包是以產(chǎn)出并且優(yōu)化為目的的,而開發(fā)則更側(cè)重效率,所以我們需要把一些壓縮和多余的優(yōu)化手段給去掉,減輕開發(fā)過程中的編譯負擔(dān)。

我們新建一份配置文件webpack.dev.config.js:

// webpack.dev.config.js
var path = require('path')
var HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  entry: {
    index: ['./src/js/index.js']
  },
  output: {
    path: path.resolve(__dirname, './dist/static')
    filename: '[name].js'
  },
  resolve: {
    extensions: ['', '.js', '.scss', '.swig']
  },
  module: {
    loaders: [
      {
        test: /\.css$/,
        loader: 'style!css'
      },
      {
        test: /\.scss$/,
        loader: 'style!css!sass'
      },
      {
        test: /\.swig$/,
        loader: 'swig'
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      chunks: ['index'],
      filename: '../index.html',
      template: './src/tpl/index',
      inject: true
    })
  ]
}

我們把extract-text-webpack-plugin去掉,再把為了避免緩存而在文件名加戳的方式也去掉,這樣就差不多了。

值得注意的是,我們把path和publicPath兩項都去掉了,這里是為了配合下面的cli方案使用,我們接下去看就會明白。

cli
cli的方式要求我們?nèi)职惭bwebpack-dev-server:

npm install webpack-dev-server -g

然后我們直接在命令行里輸入:

webpack-dev-server --config ./webpack.dev.config.js --display-error-details --devtool eval --content-base ./ --inline --progress --colors --host 0.0.0.0

天了嚕,這也太長了。這長長的一串命令,都是針對webpack-dev-server初始化的配置,當然,webpack-dev-server的配置也是可以在webpack.dev.config.js里定義的,只是我們這里主要展示cli的用法,所以就直接這樣輸入了,具體各個參數(shù)是什么功能,我們可以不必全部了解,因為這里并沒有特別關(guān)鍵的配置項,大部分都是對終端里輸出形式的一些設(shè)置,我們挑重點的來說:

  1. content-base 設(shè)置開發(fā)服務(wù)器的根目錄;
  2. host 設(shè)置為0.0.0.0使我們在局域網(wǎng)中可以通過ip的方式訪問;
  3. hot 配置熱更新。

熱更新的作用是使得我們在修改并保存代碼之后,在不刷新瀏覽器的情況下,自動更新瀏覽器對應(yīng)部分的代碼!注意,此時頁面是不會刷新的,但變化立刻就可以反映出來!這一項我們并沒有設(shè)置,為什么?因為這里有一點小問題,熱更新的功能目前并不能對.html(或者靜態(tài)模板)這樣的文件起作用,也就是說,如果我們修改的是html,它將會不起任何作用,除非我們手動刷新,才能看到效果。這就有點撿芝麻丟西瓜了,所以我們選擇了放棄它。

當然,如果是像react這樣的主要由js來構(gòu)建的項目,那我們可以毫無顧忌地使用熱更新。

我們在配置文件中去掉了publicPath的設(shè)置,其實你可以試著設(shè)置一下,你會發(fā)現(xiàn)publicPath是會影響到全部的資源包括index.html,使得我們所有的文件都被放在服務(wù)器的static目錄下,此時只能通過/static來訪問到index.html,所以我們選擇去掉這兩項設(shè)置,講文件統(tǒng)一編譯打包到根目錄下。

其他配置項有興趣的同學(xué)可以到官網(wǎng)的文檔里了解。

api
cli的方式雖然很方便很簡單,但是如果要使用更多的定制化,api會更靈活一些。

注意,這一部分內(nèi)容十分重要,因為我們之后乃至下一節(jié)的文章里,都是基于api來配置工作流的,請務(wù)必掌握這一節(jié)的內(nèi)容,如果你還有再深入研究下去的想法的話,不要滿足于cli的便捷方式而對這一部分內(nèi)容粗略帶過。

使用api的方式,意味著我們需要自己來手動定義一個開發(fā)服務(wù)器,并且補充相關(guān)配置項,為了使配置與實現(xiàn)邏輯分開,我們還是使用原來那份配置文件webpack.dev.config.js,但是新建一份js文件server.js來編寫這個服務(wù)器邏輯。

var WebpackDevServer = require('webpack-dev-server')
var webpack = require('webpack')
var config = require('./webpack.dev.config.js')
var path = require('path')

var compiler = webpack(config)

var server = new WebpackDevServer(compiler, {
  stats: {
    colors: true,
    chunks: false
  }
})

server.listen(8080, 'localhost', function() {})

ok,我們先來試著跑一下:

node ./server.js

回車,成功啦!而且運行效果貌似跟cli的一樣。

這里的內(nèi)容實在沒什么可講的,我們首先使用webpack傳入配置內(nèi)容config,得到一個編譯的實例,之后我們再創(chuàng)建一個webpackDevServer的實例(本地服務(wù)器),來跑這份編譯實例,服務(wù)器監(jiān)聽8080端口,所以我們在瀏覽器中輸入http://localhost:8080就可以訪問了,搞定!

到這里就ok了嗎?其實還沒有,我們試著修改index.js,然后保存,看看瀏覽器。

瀏覽器沒有反應(yīng),也就是說,這里還沒有實現(xiàn)自動刷新瀏覽器的功能,我們配置少了一些東西。

好,那我們接著來。

webpackDevServer的官方文檔里其實已經(jīng)說得很清楚了:

Similar to the inline mode the user must make changes to the webpack configuration.
Three changes are needed:

  • add an entry point to the webpack configuration: webpack/hot/dev-server.
  • add the new webpack.HotModuleReplacementPlugin() to the webpack configuration.
  • add hot: true to the webpack-dev-server configuration to enable HMR on the server.

這里就算看不懂意思也能猜得到吧~

  • 每個入口都添加webpack/hot/dev-server
  • plugins里增加new webpack.HotModuleReplacementPlugin()
  • 配置 hot: true

二話不說就開搞,我們按照指示修改得到最終的server.js長這樣:

var WebpackDevServer = require('webpack-dev-server')
var webpack = require('webpack')
var config = require('./webpack.dev.config.js')
var path = require('path')

for (var key in config.entry) {
  var entry = config.entry[key]
  entry.unshift('webpack-dev-server/client?http://localhost:8080', 'webpack/hot/dev-server')
}

config.plugins.push(new webpack.HotModuleReplacementPlugin())

var compiler = webpack(config)

var server = new WebpackDevServer(compiler, {
  hot: true,
  stats: {
    colors: true,
    chunks: false
  }
})

server.listen(8080, 'localhost', function() {})

都是挺簡單的東西沒啥看不懂的,咱就不細講了,直接跑起來!

修改一下index.js,保存!呀,效果出來了,挺好;
修改一下index.scss,呀,效果出來了,倍兒棒;
修改一下index.swig,保存!呀,你咋就沒反應(yīng)了啊。。。

還記得我們用cli來搭建的時候遇到的類似情況嗎?WebpackDevServer的Hot Module Replacement是不支持html模板的,所以這里也一樣,怎么解決?

還是像原來,我們把hot: true的配置項去掉就好了,ok,運行一遍,修改,保存,done!

六、總結(jié)

gulpfile.js文件我們一看就明白,邏輯清晰層次分明,webpack的配置文件則需要細細咀嚼。

相比gulp,webpack構(gòu)建工作流是不是會復(fù)雜些?當然,我們只是對比來說,事實上如果只是從操作來看,也并沒有多復(fù)雜。我描述一個感受,看大家是不是有共鳴:
gulp是一套流程管理工具,專門管理一個個的任務(wù),同時結(jié)合一些編譯模塊來處理各種資源文件;
webpack則是一個大而全的編譯器,主要用于各種資源文件的編譯和打包工作,由此為中心衍生出了一系列周邊工具,比如開發(fā)工具,插件等等。

事實上,webpackDevServer編譯的文件是存放在內(nèi)存中的,操作起來速度非常的快,整個的項目編譯完成幾乎就是那么一個刷新的瞬間,而gulp則還是硬盤上的操作,速度要慢幾個量級,我們沒有感受到明顯的差異,那是因為項目還不夠大。

有沒有留意到,我們這一節(jié)并沒有像上一節(jié)那樣介紹到ftp工具?之所以沒有作介紹,是因為webpack并沒有提供這樣的插件或者模塊去完成這樣的工作,事實上也不應(yīng)該有,因為webpack本身是一個資源處理器,與項目的上傳部署沒有太多關(guān)系。我們需要借助其他的npm包,用一種毫無聯(lián)系的方式去組合這兩個功能,我們可能需要編寫一個ftp.js,不知大家是否還記得我們上一節(jié)當中的npm run build && npm run upload命令?差不多就是這樣。這個ftp.js就跟webpack的關(guān)系相當微弱了,不像我們寫gulp那樣,擴展一個功能的時候,只需要寫多一個task。

這里概念非常抽象,我也不能完完整整地傳達,不知道大家理解多少。老方法,我還是舉個栗子來說明:
webpack就好比一套很好用的螺絲刀,基本所有的機器的維修工作都能應(yīng)付。但是如果需要完整一點的工程,我們可能還需要大錘啊電鉆啊什么亂七八糟的。但是東西一過來可能沒法整理到一起,只能拿個塑料袋粗略地裝起來;
gulp好比一個工具箱,里面也有幾件比較簡單的螺絲刀,如果有其他的工具,來了就往里面放,妥妥的。

嗯,又是一個不怎么貼切的栗子,湊合著用吧憋唧唧歪歪的。

我們先理解到這里,進一步的對比,我們會在教程最后的章節(jié)里呈現(xiàn)一次比較細致的說明。

后話:我們可以把webpack這把好用的螺絲刀放gulp這個工具箱里嗎?答案當然是yes!帥(美)的人已經(jīng)動手了,丑的還在賣萌。下一節(jié)【強化:構(gòu)建易用易擴展的工作流】我們將為大家講解如何使用gulp結(jié)合webpack,各取所長地搭建一套簡單易用、高可擴展性的工作流。

本次演示項目的git地址:webpack_base

【上一篇:入門:十分鐘自動化構(gòu)建】
【下一篇:強化:構(gòu)建易用易擴展的工作流】

(文章有任何謬誤之處,歡迎留言指出)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,119評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,382評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,038評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,853評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,616評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,112評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,192評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,355評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,869評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,727評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,928評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,467評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,165評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,570評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,813評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,585評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,892評論 2 372

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

  • 在現(xiàn)在的前端開發(fā)中,前后端分離、模塊化開發(fā)、版本控制、文件合并與壓縮、mock數(shù)據(jù)等等一些原本后端的思想開始...
    Charlot閱讀 5,462評論 1 32
  • 最近在學(xué)習(xí) Webpack,網(wǎng)上大多數(shù)入門教程都是基于 Webpack 1.x 版本的,我學(xué)習(xí) Webpack 的...
    My_Oh_My閱讀 8,199評論 40 247
  • 無意中看到zhangwnag大佬分享的webpack教程感覺受益匪淺,特此分享以備自己日后查看,也希望更多的人看到...
    小小字符閱讀 8,206評論 7 35
  • 寫在開頭 先說說為什么要寫這篇文章, 最初的原因是組里的小朋友們看了webpack文檔后, 表情都是這樣的: (摘...
    Lefter閱讀 5,310評論 4 31
  • world
    15年好運閱讀 140評論 0 0