npm(Node Package Manager)入門指南

本文是一篇英文blog翻譯繁调,原文"A Beginener's Guide to npm - the Node Package Manager", 作者 Michael Wanyoike Peter Dierx
Node.js使得在服務(wù)器端使用JavaScript編寫后臺(tái)應(yīng)用成為了可能款咖。它是基于google的V8 JavaScript運(yùn)行時(shí)環(huán)境構(gòu)建咏闪,使用C++編寫的阁危,這也意味著它運(yùn)行很快。最開始贷掖,它是為應(yīng)用的服務(wù)器環(huán)境準(zhǔn)備的昌屉,但是后來開發(fā)者開始用它創(chuàng)建工具來幫他們實(shí)現(xiàn)本地任務(wù)自動(dòng)化。此后福扬,基于Node的工具生態(tài)系統(tǒng)(如Grunt, GulpWebpack)開始出現(xiàn)并改變了前端開發(fā)的姿態(tài)腕铸。

本文更新與2017年8月6日,主要反映當(dāng)前的npm版本狀態(tài)铛碑,以及在version 5 中引入的一些改變狠裹。

為了使用Node.js中的工具(或者說是packages),我們首先需要能夠以一種有效的方式安裝并且管理它們汽烦。這就是npm-Node Package Manager發(fā)揮作用的地方涛菠。npm能安裝你想使用的包并且提供了一組很友好的使用接口。
我將在本文中講解一些使用npm的基礎(chǔ)知識(shí)撇吞,并展示怎樣在局部和全局模式下安裝俗冻,刪除,更新以及安裝特定版本的包牍颈,同時(shí)我也會(huì)說明怎樣使用package.json文件管理項(xiàng)目的依賴迄薄。
在開始使用npm之前,我們首先需要在系統(tǒng)中安裝它煮岁。

安裝Node.js

進(jìn)入Node.js 下載頁面并下載你需要的版本讥蔽。Windows和Mac有安裝器可以下載涣易,Linux則有預(yù)編譯號(hào)的二進(jìn)制文件和源代碼下載,也可以通過包管理器下載Node.js.
筆者使用Ubuntu的包管理器安裝nodejs的指令如下:

$ sudo apt install nodejs

安裝好node后冶伞,通過以下指令查看node的安裝位置和安裝版本:

$ which node
/usr/bin/node
$node --version
v6.10.3

為了驗(yàn)證Nodejs確實(shí)安裝成功新症,讓我們來運(yùn)行Node的交互式解釋器:

$ node
> console.log('Node is running');
Node is running
> .help
.break Sometimes you get stuck, this gets you out
.clear Alias for .break
.exit  Exit the repl
.help  Show repl options
.load  Load JS from a file into the REPL session
.save  Save all evaluated commands in this REPL session to a file
> .exit

以上代碼可以看出Node.js已經(jīng)成功安裝,現(xiàn)在我們可以將注意力集中在npm上响禽。npm被包含在了Nodejs的安裝中徒爹,可以通過以下命令驗(yàn)證:

$ which npm
/usr/bin/npm
$ npm --verison
3.10.10

Node Packaged Modules

npm能在局部或全局模式下安裝包。在局部模式下芋类,npm將包安裝在上一級(jí)工作目錄的node_modules文件夾中瀑焦;在全局模式下,npm將包安裝在{prefix}/lib/node_modules文件夾下梗肝,這個(gè)文件夾是root用戶所有的宾肺,{prefix}通常是/usr/usr/local齐唆。這意味著你必須有root權(quán)限才能在全局模式下安裝包,當(dāng)解析第三方依賴時(shí)可能會(huì)引發(fā)權(quán)限問題玖媚,這也是一個(gè)安全關(guān)注點(diǎn)精续“用蹋可以通過配置來改變?nèi)帜J较掳陌惭b位置。

改變?nèi)职惭b的位置

通過npm config指令查看當(dāng)前npm的配置:

$ npm config list
; cli configs
user-agent = "npm/3.10.10 node/v6.10.3 linux x64"

; userconfig /home/sitepoint/.npmrc
prefix = "/home/sitepoint/.node_modules_global"

; node bin location = /usr/bin/nodejs
; cwd = /home/sitepoint
; HOME = /home/sitepoint
; "npm config ls -l" to show all defaults.

以上指令給了我們相關(guān)的安裝信息重付,現(xiàn)在最重要的是獲取當(dāng)前的全局包的安裝位置:

