Babel 7.1介紹 transform-runtime polyfill env

什么是Babel降狠?

Babel 是一個(gè)工具鏈榜配,主要用于在舊的瀏覽器或環(huán)境中將 ECMAScript 2015+ 代碼轉(zhuǎn)換為向后兼容版本的 JavaScript 代碼。

主要做的事情:

  • 語(yǔ)法轉(zhuǎn)換
  • 實(shí)現(xiàn)目標(biāo)環(huán)境缺少的功能(es2015+)
  • 源代碼轉(zhuǎn)換 (codemods)
  • 還有更多5叭臁(點(diǎn)開(kāi)這些視頻看看)

用法

在這里會(huì)介紹如何將用es2015+寫(xiě)的JavaScript代碼轉(zhuǎn)換為能在當(dāng)前瀏覽器正常執(zhí)行的代碼临燃。包括兩方面:語(yǔ)法轉(zhuǎn)換、功能補(bǔ)充(這里暫時(shí)叫這個(gè)名字烙心,之后會(huì)相信介紹)膜廊。

  1. 安裝這些必要的包
npm install --save-dev @babel/core @babel/cli @babel/preset-env
npm install --save @babel/polyfill
  1. 在根目錄創(chuàng)建一個(gè)babel.config.js的配置文件:
const presets = [
  [
    "@babel/env",
    {
      targets: {
        edge: "17",
        firefox: "60",
        chrome: "67",
        safari: "11.1",
      },
      useBuiltIns: "usage",
    },
  ],
];
module.exports = { presets };
  • targets:表示編譯出的代碼想要支持的瀏覽器版本
  • useBuiltIns:之后詳細(xì)解釋
  1. 執(zhí)行命令
./node_modules/.bin/babel src --out-dir lib

然后你用es2015+編寫(xiě)的代碼就被轉(zhuǎn)化為能在目標(biāo)瀏覽器正常運(yùn)行的代碼了。

如何運(yùn)行的淫茵?

所有你用到的babel包都是被單獨(dú)發(fā)布在@babel作用域下(v7開(kāi)始)爪瓜,比如@babel/preset-env匙瘪、@babel/core铆铆、 @babel/cli,因?yàn)閎abel是插拔式的丹喻,所以用到什么安裝什么薄货,每個(gè)包各司其職。

@babel/core

其中最核心的包就是@babel/core碍论,它主要的作用就是編譯:

npm install --save-dev @babel/core

然后你可以在代碼里直接使用:

const babel = require("@babel/core");
babel.transform("code", optionsObject);

這里的optionsObject就和之前的babel.config.js是一樣的谅猾,如何編譯代碼,編譯成什么樣子什么標(biāo)準(zhǔn)用什么東西都在這里配置鳍悠。

@babel/cli

為什么我們能在命令行里直接使用:

./node_modules/.bin/babel src --out-dir lib

光有core是無(wú)法在命令行使用這些功能的税娜,@babel/cli支持你直接在命令行中編譯代碼。
這句話會(huì)編譯你src目錄下的所有js代碼藏研,并編譯成你想要的那樣(babel.config.js配置的)巧涧,并輸出到lib目錄下。
如果我們沒(méi)有配置babel.config.js遥倦,那么執(zhí)行這句話之后src會(huì)被原封不動(dòng)的搬到lib下(格式除外)谤绳。

--out-dir 代表輸出到哪個(gè)目錄下,你可試試--help看其他的用法袒哥,如果在這里我們沒(méi)有配置babel.config.js缩筛,我們可以通過(guò)--plugins 或者 --presets告訴 代碼應(yīng)該編譯成什么樣子。

Plugins & Presets

plugins顧名思義就是組件堡称,一個(gè)小型的js代碼程序告訴Babel
如何轉(zhuǎn)換你的源碼瞎抛,你可以自己寫(xiě)plugins也可以在github上使用別人寫(xiě)好的。來(lái)看如何使用一個(gè)插件:@babel/plugin-transform-arrow-functions

npm install --save-dev @babel/plugin-transform-arrow-functions

./node_modules/.bin/babel src --out-dir lib --plugins=@babel/plugin-transform-arrow-functions

@babel/plugin-transform-arrow-functions組件的作用就是將es2015的箭頭函數(shù)轉(zhuǎn)換成普通函數(shù):

// src/foo.js:
const fn = () => 1;

// converted to

// lib/foo.js:
var fn = function fn() {
  return 1;
};

