Webpack(一):基本配置

1. 安裝webpack到全局

在構(gòu)建之前芽腾,我們來在本地文件新建一個存放項(xiàng)目的文件夾,比如叫demo1這個項(xiàng)目栈源,然后進(jìn)入demo1該項(xiàng)目的根目錄后逊抡,執(zhí)行命令 npm init
運(yùn)行下,一路回車(先簡單的來)火窒,就會生成一個package.json文件硼补。

在項(xiàng)目中直接運(yùn)行如下命令,就可以把webpack安裝到全局去熏矿;如下命令:

npm install -g webpack

2. 安裝webpack到本項(xiàng)目已骇。

在本項(xiàng)目中,執(zhí)行如下命令票编,就可以把webpack安裝到本地項(xiàng)目中褪储,如下命令:

npm install --save-dev webpack

3. 如何使用webpack?

在編寫webpack代碼之前慧域,我們先搭建好目錄結(jié)構(gòu)如下:

### 目錄結(jié)構(gòu)如下:
demo1                                       # 工程名
|   |--- dist                               # 打包后生成的目錄文件             
|   |--- node_modules                       # 所有的依賴包
|   |--- js                                 # 存放所有js文件
|   | |-- demo1.js  
|   | |-- main.js                           # js入口文件
|   |
|   |--- webpack.config.js                  # webpack配置文件
|   |--- index.html                         # html文件
|   |--- styles                             # 存放所有的css樣式文件                              
|   |--- .gitignore  
|   |--- README.md
|   |--- package.json

index.html代碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
  <div id="app"></div>
  <script src="./dist/bundle.js"></script>
</body>
</html>

js/demo1.js 代碼假如是如下:

function demo1Func() {
  console.log(11);
};
module.exports = demo1Func;

js/main.js 代碼如下:

const demo1Func = require('./demo1.js');

demo1Func();

如上的簡單的代碼鲤竹,我們先從上面的簡單的代碼來學(xué)起,然后逐漸會慢慢的深入的講解webpack知識點(diǎn)昔榴;
我們在項(xiàng)目的根目錄中新建 webpack.config.js件辛藻;
編寫配置文件如下:

const path = require('path');

module.exports = {
  entry: './js/main.js',

  output: {
    // 將所有依賴的模塊合并輸出到一個叫bundle.js文件內(nèi)
    filename: 'bundle.js',
    // 將輸出的文件都放在dist目錄下
    path: path.resolve(__dirname, './dist')
  }
};

一切編寫文件好了以后,我們一般情況下會在項(xiàng)目的根目錄下 運(yùn)行webpack命令互订;但是當(dāng)我們運(yùn)行webpack后揩尸,會報錯如下信息:

One CLI for webpack must be installed. These are recommended choices, delivered as separate packages:
 - webpack-cli (https://github.com/webpack/webpack-cli)
   The original webpack full-featured CLI.
 - webpack-command (https://github.com/webpack-contrib/webpack-command)
   A lightweight, opinionated webpack CLI.
We will use "npm" to install the CLI via "npm install -D".
Which one do you like to install (webpack-cli/webpack-command):

因此我們可以在項(xiàng)目的目錄下 安裝下 webpack-cli ,如下命令安裝:

npm install webpack-cli -g

安裝完成后屁奏,我們再執(zhí)行webpack命令后岩榆,就會在項(xiàng)目中根目錄生成dist文件夾,該文件夾內(nèi)會生成 bundle.js 文件坟瓢。這時候我們再打開index.html勇边, 運(yùn)行后,會發(fā)現(xiàn)執(zhí)行了依賴的demo1.js了折联。

3.1 理解配置文件 entry(入口)和 出口 (output)

  • 入口(entry) 是指示webpack應(yīng)該使用哪個模塊粒褒,來作為構(gòu)建內(nèi)部依賴js的開始,進(jìn)入入口起點(diǎn)后诚镰,webpack會找出有哪些模塊和庫是入口js依賴的奕坟。
  • 出口(output) 是告訴webpack在什么地方輸出它所創(chuàng)建的bundles祥款,以及如何命名這些文件,默認(rèn)值為 './dist'.

4. 使用loader

webpack的構(gòu)建是一個采用CommonJS規(guī)范的模塊化項(xiàng)目月杉,現(xiàn)在我們還是繼續(xù)上面的項(xiàng)目刃跛,我們再在main.js會引入一個css文件。因此會在main.js代碼修改如下:

require('../styles/main.css');

const demo1Func = require('./demo1.js');

demo1Func();

然后main.css代碼如下:

#app {
  font-size: 18px;
}

如果我們現(xiàn)在直接去執(zhí)行webpack的話苛萎,就會報錯桨昙,因此我們需要在webpack中加入Loader的機(jī)制。將webpack代碼改成如下:

const path = require('path');

module.exports = {
  entry: './js/main.js',

  output: {
    // 將所有依賴的模塊合并輸出到一個叫bundle.js文件內(nèi)
    filename: 'bundle.js',
    // 將輸出的文件都放在dist目錄下
    path: path.resolve(__dirname, './dist')
  },
  module: {
    rules: [
      {
        // 用正則去匹配以 .css結(jié)尾的文件腌歉,然后需要使用loader進(jìn)行轉(zhuǎn)換
        test: /\.css$/,
        use: ['style-loader', 'css-loader?minimize']
      }
    ]
  }
};

如上代碼蛙酪,我們在webpack編譯之前需要安裝 style-loader 和 css-loader, 如下命令進(jìn)行安裝:

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

如上配置代碼中的 module.rules 數(shù)組配置了一組規(guī)則翘盖,是來告訴webpack在遇到哪些文件時使用哪些loader去加載和轉(zhuǎn)換桂塞,比如上面的使用test正則去匹配
以 .css 結(jié)尾的文件,會先使用 css-loader 讀取css文件馍驯,然后使用 style-loader將css的內(nèi)容注入到j(luò)avascript里面去阁危。

注意:
1. use屬性的值是一個使用Loader名稱組成的數(shù)組,Loader的執(zhí)行順序是由后往前的泥彤。由于loader有順序的欲芹,因此我們在配置中不能如下編寫loader卿啡;
代碼如下:

module: {
    rules: [
      {
        // 用正則去匹配以 .css結(jié)尾的文件吟吝,然后需要使用loader進(jìn)行轉(zhuǎn)換
        test: /\.css$/,
        use: ['css-loader?minimize', 'style-loader']
      }
    ]
  }

2. 每個Loader都可以通過 URL queryString 的方式傳入?yún)?shù),比如 css-loader?minimize是告訴css-loader是開啟css壓縮颈娜。
現(xiàn)在我們可以在項(xiàng)目中的根目錄運(yùn)行 webpack命令了剑逃,一切正常后,我們打開index.html后官辽,查看代碼蛹磺,發(fā)現(xiàn)css被加載到style標(biāo)簽內(nèi)了;
style-loader的原理:是將css的內(nèi)容使用javascript的字符串存儲起來同仆,在網(wǎng)頁執(zhí)行javascript時通過DOM操作萤捆,動態(tài)地向HTML head標(biāo)簽里插入 HTML style標(biāo)簽。

