webpack通俗易懂(四)

webpack通俗易懂(四)

  • 1唠粥,source-map
  • 2疏魏,devServer
  • 3, https
  • 4,eslint
  • 5晤愧,git-hooks 與 husky

辛苦編寫良久大莫,還望點贊鼓勵呦~

1,提高開發(fā)效率官份,完善團隊開發(fā)規(guī)范

1.1只厘,source-map

之前我們通過webpack, 將我們的源碼打包成了 bundle.js, 實際上客戶端(瀏覽器)讀取的是打包后的 bundle.js, 當瀏覽器執(zhí)行代碼報錯的時候,報錯的信息自然也是 bundle 的內(nèi)容舅巷。我們?nèi)绾螌箦e信息(bundle錯誤的語句及其所在行列)映射到源碼上羔味,這時候我們就需要用 source-map了,webpack已經(jīng)內(nèi)置了sourcemap功能钠右,我們只需要通過簡單的配置赋元,就可以開啟它

module.exports = {
  // 開啟 source map
  // 開發(fā)中推薦使用 'source-map' // 生產(chǎn)環(huán)境一般不開啟 sourcemap 
  devtool: 'source-map'
}

當我們執(zhí)行打包命令后,我們發(fā)現(xiàn)bundle的最后一行總是會多出一個注釋飒房,指向打包出的bundle.map.js(sourcemap文件)搁凸。 sourcemap文件用來描述源碼文件和 bundle 文件的代碼位置映射關(guān)系∏橐伲基于它坪仇,我們將bundle文件的錯誤信息映射到源碼文件上。
除開'source-map'外垃你,還可以基于我們的需求設(shè)置其他值椅文,webpack——devtool一共提供了7種SourceMap模式:

  • eval:每個module會封裝到 eval 里包裹起來執(zhí)行,并且會在末尾追加注釋 //@ sourceURL.
  • source-map:生成一個SourceMap文件
  • hidden-source-map:和 source-map一樣惜颇,但不會在 bundle 末尾追加注釋
  • inline-source-map:生成一個 DataUrl 形式的 SourceMap 文件.
  • eval-source-map:每個module會通過eval()來執(zhí)行皆刺,并且生成一個DataUrl形式的 SourceMap
  • cheap-source-map:生成一個沒有列信息(column-mappings)的SourceMaps文 件,不包含loader的 sourcemap(譬如 babel 的 sourcemap)
  • cheap-module-source-map:生成一個沒有列信息(column-mappings)的SourceMaps文件凌摄,同時 loader 的 sourcemap 也被簡化為只包含對應(yīng)行的羡蛾。

要注意的是,生產(chǎn)環(huán)境我們一般不會開啟sourcemap功能锨亏,主要有兩點原因:

  1. 通過bundle和sourcemap文件痴怨,可以反編譯出源碼————也就是說,線上產(chǎn)物有soucemap文件的話器予,就意味著有暴漏源碼的風險浪藻。
  2. 我們可以觀察到,sourcemap文件的體積相對比較巨大,這跟我們生產(chǎn)環(huán)境的追求不同(生產(chǎn)環(huán)境追求更小更輕量的bundle)乾翔。

有時候我們期望能第一時間通過線上的錯誤信息爱葵,來追蹤到源碼位置,從而快速解決掉bug以減輕損失。但又不希望sourcemap文件報漏在生產(chǎn)環(huán)境萌丈,有什么比較好的方案呢赞哗?

1.2,devServer

開發(fā)環(huán)境下辆雾,我們往往需要啟動一個web服務(wù)肪笋,方便我們模擬一個用戶從瀏覽器中訪問我們的web服務(wù),讀取我們的打包產(chǎn)物乾颁,以觀測我們的代碼在客戶端的表現(xiàn)涂乌。webpack內(nèi)置了這樣的功能,我們只需要簡單的配置就可以開啟它英岭。

安裝 devServer

yarn add -D webpack-dev-server

devServer.proxy基于強大的中間件 http-proxy-middleware 實現(xiàn)的湾盒,因此它支持很多的配置項,我們基于此诅妹,可以做應(yīng)對絕大多數(shù)開發(fā)場景的定制化配置罚勾。
基礎(chǔ)使用:

const path = require('path')
devServer: {
  static: {
    directory: path.join(__dirname, 'dist')
  }, // 默認是把dist目錄作為web服務(wù)的根目錄
  compress: true, // 可選擇開啟gzips壓縮功能,對應(yīng)靜態(tài)資源請求的響應(yīng)頭里的Content-Encoding: gzip
  port: 3000, // 端口號
},

