gulp自動化構(gòu)建案例

官網(wǎng):Gulp

代碼塊中的省略號晃财,代表相較于上次代碼未改動部分
github完整項目: pages-boilerplate

準(zhǔn)備內(nèi)容:

  1. 首先初始化項目,目錄如下圖
  2. 安裝 gulp蔓姚,作為開發(fā)時依賴項npm install --save-dev gulp
  3. 根目錄下新增gulpfile.js文件,此文件中構(gòu)建任務(wù)


    image.png

構(gòu)建任務(wù):

  • 樣式文件編譯

首先安裝gulp-sass到開發(fā)依賴

//gulpfile.js文件
const { src, dest } = require("gulp");
const sass = require("gulp-sass")(require("sass"));

const style = () => {
  return src("src/assets/styles/*.scss", { base: "src" })
    .pipe(sass())
    .pipe(dest("dist"));
};
module.exports = {
  style,
};

根目錄命令行執(zhí)行yarn gulp style驗證

  • 腳本編譯

首先安裝gulp-babel到開發(fā)依賴

const { src, dest } = require("gulp");
const babel = require("gulp-babel");

const script = () => {
  return src("src/assets/scripts/*.js", { base: "src" })
    .pipe(
      babel({
        presets: ["@babel/env"],
      })
    )
    .pipe(dest("dist"));
};
module.exports = {
  script,
};
  • 頁面模版編譯

首先安裝gulp-swig到開發(fā)依賴

const { src, dest } = require("gulp");
const swig = require("gulp-swig");

//假數(shù)據(jù)
const data = {
  menus: [
    {
      name: "Home",
      icon: "aperture",
      link: "index.html",
    },
    {
      name: "Features",
      link: "features.html",
    },
    {
      name: "About",
      link: "about.html",
    },
  ],
  pkg: require("./package.json"),
  date: new Date(),
};
const page = () => {
  return src("src/*.html", { base: "src" })
    .pipe(
      swig({
        data,
      })
    )
    .pipe(dest("dist"));
};
module.exports = {
  page,
};

根目錄命令行執(zhí)行yarn gulp compile驗證

  • 圖片和字體文件轉(zhuǎn)換

首先安裝gulp-imagemin到開發(fā)依賴

const imgage = () => {
  return src("src/assets/images/**", { base: "src" })
    .pipe(imagemin())
    .pipe(dest("dist"));
};
const font = () => {
  return src("src/assets/fonts/**", { base: "src" })
    .pipe(imagemin())
    .pipe(dest("dist"));
};

因為以上任務(wù)都是可以異步進行的,所有通過gulp提供的parallel方法轧拄,將以上任務(wù)組合起來

// gulpfile.js文件
const { src, dest, parallel } = require("gulp");
const sass = require("gulp-sass")(require("sass"));
const babel = require("gulp-babel");
const swig = require("gulp-swig");
const imagemin = require("gulp-imagemin");

const data = {
  menus: [
    {
      name: "Home",
      icon: "aperture",
      link: "index.html",
    },
    {
      name: "Features",
      link: "features.html",
    },
    {
      name: "About",
      link: "about.html",
    },
  ],
  pkg: require("./package.json"),
  date: new Date(),
};

const style = () => {
  return src("src/assets/styles/*.scss", { base: "src" })
    .pipe(sass())
    .pipe(dest("dist"));
};

const script = () => {
  return src("src/assets/scripts/*.js", { base: "src" })
    .pipe(
      babel({
        presets: ["@babel/env"],
      })
    )
    .pipe(dest("dist"));
};
const page = () => {
  return src("src/*.html", { base: "src" })
    .pipe(
      swig({
        data,
      })
    )
    .pipe(dest("dist"));
};
const imgage = () => {
  return src("src/assets/images/**", { base: "src" })
    .pipe(imagemin())
    .pipe(dest("dist"));
};
const font = () => {
  return src("src/assets/fonts/**", { base: "src" })
    .pipe(imagemin())
    .pipe(dest("dist"));
};
const compile = parallel(style, script, page, imgage, font);
module.exports = {
  compile,
};

以上,src目錄下文件處理完畢讽膏;接下來處理public

  • public處理及自動刪除dist目錄

首先安裝del到開發(fā)依賴

// gulpfile.js文件
const { src, dest, parallel, series } = require("gulp");
const sass = require("gulp-sass")(require("sass"));
const babel = require("gulp-babel");
const swig = require("gulp-swig");
const imagemin = require("gulp-imagemin");
const del = require("del");