3. 配置loader的方式也可以使用Object來實(shí)現(xiàn)俗批,比如如上的匹配css代碼俗或,可以改成如下:

use: [
    'style-loader', 
    {
      loader: 'css-loader',
      options: {
        minimize: true
      }
    }
]

因此webpack所有的配置代碼變成如下:

const path = require('path');
  module.exports = {
    entry: './js/main.js',
    output: {
      // 將所有依賴的模塊合并輸出到一個叫bundle.js文件內(nèi)
      filename: 'bundle.js',
      // 將輸出的文件都放在dist目錄下
      path: path.resolve(__dirname, './dist')
    },
    module: {
      rules: [
        {
          // 用正則去匹配以 .css結(jié)尾的文件,然后需要使用loader進(jìn)行轉(zhuǎn)換
          test: /\.css$/,
          use: [
            'style-loader', 
            {
              loader: 'css-loader',
              options: {
                minimize: true
              }
            }
          ]
        }
      ]
    }
  };

5. 使用插件(Plugin)

loader的作用是被用于轉(zhuǎn)換某些類型的模塊岁忘,而插件則可以用于執(zhí)行范圍更廣的任務(wù)辛慰,插件的范圍包括,從打包優(yōu)化和壓縮干像,一直到重新定義環(huán)節(jié)中的變量。
如果想要使用一個插件挽封,我們只需要require()它,然后把它添加到 plugins數(shù)組中苗踪。我們可以在一個配置文件中因?yàn)椴煌哪康亩啻问褂糜靡粋€插件朋截,因此我們可以使用new操作符來創(chuàng)建它的實(shí)列赵抢。

上面我們是通過loader加載了css文件到j(luò)s中去,下面我們通過plugin將注入的bundle.js文件里的css提取到單獨(dú)的文件中乐埠,我們需要使用到extract-text-webpack-plugin 插件抗斤,配置代碼如下:

const path = require('path');

// 提取css的插件
const ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
  entry: './js/main.js',

  output: {
    // 將所有依賴的模塊合并輸出到一個叫bundle.js文件內(nèi)
    filename: 'bundle.js',
    // 將輸出的文件都放在dist目錄下
    path: path.resolve(__dirname, './dist')
  },
  module: {
    rules: [
      {
        // 使用正則去匹配要用該loader轉(zhuǎn)換的css文件
        test: /\.css$/,
        loaders: ExtractTextPlugin.extract({
          // 轉(zhuǎn)換 .css文件需要使用的Loader
          use: ['css-loader']
        })
      }
    ]
  },
  plugins: [
    new ExtractTextPlugin({
      // 從js文件中提取出來的 .css文件的名稱
      filename: `main.css`
    })
  ]
};

要使用 extract-text-webpack-plugin 插件的話,首先我們需要安裝該插件丈咐,安裝插件的命令如下:

npm install --save-dev extract-text-webpack-plugin

當(dāng)安裝成功后瑞眼,我們需要運(yùn)行webpack命令后,發(fā)現(xiàn)命令行報錯了棵逊,報錯信息如下:

(node:86210) DeprecationWarning: Tapable.plugin is deprecated. Use new API on `.hooks` instead /usr/local/lib/node_modules/webpack/lib/Chunk.js:802

解決的辦法是 安裝 extract-text-webpack-plugin 時伤疙,需要如下安裝,安裝命令如下:

npm install extract-text-webpack-plugin@next

安裝成功后辆影,再運(yùn)行webpack就可以了徒像,我們可以看到在dist文件夾內(nèi)會多一個main.css, 因此我們可以在index.html中把 css文件引入進(jìn)去即可。

6. 使用DevServer

前面是使用webpack進(jìn)行打包蛙讥,但是在開發(fā)中我們還需要一個本地文件的服務(wù)器锯蛀,并且當(dāng)我們保存代碼的時候會自動進(jìn)行打包,并且還支持 Source Map次慢,以方便代碼調(diào)試等功能旁涤,因此我們現(xiàn)在需要使用到 DevServer了。

首先我們需要安裝 webpack-dev-server, 如下安裝命令:

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

當(dāng)然我們還需要全局安裝一下经备,安裝命令如下:

npm install webpack-dev-server -g

然后當(dāng)我們在命令行輸入 webpack-dev-server 運(yùn)行后拭抬,發(fā)現(xiàn)報錯了部默,報錯如下信息:

The CLI moved into a separate package: webpack-cli.
Please install 'webpack-cli' in addition to webpack itself to use the CLI. 
-> When using npm: npm install webpack-cli -D 
-> When using yarn: yarn add webpack-cli -D
module.js:471

因此我們需要重新運(yùn)行下如下命令:

npm install webpack-cli -D