當(dāng)然却紧,es2015有這么多新的語(yǔ)法桐臊,我們不可能一一的去引用每個(gè)plugins來(lái)編譯我們的代碼吧胎撤,于是就又了presets,顧名思義——預(yù)設(shè)断凶,它包含了一組我們需要的plugins伤提。就像plugin一樣,你也可以編寫(xiě)一組你最需要的plugins成為一個(gè)preset认烁。

目前這里有一個(gè)非常優(yōu)秀的preset叫env —— @babel/preset-env肿男。

npm install --save-dev @babel/preset-env

./node_modules/.bin/babel src --out-dir lib --presets=@babel/env

不需要任何配置,這個(gè)preset包含了所有現(xiàn)代js(es2015 es2016等)的所有新特性却嗡,你也可以傳遞一些配置給env舶沛,精準(zhǔn)實(shí)現(xiàn)你想要的編譯效果。

配置

更具你的需求窗价,配置肯定是不一樣的如庭,這里貼一個(gè)官方推薦配置:

const presets = [
  [
    "@babel/env",
    {
      targets: {
        edge: "17",
        firefox: "60",
        chrome: "67",
        safari: "11.1",
      },
    },
  ],
];

module.exports = { presets };

這個(gè)配置只配置了prsets,其實(shí)還可以配置plugins撼港。

Polyfill

中文翻譯是墊片柱彻,之前沒(méi)有詳細(xì)了解babel之前,我也很迷茫這個(gè)polyfill是啥餐胀,因?yàn)檎Z(yǔ)法不都給你轉(zhuǎn)換好了哟楷,還需要這個(gè)東西干啥,后來(lái)仔細(xì)想了一下否灾,要適應(yīng)新特性應(yīng)該從兩方面入手:

  1. 語(yǔ)法轉(zhuǎn)換:
() => {};

for (let i of items) {};

比如箭頭函數(shù)卖擅、for...of,在不支持這些語(yǔ)法的環(huán)境下墨技,直接會(huì)報(bào)語(yǔ)法錯(cuò)誤惩阶,因?yàn)榫幾g器根本不知道 =>這些是什么鬼符號(hào),要做到讓編譯器識(shí)別扣汪,那就要將這樣的語(yǔ)法轉(zhuǎn)換成瀏覽器能識(shí)別的代碼断楷,那么就需要語(yǔ)法轉(zhuǎn)換。

然后這里回到我們最開(kāi)始安裝包那里:

npm install --save-dev @babel/core @babel/cli @babel/preset-env
npm install --save @babel/polyfill

仔細(xì)看我們安裝core cli env都是 --save-dev崭别,這是因?yàn)槲覀儼l(fā)布的代碼都是編譯好的代碼冬筒,這些都只是開(kāi)發(fā)依賴,發(fā)布的代碼不需要依賴這些包茅主。

  1. 功能補(bǔ)充
'foo'.includes('f');

es2015里不僅只有新的語(yǔ)法舞痰,還有實(shí)例的擴(kuò)展,比如String诀姚,其實(shí)這里只是調(diào)用了String實(shí)例的一個(gè)方法响牛,我們無(wú)論怎么語(yǔ)法轉(zhuǎn)換也沒(méi)有什么用吧,如果我們?cè)诓恢С諷tring.prototype.includes的編譯器里跑這些代碼,會(huì)得到 'foo'.includes is not a function. 這樣的一個(gè)報(bào)錯(cuò)呀打,而不是語(yǔ)法報(bào)錯(cuò)矢赁。

Polyfill提供的就是一個(gè)這樣功能的補(bǔ)充,實(shí)現(xiàn)了Array贬丛、Object等上的新方法撩银,實(shí)現(xiàn)了Promise、Symbol這樣的新Class等瘫寝。到這里應(yīng)該能明白了蜒蕾,為什么安裝@babel/polyfill沒(méi)有-dev稠炬,因?yàn)榫退愦a發(fā)布后焕阿,編譯后的代碼依然會(huì)依賴這些新特性來(lái)實(shí)現(xiàn)功能。

雖然@babel/polyfill提供了我們想要的所有新方法新類首启,但是這里依然存在一些問(wèn)題:

  1. 體積太大:比如我只用了String的新特性暮屡,但是我把整個(gè)包都引進(jìn)來(lái)了,毅桃,這不是徒增了很多無(wú)用的代碼褒纲。
  2. 污染全局環(huán)境:如果你引用了 @babel/polyfill,那么像Promise這樣的新類就是掛載在全局上的钥飞,這樣就會(huì)污染了全局命名空間莺掠。可能在一個(gè)團(tuán)建建立的項(xiàng)目問(wèn)題不太大读宙,但是如果你是一個(gè)工具的開(kāi)發(fā)者彻秆,你把全局環(huán)境污染了,別人用你的工具结闸,就有可能把別人給坑了唇兑。