為了方便吭狡,我們配置一下工程的腳本命令尖殃,在package.json的scripts里:

{
  "scripts": {
    "dev": "webpack serve --mode development"
  }
}
  • 1.2.1, 添加響應(yīng)頭

有些場景需求下,我們需要為所有響應(yīng)添加headers, 來對資源的請求和響應(yīng)打入標志划煮,以便做一些安全防范送丰,或者方便發(fā)生異常后做請求的鏈路追蹤。比如:

module.exports = {
  devServer: {
    headers: {
      'X-Token': 'ZlcjLCe+sAW1S4QC8Z'
    }
  }
}
image
  • 1.2.2, 開啟代理

我們打包出的js bundle里有時會含有一些對特定接口的網(wǎng)絡(luò)請求(ajax/fetch). 要注意弛秋,此時客戶端地址是在 http://localhost:3000/ 下器躏,假設(shè)我們的接口來自 http://localhost:4001/,那制臺就會報錯跨域蟹略,在開發(fā)環(huán)境下登失,我們可以使用devServer自帶的proxy功能來解決這個問題。

我們新搭建一個服務(wù)挖炬,在當前項目下新建 server.js:

const http = require('http');
const app = http.createServer((req, res) => {
  if (req.url === '/api/user') {
    res.end('hello node')
  }
})

app.listen(4001, 'localhost', () => {
  console.log('localhost listening on 4001')
})

再次打開一個終端執(zhí)行node server.js揽浙,啟動服務(wù)

image

瀏覽器輸入:

image

下面我們開始請求,請求我們可以使用瀏覽器自帶的方法fetch意敛,這個方法返回的是一個promise

fetch('/api/user')
  .then(val => val.text()) // res.text()可以把返回的結(jié)果變成文本)
  .then(res => {
    console.log(res)
  })
image

如何解決上面跨域的問題呢:

module.exports = {
  //...
  devServer: {
    proxy: {
      '/api': 'http://localhost:4001'
    }
  } 
}
// 如果用戶在地址欄一旦請求了一個資源叫 /api 的話馅巷,我們就給他指向到 http://localhost:4001 服務(wù)器上去

現(xiàn)在對 /api/user 的請求會將請求代理到 http://localhost:4001/api/user。如果不希望傳遞 /api草姻, 則可以重寫路徑:
proxy: {
  '/api': {
    target: 'http://localhost:4001',
    pathRewrite: {
      '^/api': '/'  // 這里可以是'/'也可以是''
    }
  }
}
image
  • 1.2.3令杈,https

默認情況下,將不接受在 HTTPS 上運行且證書無效的后端服務(wù)器碴倾。如果想讓我們的本地http服務(wù)改為https服務(wù),可以這樣配置:

devServer: {
  https: true
}

重新啟動服務(wù):npx webpack, 我們發(fā)現(xiàn)訪問http://localhost:port是無法訪問我們的服務(wù)的,我們需要在地址欄里加前綴: https跌榔,注意: 由于默認配置使用的是自簽名證書异雁,所以有的瀏覽器會告訴你是不安全的,但我們依然可以繼續(xù)訪問它僧须。當然我們也可以提供自己的證書:

module.exports = {
  devServer: {
    https: {
      cacert: './server.pem',
      pfx: './server.pfx',
      key: './server.key',
      cert: './server.crt',
      passphrase: 'webpack-dev-server',
      requestCert: true,
    }
  }
}
image
  • 1.2.4, http2

我們也可以不使用https纲刀,可以使用http2

如果想要配置http2,那么直接設(shè)置:

devServer: {
   http2: true
}

http2默認自帶https自簽名證書担平,當然我們?nèi)匀豢梢酝ㄟ^https配置項來使用自己的證書

image
  • 1.2.5, historyApiFallback

如果我們的應(yīng)用是個SPA(單頁面應(yīng)用)示绊,當路由到/some 時(可以直接在地址欄里輸入),會發(fā)現(xiàn)此時刷新頁面后暂论,控制臺會報錯:

GET http://localhost:3000/some 404 (Not Found)

此時打開network面褐,刷新并查看,就會發(fā)現(xiàn)問題所在———瀏覽器把這個路由當作了靜態(tài)資源的地址去請求取胎,然而我們并沒有打包出/some這樣的資源展哭,所以這個訪問無疑是404的。如何解決它?我們可以通過配置來提供頁面代替任何404的靜態(tài)資源響應(yīng):

module.exports = {
  //...
  devServer: {
    historyApiFallback: true
  }
}