當(dāng)成功后侵蒙,我們再次運(yùn)行 webpack-dev-server 可以看到已經(jīng)啟動了服務(wù)器了,端口號默認(rèn)是 8080, 然后我們訪問 http://localhost:8080/index.html 就可以訪問到我們項(xiàng)目中頁面了傅蹂。

6.1 實(shí)時預(yù)覽
webpack在啟動時可以開啟監(jiān)聽模式纷闺,默認(rèn)是關(guān)閉的,開啟后webpack會監(jiān)聽本地文件系統(tǒng)的變化份蝴,在發(fā)生變化時候會重新構(gòu)建出新的結(jié)果犁功,在上面運(yùn)行

webpack-dev-server 后,我們需要打開一個新的命令行婚夫,在命令行中輸入如下命令來開啟監(jiān)聽模式:

webpack --watch

當(dāng)項(xiàng)目中入口文件或入口依賴的文件有改變的時候浸卦,它會自動重新構(gòu)建,構(gòu)建完成后會自動刷新下頁面案糙,但是如果修改的不是入口文件或依賴的文件
是不會有任何效果的限嫌,比如修改的是index.html 是不會重新構(gòu)建的靴庆。但是要完成上面的實(shí)時預(yù)覽,html頁面的bundle.js 要直接引入即可:如下html頁面代碼:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
  <div id="app"></div>
  <script src="bundle.js"></script>
</body>
</html>

那為什么 http://localhost:8080/bundle.js 這樣也能訪問的到呢怒医?原因是DevServer會將webpack構(gòu)建出的文件保存在內(nèi)存中炉抒,DevServer不會理會webpack.config.js里配置的output.path屬性的。

6.2 模塊熱替換

  • 除了上面介紹的改動本地入口文件或依賴文件后稚叹,會自動打包焰薄,然后會自動刷新瀏覽器即可看到更新效果外,我們還可以使用模塊熱替換技術(shù)扒袖,
  • 模塊熱替換技術(shù)能做到在不重新加載整個網(wǎng)頁的情況下塞茅,通過將已更新的模塊替換舊模塊,它默認(rèn)是關(guān)閉的季率,要開啟模塊熱替換凡桥,我們只需在啟動DevServer時帶上 --inline 參數(shù)即可。

如下命令:

webpack-dev-server --inline  或 webpack-dev-server --inline --hot

webpack-dev-server 有如下兩種啟動模式:

  • iFrame: 該模式下修改代碼后會自動打包蚀同,但是瀏覽器不會自動刷新缅刽。
  • inline: 內(nèi)聯(lián)模式,該模式下修改代碼蠢络,webpack將自動打包并刷新瀏覽器衰猛。

6.3 支持Source Map
在瀏覽器中運(yùn)行javascript代碼都是編譯器輸出的代碼,但是如果在代碼中碰到一個bug的時候刹孔,我們不好調(diào)式啡省,因此我們需要 Source Map來映射到源代碼上,Webpack支持生成 Source Map, 只需在啟動時帶上 --devtool source-map參數(shù)即可髓霞;如下命令:

webpack-dev-server --inline --hot --devtool source-map

注意:每次運(yùn)行 如上命令卦睹,感覺非常長,因此我們可以在項(xiàng)目的根目錄的package.json文件的scripts配置中添加如下配置:

"scripts": {
  "dev": "webpack-dev-server --devtool source-map --hot --inline"
}

加上如上配置后方库,我們只需要在命令行中 運(yùn)行 npm run dev 即可结序;

其他配置常見的選項(xiàng):

  • --quiet 控制臺中不輸出打包的信息
  • --compress 開啟gzip的壓縮
  • --progress 顯示打包的進(jìn)度

因此在項(xiàng)目中scripts經(jīng)常會做如下配置:

"scripts": {
  "dev": "webpack-dev-server --progress --colors --devtool source-map --hot --inline",
  "build": "webpack --progress --colors"
}

這樣的話,打包的時候會顯示打包進(jìn)度纵潦。

1. context

基礎(chǔ)目錄徐鹤,絕對路徑,用于從配置中解析入口起點(diǎn)和加載器邀层。
什么意思呢返敬?比如如下代碼配置:

  • context: path.resolve(__dirname, 'js'), 含義是使用當(dāng)前目錄下的js文件下查找入口文件。

比如如下代碼的配置也是可以的:

module.exports = {
  context: path.resolve(__dirname, 'js'),
  entry: './main.js'
}

含義是從當(dāng)前項(xiàng)目目錄下的js文件查找main.js文件作為入口文件寥院,如果在當(dāng)前目錄沒有找到該入口文件劲赠,就會報錯。
當(dāng)然我們也可以如下寫配置代碼也是可以的:如下代碼配置:

module.exports = {
  context: path.resolve(__dirname, ''),
  entry: './js/main.js'
};

或者context配置項(xiàng)不要,它也是默認(rèn)從當(dāng)前目錄下查找的凛澎,因此如果使用context的話泌绣,建議加上第二個參數(shù),是從當(dāng)前目錄下那個文件內(nèi)查找的预厌“⒙酰或者直接不要這個配置項(xiàng)。

2. entry

應(yīng)用程序的起點(diǎn)入口轧叽,從這個起點(diǎn)開始苗沧,應(yīng)用程序啟動執(zhí)行,如果傳遞一個數(shù)組的話炭晒,那么數(shù)組的每一項(xiàng)都會執(zhí)行待逞。它的類型可以是String, array, 或 object;

2.1 string(類型為字符串):
如下配置:

module.exports = {
  entry: './js/main.js',
  output: {
    // 將所有依賴的模塊合并輸出到一個叫bundle.js文件內(nèi)
    filename: 'bundle.js',
    // 將輸出的文件都放在dist目錄下
    path: path.resolve(__dirname, './dist')
  }
};

2.2 類型為數(shù)組

