Webpack 學(xué)(cai)習(xí)(keng)之路

webpack

前言

  • WebPack 是什么拼弃?

WebPack 是什么,WebPack 可以看做是模塊打包機(jī):它做的事情是,分析你的項(xiàng)目結(jié)構(gòu)照宝,找到 JavaScript 模塊以及其它的一些瀏覽器不能直接運(yùn)行的拓展語言(Scss,TypeScript 等)雹顺,并將其轉(zhuǎn)換和打包為合適的格式供瀏覽器使用丹墨。

  • WebPack 可以用來做什么?

我們都知道嬉愧,前端技術(shù)不斷發(fā)展贩挣,已有的 html隘膘,js痒蓬,css 等基礎(chǔ)的技術(shù)已經(jīng)不能滿足尋(yue)求(lai)捷(yue)徑(lan)的程序員群體了,于是 jsx察蹲,less裕便,sass绒净,以及有利于模塊化開發(fā)的 AMDCommonJS偿衰,ES2015 import 等利于完成項(xiàng)目的方案被一個(gè)個(gè)的提了出來并得以采用挂疆,但是這些方案并不能直接被瀏覽器識(shí)別支持,因此與這些方案一同提出的往往會(huì)有各種轉(zhuǎn)換工具哎垦。
?
??當(dāng)我們?cè)陧?xiàng)目中運(yùn)用了 jsx囱嫩,lesssass 等工具時(shí)漏设,往往需要使用 babel 以及其他的轉(zhuǎn)換工具將其轉(zhuǎn)換為 js墨闲,css 等瀏覽器識(shí)別的樣式。當(dāng)一個(gè)項(xiàng)目比較復(fù)雜時(shí)郑口,這個(gè)任務(wù)量無疑是龐大的鸳碧,更不要說當(dāng)代碼體積過大時(shí)我們還需要對(duì)代碼進(jìn)行壓縮,優(yōu)化犬性,分割瞻离,整個(gè)項(xiàng)目完成下來耗費(fèi)的精力和時(shí)間想一想都覺得可怕。
?
??于是乒裆,webpack 走進(jìn)了我們的視野套利。它的理念是一切皆模塊,將所有的文件都當(dāng)做模塊處理(需要注意的是鹤耍,在 webpack 中肉迫,文件是模塊,但模塊不一定是文件)稿黄。我們?cè)?webpack 可以使用各種各樣的 loader喊衫,用以轉(zhuǎn)換各種不同類型的文件,也可以使用各種各樣的插件plugin杆怕,對(duì)我們體積龐大的項(xiàng)目代碼進(jìn)行優(yōu)化族购,分割壳贪,壓縮,提取等寝杖。

  • WebPack和別的打包工具如Grunt以及Gulp的區(qū)別在哪里违施?

Gulp / Grunt 是一種工具,能夠優(yōu)化前端工作流程朝墩。比如自動(dòng)刷新頁面醉拓、雪碧圖伟姐、壓縮 css收苏、js、編譯 less 等等愤兵,但是這些操作都需要在gulp的配置文件中詳細(xì)設(shè)置鹿霸。
??webpack 是預(yù)編譯的,你在本地直接寫 JS秆乳,不管是 AMD / CMD / ES6 風(fēng)格的模塊化懦鼠,它都能認(rèn)識(shí),不需要另外再在瀏覽器中加載解釋器屹堰,它還可以只通過一個(gè)文件入口自動(dòng)尋找其依賴的所有模塊肛冶,包括文件模塊,編譯成一個(gè)或多個(gè)瀏覽器認(rèn)識(shí)的 JS扯键,還可以通過插件plugin對(duì)生成的js代碼進(jìn)行各種優(yōu)化睦袖,這些操作只需要在配置文件中設(shè)置用得到的loader或者plugin就可以了,不用告訴webpack具體怎樣操作荣刑。
??兩者功能有重合部分馅笙,如壓縮,合并等厉亏,但是各有優(yōu)勢(shì)董习,可以結(jié)合使用
?
??綜上:
??? 1. gulp/grunt 是工具鏈,構(gòu)建工具爱只,自動(dòng)化皿淋,提高效率用。
??? 2. webpack 是文件打包工具恬试,模塊化識(shí)別窝趣,編譯模塊代碼,優(yōu)化代碼方案用忘渔。

本文結(jié)構(gòu):

本文將通過以下十七部分介紹webpack使用方法:
1. webpack環(huán)境構(gòu)建
2. webpack打包ES6文件
3. 引入webpack配置文件
4. webpack-dev-server
5. Source Maps
6. 編譯器
7. webpack打包jsx文件
8. webpack打包c(diǎn)ss文件
9. webpack打包img文件
10. 插件
11. BannerPlugin插件
12. HtmlWebpackPlugin插件
13. HMR插件
14. BundleAnalyzerPlugin插件
15. ExtractTextPlugin插件
16. CommonsChunkPlugin插件
17. UglifyJsPlugin插件

WebPack踩坑之路開始

一高帖、 webpack環(huán)境構(gòu)建
  1. 首先全局安裝 webpack:
    在終端中輸入
npm install -g webpack 
  1. 我們可以使用 Webstom 編輯器新建一個(gè)空項(xiàng)目 webpackdemo,也可以在桌面新建一個(gè)空文件夾畦粮,名字自定散址,然后在里面新建一個(gè) app 文件夾和一個(gè) build 文件夾乖阵,在 app 文件夾中創(chuàng)建 main.js文件和Greeter.js文件,在 build 文件夾下創(chuàng)建 index.html 文件预麸。

這里的app文件夾里面就是我們平常寫的代碼目錄,在 webpack 中我們會(huì)選擇一個(gè)主js文件main.js瞪浸,如果需要其他的 js,css吏祸,img文件对蒲,可以將其作為模塊引入到 main.js 中,而 build 文件夾中存放的是我們使用 webpack 將繁雜的 css 和 js 打包過后生成的文件贡翘。

  1. 因?yàn)槲覀兪窃趎ode環(huán)境下打包文件的蹈矮,因此每一個(gè)新的項(xiàng)目都需要一個(gè) package.json 文件,它是一個(gè)標(biāo)準(zhǔn)的 npm 說明文件鸣驱,包含了當(dāng)前項(xiàng)目依賴的模塊泛鸟,自定義的腳本任務(wù)等,創(chuàng)建該文件的方法是進(jìn)入 webpackdemo 文件夾中踊东,然后在命令窗口輸入:npm init北滥,接著一路按回車就可以了。
  1. 我們雖然已經(jīng)在全局安裝了 webpack 闸翅,但為了穩(wěn)妥起見再芋,還是在當(dāng)前項(xiàng)目中再安裝一遍 webpack:
npm install --save-dev webpack

這里的 --save-dev 會(huì)將安裝的該模塊的名稱存儲(chǔ)在 package.json 文件中的 devDependencies 關(guān)鍵字下,便于我們查看已安裝模塊信息坚冀。

現(xiàn)在我們的項(xiàng)目結(jié)構(gòu)如下圖:

項(xiàng)目結(jié)構(gòu)圖
二济赎、 webpack打包js文件
  1. 我們先在 index.html 中寫入代碼:
// index.html

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>webpackdom</title>
  </head>
  <body>
    <div id='root'>
    </div>
  <!-- 這里引入的 bundle.js 文件現(xiàn)在還不存在,是將來我們用 webpack 打包出來的文件 -->
    <script src="bundle.js"></script>          
  </body>
</html>

這里引入的 bundle.js 是通過webpack打包后的可以供瀏覽器識(shí)別的 js 文件(現(xiàn)在還不存在)

  1. 接著我們?cè)?Greeter.js 中寫入一個(gè)函數(shù)遗菠,用途是在頁面中打印出來一句話联喘,然后將該函數(shù)作為一個(gè)模塊導(dǎo)出:
// Greeter.js

module.exports = function() {
  var greet = document.createElement('div');
  greet.textContent = "Hi there and greetings!";
  return greet;
};

  1. 接下來編寫我們的 main.js 文件,引入Greeter 文件導(dǎo)出的模塊,并將該模塊添加到頁面的div節(jié)點(diǎn)中:
// main.js 

const greeter = require('./Greeter.js');
document.querySelector("#root").appendChild(greeter());

  1. 上述文件編寫完畢后辙纬,我們可以在命令窗口輸入webpack打包命令:
//webpack 打包命令

webpack {entry-file} {output for bundled file}
    {entry-file}                  //入口文件路徑豁遭,即我們所說的主js文件main.js
    {output for bundled file}     //打包輸出的js文件路徑

在我們的這個(gè)demo中,需要輸入的命令是:
    webpack app/main.js build/bundle.js

打包成功界面:

命令行打包

上圖顯示的 bundle.js 即為 main.jsGreeter.jswebpack 打包成功后生成的文件贺拣,打開 index.html 蓖谢,在瀏覽器頁面會(huì)顯示如下內(nèi)容

頁面顯示結(jié)果

至此為止,我們成功的用webpack打包了 Greeter.js 文件譬涡。

三闪幽、 引入webpack配置文件

我們?cè)谶M(jìn)行上述操作時(shí)會(huì)發(fā)現(xiàn),如果 webpack 每次打包都必須輸入那行很長(zhǎng)的打包命令涡匀,無疑是追求高(xiang)效(tou)率(lan)的我們所不能容忍的盯腌,我們希望通過更簡(jiǎn)單的命令來讓 webpack 工作。但是我們命令簡(jiǎn)單了陨瘩,就需要另建一個(gè)文件來告訴 webpack 它需要怎樣工作腕够,這個(gè)文件就是webpack配置文件级乍。

webpack配置文件作用具體是什么呢?
??它是來告訴 webpack 帚湘,你要從哪個(gè)文件(入口文件)開始玫荣,找和這個(gè)文件有關(guān)系的所有模塊,包含引入的第三方模塊和文件模塊大诸。
??找到這些模塊后捅厂,假如這些模塊中用了比如 less, sass, es2015, jsx 等瀏覽器不能直接識(shí)別支持的語法,webpack 會(huì)自己用我們?cè)谂渲梦募性O(shè)置好的轉(zhuǎn)換工具(loader)资柔,將這些語法轉(zhuǎn)換成 CSS3 ES5 等瀏覽器可以直接識(shí)別的語法焙贷,然后將這些模塊和入口文件一起打包成一個(gè)文件。
??但是這個(gè)文件如果不進(jìn)行處理建邓,體積會(huì)很大盈厘。因此在這里 webpack 會(huì)引用我們?cè)谂渲梦募性O(shè)置的插件(plugin)對(duì)生成的文件進(jìn)行優(yōu)化,比如分離css官边,切割代碼,分離引入的第三方模塊等外遇。

我們先在根目錄下創(chuàng)建一個(gè) webpack.config.js 注簿,在里面寫入以下代碼:

// webpack.config.js

module.exports ={
        entry:__dirname + '/app/main.js',      //入口文件
        output:{
                path: __dirname + '/build',    //輸出文件路徑
                filename:'bundle.js'           //輸出文件名
        }
}

這樣我們的一個(gè)最基本最簡(jiǎn)單的webpack配置文件就創(chuàng)建好了,現(xiàn)在我們可以在命令窗口輸入webpack跳仿,然后回車诡渴,

配置文件打包

出現(xiàn)上圖內(nèi)容即為打包成功。

以上我們已經(jīng)用了兩種打包方式菲语,分別是命令行打包和配置文件打包妄辩,在這里繼續(xù)介紹第三種打包方式:命令窗口輸入 npm run xxx 引導(dǎo)任務(wù)執(zhí)行。
首先我們進(jìn)入 package.json 文件山上,找到 scripts 屬性眼耀,在下面添加

"xxx":"webpack"        // xxx為個(gè)人定義的屬性名,可以用 `npm run xxx` 來運(yùn)行后面的文件

此時(shí) package.json 中的代碼如下:

// package.json

{
  "name": "webpackdemo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev":"webpack"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^3.6.0"
  }
}

這里有個(gè)坑:JSON 文件中 不能 添加 注釋 E搴丁O啊!

接下來我們運(yùn)行 npm run dev 妄帘,如果你在上面加的屬性名是楞黄,同樣會(huì)出現(xiàn)以下結(jié)果

npm run dev 輸出結(jié)果

以上,我們引入了 webpack.config.js 配置文件并總結(jié)出了三種 webpack 打包:

  • 命令行打包 webpack {entry-file} {output for bundled file}
  • webpack打包 webpack
  • npm run xxx 打包 npm run xxx

推薦使用第二種方式