此時重啟服務(wù)刷新后發(fā)現(xiàn)請求變成了index.html, 當然, 在多數(shù)業(yè)務(wù)場景下闻蛀,我們需要根據(jù)不同的訪問路徑定制替代的頁面匪傍,這種情況下,我們可以使用rewrites這個配置項觉痛。 類似這樣:

module.exports = {
  //...
  devServer: {
    historyApiFallback: {
      rewrites: [
        { from: /^\/$/, to: '/views/landing.html' },
        { from: /^\/subpage/, to: '/views/subpage.html' },
        { from: /./, to: '/views/404.html' },
      ]
    }
  }
}
  • 1.2.6, 開發(fā)服務(wù)器主機

如果我們在開發(fā)環(huán)境中起了一個devserve服務(wù)役衡,并希望在同一局域網(wǎng)下的同事也能訪問它,只需要配置:

devServer: {
  host: '0.0.0.0'
}

這時候薪棒,如果我們的同事跟我們處在同一局域網(wǎng)下手蝎,就可以通過局域網(wǎng)ip來訪問我們的服務(wù) 啦

image

1.3, 模塊熱替換與熱加載

  • 模塊熱替換
    模塊熱替換(HMR - hot module replacement)功能會在應(yīng)用程序運行過程中,
    替換盗尸、添加或刪除 模塊柑船,而無需重新加載整個頁面
module.exports = {
  //...
  devServer: {
    hot: true,
  },
}

HMR 加載樣式,如果我們配置了style-loader泼各,那么現(xiàn)在已經(jīng)同樣支持樣式文件的
熱替換功能了

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader'],
      },
    ],
  },
}

這是因為style-loader的實現(xiàn)使用了module.hot.accept鞍时,在CSS依賴模塊更新之后,
會對 style 標簽打補丁扣蜻。從而實現(xiàn)了這個功能逆巍。
熱加載(文件更新時,自動刷新我們的服務(wù)和頁面) 新版的webpack-dev-server
默認已經(jīng)開啟了熱加載的功能莽使。 它對應(yīng)的參數(shù)是devServer.liveReload锐极,默認為
true。 注意芳肌,如果想要關(guān)掉它灵再,要將liveReload設(shè)置為false的同時肋层,也要關(guān)掉
hot

image
module.exports = {
  //...
  devServer: {
    liveReload: false, //默認為true,即開啟熱更新功能翎迁。
  },
};

1.4栋猖,eslint

eslint是用來掃描我們所寫的代碼是否符合規(guī)范的工具。往往我們的項目是多人協(xié)作開發(fā)的汪榔,我們期望統(tǒng)一的代碼規(guī)范蒲拉,這時候可以讓eslint來對我們進行約束。嚴格意義上來說痴腌,eslint配置跟webpack無關(guān)雌团,但在工程化開發(fā)環(huán)境中,它往往是不可或缺的

yarn add eslint -D
npx eslint --init

我們可以看到控制臺里的展示:

image

并生成了一個配置文件(.eslintrc.json)士聪,這樣我們就完成了eslint的基本規(guī)則配置锦援。 eslint配置文件里的配置項含義如下:

    1. env 指定腳本的運行環(huán)境。每種環(huán)境都有一組特定的預(yù)定義全局變量戚嗅。此處使用的 browser 預(yù)定義了瀏覽器環(huán)境中的全局變量雨涛,es6 啟用除了 modules 以外的所有 ECMAScript 6 特性(該選項會自動設(shè)置 ecmaVersion 解析器選項為 6)。
    1. globals 腳本在執(zhí)行期間訪問的額外的全局變量懦胞。也就是 env 中未預(yù)定義替久,但我
      們又需要使用的全局變量。
    1. extends 檢測中使用的預(yù)定義的規(guī)則集合躏尉。
    1. rules 啟用的規(guī)則及其各自的錯誤級別蚯根,會合并 extends 中的同名規(guī)則,定義沖
      突時優(yōu)先級更高胀糜。
    1. parserOptions ESLint 允許你指定你想要支持的 JavaScript 語言選項颅拦。
      ecmaFeatures 是個對象,表示你想使用的額外的語言特性教藻,這里 jsx 代表啟用 JSX距帅。ecmaVersion 用來指定支持的 ECMAScript 版本 。默認為 5括堤,即僅支持 es5碌秸,你可以使用 6、7悄窃、8讥电、9 或 10 來指定你想要使用的 ECMAScript 版本。你 也可以用使用年份命名的版本號指定為 2015(同 6)轧抗,2016(同 7)恩敌,或 2017(同 8)或 2018(同 9)或 2019 (same as 10)。上面的 env 中啟用了 es6横媚,自動設(shè)置了ecmaVersion 解析器選項為 6纠炮。 plugins plugins 是一個 npm 包月趟,通常輸出 eslint 內(nèi)部未定義的規(guī)則實現(xiàn)。rules 和 extends 中定義的規(guī)則抗碰, 并不都在 eslint 內(nèi)部中有實現(xiàn)狮斗。比如 extends 中的 plugin:react/recommended,其中定義了規(guī)則開關(guān)和等級弧蝇,但是這些規(guī)則如何 生效的邏輯是在其對應(yīng)的插件 ‘react’ 中實現(xiàn)的