...
const extra = () => {
  return src("public/**", { base: "public" }).pipe(dest("dist"));
};
const compile = parallel(style, script, page, image, font);
//因為要在編譯之前檩电,把dist目錄清除,所有用series再次組合
const build = series(clean, parallel(compile, extra));
module.exports = {
  compile,
  build,
  clean,
};

  • 自動加載插件

首先安裝gulp-load-plugins到開發(fā)依賴府树,然后只需要把所有g(shù)ulp-開頭的插件引用更改為plugins.+插件不包括gulp-的內(nèi)容
例:(gulp-babel改為plugins.babel)

// gulpfile.js
const { src, dest, parallel, series } = require("gulp");
const sass = require("gulp-sass")(require("sass"));
// 刪除即可
// const plugins.babel = require("gulp-babel");
// const plugins.swig = require("gulp-swig");
// const plugins.imagemin = require("gulp-imagemin");
const del = require("del");
const plugins = require("gulp-load-plugins")();

...
const script = () => {
  return src("src/assets/scripts/*.js", { base: "src" })
    .pipe(
      plugins.babel({
        presets: ["@babel/env"],
      })
    )
    .pipe(dest("dist"));
};
const page = () => {
  return src("src/*.html", { base: "src" })
    .pipe(
      plugins.swig({
        data,
      })
    )
    .pipe(dest("dist"));
};
const image = () => {
  return src("src/assets/images/**", { base: "src" })
    .pipe(plugins.imagemin())
    .pipe(dest("dist"));
};
const font = () => {
  return src("src/assets/fonts/**", { base: "src" })
    .pipe(plugins.imagemin())
    .pipe(dest("dist"));
};
...

  • 開發(fā)服務(wù)器

首先安裝browser-sync到開發(fā)依賴
這里只記錄簡單用法是嗜,具體可參考官網(wǎng)^

// 實現(xiàn)這個項目的構(gòu)建任務(wù)
const { src, dest, parallel, series } = require("gulp");
...
const browserSync = require("browser-sync").create();
...
const serve = () => {
  browserSync.init({
    files: "dist/**", //files指定文件,監(jiān)聽到變化就自動刷新(注:此配置只會監(jiān)聽dist目錄挺尾,而src不會鹅搪,因為src修改后需要重新編譯,下面會處理)
    server: "dist",
  });
};
...
module.exports = {
  serve,
};

  • 監(jiān)聽文件變化以及構(gòu)建優(yōu)化

注意:可能因為swig模版引擎的緩存機制導(dǎo)致頁面不會變化遭铺,此時需要配置swig中的cache為false

  • 圖片和字體等文件在開發(fā)階段沒必要構(gòu)建丽柿,因為這些文件可能只是做了壓縮,并不影響頁面上的呈現(xiàn)效果魂挂,所以為了減小開發(fā)階段的開銷甫题,這些文件只在發(fā)布上線之前構(gòu)建
  • 所以對于圖片和public中的文件,在此直接請求源文件(非dist)
//gulpfile.js
const { src, dest, parallel, series, watch } = require("gulp");
...
const page = () => {
  return src("src/*.html", { base: "src" })
    .pipe(
      plugins.swig({
        data,
        defaults: { cache: false },  //配置成false涂召,防止緩存機制導(dǎo)致頁面不會變化
      })
    )
    .pipe(dest("dist"));
};
...
const serve = () => {
  watch("src/assets/styles/*.scss", script);
  watch("src/assets/scripts/*.js", script);
  watch("src/*.html", page);
  // watch("src/assets/images/**", image);
  // watch("src/assets/fonts/**", font);
  // watch("public/**", extra);

  // 想要監(jiān)聽public或者imgags變化坠非,可以利用browserSync提供的reload方法
  // 該 reload 方法會通知所有的瀏覽器相關(guān)文件被改動,要么導(dǎo)致瀏覽器刷新果正,要么注入文件炎码,實時更新改動盟迟。
  watch(
    ["src/assets/images/**", "src/assets/fonts/**", "public/**"],
    browserSync.reload()
  );
  browserSync.init({
    files: "dist/**", //files指定文件,監(jiān)聽到變化就自動刷新(注:此配置只會監(jiān)聽dist目錄潦闲,而src不會攒菠,因為src修改后需要重新編譯,下面會處理)
    server: {
      baseDir: ["dist", "src", "public"], //多個基目錄歉闰,在dist目錄下找不到就去src找辖众,否則就去public找,以此類推
    },
  });
};
...
//  構(gòu)建任務(wù)優(yōu)化
const compile = parallel(style, script, page);
// 上線之前執(zhí)行的任務(wù)
const build = series(clean, parallel(compile, extra, image, font));
// 開發(fā)階段執(zhí)行的任務(wù)
const develop = series(compile, serve);
module.exports = {
  build,
  clean,
  serve,
  develop,
};

  • useref文件引用及文件壓縮