四抡驼、 webpack-dev-server

本小節(jié)我們將介紹一個(gè)本地服務(wù)器 webpack-dev-server鬼廓。
webpack-dev-server 基于 node.js 構(gòu)建,可以讓瀏覽器監(jiān)聽我們的代碼修改致盟,代碼一旦改動(dòng)并保存碎税,瀏覽器會(huì)立刻自動(dòng)刷新柏副。
在使用 webpack-dev-server 之前,我們需要先安裝它作為項(xiàng)目依賴蚣录,在命令窗口輸入以下指令:

npm install --save-dev webpack-dev-server

我們?nèi)粝胧褂?webpack-dev-server 包括后面要講的各種 loader 或者 plugin , 都需要在 webpack.config.js 文件中進(jìn)行配置:

devServer配置選項(xiàng) 功能描述
contentBase 默認(rèn)webpack-dev-server會(huì)為根文件夾提供本地服務(wù)器割择,如果想為另外目錄下的文件夾提供服務(wù)器,應(yīng)該在該配置選項(xiàng)中重新設(shè)置所在目錄
prot 設(shè)置默認(rèn)監(jiān)聽端口萎河,默認(rèn)為"8080"
inline 設(shè)置為true時(shí)荔泳,當(dāng)源文件改變時(shí)會(huì)自動(dòng)刷新頁面
historyApiFallback 在開發(fā)單頁應(yīng)用時(shí)非常有用,依賴于HTML5 history API虐杯,如果設(shè)置為true玛歌,所有的跳轉(zhuǎn)將指向index.html

接下來更新 webpack.config.js 文件

//webpack.config.js

module.exports ={
        entry:__dirname + '/app/main.js',
        output:{
                path: __dirname + '/build',
                filename:'bundle.js'
        },
        //更新部分代碼
        devServer: {
                contentBase:"./build",      //本地服務(wù)器加載頁面所在目錄
                historyApiFallback:true,    //不跳轉(zhuǎn)
                inline:true                 //實(shí)時(shí)刷新
        }

}

package.json 中的 scripts 對(duì)象中添加以下命令,用以開啟本地服務(wù):

//package.json

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack",
    "server": "webpack-dev-server --open"
  }

接下來在命令窗口輸入 npm run server 啟動(dòng)服務(wù)器擎椰,正常情況下會(huì)自動(dòng)在瀏覽器打開 localhost:8080 ,若沒有自動(dòng)打開可以在瀏覽器窗口中手動(dòng)輸入支子。

啟動(dòng)服務(wù)成功

然后我們可以在 Greeter.js 中修改一下要輸出的內(nèi)容,保存的同時(shí)可以觀察到命令窗口中會(huì)服務(wù)器會(huì)自動(dòng)刷新达舒,同時(shí)瀏覽器窗口會(huì)自動(dòng)刷新html內(nèi)容值朋。

五、 Source Maps

我們都知道巩搏,打包生成的文件其實(shí)可讀性是很差的昨登。如果我們?cè)诒镜鼐帉懘a時(shí)候不小心寫錯(cuò)了,然后打包生成的文件肯定是達(dá)不到我們想要的效果贯底,而在生成的文件中查錯(cuò)即找bug是不現(xiàn)實(shí)的丰辣,我們需要直觀明顯的顯示出錯(cuò)位置,這個(gè)時(shí)候就需要使用Source Maps 來顯示出來我們寫的代碼出錯(cuò)的位置禽捆。
同樣笙什,我們需要在 webpack.config.js 中進(jìn)行配置。

devtool選項(xiàng) 配置結(jié)果
source-map 在一個(gè)單獨(dú)的文件中產(chǎn)生一個(gè)完整且功能完全的文件胚想。這個(gè)文件具有最好的source map琐凭,但是它會(huì)減慢打包速度;
cheap-module-source-map 在一個(gè)單獨(dú)的文件中生成一個(gè)不帶列映射的map顿仇,不帶列映射提高了打包速度淘正,但是也使得瀏覽器開發(fā)者工具只能對(duì)應(yīng)到具體的行,不能對(duì)應(yīng)到具體的列(符號(hào))臼闻,會(huì)對(duì)調(diào)試造成不便鸿吆;
eval-source-map 使用eval打包源文件模塊,在同一個(gè)文件中生成干凈的完整的source map述呐。這個(gè)選項(xiàng)可以在不影響構(gòu)建速度的前提下生成完整的sourcemap惩淳,但是對(duì)打包后輸出的JS文件的執(zhí)行具有性能和安全的隱患。在開發(fā)階段這是一個(gè)非常好的選項(xiàng),在生產(chǎn)階段則一定不要啟用這個(gè)選項(xiàng)思犁;
cheap-module-eval-source-map 這是在打包文件時(shí)最快的生成source map的方法代虾,生成的Source Map會(huì)和打包后的JavaScript文件同行顯示,沒有列映射激蹲,和eval-source-map選項(xiàng)具有相似的缺點(diǎn)棉磨;

上述選項(xiàng)由上到下打包速度越來越快,同時(shí)負(fù)面作用也越來越大学辱,較快的打包速度的后果是對(duì)打包后的文件的執(zhí)行有一定的影響乘瓤。
中小型的項(xiàng)目推薦使用eval-source-map,大型項(xiàng)目考慮時(shí)間成本時(shí)可以使用cheap-module-eval-source-map策泣。另外衙傀,Source Map 只應(yīng)該在開發(fā)階段使用,生產(chǎn)階段記得將該配置其去除萨咕。

更新webpack.config.js:

//webpack.config.js

module.exports ={
        entry:__dirname + '/app/main.js',
        output:{
                path: __dirname + '/build',
                filename:'bundle.js'
        },

        devServer: {
                contentBase:"./build",
                historyApiFallback:true,
                inline:true
        },
        //更新代碼:
        devtool: "eval-source-map"    //配置Source Map 
}
六统抬、 編譯器

本小節(jié)我們將認(rèn)識(shí)webpack的可以說最為強(qiáng)大的功能之一:編譯器(裝載器)Loaders

webpack1.x 中是loaders危队,在webpack2.x中將loaders換為了rules聪建,我們?cè)诰W(wǎng)上搜到的大多教程都是基于webpack1.x的,和現(xiàn)在使用的webpack2.x有些許出入交掏,不同之處詳見:Webpack2 升級(jí)指南和特性摘要