一個(gè)解決方案就是引入transform runtime 來(lái)替代 @babel/polyfill

幸運(yùn)的是桦锄,我們有env這個(gè)preset扎附,它又一個(gè)useBuiltIns選項(xiàng),如果設(shè)置成"usage"结耀,那么將會(huì)自動(dòng)檢測(cè)語(yǔ)法幫你require你代碼中使用到的功能留夜。

const presets = [
  [
    "@babel/env",
    {
      targets: {
        edge: "17",
        firefox: "60",
        chrome: "67",
        safari: "11.1",
      },
      useBuiltIns: "usage",
    },
  ],
];

module.exports = { presets };

比如我在代碼中:

Promise.resolve().finally();

如果在edge17不支持這個(gè)特性的環(huán)境里運(yùn)行,將會(huì)幫你編譯成:

require("core-js/modules/es.promise.finally");

Promise.resolve().finally();

@babel/plugin-transform-runtime

npm install --save-dev @babel/plugin-transform-runtime

npm install --save @babel/runtime

主要功能:

  1. 避免多次編譯出helper函數(shù):
    Babel轉(zhuǎn)移后的代碼想要實(shí)現(xiàn)和原來(lái)代碼一樣的功能需要借助一些幫助函數(shù)图甜,比如:
class Person {}

會(huì)被轉(zhuǎn)換為:

"use strict";

function _classCallCheck(instance, Constructor) {
  if (!(instance instanceof Constructor)) {
    throw new TypeError("Cannot call a class as a function");
  }
}

var Person = function Person() {
  _classCallCheck(this, Person);
};

這里_classCallCheck就是一個(gè)helper函數(shù)香伴,試想下如果我們很多文件里都聲明了類,那么就會(huì)產(chǎn)生很多個(gè)這樣的helper函數(shù)具则,積少成多增大了代碼體積即纲。
這里的@babel/runtime包就聲明了所有需要用到的幫助函數(shù),而@babel/plugin-transform-runtime的作用就是將所有需要helper函數(shù)的文件博肋,依賴@babel/runtime包:

"use strict";

var _classCallCheck2 = require("@babel/runtime/helpers/classCallCheck");

var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);

function _interopRequireDefault(obj) {
  return obj && obj.__esModule ? obj : { default: obj };
}

var Person = function Person() {
  (0, _classCallCheck3.default)(this, Person);
};

這里就沒(méi)有再編譯出helper函數(shù)classCallCheck了低斋,而是直接引用了@babel/runtime中的helpers/classCallCheck蜂厅。

  1. 解決@babel/polyfill提供的類或者實(shí)例方法污染全局作用域的情況。
    @babel/plugin-transform-runtime會(huì)為代碼創(chuàng)建一個(gè)沙盒環(huán)境膊畴,為core-js這里內(nèi)建的實(shí)例提供假名掘猿,你可以無(wú)縫的使用這些新特性,而不需要使用require polyfill唇跨。

"foobar".includes("foo")稠通,這樣的實(shí)例方法仍然是不能正常執(zhí)行的,因?yàn)樗趻燧d在String.prototype上的买猖,如果需要使用這樣的實(shí)例方法改橘,還是不得不require('@babel/polyfill')

比如:

var sym = Symbol();

var promise = new Promise();

console.log(arr[Symbol.iterator]());

會(huì)被編譯成:

"use strict";

var _getIterator2 = require("@babel/runtime-corejs2/core-js/get-iterator");

var _getIterator3 = _interopRequireDefault(_getIterator2);

var _promise = require("@babel/runtime-corejs2/core-js/promise");

var _promise2 = _interopRequireDefault(_promise);

var _symbol = require("@babel/runtime-corejs2/core-js/symbol");

var _symbol2 = _interopRequireDefault(_symbol);

function _interopRequireDefault(obj) {
  return obj && obj.__esModule ? obj : { default: obj };
}

var sym = (0, _symbol2.default)();

var promise = new _promise2.default();

console.log((0, _getIterator3.default)(arr));

這樣像Symbol、Promise這樣的新類也不會(huì)污染全局環(huán)境了玉控。

用法:

配置在配置文件里飞主,以.babelrc舉例:
無(wú)選項(xiàng)配置:

{
  "plugins": ["@babel/plugin-transform-runtime"]
}

有選項(xiàng)配置(默認(rèn)值):

{
  "plugins": [
    [
      "@babel/plugin-transform-runtime",
      {
        "corejs": false,
        "helpers": true,
        "regenerator": true,
        "useESModules": false
      }
    ]
  ]
}