$ npm config get prefix
/usr

這個(gè)前綴是我們需要修改的顷级,我們將它改成home目錄。首先在home創(chuàng)建一個(gè)新的文件夾:

$ cd ~ && mkdir .node_modules_global
$ npm confi set prefix=$HOME/.node_modules_global

通過這樣簡(jiǎn)單地修改配置确垫,我們已經(jīng)修改了全局包的安裝位置弓颈,同時(shí)在home目錄下創(chuàng)建了一個(gè).npmrc文件。

$ npm config get prefix
/home/sitepoint/.node_modules_global
$ cat .npmrc
prefix=/home/sitepoint/.node_modules_global

此時(shí)删掀,在系統(tǒng)的某個(gè)地方翔冀,我們?nèi)匀挥幸粋€(gè)root用戶所有的npm安裝。但是因?yàn)槲覀冃薷牧巳职陌惭b位置披泪,我們可以利用這一點(diǎn)纤子。我們需要重新安裝npm,但是這一次將它安裝在當(dāng)前登錄用戶所有的目錄下款票。重新安裝會(huì)安裝最新版本的npm控硼。

$ npm install npm --global
└─┬ npm@5.0.2
  ├── abbrev@1.1.0
  ├── ansi-regex@2.1.1
....
├── wrappy@1.0.2
└── write-file-atomic@2.1.0

最后,我們需要將.node_modules_global/bin添加在$PATH環(huán)境變量艾少,這樣我們就能直接從命令行運(yùn)行全局包卡乾。通過在.profile, .bash_profile.bashrc中添加以下語句

export PATH="$HOME/.node_modules_global/bin:$PATH"

重新啟動(dòng)terminal即可。
現(xiàn)在我們的.node_modules_global/bin目錄下的npm會(huì)首先被找到并使用:

$ which npm
/home/sitepoint/.node_modules_global/bin/npm
$ npm --version
5.0.2

在全局模式下安裝包

現(xiàn)在我們只在全局模式下安裝了包-npm本身這個(gè)包∧范ぃ現(xiàn)在讓我們安裝 UglifyJS
(一個(gè)JavaScript最小化工具)说订。我們使用--global標(biāo)記抄瓦,為了簡(jiǎn)化,也可以使用-g

$ npm install uglify-js --global
/home/sitepoint/.node_modules_global/bin/uglifyjs -> /home/sitepoint/.node_modules_global/lib/node_modules/uglify-js/bin/uglifyjs
+ uglify-js@3.0.15
added 4 packages in 5.836s

從輸出中可以看到陶冷,有額外的包被安裝了-這些包是UglifyJS的依賴钙姊。

列出全局包

我們可以通過npm list指令列出已經(jīng)安裝的全局包

$ npm list --global
home/sitepoint/.node_modules_global/lib
├─┬ npm@5.0.2
│ ├── abbrev@1.1.0
│ ├── ansi-regex@2.1.1
│ ├── ansicolors@0.3.2
│ ├── ansistyles@0.1.3
....................
└─┬ uglify-js@3.0.15
  ├─┬ commander@2.9.0
  │ └── graceful-readlink@1.0.1
  └── source-map@0.5.6

可以看到輸出非常多,通過--depth=0選項(xiàng)值看主要的包:

$ npm list -g --depth=0
/home/sitepoint/.node_modules_global/lib
├── npm@5.0.2
└── uglify-js@3.0.15

這樣好多了埂伦,只顯示我們通過命令安裝的包和它們的版本號(hào)煞额。
任何全局安裝的包都能通過命令行調(diào)用。例如沾谜,下面的指令展示了我們?cè)鯓邮褂肬glify來將example.js壓縮成example.min.js

$ uglifyjs example.js -o example.min.js

在局部模式下安裝包

當(dāng)在局部模式下安裝包時(shí)膊毁,通常會(huì)用到一個(gè)package.json文件。下面讓我們開始創(chuàng)建一個(gè)基跑。

$ npm init
package name: (project)
version: (1.0.0)
description: Demo of package.json
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)

一路回車使用默認(rèn)值婚温,然后輸入yes進(jìn)行確認(rèn)。這樣就會(huì)在項(xiàng)目的根路徑下生成一個(gè)package.json文件媳否。系統(tǒng)生成的package.json格式如下:

{
  "name": "project",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

小提示:如果想快速生成一個(gè)package.json文件栅螟,使用npm init --y指令就行。

除了mainscripts這兩個(gè)字段篱竭,其他的都不需要再作解釋力图。main字段是整個(gè)程序的入口點(diǎn),scripts字段指明了在包的生命周期的不同時(shí)刻能執(zhí)行的腳本命令掺逼。目前我們不需要管這些吃媒,但是如果你想了解的更多,參考 package.json documentation on npmusing npm as a build tool這兩篇文章.
現(xiàn)在讓我們嘗試安裝Underscore.

$ npm install underscore
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN project@1.0.0 No description
npm WARN project@1.0.0 No repository field.

+ underscore@1.8.3
added 1 package in 0.344s

注意到創(chuàng)建了一個(gè)lockfile吕喘。我們?cè)诤竺嬖儆懻撨@個(gè)

現(xiàn)在如果我們?cè)倏匆幌?code>package.json文件赘那,我們會(huì)發(fā)現(xiàn)dependencies字段下添加了新的條目:

{
  ...
  "dependencies": {
    "underscore": "^1.8.3"
  }
}

通過package.json文件管理依賴

正如你前面所看到的那樣,UnderScore v1.8.3被安裝到了我們的項(xiàng)目中氯质。最前面的^符號(hào)表示npm在安裝這個(gè)包時(shí)會(huì)安裝它們找到的與主版本匹配(除非有package-lock.json)的最高的版本漓概。在我們的例子中,這表示任何低于v2.0.0的包病梢。這種版本依賴(major.minor.patch)的方法被稱為語義版本(semantic versioning)胃珍。這里是更多詳細(xì)信息: Semantic Versioning: Why You Should Be Using it.
同時(shí)也要注意到Underscore被作為dependencies字段的一個(gè)屬性所保存,這是最新的npm版本的默認(rèn)行為蜓陌,這種行為被應(yīng)用于使應(yīng)用程序跑起來必須的包中觅彰。可以通過--save-dev標(biāo)記將包保存為devDependency钮热。devDependencies是開發(fā)階段需要的包填抬,例如運(yùn)行測(cè)試或轉(zhuǎn)譯代碼相關(guān)的包。
可以通過在package.json中添加private: true來組織私包意外發(fā)布隧期,這樣也能抑制npm install中生成的警告信息飒责。
到目前為止赘娄,使用package.json最大的原因是它能很方便地指明項(xiàng)目的依賴。例如宏蛉,當(dāng)你克隆別人的代碼時(shí)遣臼,你所需要做的就是在項(xiàng)目的跟路徑下執(zhí)行npm i指令,npm會(huì)解析并抓取那些使項(xiàng)目運(yùn)行起來所有必須的包拾并。我們會(huì)在后面詳細(xì)討論這點(diǎn)揍堰。
在結(jié)束本節(jié)之前,讓我們快速檢查一下Underscore使用在工作嗅义。在項(xiàng)目根目錄下創(chuàng)建一個(gè)test.js文件屏歹,并添加一下語句:

const _ = require('underscore');
console.log(_.range(5));

通過node test.js運(yùn)行這個(gè)文件,應(yīng)該能在屏幕上看到[0, 1, 2, 3, 4]的輸出之碗。

卸載本地包

npm是一個(gè)包管理器蝙眶,因此它必須具有刪除包的功能。我們假設(shè)當(dāng)前的Unserscore包引起了一些兼容性問題褪那,需要把這個(gè)包刪除然后安裝一個(gè)老版本械馆,如下:

$ npm uninstall underscore
removed 2 packages in 0.107s
$ npm list
project@1.0.0 /home/sitepoint/project
└── (empty)

安裝指定版本的包

現(xiàn)在可以安裝我們所需要的版本的Underscore包了,通過@符號(hào)添加版本號(hào):
$ npm install underscore@1.8.2

  • underscore@1.8.2
    added 1 package in 1.574s

$ npm list
project@1.0.0 /home/sitepoint/project
└── underscore@1.8.2

更新包

讓我們檢查Underscore包是否有更新:

$ npm outdated
Package     Current  Wanted  Latest  Location
underscore    1.8.2   1.8.3   1.8.3  project