聽說過webpack的童鞋們肯定都見過loaders這個(gè)單詞妆偏,那么問題來了,loaders是用來做什么的?
大家對(duì)webpack可以將那些使用瀏覽器不能識(shí)別支持的各種語法編寫的文件打包都有所耳聞盅弛,那webpack這種強(qiáng)大的功能是用什么實(shí)現(xiàn)的呢?答案就是Loaders叔锐。webpack通過各種不同的loader調(diào)用外部的腳本或工具挪鹏,實(shí)現(xiàn)對(duì)不同類型文件的轉(zhuǎn)換編譯處理,例如將sass轉(zhuǎn)換為css,ES6/ES7轉(zhuǎn)換為ES5,React中用到的jsx轉(zhuǎn)換為js等愉烙。

同上讨盒,我們也需要在配置文件webpack.config.js中的module關(guān)鍵字下配置loaders,即webpack2.x中的rules(后面如果再出現(xiàn)rules即為loaders)。rules是一個(gè)數(shù)組步责,里面存放著需要使用的許多loader,每個(gè)loader都是一個(gè)對(duì)象返顺,下面是loader中常用的幾個(gè)屬性:

  • test:一個(gè)用以匹配loaders所處理文件的拓展名的正則表達(dá)式(必須)
  • loader: loader的名稱(必須)
  • include/exclude : 手動(dòng)添加必須處理的文件(文件夾)/屏蔽不需要處理的文件(文件夾)(可選);
  • query: 為loaders提供額外的設(shè)置選項(xiàng)(可選)

在配置loader之前蔓肯,我們將Greeter.js里的問候消息放在一個(gè)單獨(dú)的JSON文件中遂鹊,通過合適的配置使Greeter.js可以讀取JSON文件中的值,各文件修改后的代碼如下:
在app文件夾中創(chuàng)建帶有問候信息的JSON文件(命名為config.json)

//config.json

{
  "greetText":"hello webpack!"
}

更新后的Greeter.js

//Greeter.js

//更新內(nèi)容:
var config = require('./config.json');        //引入上面創(chuàng)建的 config.json 文件
module.exports = function(){                  //將該模塊公開蔗包,外部其他文件可以調(diào)用該模塊
        var greet = document.createElement('div');    //創(chuàng)建一個(gè)div
        greet.textContent = config.greetText;         //將 config.json 文件中g(shù)reetText屬性中的內(nèi)容添加到創(chuàng)建的div中
        return greet;                                 //將該div塊返回出去
}

webpack1.x 中秉扑,json 文件需要在配置文件中單獨(dú)使用json-loader轉(zhuǎn)換處理,而 webpack2.x 內(nèi)置了可以處理json的模塊调限,不需要再單獨(dú)配置舟陆。

七误澳、 webpack打包ES6文件

我們繼續(xù)打包文件,不過這次打包的是``類型文件秦躯,需要用到Babel忆谓。它是隨著ES6,ES7,JSXjs語法的興起而產(chǎn)生的,作用就是用來將這些目前尚未被瀏覽器完全支持的語法轉(zhuǎn)換為可以被瀏覽器識(shí)別支持的ES5踱承。
Babel包含了幾個(gè)模塊化的包倡缠,核心功能在babel-corenpm包中,對(duì)于每一個(gè)你需要的功能或拓展勾扭,你都需要安裝單獨(dú)的包毡琉,平時(shí)用的最多的是解析ES6babel-preset-es2015包和解析JSXbabel-preset-react包。
所以我們可以將上述的幾個(gè) npm 包安裝一次性的安裝下來:

//npm 一次安裝多個(gè)依賴模塊妙色,模塊之間需要用空格隔開
npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react

接下來我們?cè)谂渲梦募信渲?code>babel:

//webpack.config.js

module.exports ={
    entry:__dirname + '/app/main.js',
    output:{
        path: __dirname + '/build',
        filename:'bundle.js'
    },

    devServer: {
        contentBase:"./build",
        historyApiFallback:true,
        inline:true
    },
    devtool: "eval-source-map",

    //更新內(nèi)容
    module:{
        rules:[
            {
                test:/(\.jsx|\.js)$/,   //該正則也可以寫作  /\.jsx?$/
                use:{
                    loader: "babel-loader",
                    options: {
                        presets:[
                            "es2015","react"
                        ]
                    }
                },
                exclude:/node_modules/
            }
        ]
    }

}

現(xiàn)在用上面的配置我們就可以打包出用 ES6 語法編寫的代碼了桅滋。
下面我們修改代碼,將上述文件中的代碼改為 ES6 語法的代碼身辨,不過這里我們會(huì)用到 react丐谋,因此先安裝ReactReact-DOM,命令如下:

npm install --save-dev react react-dom

然后更新 Greeter.js 代碼:

//Greeter.js

//更新內(nèi)容:
import React, {Component} from 'react';    //引入React組件
import config from './config.json';        

class Greeter extends Component {          //創(chuàng)建class類 
    render(){
        return(
            <div>
                {config.greetText}
            </div>
        );
    }
}
export default Greeter;                   //返回react組件

更新 main.js 代碼:

//main.js

import React from 'react';
import {render} from 'react-dom';
import Greeter from './Greeter';

render(<Greeter />,document.getElementById("root"));

更新完畢后我們可以運(yùn)行打包命令 webpack 煌珊,打包成功后再運(yùn)行 npm run server 啟動(dòng)服務(wù)器,服務(wù)器會(huì)自動(dòng)在瀏覽器中打開 html 頁面号俐,輸出 「 hello webpack! 」:

localhost:8080

Babel的配置:
Babel 可以在配置文件中配置,但是它同時(shí)也有特別多特別多的設(shè)置選項(xiàng)定庵,雖然可以在 webpack.config.js 文件中設(shè)置吏饿,但是如果有很多設(shè)置選項(xiàng),webpack.config.js 就會(huì)顯得很臃腫蔬浙,因此我們可以把 babel 的設(shè)置選項(xiàng)提取出來猪落,單獨(dú)放在一個(gè)名為 .babelrc 的文件中。這里的 babel 的設(shè)置選項(xiàng)即為下圖中選中的部分:

babel下的設(shè)置選項(xiàng)

現(xiàn)在我們就可以提取出相關(guān)部分畴博,webpack 會(huì)自動(dòng)調(diào)用 .babelrc 中的配置選項(xiàng)笨忌,修改代碼如下:

//webpack.config.js

module.exports = {
    entry: __dirname + '/app/main.js',
    output: {
        path: __dirname + '/build',
        filename: 'bundle.js'
    },
    devServer: {
        contentBase: "./build",
        historyApiFallback: true,
        inline: true
    },
    devtool: "eval-source-map",
    module: {
        rules: [{
            test: /(\.jsx|\.js)$/, //該正則也可以寫作  /\.jsx?$/
            use: {
                loader: "babel-loader",
                //將以下部分代碼注掉,該 babel-loader 的options 部分我們將在 .babelrc 中單獨(dú)設(shè)置
                // options: {
                //      presets:[
                //              "es2015","react"
                //      ]
                // }
            },
            exclude: /node_modules/
        }]
    }
}

在該項(xiàng)目的根目錄創(chuàng)建 .babelrc 文件

//.babelrc

{
  "presets": ["react","es2015"]
}

該文件中 只能 存放 babel-loader 下的設(shè)置選項(xiàng)俱病,其他的loader設(shè)置不能在這里寫

我們可以先打包官疲,再開啟本地服務(wù)器,查看是否配置成功亮隙。

八途凫、 webpack打包c(diǎn)ss文件

通過前面幾節(jié)練習(xí),我們也許可能似乎好像貌似大概模模糊糊隱隱約約明白了webpack是干嘛的咱揍,該怎么用颖榜,所以我們繼續(xù)打包下一種類型文件:css
打包c(diǎn)ss文件的話,我們需要使用css-loaderstyle-loader,兩者處理任務(wù)不同掩完,css-loader能使用類似 @importutl(...)的方法實(shí)現(xiàn)require()的功能噪漾,style-loader將所有的計(jì)算后的樣式加入頁面中,兩者組合在一起使你能夠把樣式表嵌入到打包后的 js 文件且蓬。

首先欣硼,安裝兩個(gè)loader:

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

在配置文件中配置:

//webpack.config.js

module.exports = {

      ...
  module: {
        rules: [{
            test: /(\.jsx|\.js)$/, //該正則也可以寫作  /\.jsx?$/
            use: {
                    loader: "babel-loader"
            },
            exclude: /node_modules/
        },
        
        //更新代碼:
        {
            test: /\.css$/,
            use: [{
                loader: "style-loader"
            }, {
                loader: "css-loader"
            }]
        }
        
        ]
    }
}

注意這里對(duì)同一個(gè)文件引入多個(gè) loader 的方法。

接下來在 app 文件中創(chuàng)建 main.css 的文件恶阴,設(shè)置一下樣式:

//main.css

body {
    background-color: pink;
    color: salmon;
}
div {
    font-size: 30px;
}

本實(shí)例中的 webpack 入口唯一诈胜,即為 main.js ,所以其他的所有的模塊都需要通過 import / require / url 等與之建立關(guān)聯(lián)冯事,為了讓 webpack 能找到該
css 文件焦匈, 我們把它導(dǎo)入到 main.js 中,如下:

//main.js

import React from 'react';
import {render} from 'react-dom';
import Greeter from './Greeter';

import './main.css';    //使用 import 引入 css 文件

render(<Greeter />,document.getElementById("root"));

通常情況下昵仅,css 會(huì)和 js 打包到同一文件中缓熟,并不會(huì)打包成一個(gè)單獨(dú)的
css 文件,但是也是可以將其分離的摔笤,我們?cè)诤竺鎯?nèi)容將會(huì)講到如何將 css 與 js 分離够滑。

同樣,先運(yùn)行 webpack 打包吕世,再啟動(dòng)本地服務(wù)器看是否將 css 文件打包成功彰触,啟動(dòng)服務(wù)器命令是 npm run server

打包成功并且實(shí)現(xiàn)效果

以上命辖,我們實(shí)現(xiàn)了對(duì) css 文件的打包况毅。

CSS module
眾所周知,現(xiàn)在使用JavaScript 進(jìn)行模塊化開發(fā)已經(jīng)成了主流尔艇,我們可以把復(fù)雜的代碼轉(zhuǎn)化為一個(gè)一個(gè)的小的模塊俭茧,并且這些小模塊之間的依賴關(guān)系很明確,每個(gè)小模塊中不摻雜其他內(nèi)容漓帚,配合優(yōu)化工具,依賴管理和加載管理可以自動(dòng)完成午磁,省時(shí)省力尝抖。
與此同時(shí),CSS 也在不斷的朝著模塊化方向發(fā)展迅皇。而 webpack 從一開始就對(duì) css 模塊化提供了支持昧辽,在 css-loader 中進(jìn)行配置后,接下來做的就是把 modules 傳遞到需要的地方登颓,然后就可以直接把 css 的類名傳遞到組件代碼中搅荞,并且這樣做只對(duì)當(dāng)前組件有效,不用擔(dān)心在不同的模塊中使用相同的類名造成沖突。具體代碼如下:

//webpack.config.js

module.exports = {

      ...
  module: {
        rules: [{
            test: /(\.jsx|\.js)$/, //該正則也可以寫作  /\.jsx?$/
            use: {
                    loader: "babel-loader"
            },
            exclude: /node_modules/
        },
        
        //更新代碼:
        {
            test: /\.css$/,
            use: [{
                loader: "style-loader"
            }, {
                loader: "css-loader",

                //添加以下代碼:
                 options: {
                    modules:true
                }

            }]
        }
        
        ]
    }
}

在app文件夾下創(chuàng)建一個(gè) Greeter.css 文件

//Greeter.css

.root {
    display: flex;
    justify-content: center;
    border: 3px solid seagreen;
}

將 .root 導(dǎo)入到 Greeter.js 中:

//Greeter.js

import React, {Component} from 'react';
import config from './config.json';

//更新代碼部分:
import styles from './Greeter.css';     //引入模塊

class Greeter extends Component {
    render(){
        return(

            //添加類名
            <div className={styles.root}>       
                {config.greetText}
            </div>
        );
    }
}
export default Greeter;

運(yùn)行


應(yīng)用了 css module 后的樣式

CSS modules是一個(gè)很大的主題咕痛,有興趣的童鞋可以去 官方文檔 查看了解更多