這個(gè)插件的默認(rèn)配置默認(rèn)用戶已經(jīng)提供了所有polyfillable APIs,因此想要無(wú)縫使用不污染全局環(huán)境的內(nèi)建功能需要特別標(biāo)明corejs高诺。

可選項(xiàng):

  • corejs:默認(rèn)false碌识,或者數(shù)字:{ corejs: 2 },代表需要使用corejs的版本虱而。

  • helpers:默認(rèn)是true筏餐,是否替換helpers。

  • polyfill :v7無(wú)該屬性

  • regenerator:默認(rèn)true牡拇,generator是否被轉(zhuǎn)譯成用regenerator runtime包裝不污染全局作用域的代碼魁瞪。

  • useESModules:默認(rèn)false,如果是true將不會(huì)用@babel/plugin-transform-modules-commonjs進(jìn)行轉(zhuǎn)譯诅迷,這樣會(huì)減小打包體積佩番,因?yàn)椴恍枰3终Z(yǔ)義。

  • false:

exports.__esModule = true;

exports.default = function(instance, Constructor) {
  if (!(instance instanceof Constructor)) {
    throw new TypeError("Cannot call a class as a function");
  }
};
  • true:
export default function(instance, Constructor) {
  if (!(instance instanceof Constructor)) {
    throw new TypeError("Cannot call a class as a function");
  }
}

babel-polyfill vs babel-runtime

以下出自:github -了解Babel 6生態(tài)

babel-polyfillbabel-runtime是達(dá)成同一種功能(模擬ES2015環(huán)境罢杉,包括global keywords趟畏,prototype methods,都基于core-js提供的一組polyfill和一個(gè)generator runtime)的兩種方式:

  1. babel-polyfill通過(guò)向全局對(duì)象和內(nèi)置對(duì)象的prototype上添加方法來(lái)達(dá)成目的滩租。這意味著你一旦引入babel-polyfill赋秀,像Map,Array.prototype.find這些就已經(jīng)存在了——全局空間被污染律想。

  2. babel-runtime不會(huì)污染全局空間和內(nèi)置對(duì)象原型猎莲。事實(shí)上babel-runtime是一個(gè)模塊,你可以把它作為依賴來(lái)達(dá)成ES2015的支持技即。

比如當(dāng)前環(huán)境不支持Promise著洼,你可以通過(guò)require(‘babel-runtime/core-js/promise’)來(lái)獲取Promise。這很有用但不方便。幸運(yùn)的是身笤,babel-runtime并不是設(shè)計(jì)來(lái)直接使用的——它是和babel-plugin-transform-runtime一起使用的豹悬。babel-plugin-transform-runtime會(huì)自動(dòng)重寫(xiě)你使用Promise的代碼,轉(zhuǎn)換為使用babel-runtime導(dǎo)出(export)的Promise-like對(duì)象液荸。

注意: 所以plugin-transform-runtime一般用于開(kāi)發(fā)(devDependencies)瞻佛,而runtime自身用于部署的代碼(dependencies),兩者配合來(lái)一起工作娇钱。

那么我們什么時(shí)候用babel-polyfill伤柄,什么時(shí)候用babel-runtime?

babel-polyfill會(huì)污染全局空間文搂,并可能導(dǎo)致不同版本間的沖突适刀,而babel-runtime不會(huì)。從這點(diǎn)看應(yīng)該用babel-runtime细疚。

但記住蔗彤,babel-runtime有個(gè)缺點(diǎn)川梅,它不模擬實(shí)例方法疯兼,即內(nèi)置對(duì)象原型上的方法,所以類似Array.prototype.find贫途,你通過(guò)babel-runtime是無(wú)法使用的吧彪。
最后,請(qǐng)不要一次引入全部的polyfills(如require('babel-polyfill'))丢早,這會(huì)導(dǎo)致代碼量很大姨裸。請(qǐng)按需引用最好。

@babel/preset-env

以下出自:github -Babel 7 及新用法

preset-env 是 JS 中的 autoprefixer 根據(jù)環(huán)境來(lái)應(yīng)用不同的plugins怨酝。支持的plugins超過(guò)babel-preset-latest(2015-2017)傀缩。

用法:

{
  "presets": [
    [
      "env",
      {
        "targets": { // 目標(biāo)環(huán)境
          "browsers": [ // 瀏覽器
            "last 2 versions",
            "ie >= 10"
          ],
          "node": "current" // node
        },
        "modules": true,  // 是否轉(zhuǎn)譯module syntax,默認(rèn)是 commonjs
        "debug": true, // 是否輸出啟用的plugins列表
        "spec": false, // 是否允許more spec compliant农猬,但可能轉(zhuǎn)譯出的代碼更慢
        "loose": false, // 是否允許生成更簡(jiǎn)單es5的代碼赡艰,但可能不那么完全符合ES6語(yǔ)義
        "useBuiltIns": false, // 怎么運(yùn)用 polyfill
        "include": [], // 總是啟用的 plugins
        "exclude": [],  // 強(qiáng)制不啟用的 plugins
        "forceAllTransforms": false, // 強(qiáng)制使用所有的plugins,用于只能支持ES5的uglify可以正確壓縮代碼
      }
    ]
  ],
}

這里主要需要注意的是useBuiltIns用于指定怎么處理polyfill斤葱,可以選值"usage" | "entry" | false慷垮,默認(rèn)是false

  • useBuiltIns: 'usage':當(dāng)每個(gè)文件里用到(需要polyfill的特性)時(shí)揍堕,在文件中添加特定的import語(yǔ)句料身。這可以保證每個(gè)polyfill的特性僅load一次。
/// input
var a = new Promise(); // a.js
var b = new Map(); // b.js
/// output
// a.js
import "core-js/modules/es6.promise";
var a = new Promise();
// b.js
import "core-js/modules/es6.map";
var b = new Map();
  • useBuiltIns: 'entry':替換import "@babel/polyfill" / require("@babel/polyfill")語(yǔ)句為獨(dú)立的(根據(jù)環(huán)境)需要引入的polyfill特性的import語(yǔ)句衩茸。
// input
import "@babel/polyfill";
// output
import "core-js/modules/es7.string.pad-start";
import "core-js/modules/es7.string.pad-end";

需要注意芹血,在整個(gè)項(xiàng)目中,"@babel/polyfill"只能require一次,否則報(bào)錯(cuò)幔烛。建議用獨(dú)立的entry文件引入隙畜。

  • useBuiltIns: false:對(duì)@babel/polyfill不做任何處理。

ReferenceError: regeneratorRuntime is not defined
需要注意说贝,當(dāng)你使用async/await并被preset-env轉(zhuǎn)譯后议惰,運(yùn)行時(shí)可能會(huì)出現(xiàn)以上錯(cuò)誤,這是因?yàn)椋?br> plugin-transform-regenerator使用regenerator來(lái)轉(zhuǎn)譯 async/generator 函數(shù)乡恕,但是它本身不包括regeneratorRuntime言询,你需要使用babel-polyfill/regenerator runtime來(lái)使regeneratorRuntime 存在。

通常情況下傲宜,加上transform-runtime plugin即可运杭。

參考文獻(xiàn):

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末报嵌,一起剝皮案震驚了整個(gè)濱河市虱咧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌锚国,老刑警劉巖腕巡,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異血筑,居然都是意外死亡绘沉,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)豺总,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)车伞,“玉大人,你說(shuō)我怎么就攤上這事喻喳×砭粒” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵沸枯,是天一觀的道長(zhǎng)日矫。 經(jīng)常有香客問(wèn)我,道長(zhǎng)绑榴,這世上最難降的妖魔是什么哪轿? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮翔怎,結(jié)果婚禮上窃诉,老公的妹妹穿的比我還像新娘杨耙。我一直安慰自己,他們只是感情好飘痛,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布珊膜。 她就那樣靜靜地躺著,像睡著了一般宣脉。 火紅的嫁衣襯著肌膚如雪车柠。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,031評(píng)論 1 285
  • 那天塑猖,我揣著相機(jī)與錄音竹祷,去河邊找鬼。 笑死羊苟,一個(gè)胖子當(dāng)著我的面吹牛塑陵,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蜡励,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼令花,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了凉倚?” 一聲冷哼從身側(cè)響起兼都,我...
    開(kāi)封第一講書(shū)人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎占遥,沒(méi)想到半個(gè)月后俯抖,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體输瓜,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瓦胎,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了尤揣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片搔啊。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖北戏,靈堂內(nèi)的尸體忽然破棺而出负芋,到底是詐尸還是另有隱情,我是刑警寧澤嗜愈,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布旧蛾,位于F島的核電站,受9級(jí)特大地震影響蠕嫁,放射性物質(zhì)發(fā)生泄漏锨天。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一剃毒、第九天 我趴在偏房一處隱蔽的房頂上張望病袄。 院中可真熱鬧搂赋,春花似錦、人聲如沸益缠。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)幅慌。三九已至宋欺,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間胰伍,已是汗流浹背迄靠。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留喇辽,地道東北人掌挚。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像菩咨,于是被迫代替她去往敵國(guó)和親吠式。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

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