新建項目文件夾,并在繼承終端中打開:

yarn init -y
npm install eslint -D
npx eslint --init

新建src -> app.js

// app.js
console.log('hello eslit')

npx eslint ./src
// eslintrc.json
{
  "rules": {
    "no-console": "warn" // 可以在rules中自定義約束規(guī)范
  }
}

執(zhí)行npx eslint ./src就可以檢測出代碼是否存在語法錯誤等規(guī)范問題折砸,我們可以在控制臺看出哪些不符合規(guī)范看疗,這樣并不直觀,我們可以通過安裝vscode插件eslint醒目的看到代碼上有紅色波浪線??睦授。

我們可以通過命令來讓elisnt檢測代碼——在我們的package.scripts里添加一個腳本命令:

// package.json
{
  "scripts": {
    "eslint": "eslint ./src"
  }
}

然后執(zhí)行

eslint src

以上我們直觀的看到代碼規(guī)范錯誤是通過安裝vscode插件两芳,如果不想使用插件,又想實時提示報錯去枷,我們可以結(jié)合 webpack 的打包編譯功能來實現(xiàn)怖辆。

rules: [
  {
    test: /\.(js|jsx)$/,
    exclude: /node-modules/,
    use: ['babel-loader', 'eslint-loader']
  }
]

因為我們使用了devServer,因此需要在devServer下添加一個對應(yīng)的配置參數(shù):

module.exports = {
  devServer: {
    liveReload: false, //默認為true删顶,即開啟熱更新功能竖螃。
  }
}

現(xiàn)在我們就可以實時地看到代碼里的不規(guī)范報錯啦

1.5,git-hooks 與 husky

為了保證團隊里的開發(fā)人員提交的代碼符合規(guī)范逗余,我們可以在開發(fā)者上傳代碼時進行校驗特咆。我們常用 husky 來協(xié)助進行代碼提交時的 eslint 校驗。在使用husky之前录粱,我們先來研究一下 git-hooks

我們回到項目的根目錄下腻格。git init, ls -a 命令 ———— “-a”可以顯示隱藏目錄(目錄名的第一位是.)

image

接來下我們進入到這個文件夾,進一步查看它內(nèi)部的內(nèi)容

cd .git
ls -a
image

可以看到啥繁,當前目錄下存在一個hooks文件夾菜职,顧名思義,這個文件夾提供了git 命令相關(guān)的鉤子

cd hooks
ls -a
image

那我們可以看到有很多git命令相關(guān)的文件名旗闽。比如"pre-commit.sample pre- push.sample"酬核。 回到正題——我們期望在git提交(commit)前,對我們的代碼進行檢測宪睹,如果不能通 過檢測愁茁,就無法提交我們的代碼, 這個動作的時機應(yīng)該是?————"pre commit", 也就是 commit之前。

現(xiàn)在亭病,我們查看一下pre-commit.sample的內(nèi)容

# cat命令可以查看一個文件的內(nèi)容 
cat pre-commit.sample

OK鹅很,它返回了這樣的內(nèi)容,是一串shell注釋罪帖。翻譯過來大概意思是促煮,這是個示例鉤子邮屁,然后我們看到了這一句話

# To enable this hook, rename this file to "pre-commit"

意思是要啟用這個鉤子的話,我們就把這個文件的后綴名去掉菠齿。

雖然這樣對我們本地來講是可行的佑吝,但要注意,.git文件夾的改動無法同步到遠端倉庫

所以我們期望將git-hook的執(zhí)行權(quán)移交到外面來

好的绳匀,我們回到項目的根目錄下芋忿,然后我們新建一個文件夾,暫時命名為".mygithooks" 然后在此文件夾下疾棵,新增一個git-hook文件,命名為"pre-commit"戈钢,并寫入以下內(nèi)容:

echo pre-commit執(zhí)行啦

好了,我們新建了自己的git-hook是尔,但此時git并不能識別殉了。下面我們執(zhí)行這行命令:

# 項目根目錄下
git config core.hooksPath .mygithooks