CSS預(yù)處理器

  • sass 和 less 可以讓我們寫 css 樣式更靈活痢甘,我想大家應(yīng)該已經(jīng)猜到了要在配置文件中使用相關(guān)的 loaders 進(jìn)行配置,用到的 loaders 即為 less-loader 和 sass-loader 茉贡。

  • 另外再介紹一個(gè) css 的處理平臺(tái) PostCSS塞栅,它可以讓你的 CSS 實(shí)現(xiàn)更多的功能,可以去閱讀 官方文檔 了解更多

  • 這里我們用一實(shí)例說明 PostCSS 如何為 CSS 代碼自動(dòng)添加適應(yīng)不同瀏覽器的CSS前綴腔丧,可以簡(jiǎn)單理解為調(diào)兼容

首先安裝 postcss-loaderautoprefixer (自動(dòng)添加前綴插件)

npm install --save-dev postcss-loader autoprefixer

安裝完成后放椰,將 webpack.config.js 更新:

//webpack.config.js

module.exports = {

      ...
  module: {
        rules: [{
            test: /(\.jsx|\.js)$/, //該正則也可以寫作  /\.jsx?$/
            use: {
                    loader: "babel-loader"
            },
            exclude: /node_modules/
        },
        
        //更新代碼:
        {
            test: /\.css$/,
            use: [{
                loader: "style-loader"
            }, {
                loader: "css-loader",
                 options: {
                    modules:true
                }
            },{
                      loader:"postcss-loader"
            }]
        }
        
        ]
    }
}

在根目錄創(chuàng)建 postcss.config.js ,添加如下代碼:

//postcss.config.js

module.exports = {
    plugins:[
        require('autoprefixer')
    ]
}
九愉粤、 webpack打包img文件

本小節(jié)我們將使用webpack打包兩張圖片砾医,并將其放到頁面內(nèi)

十、 插件(Plugins)

插件(Plugins)是用來拓展Webpack功能的衣厘,它們會(huì)在整個(gè)構(gòu)建過程中生效如蚜,執(zhí)行相關(guān)的任務(wù)。

Plugins 和 Loaders 的區(qū)別:
?>> loaders 是在打包構(gòu)建過程中用來處理源文件的(JSX头滔,Scss怖亭,Less..),一次處理一個(gè)坤检。
?>> plugins 并不直接操作單個(gè)文件兴猩,它直接對(duì)整個(gè)構(gòu)建過程起作用,比如切割代碼早歇,分離css倾芝,壓縮代碼等。箭跳。晨另。

使用插件的方法:
首先通過npm安裝插件,然后在配置文件中引入該插件谱姓,接著在與 rules 同層級(jí)的位置添加一個(gè) plugins 關(guān)鍵字借尿,結(jié)構(gòu)如圖, plugins 是一個(gè)數(shù)組屉来,可以添加多個(gè)插件路翻,后面將介紹幾種常用插件及其基本配置方法。

plugins 在配置文件中的位置
十一茄靠、 BannerPlugin插件

該插件的作用是給打包后的代碼添加一個(gè)版權(quán)聲明茂契,是webpack自帶的插件,不用再次安裝慨绳,配置方法如下:
首先在配置文件中引入 webpack :

const webpack = require('webpack');

接著在 plugins 插件數(shù)組中創(chuàng)建該插件掉冶,代碼如下:

 plugins:[
      new webpack.BannerPlugin('版權(quán)所有真竖,翻版必究')
    ]

然后運(yùn)行打包命令,打開打包生成的文件厌小,會(huì)在頭部顯示版權(quán)聲明恢共,如圖:

版權(quán)聲明
十二、 HtmlWebpackPlugin插件

該插件的作用是按照一個(gè)簡(jiǎn)單的 index.html 模板文件召锈,在最終路徑生成一個(gè)可以自動(dòng)引用打包后的 js 文件的新的 index.html 文件旁振,主要用于每次生成的 js 文件名稱都不相同時(shí),例如我們?yōu)榱藘?yōu)化緩存在輸出的 js 文件的名字中加了 hash 值的時(shí)候涨岁。
首先安裝:

npm install --save-dev html-webpack-plugin

這個(gè)插件可以自動(dòng)完成我們之前手動(dòng)做的一些事情拐袜,還可以生成 html 文件,此時(shí)我們項(xiàng)目結(jié)構(gòu)中的 build 文件夾就可以讓 webpack 自己去創(chuàng)建了梢薪,因此就不需要 build 文件夾了蹬铺,可以先把該文件夾刪掉,然后用webpack生成秉撇。
如果我們想利用該插件自動(dòng)生成 html甜攀,則需要在 app 文件夾中創(chuàng)建一個(gè) index.tmpl.html 文件,該模板必須包含 html 的必要元素琐馆,如 title 等规阀。webpack在編譯過程中,會(huì)依據(jù)此模板生成 html 瘦麸,自動(dòng)為該 html 添加它所依賴的 css 谁撼,js 等其他文件。 index.tmpl.html 文件模板代碼如下:

//index.tmpl.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Webpack Sample Project</title>
  </head>
  <body>
    <div id='root'>
    </div>
  </body>
</html>

更新webpack的配置文件滋饲,代碼如下:

//webpack.comfig.js

const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry: __dirname + "/app/main.js",    //已多次提及的唯一入口文件
    output: {
        path: __dirname + "/build",       //我們?cè)谶@里設(shè)置輸出路徑厉碟,若該路徑不存在,webpack會(huì)自動(dòng)創(chuàng)建
        filename: "[name]-[hash].js"      //輸出文件的文件名屠缭,這里[name]是自動(dòng)匹配的箍鼓,[hash]是自動(dòng)生成的
    },

    devServer: {
        contentBase: "./public",//本地服務(wù)器所加載的頁面所在的目錄
        historyApiFallback: true,//不跳轉(zhuǎn)
        inline: true//實(shí)時(shí)刷新
    },
    module: {
        rules: [
            {
                test: /(\.jsx|\.js)$/,
                use: {
                    loader: "babel-loader"
                },
                exclude: /node_modules/
            },
            {
                test: /\.css$/,
                use: [
                    {
                        loader: "style-loader"
                    },
                   {
                        loader: "css-loader",
                        options: {
                            modules: true
                        }
                    },
                   {
                        loader: "postcss-loader"
                    }
                ]
            }
        ]
    },
    plugins: [
        new webpack.BannerPlugin('版權(quán)所有,翻版必究'),
        new HtmlWebpackPlugin({
            template: __dirname + "/app/index.tmpl.html"http://new 一個(gè)這個(gè)插件的實(shí)例呵曹,并傳入相關(guān)的參數(shù)
        })
    ]
};