module.exports = {
  entry: ['./js/main.js', './js/main2.js'],
  output: {
    // 將所有依賴的模塊合并輸出到一個叫bundle.js文件內(nèi)
    filename: 'bundle.js',
    // 將輸出的文件都放在dist目錄下
    path: path.resolve(__dirname, './dist')
  }
};

如果類型為數(shù)組的話,將會創(chuàng)建多個主入口网严,并且把數(shù)組中的js打包在一起到一個文件里面去识樱。

2.3 類型為對象時

module.exports = {
  entry: {
    'main': './js/main.js',
    'main2': './js/main2.js'
  },
  output: {
    filename: '[name].js', // [name] 的值是entry的鍵值, 會輸出多個入口文件
    // 將輸出的文件都放在dist目錄下
    path: path.resolve(__dirname, './dist')
  }
};

3. Output

output配置是輸出最終想要的代碼,它是一個object, 里面包含很多配置項(xiàng)震束。

3.1 filename 和 path的理解
filename: 輸出文件的名稱怜庸,為string類型.

  1. 如果只有一個輸出文件,可以將名稱寫死垢村;如:filename: 'bundle.js';
    path: 文件被寫入硬盤的位置割疾。必須是string類型的絕對路徑,一般通過Node.js的path模塊獲取絕對路徑嘉栓,如下代碼:
    path: path.resolve(__dirname, './dist')

單個入口配置代碼如下:

{
  entry: './js/main.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, './dist')
  }
}

多個入口

如果有多個chunk要輸出時宏榕,就需要借助[name]變量了,webpack會為每個chunk取一個名稱侵佃,因此我們根據(jù)chunk的名稱來區(qū)分輸出的文件名麻昼。如下:filename: '[name].js'

多個入口配置代碼如下:

module.exports = {
  entry: {
    'main': './js/main.js',
    'main2': './js/main2.js'
  },
  output: {
    filename: '[name].js', // [name] 的值是entry的鍵值, 會輸出多個入口文件
    // 將輸出的文件都放在dist目錄下
    path: path.resolve(__dirname, './dist')
  }
};

如上配置,會輸出 main.js 和 main2.js馋辈。
內(nèi)置變量除了包括name抚芦,還包括,id, hash, chunkhash首有。

id: Chunk的唯一標(biāo)識燕垃,從0開始枢劝。
hash: Chunk的唯一標(biāo)識的Hash值井联。比如[hash:8] 代表8位的hash值。默認(rèn)是20位您旁。
chunkhash: Chunk內(nèi)容的Hash值烙常。

如下hash配置代碼:

entry: {
  'main': './js/main.js',
  'main2': './js/main2.js'
},
output: {
  filename: '[name]_[hash:8].js', // [name] 的值是entry的鍵值, 會輸出多個入口文件
  // 將輸出的文件都放在dist目錄下
  path: path.resolve(__dirname, './dist')
}

就會生成 main_xxxx.js 和 main2_xxxx.js 其中xxxx是hash值的隨機(jī)八位。

3.2 chunkFilename的理解
chunkFilename 和 filename非常類似,但是chunkFilename是未被列在entry中的蚕脏,但是又需要被打包出來的文件命名配置侦副,什么場景需要這樣的呢?
比如 異步按需加載模塊的時候驼鞭,一般這樣的文件沒有被列在entry中秦驯,比如如下項(xiàng)目在js文件內(nèi)再新建plugins文件夾,存放比如js插件使用的挣棕,目錄
結(jié)構(gòu)如下:

### 目錄結(jié)構(gòu)如下:
demo1                                       # 工程名
|   |--- dist                               # 打包后生成的目錄文件             
|   |--- node_modules                       # 所有的依賴包
|   |--- js                                 # 存放所有js文件
|   | |-- demo1.js  
|   | |-- main.js                           # js入口文件
|   | |-- main2.js                          # js的多個入口文件
|   | |-- plugins                           # plugins文件夾译隘,存放js插件類的
|   | | |--- a.js
|   |
|   |--- webpack.config.js                  # webpack配置文件
|   |--- index.html                         # html文件
|   |--- styles                             # 存放所有的css樣式文件                              
|   |--- .gitignore  
|   |--- README.md
|   |--- package.json

如上目錄結(jié)構(gòu) 在js文件夾內(nèi),再新建plugins文件夾洛心,里面包含一個a.js文件固耘;代碼如下:

function a() {
  console.log('a.js');
}
module.exports = a;

然后我們在main2.js入口文件如下編寫代碼;使用異步方式引用a.js; 代碼如下:

require.ensure(['./plugins/a.js'], function(require) {
  var aModule = require('./plugins/a.js');
}, 'a');

然后在webpack的output配置添加 chunkFilename 配置如下:

module.exports = {
  context: path.resolve(__dirname, ''),
  entry: {
    'main': './js/main.js',
    'main2': './js/main2.js'
  },
  output: {
    filename: '[name]_[hash:8].js', // [name] 的值是entry的鍵值, 會輸出多個入口文件
    chunkFilename: '[name].min.js', 
    // 將輸出的文件都放在dist目錄下
    path: path.resolve(__dirname, './dist')
  }
};

其中上面的 require.ensure() API的第三個參數(shù)是給這個模塊命名的词身,因此在webpack配置完成后厅目,繼續(xù)打包下,會在dist文件夾下打出 a.min.js 文件
了法严。所以這就是 chunkFilename 的用途場景了损敷。

3.3 publicPath的理解

output.path 是指所有輸出文件的本地文件目錄(絕對路徑)。比如配置如下:

output: {
  filename: 'bundle.js',
  // 將輸出的文件都放在dist目錄下
  path: path.resolve(__dirname, 'dist')
}

那么webpack會將所有文件輸出到 dist/下深啤。也就是說path是存放打包后的文件的輸出目錄嗤锉。

正式環(huán)境下publicPath的理解:
publicPath正式環(huán)境可以理解為改變相對目錄下的靜態(tài)資源文件的路徑為正確的路徑。比如圖片引入的是相對路徑墓塌,可以配置publicPath成為正確的路徑瘟忱。
它是指定資源文件引用的目錄(相對于服務(wù)器的根目錄來講)。