Current列展示的是本地安裝的版本武通,Latest列展示的是最新的版本,Wanted列展示的是在不破壞已有代碼前提下我們能更新到的最新的版本
還記得前面提到的package-lock.json文件嗎珊搀?package-lock.json在npm v5中引入冶忱,是為了保證安裝項(xiàng)目的不同機(jī)器上的依賴相同。這個(gè)文件在執(zhí)行任何修改node_modulespackage.json的操作中自動(dòng)生成境析。
可以直接試一下囚枪。先刪除node_modules文件夾,然后執(zhí)行npm i指令劳淆。最新版本的npm會(huì)安裝Underscorev1.8.2(這個(gè)版本是在package-lock.json文件中指定的)链沼。由于語義版本的原因,更早版本的npm會(huì)安裝v1.8.3版本沛鸵,也可以通過手動(dòng)創(chuàng)建npm-shrinkwrap.json文件解決這個(gè)問題括勺。
現(xiàn)在我們假設(shè)最新的Underscore已經(jīng)修復(fù)了我們之前假設(shè)的問題,這時(shí)曲掰,我們就想把包進(jìn)行更新疾捍。npm update package-name用于更新包:

$ npm update underscore
+ underscore@1.8.3
updated 1 package in 0.236s

$ npm list
project@1.0.0 /home/sitepoint/project
└── underscore@1.8.3

小提示: 要想上面的指令工作,Underscore必須在package.json中列出來栏妖。我們也可以執(zhí)行npm update更新多個(gè)包乱豆。

搜索包

在本教程中,我們已經(jīng)使用了幾次mkdir指令吊趾。那么是否有node包也能執(zhí)行相同的功能呢宛裕?讓我們通過npm search來找以下:

$ npm search mkdir
NAME      | DESCRIPTION          | AUTHOR          | DATE       | VERSION
mkdir     | Directory crea…      | =joehewitt      | 2012-04-17 | 0.0.2
fs-extra  | fs-extra conta…      | =jprichardson…  | 2017-05-04 | 3.0.1
mkdirp    | Recursively mkdir,…  | =substack       | 2015-05-14 | 0.5.1
...

可以看到有一個(gè)mkdirp指令瑟啃,先進(jìn)行安裝:

$ npm install mkdirp
+ mkdirp@0.5.1
added 2 packages in 3.357s

現(xiàn)在創(chuàng)建一個(gè)mkdir.js文件,并且復(fù)制-粘貼以下代碼:

const mkdirp = require('mkdirp');
mkdirp('foo', function (err) {
  if (err) console.error(err)
  else console.log('Directory created!')
});

然后在terminal下運(yùn)行它:

$ node mkdir.js
Directory created!

重新安裝項(xiàng)目依賴

先再安裝一個(gè)包:

$ npm install request
+ request@2.81.0
added 54 packages in 15.92s

檢查package.json文件

"dependencies": {
  "mkdirp": "^0.5.1",
  "request": "^2.81.0",
  "underscore": "^1.8.2"
},

注意到依賴列表自動(dòng)更新了揩尸。在以前的npm版本中蛹屿,必須執(zhí)行npm install request --save才會(huì)將依賴保存到package.json文件中。如果你執(zhí)行安裝包但是不將它保存進(jìn)package.json文件中疲酌,使用--no-save即可蜡峰。
假設(shè)你將項(xiàng)目源碼克隆到另外一臺(tái)機(jī)器上了,此時(shí)需要安裝依賴朗恳。首先刪除node_modules文件夾湿颅,然后執(zhí)行npm install

$ rm -R node_modules
$ npm list
project@1.0.0 /home/sitepoint/project
├── UNMET DEPENDENCY mkdirp@^0.5.1
├── UNMET DEPENDENCY request@^2.81.0
└── UNMET DEPENDENCY underscore@^1.8.2

npm ERR! missing: mkdirp@^0.5.1, required by project@1.0.0
npm ERR! missing: request@^2.81.0, required by project@1.0.0
npm ERR! missing: underscore@^1.8.2, required by project@1.0.0

$ npm install
added 57 packages in 1.595s

再次看一下node_modules目錄,發(fā)現(xiàn)它被重新建立了粥诫。這樣你就能很簡(jiǎn)單地將代碼分享給別人油航,而不用把項(xiàng)目依賴的源代碼也打包分享。

管理緩存

當(dāng)npm安裝一個(gè)包怀浆,它就會(huì)保留一份副本谊囚。下次想再次安裝的時(shí)候就不需要聯(lián)網(wǎng)了。附件被魂村在home目錄下的.npm文件夾下执赡。

$ ls ~/.npm
anonymous-cli-metrics.json  _cacache  _locks  npm  registry.npmjs.org