重新打包款咖,我們會(huì)發(fā)現(xiàn)自動(dòng)生成了build文件夾,里面自動(dòng)生成了一個(gè)js文件和一個(gè)html文件奄喂,運(yùn)行服務(wù)器之剧,觀察最終頁面效果是不是我們想要的效果

十三、 HMR插件

Hot Module Replacement (HMR) 也是我們常用的一個(gè)插件砍聊,它允許你在修改組件代碼后,自動(dòng)刷新實(shí)時(shí)預(yù)覽修改后的效果贰军。

配置方式:

  • 在配置文件中添加 HMR 插件
  • 在 devServer 中添加 hot 參數(shù)

配置完之后JS還是不能自動(dòng)熱加載的玻蝌,還需要在JS模塊中執(zhí)行一個(gè)webpackk提供的API才能實(shí)現(xiàn)熱加載蟹肘。另一種方法是用Babel對(duì)React模塊進(jìn)行功能熱加載,不過用該種方法需要對(duì)babel設(shè)置選項(xiàng)進(jìn)行設(shè)置俯树,代碼如下:

//webpack.config.js

const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');


module.exports = {
    entry: __dirname + "/app/main.js",//已多次提及的唯一入口文件
    output: {
        path: __dirname + "/build",
        filename: "bundle.js"
    },
    devtool: 'eval-source-map',
    devServer: {
        contentBase: "./public",//本地服務(wù)器所加載的頁面所在的目錄
        historyApiFallback: true,//不跳轉(zhuǎn)
        inline: true,
        hot: true
    },
    module: {
        rules: [
            {
                test: /(\.jsx|\.js)$/,
                use: {
                    loader: "babel-loader"
                },
                exclude: /node_modules/
            },
            {
                test: /\.css$/,
                use: [
                    {
                        loader: "style-loader"
                    }, {
                        loader: "css-loader",
                        options: {
                            modules: true
                        }
                    }, {
                        loader: "postcss-loader"
                    }
                ]
            }
        ]
    },
    plugins: [
        new webpack.BannerPlugin('版權(quán)所有帘腹,翻版必究'),
        new HtmlWebpackPlugin({
            template: __dirname + "/app/index.tmpl.html"http://new 一個(gè)這個(gè)插件的實(shí)例,并傳入相關(guān)的參數(shù)
        }),
        new webpack.HotModuleReplacementPlugin()//熱加載插件


安裝 react-transform-hmr

npm install --save-dev babel-plugin-react-transform react-transform-hmr

配置Babel:

//.babelrc

{
  "presets": ["react", "es2015"],
  "env": {
    "development": {
    "plugins": [["react-transform", {
       "transforms": [{
         "transform": "react-transform-hmr",
         
         "imports": ["react"],
         
         "locals": ["module"]
       }]
     }]]
    }
  }
}

接下來我們來修改下 package.json 文件下的 scripts 關(guān)鍵字下的內(nèi)容:

將 "server" 改變?yōu)?"start",再更新后面的內(nèi)容

如果你使用的是React许饿,那么現(xiàn)在輸入npm start就可以熱加載模塊了阳欲,每次保存都能在瀏覽器中看到內(nèi)容。

現(xiàn)在大概講述一下 webpack-dev-server 和 HMR 大概有什么區(qū)別陋率,詳情參見webpack-dev-server配置球化。

  • webpack-dev-server 為我們提供了本地服務(wù)器,通過對(duì)其選項(xiàng)的一些設(shè)置瓦糟,我們可以保存代碼后讓瀏覽器自動(dòng)刷新筒愚,顯示我們修改后的代碼
  • HMR 其實(shí)是一個(gè)插件,可以配合 webpack-dev-server 使用菩浙,當(dāng)對(duì)其配置完成后并運(yùn)行服務(wù)器后巢掺,我們修改代碼,然后保存的同時(shí)劲蜻,瀏覽器內(nèi)容并不會(huì)全部刷新陆淀,而是只更新修改部分內(nèi)容,比如我們修改了一個(gè)邊框樣式先嬉,那么頁面中其他的內(nèi)容樣式都不會(huì)動(dòng)轧苫,只會(huì)刷新邊框的樣式。
    想了解更深入的童鞋可以去看上面發(fā)的鏈接里的內(nèi)容坝初,也可以自己在網(wǎng)上搜索兩者區(qū)別浸剩。
十四、 BundleAnalyzerPlugin插件

在介紹該插件之前鳄袍,我們可以先對(duì)前面的代碼打包绢要,然后看一下打包出來的那個(gè)JS文件體積,會(huì)發(fā)現(xiàn)我們僅僅寫了那么幾行代碼拗小,但是打包出來的js文件都有2M+重罪,此時(shí)假設(shè)項(xiàng)目已經(jīng)完成,該上線了哀九,但這種直接打包出來的文件是肯定不能直接推到線上的剿配,因?yàn)轶w積太大。
此時(shí)就可以用到該插件了阅束。這個(gè)插件作用是分析項(xiàng)目依賴的呼胚,配置好該插件之后,運(yùn)行完打包命令息裸,瀏覽器會(huì)自動(dòng)打開一個(gè)窗口蝇更,顯示具體依賴的模塊沪编,清晰明了直觀。

配置:首先安裝該模塊

npm install webpack-bundle-analyzer --save-dev

在配置文件中引入以及在插件 plugins 數(shù)組中實(shí)例化出一個(gè)插件:

//webpack.config.js

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
  ...
module.exports = {
  ...
  plugins:[
      ...
    new BundleAnalyzerPlugin()
  ]
}

再次運(yùn)行打包命令年扩,瀏覽器自動(dòng)打開頁面如下圖:

image.png

我們可以清楚地看到生成的 main.js 文件有 2.5Mb蚁廓,體積很大拐叉,我們需要對(duì)其進(jìn)行優(yōu)化皆的。

十五、 ExtractTextPlugin插件