先看styles/main.css代碼如下:

#app {
  font-size: 18px;
  width: 200px;
  height: 200px;
  backround: url('../images/1.jpg') no-repeat;
}

iamges文件夾內(nèi)有一張圖片為1.jpg, 因此上面是css的引入路徑苫幢。然后手動創(chuàng)建 index.html代碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <link href="dist/main.css" rel="stylesheet" type="text/css" />
</head>
<body>
  <div id="app"></div>
  <script src="dist/bundle.js"></script>
</body>
</html>

現(xiàn)在我們執(zhí)行 npm run build 進(jìn)行打包后访诱,打開index.html發(fā)現(xiàn)css中圖片的引用的路徑為:backround: url(1.jpg) no-repeat; 很明顯圖片的引用路徑不對,它引入是根目錄下的圖片韩肝,因此如果我們在打包的時候加上 publicPath触菜,配置如下:

output: {
  filename: 'bundle.js',
  // 將輸出的文件都放在dist目錄下
  path: path.resolve(__dirname, 'dist'),
  publicPath: '/dist/'
}

重新打包下,再看下css引入路徑為 backround: url(/dist/1.jpg) no-repeat哀峻;說明引入是對的涡相。

開發(fā)環(huán)境下publicPath的理解:

output的配置如下:

output: {
  filename: 'bundle.js',
  // 將輸出的文件都放在dist目錄下
  path: path.resolve(__dirname, 'dist'),
  // publicPath: '/dist/'
}

然后把dist目錄刪除掉,執(zhí)行 npm run dev后剩蟀,開發(fā)環(huán)境打包后并沒有生成dist目錄催蝗,而我們的index.html引入了 dist/bundle.js 和 dist/main.css, 因此頁面會發(fā)現(xiàn)找不到j(luò)s和css文件。那么打包后文件放在那里去了呢育特?我們可以看如下圖:

啟動了webpack-dev-server, 然后整個項(xiàng)目運(yùn)行在localhost:8080下面丙号,也就是服務(wù)器地址是localhost:8080, 當(dāng)我們在瀏覽器中輸入服務(wù)器地址,服務(wù)器會簽就會到服務(wù)器請求js 文件犬缨,js的地址是dist/bundle.js喳魏, 沒有,報錯了怀薛。
看如上截圖的:wepback output is served from / , 這里指明了webpack 打包后文件放到了/ 目錄下刺彩,也就是根目錄下,webpack-dev-server 進(jìn)行打包時
它默認(rèn)把css和js及圖片打包到根目錄下枝恋。
現(xiàn)在把output配置改成如下:

output: {
  filename: 'bundle.js',
  // 將輸出的文件都放在dist目錄下
  path: path.resolve(__dirname, 'dist'),
  publicPath: '/dist/'
};

再進(jìn)行運(yùn)行下 npm run dev 后看到如下所示:

wepback output is served from /dist/ 這里指明了webpack 打包后文件放到了/dist/ 目錄下了迂苛,因?yàn)閖s和css文件可以重新訪問了。

3.4 crossOriginLoading

Webpack輸出的部分代碼有可能需要異步加載鼓择,而異步加載是通過JSON方式實(shí)現(xiàn)的三幻。JSONP的原理是動態(tài)地向HTML中插入一個<script src="url"></script>,crossOriginLoading則是用于配置這個異步插入的標(biāo)簽的 crossorigin的值呐能。

script標(biāo)簽的crossorigin屬性可以取以下的值:
1. anonymous(默認(rèn))念搬,啟用跨域加載,在加載此腳本資源時不會帶上用戶的Cookies; 即發(fā)送不帶憑據(jù)的 credential的請求摆出。
2. use-credentials 啟用跨域加載朗徊,在加載此腳本資源時會帶上用戶的Cookies. 發(fā)送帶憑據(jù)的credential的請求。
3. false 禁用跨域加載偎漫。

3.5 libraryTarget 和 library

這兩個屬性大家可能比較陌生爷恳,一般項(xiàng)目中不需要關(guān)注這兩個屬性,但是當(dāng)我們開發(fā)類庫象踊,使用webpack去構(gòu)建一個可以被其他模塊導(dǎo)入使用的庫時會使用到温亲。一般情況下,webpack對js模塊進(jìn)行打包杯矩,即多個js模塊和一個入口模塊栈虚,打包成一個bundle文件,可以直接被瀏覽器或者其他javascript引擎執(zhí)行史隆,

相當(dāng)于直接編譯生成一個完成的可執(zhí)行文件魂务。但是當(dāng)我們需要發(fā)布一個javascript庫的時候,比如在npm社區(qū)中發(fā)布自己的庫泌射,這個時候我們的webpack就需要相應(yīng)的配置.

libraryTarget 是配置以何種方式導(dǎo)出庫粘姜。可以是 var, commonjs, 'commonjs2', amd, this,umd模式等熔酷。
library 配置導(dǎo)出庫的名稱孤紧。
他們一般都組合使用的。

我們下面來編寫一個簡單的庫纯陨,假如名字叫 demo1.js坛芽,代碼如下:

function sayHello() {
  console.log('Hello');
}

function sayFunc() {
  console.log('say');
}

export default {
  sayHello: sayHello,
  sayFunc: sayFunc
}

然后我們在main.js代碼引入該文件

import foo from './demo1.js';

console.log(foo);
foo.sayHello(); // 可以執(zhí)行

webpack打包配置如下:

entry: './js/main.js',
output: {
  filename: 'bundle.js',
  // 將輸出的文件都放在dist目錄下
  path: path.resolve(__dirname, 'dist')
}

這樣會輸出一個立即執(zhí)行的函數(shù)留储,bundle代碼大致結(jié)構(gòu)如下:

(function(modules) { // webpackBootstrap
  var installedModules = {};
  function __webpack_require__(moduleId) {
    // ....
  }
  return __webpack_require__(__webpack_require__.s = "./js/main.js");
})
({
  "./js/demo1.js":
  (function(module, __webpack_exports__, __webpack_require__) {
      "use strict";
      eval("__webpack_require__.r(__webpack_exports__);\nfunction sayHello() {\n  console.log('Hello');\n}\n\nfunction sayFunc() {\n  console.log('say');\n}\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n  sayHello: sayHello,\n  sayFunc: sayFunc\n});\n\n//# sourceURL=webpack:///./js/demo1.js?");
  }),
  "./js/main.js":
  (function(module, __webpack_exports__, __webpack_require__) {
      "use strict";
      eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _demo1_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./demo1.js */ \"./js/demo1.js\");\n\n\nconsole.log(_demo1_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"]);\n_demo1_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].sayHello();\n\n\n\n//# sourceURL=webpack:///./js/main.js?");
  })
});

3.5.1 commonjs2 模式
如果我們需要將打包返回值交給編譯后的文件 module.export, 因此我們這邊可以使用 libraryTarget 和 library翼抠, webpack配置如下:

entry: './js/main.js',
output: {
  filename: 'bundle.js',
  // 將輸出的文件都放在dist目錄下
  path: path.resolve(__dirname, 'dist'),
  libraryTarget: 'commonjs2',
  library: 'util'
}

main.js 代碼如下:

import demo1 from './demo1.js';

demo1.js 代碼如下:

function sayHello() {
  console.log('Hello');
}

function sayFunc() {
  console.log('say');
}

export default {
  sayHello: sayHello,
  sayFunc: sayFunc
}

打包后的文件是如下格式代碼:

module.exports = (function(modules) { // webpackBootstrap
  var installedModules = {};
  function __webpack_require__(moduleId) {
    // ....
  }
  return __webpack_require__(__webpack_require__.s = "./js/main.js");
})
({
  "./js/demo1.js":
  (function(module, __webpack_exports__, __webpack_require__) {
      "use strict";
      eval("__webpack_require__.r(__webpack_exports__);\nfunction sayHello() {\n  console.log('Hello');\n}\n\nfunction sayFunc() {\n  console.log('say');\n}\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n  sayHello: sayHello,\n  sayFunc: sayFunc\n});\n\n//# sourceURL=webpack:///./js/demo1.js?");
  }),
  "./js/main.js":
  (function(module, __webpack_exports__, __webpack_require__) {
      "use strict";
      eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _demo1_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./demo1.js */ \"./js/demo1.js\");\n\n\nconsole.log(_demo1_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"]);\n_demo1_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].sayHello();\n\n\n\n//# sourceURL=webpack:///./js/main.js?");
  })
});

那么從npm社區(qū)下載庫后咙轩,使用庫的方法是如下:

const util1 = require('library-name-in-npm');
util1.xxx(); // xxx就是 某個方法名稱

3.5.2 commonjs
編寫的庫將通過commonjs導(dǎo)出。
webpack 配置代碼如下:

entry: './js/main.js',
output: {
  filename: 'bundle.js',
  // 將輸出的文件都放在dist目錄下
  path: path.resolve(__dirname, 'dist'),
  libraryTarget: 'commonjs',
  library: 'util'
}

打包后的文件變成如下代碼:

exports["util"] =
  (function(modules) { // webpackBootstrap
    var installedModules = {};
    function __webpack_require__(moduleId) {
      // ....
    }
    return __webpack_require__(__webpack_require__.s = "./js/main.js");
  })
  ({
    "./js/demo1.js":
   (function(module, __webpack_exports__, __webpack_require__) {
    "use strict";
    eval("__webpack_require__.r(__webpack_exports__);\nfunction sayHello() {\n  console.log('Hello');\n}\n\nfunction sayFunc() {\n  console.log('say');\n}\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n  sayHello: sayHello,\n  sayFunc: sayFunc\n});\n\n//# sourceURL=webpack://util/./js/demo1.js?");
  }),
    "./js/main.js":
    (function(module, __webpack_exports__, __webpack_require__) {
      "use strict";
      eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _demo1_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./demo1.js */ \"./js/demo1.js\");\n\n\n\n\n\n//# sourceURL=webpack://util/./js/main.js?");

    })
});

如上代碼:配置了 output.library = 'LibraryName'; webpack就會輸出代碼格式為:
exports['LibraryName'] = lib_code;

使用庫的方法代碼如下:

require('library-name-in-npm')['LibraryName'].doSomething();

注意:lib_code 為所有的webpack打包的代碼阴颖;library-name-in-npm 是指模塊被發(fā)布到npm代碼倉庫的名稱活喊。

3.5.3 this
編寫的庫將通過this被賦值給library指定的名稱。

webpack配置代碼如下:

entry: './js/main.js',
output: {
  filename: 'bundle.js',
  // 將輸出的文件都放在dist目錄下
  path: path.resolve(__dirname, 'dist'),
  libraryTarget: 'this',
  library: 'util'
}

打包后的js文件如下格式:

this["util"] =
  (function(modules) { // webpackBootstrap
    var installedModules = {};
    function __webpack_require__(moduleId) {
      // ....
    }
    return __webpack_require__(__webpack_require__.s = "./js/main.js");
  })
  ({
    "./js/demo1.js":
   (function(module, __webpack_exports__, __webpack_require__) {
    "use strict";
    eval("__webpack_require__.r(__webpack_exports__);\nfunction sayHello() {\n  console.log('Hello');\n}\n\nfunction sayFunc() {\n  console.log('say');\n}\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n  sayHello: sayHello,\n  sayFunc: sayFunc\n});\n\n//# sourceURL=webpack://util/./js/demo1.js?");
  }),
    "./js/main.js":
    (function(module, __webpack_exports__, __webpack_require__) {
      "use strict";
      eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _demo1_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./demo1.js */ \"./js/demo1.js\");\n\n\n\n\n\n//# sourceURL=webpack://util/./js/main.js?");

    })
});