針對html文件中和敬,會有一些node_modules中的引用文件凹炸,在開發(fā)階段,我們可以通過Browsersync模塊中server的routes做一個映射來解決

// index.html文件
<!DOCTYPE html>
<html lang="en">

<head>
  ...
  <!-- build:css assets/styles/vendor.css -->
  <link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.css">
  <!-- endbuild -->
...
// gulpfile.js文件
...
const serve = () => {
 ...
  browserSync.init({
    files: "dist/**", //files指定文件昼弟,監(jiān)聽到變化就自動刷新(注:此配置只會監(jiān)聽dist目錄啤它,而src不會,因為src修改后需要重新編譯私杜,下面會處理)
    server: {
      baseDir: ["dist", "src", "public"], //多個基目錄蚕键,在dist目錄下找不到就去src找,否則就去public找衰粹,以此類推
      routes: {
        "/node_modules": "node_modules",  //通過映射锣光,獲取node_modules下的引用
      },
    },
  });
};
...

但是線上環(huán)境此方法行不通了,useref插件便可以解決這個問題(注:它只負責(zé)合并铝耻,不負責(zé)壓縮誊爹,配合gulp-if插件可實現(xiàn)壓縮
gulp-useref這是一款可以將html引用的多個css和js合并起來,減小依賴的文件個數(shù)瓢捉,從而減少瀏覽器發(fā)起的請求次數(shù)频丘。gulp-useref根據(jù)注釋將html中需要合并壓縮的區(qū)塊找出來,對區(qū)塊內(nèi)的所有文件進行合并

useref插件會自動處理html中的構(gòu)建注釋泡态,構(gòu)建注釋模塊由build:開始搂漠,endbulid結(jié)束,中間內(nèi)容都是引入模塊某弦,build:后會跟標(biāo)記桐汤,說明引入的是js或css,最后再指定一個路徑靶壮,最終注釋模塊內(nèi)的引入都是打包到這一個路徑中

//  構(gòu)建注釋
<!-- build:css assets/styles/vendor.css -->
  <link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.css">
<!-- endbuild -->

使用前后對比

  • index.html

    vs

  • index.html

接下來開始壓縮文件
要壓縮的文件有html css js怔毛,所有分別安裝gulp-clean-css gulp-htmlmin gulp-uglify到開發(fā)依賴,另外我們需要針對不同文件做不同壓縮腾降,所以還需安裝gulp-if

...
const useref = () => {
  // 為啥不是src下的文件呢拣度,因為src下的html是模版,沒有意義,必須得是生成后的dist目錄才有意義
  return (
    src("dist/*.html", { base: "dist" })
      .pipe(plugins.useref({ searchPath: ["dist", "."] }))
      // html js css
      .pipe(plugins.if(/\.js$/, plugins.uglify()))
      .pipe(plugins.if(/\.css$/, plugins.cleanCss()))
      .pipe(
        plugins.if(
          /\.html$/,
          plugins.htmlmin({
            collapseWhitespace: true, //壓縮html的空白行
            minifyCSS: true, //壓縮html中的css
            minifyJS: true, //壓縮html中的js
          })
        )
      )
      .pipe(dest("release")) //因為放到dist目錄抗果,可能導(dǎo)致讀寫沖突筋帖,所以臨時寫一個目錄
  );
};
...

  • 重新規(guī)劃構(gòu)建過程

原本打包上線的目錄應(yīng)該是dist目錄,但是因為上述打包過程防止讀寫沖突窖张,臨時把文件放在了release目錄幕随,這個時候蚁滋,我們需要上線的應(yīng)該是release目錄宿接,而release目錄又沒有圖片和字體文件,所以需要重新調(diào)整辕录;

其實睦霎,在useref之前生成的文件算是一個中間產(chǎn)物,所以應(yīng)該把script走诞,page副女,style這些任務(wù)生成的文件放在一個臨時目錄,然后useref拿到臨時目錄文件蚣旱,轉(zhuǎn)換后再放到最終目錄dist碑幅;(因為image,font塞绿,extra這三個任務(wù)在打包上線之前才會做沟涨,不會影響useref,所以直接放到dist)异吻;

所以修改后代碼如下:

//gulpfile.js文件
...
const clean = () => {
  return del(["dist", "temp"]);
};

const style = () => {
  return src("src/assets/styles/*.scss", { base: "src" })
    .pipe(sass())
    .pipe(dest("temp"));
};

const script = () => {
  return src("src/assets/scripts/*.js", { base: "src" })
    .pipe(
      plugins.babel({
        presets: ["@babel/env"],
      })
    )
    .pipe(dest("temp"));
};
const page = () => {
  return src("src/*.html", { base: "src" })
    .pipe(
      plugins.swig({
        data,
        defaults: { cache: false },
      })
    )
    .pipe(dest("temp"));
};
...
const serve = () => {
  watch("src/assets/styles/*.scss", script);
  watch("src/assets/scripts/*.js", script);
  watch("src/*.html", page);
  // 想要監(jiān)聽public或者imgags變化裹赴,可以利用browserSync提供的reload方法
  // 該 reload 方法會通知所有的瀏覽器相關(guān)文件被改動,要么導(dǎo)致瀏覽器刷新诀浪,要么注入文件棋返,實時更新改動。
  watch(
    ["src/assets/images/**", "src/assets/fonts/**", "public/**"],
    browserSync.reload()
  );
  browserSync.init({
    files: "dist/**", //files指定文件雷猪,監(jiān)聽到變化就自動刷新(注:此配置只會監(jiān)聽dist目錄睛竣,而src不會,因為src修改后需要重新編譯求摇,下面會處理)
    server: {
      baseDir: ["temp", "src", "public"], //多個基目錄射沟,在dist目錄下找不到就去src找,否則就去public找月帝,以此類推
      routes: {
        "/node_modules": "node_modules", //通過映射躏惋,獲取node_modules下的引用
      },
    },
  });
};
const useref = () => {
  // 為啥不是src下的文件呢,因為src下的html是模版嚷辅,沒有意義簿姨,必須得是生成后的dist目錄才有意義
  return (
    src("temp/*.html", { base: "temp" })
      .pipe(plugins.useref({ searchPath: ["temp", "."] }))
      // html js css
      .pipe(plugins.if(/\.js$/, plugins.uglify()))
      .pipe(plugins.if(/\.css$/, plugins.cleanCss()))
      .pipe(
        plugins.if(
          /\.html$/,
          plugins.htmlmin({
            collapseWhitespace: true, //壓縮html的空白行
            minifyCSS: true, //壓縮html中的css
            minifyJS: true, //壓縮html中的js
          })
        )
      )
      .pipe(dest("dist")) //因為放到dist目錄,可能導(dǎo)致讀寫沖突,所以臨時寫一個目錄
  );
};
const compile = parallel(style, script, page);
// 上線之前執(zhí)行的任務(wù)
// 因為useref依賴compile任務(wù)扁位,所以兩者同步組合准潭,然后和其他任務(wù)異步組合
const build = series(
  clean,
  parallel(series(compile, useref), extra, image, font)
);
// 開發(fā)階段執(zhí)行的任務(wù)
const develop = series(compile, serve);
module.exports = {
  build,
  clean,
  serve,
  compile,
  develop,
  useref,
};

如下圖:命令行構(gòu)建日志可以驗證任務(wù)配置沒問題

  • image.png

  • 完整版gulpfile.js

只暴露必要的任務(wù)

// 實現(xiàn)這個項目的構(gòu)建任務(wù)
const { src, dest, parallel, series, watch } = require("gulp");
const sass = require("gulp-sass")(require("sass"));
const del = require("del");
const plugins = require("gulp-load-plugins")();
const browserSync = require("browser-sync").create();

const data = {
  menus: [
    {
      name: "Home",
      icon: "aperture",
      link: "index.html",
    },
    {
      name: "Features",
      link: "features.html",
    },
    {
      name: "About",
      link: "about.html",
    },
  ],
  pkg: require("./package.json"),
  date: new Date(),
};

const clean = () => {
  return del(["dist", "temp"]);
};

const style = () => {
  return src("src/assets/styles/*.scss", { base: "src" })
    .pipe(sass())
    .pipe(dest("temp"));
};

const script = () => {
  return src("src/assets/scripts/*.js", { base: "src" })
    .pipe(
      plugins.babel({
        presets: ["@babel/env"],
      })
    )
    .pipe(dest("temp"));
};
const page = () => {
  return src("src/*.html", { base: "src" })
    .pipe(
      plugins.swig({
        data,
        defaults: { cache: false },
      })
    )
    .pipe(dest("temp"));
};
const image = () => {
  return src("src/assets/images/**", { base: "src" })
    .pipe(plugins.imagemin())
    .pipe(dest("dist"));
};
const font = () => {
  return src("src/assets/fonts/**", { base: "src" })
    .pipe(plugins.imagemin())
    .pipe(dest("dist"));
};
const extra = () => {
  return src("public/**", { base: "public" }).pipe(dest("dist"));
};

const serve = () => {
  watch("src/assets/styles/*.scss", script);
  watch("src/assets/scripts/*.js", script);
  watch("src/*.html", page);
  // 想要監(jiān)聽public或者imgags變化,可以利用browserSync提供的reload方法
  // 該 reload 方法會通知所有的瀏覽器相關(guān)文件被改動域仇,要么導(dǎo)致瀏覽器刷新刑然,要么注入文件,實時更新改動暇务。
  watch(
    ["src/assets/images/**", "src/assets/fonts/**", "public/**"],
    browserSync.reload()
  );
  browserSync.init({
    files: "dist/**", //files指定文件泼掠,監(jiān)聽到變化就自動刷新(注:此配置只會監(jiān)聽dist目錄,而src不會垦细,因為src修改后需要重新編譯择镇,下面會處理)
    server: {
      baseDir: ["temp", "src", "public"], //多個基目錄,在dist目錄下找不到就去src找,否則就去public找,以此類推
      routes: {
        "/node_modules": "node_modules", //通過映射厦画,獲取node_modules下的引用
      },
    },
  });
};
const useref = () => {
  // 為啥不是src下的文件呢,因為src下的html是模版吝梅,沒有意義,必須得是生成后的dist目錄才有意義
  return (
    src("temp/*.html", { base: "temp" })
      .pipe(plugins.useref({ searchPath: ["temp", "."] }))
      // html js css
      .pipe(plugins.if(/\.js$/, plugins.uglify()))
      .pipe(plugins.if(/\.css$/, plugins.cleanCss()))
      .pipe(
        plugins.if(
          /\.html$/,
          plugins.htmlmin({
            collapseWhitespace: true, //壓縮html的空白行
            minifyCSS: true, //壓縮html中的css
            minifyJS: true, //壓縮html中的js
          })
        )
      )
      .pipe(dest("dist")) //因為放到dist目錄惹骂,可能導(dǎo)致讀寫沖突苏携,所以臨時寫一個目錄
  );
};
const compile = parallel(style, script, page);
// 上線之前執(zhí)行的任務(wù)
// 因為useref依賴compile任務(wù),所以兩者同步組合析苫,然后和其他任務(wù)異步組合
const build = series(
  clean,
  parallel(series(compile, useref), extra, image, font)
);
// 開發(fā)階段執(zhí)行的任務(wù)
const develop = series(compile, serve);
module.exports = {
  build,
  clean,
  develop,
};

也可在package.json中配置腳本兜叨,方便執(zhí)行

//package.json文件
{
  "scripts": {
    "clean": "gulp clean",
    "build": "gulp build",
    "develop": "gulp develop"
  },
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市衩侥,隨后出現(xiàn)的幾起案子国旷,更是在濱河造成了極大的恐慌,老刑警劉巖茫死,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件跪但,死亡現(xiàn)場離奇詭異,居然都是意外死亡峦萎,警方通過查閱死者的電腦和手機屡久,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來爱榔,“玉大人被环,你說我怎么就攤上這事∠暧模” “怎么了筛欢?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵浸锨,是天一觀的道長。 經(jīng)常有香客問我版姑,道長柱搜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任剥险,我火速辦了婚禮聪蘸,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘表制。我一直安慰自己健爬,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布夫凸。 她就那樣靜靜地躺著浑劳,像睡著了一般阱持。 火紅的嫁衣襯著肌膚如雪夭拌。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天衷咽,我揣著相機與錄音鸽扁,去河邊找鬼。 笑死镶骗,一個胖子當(dāng)著我的面吹牛桶现,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播鼎姊,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼骡和,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了相寇?” 一聲冷哼從身側(cè)響起慰于,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎唤衫,沒想到半個月后婆赠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡佳励,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年休里,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赃承。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡妙黍,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出瞧剖,到底是詐尸還是另有隱情拭嫁,我是刑警寧澤,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站噩凹,受9級特大地震影響巴元,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜驮宴,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一逮刨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧堵泽,春花似錦修己、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至纹安,卻和暖如春尤辱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背厢岂。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工光督, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人塔粒。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓结借,卻偏偏與公主長得像,于是被迫代替她去往敵國和親卒茬。 傳聞我的和親對象是個殘疾皇子船老,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,619評論 2 354

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