上述命令給我們自己的文件,配置了git-hook的執(zhí)行權(quán)限拟枚。
但這個時候我們git commit的話薪铜,可能會報這樣的waring,并且沒有執(zhí)行我們的
shell:

hint: The 'pre-commit' hook was ignored because it's not set as
executable.
hint: You can disable this warning with `git config
advice.ignoredHook false`

這是因為我們的操作系統(tǒng)沒有給出這個文件的可執(zhí)行權(quán)限恩溅。
因此我們得再執(zhí)行這樣一句命令:

chmod +x .mygithooks/pre-commit

ok!現(xiàn)在我們嘗試執(zhí)行g(shù)it add . && git commit -m "any meesage"隔箍。 我們發(fā)現(xiàn)控制臺日志會先打印 “pre-commit執(zhí)行啦”。 這意味著成功啦!

總結(jié):

也就是說暴匠,我們搞git-hook的話鞍恢,要分三步走:

    1. 新增任意名稱文件夾以及文件pre-commit(這個文件名字比如跟要使用的git- hook名字一致)!
    1. 執(zhí)行以下命令來移交git-hook的配置權(quán)限
git config core.hooksPath .mygithooks
    1. 給這個文件添加可執(zhí)行權(quán)限:
chmod +x .mygithooks/pre-commit

然后就成功啦。 這時候我們可以在pre-commit里寫任意腳本每窖,比如:

eslint src

當eslint掃描代碼帮掉,出現(xiàn)error時,會在結(jié)束掃描時將退出碼設(shè)為大于0的數(shù)字窒典。 也就是會報錯蟆炊,這時候commit就無法往下執(zhí)行啦,我們成功的攔截了此次錯誤操作瀑志。

husky

husky在升級到7.x后涩搓,做了跟我們上述同樣的事。 安裝它之前劈猪,我們需要在package.json中的script里昧甘,先添加

"sctript": {
    //...others
    "prepare": "husky install"
}

prepare是一個npm鉤子,意思是安裝依賴的時候战得,會先執(zhí)行husky install命令充边。 這個命令就做了上述的123這三件事! 我們安裝了7.x的husky會發(fā)現(xiàn),項目根目錄下生成了.husky的文件夾。 當然浇冰,7.x的husky似乎是有bug的贬媒,如果不能正常使用,那么我們只需要驗證兩件事:

    1. 是否移交了git-hook的配置權(quán)限?
      執(zhí)行命令 "git config --list"查看core.hooksPath配置是否存在肘习,是否正確指向 了.husky际乘。
      如果沒有,我們只需要手動的給加上就行:
git config core.hooksPath .husky
  1. 是否是可執(zhí)行文件? 參考上述總結(jié)中的3即可 這時我們的husky就正常了
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末漂佩,一起剝皮案震驚了整個濱河市脖含,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌投蝉,老刑警劉巖器赞,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異墓拜,居然都是意外死亡,警方通過查閱死者的電腦和手機请契,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進店門咳榜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人爽锥,你說我怎么就攤上這事涌韩。” “怎么了氯夷?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵臣樱,是天一觀的道長。 經(jīng)常有香客問我腮考,道長雇毫,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任踩蔚,我火速辦了婚禮棚放,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘馅闽。我一直安慰自己飘蚯,他們只是感情好,可當我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布福也。 她就那樣靜靜地躺著局骤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪暴凑。 梳的紋絲不亂的頭發(fā)上峦甩,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天,我揣著相機與錄音搬设,去河邊找鬼穴店。 笑死撕捍,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的泣洞。 我是一名探鬼主播忧风,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼球凰!你這毒婦竟也來了狮腿?” 一聲冷哼從身側(cè)響起效诅,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤兄渺,失蹤者是張志新(化名)和其女友劉穎辜贵,沒想到半個月后脓杉,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體县昂,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡滑黔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年趁蕊,在試婚紗的時候發(fā)現(xiàn)自己被綠了目派。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片伊者。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡英遭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出亦渗,到底是詐尸還是另有隱情挖诸,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布法精,位于F島的核電站多律,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏搂蜓。R本人自食惡果不足惜狼荞,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望洛勉。 院中可真熱鬧粘秆,春花似錦、人聲如沸收毫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽此再。三九已至昔搂,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間输拇,已是汗流浹背摘符。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人逛裤。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓瘩绒,卻偏偏與公主長得像,于是被迫代替她去往敵國和親带族。 傳聞我的和親對象是個殘疾皇子锁荔,可洞房花燭夜當晚...
    茶點故事閱讀 45,512評論 2 359

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