使用庫的方法如下:

this.LibraryName.doSomething();

3.5.4 window
編寫的庫將通過window賦值給library指定的名稱量愧,輸出的代碼格式如下:
window['LibraryName'] = lib_code;

webpack的配置如下:

entry: './js/main.js',
output: {
  filename: 'bundle.js',
  // 將輸出的文件都放在dist目錄下
  path: path.resolve(__dirname, 'dist'),
  libraryTarget: 'window',
  library: 'util'
}

打包后的js代碼如下:

window["util"] =
  (function(modules) { // webpackBootstrap
    var installedModules = {};
    function __webpack_require__(moduleId) {
      // ....
    }
    return __webpack_require__(__webpack_require__.s = "./js/main.js");
  })
  ({
    "./js/demo1.js":
   (function(module, __webpack_exports__, __webpack_require__) {
    "use strict";
    eval("__webpack_require__.r(__webpack_exports__);\nfunction sayHello() {\n  console.log('Hello');\n}\n\nfunction sayFunc() {\n  console.log('say');\n}\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n  sayHello: sayHello,\n  sayFunc: sayFunc\n});\n\n//# sourceURL=webpack://util/./js/demo1.js?");
  }),
    "./js/main.js":
    (function(module, __webpack_exports__, __webpack_require__) {
      "use strict";
      eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _demo1_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./demo1.js */ \"./js/demo1.js\");\n\n\n\n\n\n//# sourceURL=webpack://util/./js/main.js?");

    })
});

使用庫的方法如下代碼:

window.LibraryName.doSomething();

3.5.5 global
編寫的庫將通過global賦值給通過library指定的名稱钾菊,即把庫掛載到global上,輸出格式的代碼如下:
global['LibraryName'] = lib_code;

和上面的window是一樣的偎肃,無非就是把window改成global煞烫;

使用庫的方法如下所示:

global.LibraryName.doSomething();

也可以打包成 'amd' 或 'umd' 模式結(jié)構(gòu)代碼, 在此介紹省略哦~

4. 模式(mode)

提供mode配置項(xiàng)累颂,告訴webpack使用對應(yīng)的模式滞详。

在webpack配置中提供mode選項(xiàng)。如下代碼:

module.exports = {
  mode: 'production' // 或開發(fā)環(huán)境下 'development'
};

注意:使用 development模式代碼不會被壓縮紊馏,使用 production 代碼會被壓縮料饥。

也可以在CLI參數(shù)中傳遞,比如如下代碼:

webpack --mode=production

5.理解使用Loader

我們都知道webpack是適用于資源進(jìn)行打包的朱监,里面的所有資源都是模塊岸啡,內(nèi)部實(shí)現(xiàn)了對模塊資源進(jìn)行加載機(jī)制,但是webpack只能處理js模塊赫编,如果要處理其他類型的文件巡蘸,就需要使用loader進(jìn)行轉(zhuǎn)換。Loader可以理解為是模塊和資源的轉(zhuǎn)換器擂送,它本身也是一個函數(shù)赡若,接收源文件作為參數(shù),返回轉(zhuǎn)換的結(jié)果团甲。

配置loader逾冬,需要使用rules模塊來讀取和解析規(guī)則,它是一個數(shù)組躺苦,數(shù)組里面中的每一項(xiàng)描述了如何處理部分文件身腻。
1. 條件匹配: 通過配置test,include匹厘,exclude三個配置項(xiàng)來選中l(wèi)oader需要應(yīng)用規(guī)則的文件嘀趟。
2. 應(yīng)用規(guī)則: 對選中的文件通過use配置項(xiàng)來應(yīng)用loader,可以只應(yīng)用一個loader或者按照從右往左的順序應(yīng)用一組loader(切記:loader使用順序是從右往左的)愈诚,也可以向loader傳入?yún)?shù)她按。
3. 重置順序: Loader執(zhí)行的順序默認(rèn)是從右到左執(zhí)行的牛隅,但是我們可以通過enforce選項(xiàng)可以將其中一個Loader的執(zhí)行順序放到最前或最后。

具體的配置代碼可以參考如下:

module.exports = {
  module: {
    rules: [
      {
        // 正則匹配 以 js結(jié)尾的
        test: /\.js$/,
        // babel 轉(zhuǎn)換js文件酌泰,?cacheDirectory 用于緩存babel的編譯結(jié)果媒佣,加快重新編譯的速度
        use: ['babel-loader?cacheDirectory'],
        // include只包含src目錄下的js文件,加快查找速度
        include: path.resolve(__dirname, 'src')
      },
      {
        // 正則匹配以 styl結(jié)尾的文件
        test: /\.styl$/,
        /* 
          use使用順序從右到左執(zhí)行陵刹,先使用stylus-loader插件去解析以styl結(jié)尾的文件成css文件默伍,
          再使用css-loader插件去讀取css文件,最后由 style-loader 將css的內(nèi)容注入到j(luò)avascript里面衰琐。
        */
        use: ['style-loader', 'css-loader', 'stylus-loader'],

        // 排除node_modules目錄下的文件
        exclude: path.resolve(__dirname, 'node_modules')
      },
      {
        // 對非文本文件采用file-loader去加載
        test: /\.(gif|png|jpe?g|eot|woff|ttf|svg|pdf)$/,
        use: ['file-loader']
      }
    ]
  }
}

注意:在loader需要傳入多個參數(shù)時也糊,我們可以通過一個Object來描述,如下面是babel-loader配置:

use: [
  {
    loader: 'babel-loader',
    options: {
      cacheDirectory: true
    },
    /*
      enforce: 'post' 的含義是將Loader執(zhí)行的順序放到最后
      enforce: 'pre' 的含義是將Loader執(zhí)行順序放到最前面
    */
    enforce: 'post'
  }
]