這時(shí)我們最應(yīng)該做的就是將Source Maps 配置選項(xiàng)縮小代碼體積所以我們就需要用插件對(duì)生成代碼進(jìn)行優(yōu)化承桥,ExtractTextPlugin就是其中之一况脆,作用是將編譯后的css與js文件分離饭宾。
配置方法如下:

  • 安裝該插件:npm install --save-dev extract-text-webpack-plugin
  • 在配置文件中設(shè)置如下:
const ExtractTextPlugin = require('extract-text-webpack-plugin');
  ...
module.exports={
  ...
  module:{
    rules:[
      ...
      {
        test: /\.css$/,
        use:ExtractTextPlugin.extract({
          fallback:"style-loader",
          use:{
             loader:"css-loader",
             options:{
                module:true
             }
           }
        }) 
      }
    ]
  },
  plugins:[
    ...
    new ExtractTextPlugin("style.css")  //括號(hào)中的內(nèi)容為分離出的css文件的名字  
  ]
}
 

打包后會(huì)在目標(biāo)文件夾生成css文件。

十六漠另、 CommonsChunkPlugin插件

經(jīng)過以上操作步驟后捏雌,打包出的文件的體積依然很大,所以我們繼續(xù)優(yōu)化笆搓,此處引入 CommonsChunkPlugin插件 性湿。
這個(gè)模塊的作用是提取出我們用的第三方模塊庫,例如 react 满败,react-dom 等肤频,這些體積較大的模塊我們可以把它摘出來,另存為一個(gè)js文件算墨,然后通過 HtmlWebpackPlugin 插件宵荒,html會(huì)自動(dòng)將該js文件引入到html中。

更新配置文件:

//webpack.config.js


  ...
module.exports = {
  //此處我們修改下入口文件
  entry:{
      app:__dirname + "/app/main.js",
      vendors:['react','react-dom']
    }, 
  ...
  plugins:[
      ...
    new webpack.optimize.CommonsChunkPlugin({name:'vendor', filename: 'vendor.js'})
  ]
}

打包文件净嘀,成功提取出vender.js报咳,再觀察生成的文件大小,我們主要的js文件體積就縮小了挖藏。更多webpack優(yōu)化方案

十七暑刃、 UglifyJsPlugin插件

到這里的時(shí)候代碼體積其實(shí)已經(jīng)不大了,但是我們?yōu)榱俗非髽O致膜眠,就會(huì)用到該插件岩臣,將代碼深度壓縮,經(jīng)過壓縮的js文件體積會(huì)變得更小宵膨。對(duì)代碼的壓縮混淆架谎,不僅可以保證代碼的安全性,還可以降低資源文件的大小辟躏,減少網(wǎng)絡(luò)傳輸谷扣。
該插件是對(duì)生成的所有 js 文件進(jìn)行壓縮,具體配置如下:

new webpack.optimize.UglifyJsPlugin(),

&ems p;「」

常用終端命令:

cd ..                             //返回上層目錄
cd firDiector/sonDirector         //進(jìn)入當(dāng)前目錄下的 firDiector 
                              文件夾中的 sonDirector 文件夾
touch file-name.xx                //創(chuàng)建filename.xx的文件
mkdir director-name               //創(chuàng)建名為director-name的文件夾
npm init                          //在當(dāng)前文件夾
npm install webpack -g            //全局安裝webpack捎琐,-g 的位置可在前
npm install --save-dev webpack    //在當(dāng)前目錄下安裝webpack模塊抑钟,
                              --save-dev表示在package.json添加當(dāng)前
                              安裝模塊的簡(jiǎn)介涯曲,推薦添加
npm uninstall webpack             //刪除webpack模塊
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市在塔,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌拨黔,老刑警劉巖蛔溃,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異篱蝇,居然都是意外死亡贺待,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門零截,熙熙樓的掌柜王于貴愁眉苦臉地迎上來麸塞,“玉大人,你說我怎么就攤上這事涧衙∧墓ぃ” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵弧哎,是天一觀的道長(zhǎng)雁比。 經(jīng)常有香客問我,道長(zhǎng)撤嫩,這世上最難降的妖魔是什么偎捎? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮序攘,結(jié)果婚禮上茴她,老公的妹妹穿的比我還像新娘。我一直安慰自己程奠,他們只是感情好丈牢,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著梦染,像睡著了一般赡麦。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上帕识,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天泛粹,我揣著相機(jī)與錄音,去河邊找鬼肮疗。 笑死晶姊,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的伪货。 我是一名探鬼主播们衙,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼钾怔,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了蒙挑?” 一聲冷哼從身側(cè)響起宗侦,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎忆蚀,沒想到半個(gè)月后矾利,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡馋袜,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年男旗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片欣鳖。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡察皇,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出泽台,到底是詐尸還是另有隱情什荣,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布师痕,位于F島的核電站溃睹,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏胰坟。R本人自食惡果不足惜因篇,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望笔横。 院中可真熱鬧竞滓,春花似錦、人聲如沸吹缔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽厢塘。三九已至茶没,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間晚碾,已是汗流浹背抓半。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留格嘁,地道東北人笛求。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親探入。 傳聞我的和親對(duì)象是個(gè)殘疾皇子狡孔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

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

  • 無意中看到zhangwnag大佬分享的webpack教程感覺受益匪淺,特此分享以備自己日后查看蜂嗽,也希望更多的人看到...
    小小字符閱讀 8,140評(píng)論 7 35
  • GitChat技術(shù)雜談 前言 本文較長(zhǎng)苗膝,為了節(jié)省你的閱讀時(shí)間,在文前列寫作思路如下: 什么是 webpack植旧,它要...
    蕭玄辭閱讀 12,671評(píng)論 7 110
  • 最近在學(xué)習(xí) Webpack,網(wǎng)上大多數(shù)入門教程都是基于 Webpack 1.x 版本的,我學(xué)習(xí) Webpack 的...
    My_Oh_My閱讀 8,166評(píng)論 40 247
  • 在現(xiàn)在的前端開發(fā)中荚醒,前后端分離、模塊化開發(fā)隆嗅、版本控制、文件合并與壓縮侯繁、mock數(shù)據(jù)等等一些原本后端的思想開始...
    Charlot閱讀 5,431評(píng)論 1 32
  • 大好年華里胖喳,你活著,你努力著贮竟,就值得被愛丽焊。 天真的愛來自于“我被你愛著,所以我愛你咕别〖冀。”成熟的愛,則是“我被你愛著惰拱,...
    holly萌閱讀 144評(píng)論 0 0