隨著舊包的加入镰踏,這個(gè)目錄會(huì)變得很亂,因此時(shí)不時(shí)清理一下是很有必要的

$npm cache clean

如果系統(tǒng)上有多個(gè)node項(xiàng)目想要清理沙合,可以通過以下指令清理所有的node_modules目錄

find . -name "node_modules"  -type  d -exec rm -rf '{}' +

別名

你可能已經(jīng)注意到了奠伪,有多種方式來執(zhí)行npm命令。以下是一個(gè)常用的npm命令別名清單:

  • npm i <package> – 安裝本地包
  • npm i -g <package> – 安裝全局包
  • npm un <package> – 卸載本地包
  • npm up – 更新包
  • npm t – 運(yùn)行測(cè)試
  • npm ls – 列出已安裝的包
  • npm ll 或 npm la – 列出包時(shí)顯示詳細(xì)信息
    可以一次安裝多個(gè)包
    $ npm i express momemt lodash mongoose body-parser webpack
    如果想要學(xué)習(xí)所有常用的npm命令首懈,只需要執(zhí)行npm help即可绊率。也可以通過我們的文章10 Tips and Tricks That Will Make You an npm Ninja來了解更多。

版本管理

可以使用一些工具在同一臺(tái)機(jī)器上管理多個(gè)版本的node.js.其中一個(gè)是n究履,另一個(gè)是 nvm (Node Version Manager). 如果你對(duì)這些感興趣滤否,參考這篇文章Install Multiple Versions of Node.js using nvm.

結(jié)論

在本教程中,我講解了一些使用npm的基礎(chǔ)最仑,展示了怎樣從官網(wǎng)頁面安裝Node.js藐俺,怎樣修改全局包的位置(避免使用sudo)以及怎樣在局部和全局模式下安裝包,最后還講了關(guān)于刪除泥彤、更新以及安裝特定版本的包相關(guān)的東西紊搪。參考npm Github releases page了解更多新版本特性。
鎖著v5版本的到來全景,npm在向前端開發(fā)的世界里邁了一大步耀石。據(jù)它的COO所說,npm的用戶正在改變,大部分使用它的人不再用它來寫Node應(yīng)用了滞伟。相反揭鳞,它正成為前端開發(fā)中用于打包JavaScript的工具了(嚴(yán)格來說,可以使用它安裝任何東西)以及編寫現(xiàn)代JavaScript的一個(gè)集成部分了梆奈。那么野崇,你是否正在在項(xiàng)目中使用npm呢?如果沒有的話亩钟, 現(xiàn)在就是時(shí)候了乓梨。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市清酥,隨后出現(xiàn)的幾起案子扶镀,更是在濱河造成了極大的恐慌,老刑警劉巖焰轻,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件臭觉,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡辱志,警方通過查閱死者的電腦和手機(jī)蝠筑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來揩懒,“玉大人什乙,你說我怎么就攤上這事∫亚颍” “怎么了臣镣?”我有些...
    開封第一講書人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)和悦。 經(jīng)常有香客問我,道長(zhǎng)渠缕,這世上最難降的妖魔是什么鸽素? 我笑而不...
    開封第一講書人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮亦鳞,結(jié)果婚禮上馍忽,老公的妹妹穿的比我還像新娘。我一直安慰自己燕差,他們只是感情好遭笋,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著徒探,像睡著了一般瓦呼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上测暗,一...
    開封第一講書人閱讀 49,079評(píng)論 1 285
  • 那天央串,我揣著相機(jī)與錄音磨澡,去河邊找鬼。 笑死质和,一個(gè)胖子當(dāng)著我的面吹牛稳摄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播饲宿,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼厦酬,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了瘫想?” 一聲冷哼從身側(cè)響起仗阅,我...
    開封第一講書人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎殿托,沒想到半個(gè)月后霹菊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡支竹,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年旋廷,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片礼搁。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡饶碘,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出馒吴,到底是詐尸還是另有隱情扎运,我是刑警寧澤,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布饮戳,位于F島的核電站豪治,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏扯罐。R本人自食惡果不足惜负拟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望歹河。 院中可真熱鬧掩浙,春花似錦、人聲如沸秸歧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽键菱。三九已至谬墙,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背芭梯。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來泰國打工险耀, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人玖喘。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓甩牺,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親累奈。 傳聞我的和親對(duì)象是個(gè)殘疾皇子贬派,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

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