當(dāng)然羡宙,上面的test狸剃,include,exclude配置也可以傳入多個狗热,因此他們也支持?jǐn)?shù)組的方式來傳遞了钞馁。比如如下配置:

{
  test: [
    /\.js$/,
    /\.jsx$/
  ],
  include: [
    path.resolve(__dirname, 'src'),
    path.resolve(__dirname, 'src2')
  ],
  exclude: [
    path.resolve(__dirname, 'node_modules'),
    path.resolve(__dirname, 'node_modules2')
  ]
}

6.理解noParse

該配置項(xiàng)可以讓webpack忽略對部分未采用模塊化文件的遞歸解析和處理,該忽略的文件不能包含import斗搞,require指攒, define等模塊化語句。
那么這樣做的好處是可以提高構(gòu)建性能僻焚,比如像一些庫jquery等就沒有必要去使用webpack去遞歸解析和處理了允悦。
使用配置代碼如下:

module.exports = {
  module: {
    noParse: /jquery|xxjs/
  }
}

也可以使用函數(shù),但是webpack需要從3.0版本才支持虑啤;如下配置代碼:

module.exports = {
  module: {
    noParse: (content) => {
      // content代表一個模塊的文件路徑
      return /jquery|xxjs/.test(content);
    }
  }
}

7. 理解alias

resolve.alias 是通過別名來將原導(dǎo)入路徑映射成一個新的導(dǎo)入路徑隙弛。比如如下配置:

module.exports = {
  entry: './js/main.js',
  output: {
    filename: 'bundle.js',
    // 將輸出的文件都放在dist目錄下
    path: path.resolve(__dirname, 'dist')
  },
  resolve: {
    alias: {
      components: './src/components'
    }
  }
}

如上代碼配置,當(dāng)我通過 import xxx from 'components/xxx' 導(dǎo)入時狞山,實(shí)際上被alias替換成了
import xxx from './src/components/xxx';

8.理解extensions

在使用 import 導(dǎo)入文件時全闷,有時候沒有帶入文件的后綴名,webpack會自動帶上后綴去訪問文件是否存在萍启,那么默認(rèn)的后綴名為
['.js', '.json']; 即:
extensions: ['.js', '.json']; 如果我們想自己配置.vue后綴名总珠,防止在導(dǎo)入文件時候不需要加上后綴;我們可以使用webpack做如下配置:

module.exports = {
  entry: './js/main.js',
  output: {
    filename: 'bundle.js',
    // 將輸出的文件都放在dist目錄下
    path: path.resolve(__dirname, 'dist')
  },
  resolve: {
    alias: {
      components: './src/components'
    },
    extensions: ['.js', '.vue'];
  }
}

9.理解Externals

Externals 用來告訴webpack在構(gòu)建代碼時使用了不處理應(yīng)用的某些依賴庫勘纯,依然可以在代碼中通過AMD局服,CMD或window全局方式訪問。
什么意思呢驳遵?就是說我們在html頁面中引入了jquery源文件后淫奔,比如如下代碼:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <script src="http://code.jquery.com/jquery-1.12.0.min.js"></script>
  <link href="dist/main.css" rel="stylesheet" type="text/css" />
</head>
<body>
  <div id="app"></div>
  <script src="dist/bundle.js"></script>
</body>
</html>

但是我們想在模塊化的源代碼里導(dǎo)入和使用jquery,首先我們肯定需要安裝下 jquery依賴包堤结,npm install --save jquery, 然后我們編寫如下代碼進(jìn)行使用:

const $ = require('jquery');
console.log($);

構(gòu)建打包后我們會發(fā)現(xiàn)輸出的文件里面包含jquery的內(nèi)容唆迁,這導(dǎo)致了jquery庫引入了兩次鸭丛,并且導(dǎo)致了bundle.js文件變得更大,浪費(fèi)加載流量唐责。因此 Externals 配置項(xiàng)就是來解決這個問題的鳞溉。

通過externals 可以告訴webpack在javascript運(yùn)行環(huán)境中已經(jīng)內(nèi)置了哪些全局變量,不用將這些代碼打包到代碼里面去妒蔚。
因此我們可以做如下配置:

module.export = {
  externals: {
    jquery: 'jQuery'
  }
};
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末穿挨,一起剝皮案震驚了整個濱河市月弛,隨后出現(xiàn)的幾起案子肴盏,更是在濱河造成了極大的恐慌,老刑警劉巖帽衙,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件菜皂,死亡現(xiàn)場離奇詭異,居然都是意外死亡厉萝,警方通過查閱死者的電腦和手機(jī)恍飘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來谴垫,“玉大人章母,你說我怎么就攤上這事◆婕簦” “怎么了乳怎?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長前弯。 經(jīng)常有香客問我蚪缀,道長,這世上最難降的妖魔是什么恕出? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上豪直,老公的妹妹穿的比我還像新娘吗伤。我一直安慰自己,他們只是感情好的畴,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布渊抄。 她就那樣靜靜地躺著,像睡著了一般苗傅。 火紅的嫁衣襯著肌膚如雪抒线。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天渣慕,我揣著相機(jī)與錄音嘶炭,去河邊找鬼抱慌。 笑死,一個胖子當(dāng)著我的面吹牛眨猎,可吹牛的內(nèi)容都是我干的抑进。 我是一名探鬼主播,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼睡陪,長吁一口氣:“原來是場噩夢啊……” “哼寺渗!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起兰迫,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤信殊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后汁果,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體涡拘,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年据德,在試婚紗的時候發(fā)現(xiàn)自己被綠了鳄乏。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡棘利,死狀恐怖橱野,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情善玫,我是刑警寧澤水援,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站蝌焚,受9級特大地震影響裹唆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜只洒,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一许帐、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧毕谴,春花似錦成畦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至舀武,卻和暖如春拄养,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背银舱。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工瘪匿, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留跛梗,地道東北人。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓棋弥,卻偏偏與公主長得像核偿,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子顽染,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評論 2 353