Webpack系列——手把手教你使用Webpack搭建簡(jiǎn)易的React開發(fā)環(huán)境

文章首發(fā)于我的github及個(gè)人博客,github請(qǐng)看https://github.com/huruji/blog/issues/8舞虱,轉(zhuǎn)載請(qǐng)注明出處独撇。

在這篇文章中我們開始利用我們之前所學(xué)搭建一個(gè)簡(jiǎn)易的React開發(fā)環(huán)境厘灼,用以鞏固我們之前學(xué)習(xí)的Webpack知識(shí)义图。首先我們需要明確這次開發(fā)環(huán)境需要達(dá)到的效果:1、能夠編譯JSX語(yǔ)言 2蝌戒、css樣式使用Sass開發(fā) 3.能夠?qū)⒒A(chǔ)的ES6轉(zhuǎn)化為ES5 4.能夠使用ESLint在開發(fā)的時(shí)候?yàn)槲覀冏龃a風(fēng)格審查

首先串塑,安裝基本使用的webpack、webpack-dev-server

npm i webpack webpack-dev-server -D

基本頁(yè)面的生成

為了可以生成一個(gè)基本的頁(yè)面我們使用html-webpack-plugin北苟,為了方便我們定制桩匪,我們自己在src定義一個(gè)html文件,使用template指定這個(gè)文件友鼻。

安裝html-webpack-plugin

npm i html-webpack-plugin -D

在src文件夾下生成一個(gè)html文件傻昙,內(nèi)容如下:

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

在webpack.config.js中寫入以下內(nèi)容作為基本的設(shè)置:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const config = {
  entry: './src/main.js',
  output: {
    filename: 'bundle-[hash].js',
    path: path.join(__dirname, 'dist')
  },
  devtool:'inline-source-map',
  devServer: {
    contentBase: './dist',
    hot: true
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    new webpack.HotModuleReplacementPlugin()
  ]
}

module.exports = config;

此時(shí)在命令行中運(yùn)行以下命令可以看到一切正常運(yùn)行闺骚,盡管目前在瀏覽器上還沒(méi)有任何效果:

webpack-dev-server --open

編譯es6和jsx語(yǔ)言

在React開發(fā)的時(shí)候我們使用jsx語(yǔ)言和es6,因此需要使用babel對(duì)我們的開發(fā)進(jìn)行一個(gè)編譯妆档,使用babel即可:
安裝babel-loader:

npm i babel-loader -D

為了使用這個(gè)babel-loader僻爽,我們需要安裝babel-core(當(dāng)我們需要以編程方式使用babel時(shí)就需要安裝這個(gè)):

npm i babel-core -D

為了編譯es6和jsx需要安裝相應(yīng)的preset,即需要安裝babel-preset-react和babel-preset-es2015:

npm i babel-preset-es2015 babel-preset-react -D

在webpack的配置文件中引入babel-loader:

const config = {
  //....
  module:{
    rules: [
      {
        test: /\.(js|jsx)$/,
        use:[
          'babel-loader'
        ]
      }
    ]
  }
  // ......
}

module.exports = config;

配置babel的配置文件过吻,在.babelrc文件中寫入以下內(nèi)容:

{
  "presets": [
    "es2015",
    "react"
  ]
}

此時(shí)我們測(cè)試一下是否可以正常編譯jsx和es2015,安裝react和react-dom蔗衡,同時(shí)在src中的main.js和App.js寫入部分內(nèi)容

npm i react react-dom -S

main.js

import ReactDOM from 'react-dom';
import React from 'react';
import App from './App';

ReactDOM.render(<App />, document.getElementById('app'));

App.js

import React from 'react';

export default function () {
  return (
    <div className="header">
      React
    </div>
  );
}

在命令行運(yùn)行命令纤虽,可以發(fā)現(xiàn)瀏覽器已經(jīng)正常顯示了,也就是說(shuō)正常編譯了jsx和es6

webpack-dev-server --open

此時(shí)绞惦,整個(gè)webpack.config.js文件內(nèi)容如下:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const config = {
  entry: './src/main.js',
  output: {
    filename: 'bundle-[hash].js',
    path: path.join(__dirname, 'dist')
  },
  devtool:'inline-source-map',
  devServer: {
    contentBase: './dist',
    hot: true
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)/,
        use:[
          'babel-loader'
        ]
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      title:'React簡(jiǎn)易開發(fā)環(huán)境',
      template: './src/index.html'
    }),
    new webpack.HotModuleReplacementPlugin()
  ]
}

module.exports = config;

編譯Sass樣式

編譯Sass和之前文章提到的一樣逼纸,需要使用style-loader、css-loader济蝉、sass-loader杰刽,首先進(jìn)行安裝:

npm i style-loader css-loader sass-loader -D

因?yàn)閟ass-loader是依賴node-sass的,同時(shí)因?yàn)閟ass-loader的uri是相對(duì)于output的王滤,因此需要使用resolve-url-loader

npm i node-sass resolve-url-loader -D

在webpack.config.js中進(jìn)行配置:

const config = {
  // ......
  module: {
    rules: [
      //......
      {
        test: /\.(sass|scss|css)/,
        use: [
        "style-loader",
        "css-loader",
        "resolve-url-loader",
        "sass-loader?sourceMap"
        ]
      }
    ]
  },
  // ......
}

module.exports = config;

在src文件夾中新建一個(gè)名為sass的文件夾贺嫂,同時(shí)新建_header.scss、_variablers.scss雁乡、main.scss,三個(gè)文件內(nèi)容分別為:
_variablers.scss

$bgColor: red;
$fontColor: #fff;

_header.scss

.header{
    background: $bgColor;
    color: $fontColor;
    height:300px;
}

main.scss

@import "variables"
,"header"

在main.js中引入main.scss文件:

import './sass/main.scss';

此時(shí)再次運(yùn)行命令第喳,可以在瀏覽器中看到header部分的樣式已經(jīng)生效。

此時(shí)整個(gè)webpack.config.js文件內(nèi)容如下:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const config = {
  entry: './src/main.js',
  output: {
    filename: 'bundle-[hash].js',
    path: path.join(__dirname, 'dist')
  },
  devtool:'inline-source-map',
  devServer: {
    contentBase: './dist',
    hot: true
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)/,
        use:[
          'babel-loader'
        ]
      },{
        test: /\.(sass|scss|css)/,
        use: [
        "style-loader",
        "css-loader",
        "resolve-url-loader",
        "sass-loader?sourceMap"
        ]
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      title:'React簡(jiǎn)易開發(fā)環(huán)境',
      template: './src/index.html'
    }),
    new webpack.HotModuleReplacementPlugin()
  ]
}

module.exports = config;

配置ESLint為我們做代碼風(fēng)格檢查

使用eslint首先安裝eslint和eslint-loader:

npm i eslint eslint-loader -D

為了讓eslint支持es6我們需要將eslint的解析器修改為babel-eslint踱稍,使用npm安裝

npm i babel-eslint -D

在webpack.config.js中配置eslint-loader

const config = {
  // ......
  module: {
    rules: [
      {
        test: /\.(js|jsx)/,
        use:[
          'babel-loader',
          'eslint-loader'
        ]
      }
    ]
  },
  // ......
}

module.exports = config;

新建一個(gè)eslint的配置文件.eslintrc.js:

module.exports = {
  "parserOptions": {
    "ecmaVersion": 6,
    "sourceType": "module",
    "ecmaFeatures": {
      "jsx": true
    }
  },
  "env": {
    "browser": true,
    "node": true
  },
  "parser": "babel-eslint"
};

此時(shí)運(yùn)行命令行會(huì)發(fā)現(xiàn)正常運(yùn)行曲饱,原因是eslint默認(rèn)所有規(guī)則都是禁用的,我們?cè)?eslintrc.js中添加一條簡(jiǎn)單的禁用console的規(guī)則珠月,當(dāng)出現(xiàn)console時(shí)扩淀,將會(huì)報(bào)warning

module.exports = {
  "parserOptions": {
    "ecmaVersion": 6,
    "sourceType": "module",
    "ecmaFeatures": {
      "jsx": true
    }
  },
  "env": {
    "browser": true,
    "node": true
  },
  "parser": "babel-eslint",
  "rules": {
    "no-console": 1
  }
};

此時(shí)再次運(yùn)行命令,可以發(fā)現(xiàn)以下界面啤挎,控制臺(tái)已經(jīng)很明確的告訴我們驻谆,我們的App.js中出現(xiàn)了console,說(shuō)明此時(shí)eslint已經(jīng)生效庆聘。

console

但是在一個(gè)項(xiàng)目中我們?nèi)绻渲妹恳粋€(gè)規(guī)則會(huì)顯得非常麻煩旺韭,因此我們選擇使用airbnb的規(guī)則,使用npm安裝:

npm i eslint-config-airbnb -D

安裝完成之后可以發(fā)現(xiàn)控制臺(tái)告訴我們需要安裝eslint-plugin-jsx-a11y掏觉、eslint-plugin-import区端、eslint-plugin-react,同時(shí)安裝時(shí)應(yīng)該大于或者等于某個(gè)版本號(hào):

airbnb
npm i eslint-plugin-jsx-a11y@5.1.1 eslint-plugin-import@2.7.0 eslint-plugin-react@7.1.0 -D

在.eslintrc.js文件中使用extends指定繼承自airbnb的配置澳腹,如下:

module.exports = {
  "parserOptions": {
    "ecmaVersion": 6,
    "sourceType": "module",
    "ecmaFeatures": {
      "jsx": true
    }
  },
  "extends": "airbnb",
  "env": {
    "browser": true,
    "node": true
  },
  "parser": "babel-eslint",
  "rules": {
    "no-console": 1
  }
};

此時(shí)织盼,再次運(yùn)行命令之后可以發(fā)現(xiàn)杨何,在命令行和控制臺(tái)中都報(bào)出了我們的代碼風(fēng)格問(wèn)題,如下:


airbnb2

airbnb中的所有規(guī)則我們可以根據(jù)我們的需要進(jìn)行重寫沥邻,我們注意到其中一條error如下:

JSX not allowed in files with extension '.js'      react/jsx-filename-extension

前面的為相應(yīng)說(shuō)明危虱,后面的為規(guī)則,這條不允許我們?cè)?js文件中書寫JSX語(yǔ)言唐全,后面為對(duì)應(yīng)的規(guī)則埃跷,顯然是eslint-plugin-react插件的規(guī)則,我們可以重寫以允許我們?cè)?js文件中書寫JSX邮利,如下:

module.exports = {
  "parserOptions": {
    "ecmaVersion": 6,
    "sourceType": "module",
    "ecmaFeatures": {
      "jsx": true
    }
  },
  "extends": "airbnb",
  "env": {
    "browser": true,
    "node": true
  },
  "parser": "babel-eslint",
  "rules": {
    "no-console": 1,
    "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }]
  }
};

再次運(yùn)行可以發(fā)現(xiàn)這條error已經(jīng)不存在了弥雹。

在項(xiàng)目中解析圖片模塊

在之前的文章中我們已經(jīng)提到過(guò)了,我們可以使用file-loader來(lái)實(shí)現(xiàn):

npm i file-loader -D

在webpack.config.js中配置:

const config = {
  // ......
  module: {
    rules: [
      {
        test: /\.(png|jpg|svg|gif)/,
        use:[
          "file-loader"
        ]
      }
    ]
  },
  // ......
}

module.exports = config;

此時(shí)我們可以引入圖片資源了延届。

支持更多的ES6方法

我們?cè)谑褂胋abel的時(shí)候我們需要明確知道的一點(diǎn)是剪勿,babel默認(rèn)只是為我們轉(zhuǎn)化語(yǔ)法層面上的東西(如箭頭函數(shù)),并不會(huì)為我們?nèi)⒁恍┓椒ㄟM(jìn)行轉(zhuǎn)化為es2015的實(shí)現(xiàn)方庭,也就是說(shuō)如果我使用Array.of方法厕吉,如果瀏覽器不支持這個(gè)方法,及時(shí)按照上面的babel轉(zhuǎn)化也是依舊沒(méi)有辦法運(yùn)行的械念,我們可以在App.js中使用Array.of方法來(lái)測(cè)試一下头朱,如下:

Array.of(1,2,3,4).forEach(function(item){
        console.log(item);
    });

我們這次使用webpack命令直接在dist文件夾中生成相應(yīng)的文件,我們可以在js文件中找到以下內(nèi)容:


qq 20170912020314

這就驗(yàn)證了上文的說(shuō)法龄减,因此我們需要使用babel-polyfill
首先進(jìn)行安裝:

npm i install babel-polyfill -D

安裝完成之后我們需要在webpack的入口中進(jìn)行配置髓窜,將webpack的entry修改為以下內(nèi)容:

entry: ['babel-polyfill','./src/main.js']

開發(fā)與生產(chǎn)環(huán)境分離

我們現(xiàn)在使用webpack命令為我們打包一下內(nèi)容,我們會(huì)發(fā)現(xiàn)打包后的文件非常大欺殿,只有部分內(nèi)容卻打包之后有3000+kb寄纵,這是不能用在生產(chǎn)環(huán)境上的,如下:


default

文件體積太大一個(gè)重要原因是devtool開啟了inline-source-map方便我們定位bug脖苏,同時(shí)代碼沒(méi)有壓縮也是重要原因之一程拭,因此我們需要將開發(fā)和生產(chǎn)環(huán)境分離,使用不同的webpack配置棍潘。

還記得我們系列之前介紹的webpack-merge嗎恃鞋?我們通過(guò)這個(gè)插件可以將公共的配置分離到一起。首先進(jìn)行安裝

npm i webpack-merge -D

新建一個(gè)名為webpack.common.js文件作為公共配置亦歉,寫入以下內(nèi)容:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

const config = {
  entry: ['babel-polyfill','./src/main.js'],
  output: {
    filename: 'bundle-[hash].js',
    path: path.join(__dirname, 'dist')
  },
  plugins: [
    new HtmlWebpackPlugin({
      title:'React簡(jiǎn)易開發(fā)環(huán)境',
      template: './src/index.html'
    })
  ]
}

module.exports = config;

新建一個(gè)名為webpack.dev.js文件作為開發(fā)環(huán)境配置恤浪,寫入以下內(nèi)容:

const merge = require('webpack-merge');
const common = require('./webpack.common');
const webpack = require('webpack');

const config = merge(common, {
  devtool:'inline-source-map',
  devServer: {
    contentBase: './dist',
    hot: true
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)/,
        use:[
          'babel-loader',
          'eslint-loader'
        ]
      },{
        test: /\.(sass|scss|css)/,
        use: [
        "style-loader",
        "css-loader",
        "resolve-url-loader",
        "sass-loader?sourceMap"
        ]
      },{
        test: /\.(png|jpg|svg|gif)/,
        use:[
          "file-loader"
        ]
      }
    ]
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin()
  ]
});

module.exports = config;

剛剛我們提到我們?cè)陂_發(fā)環(huán)境中應(yīng)該壓縮混淆代碼同時(shí)精簡(jiǎn)輸出,因此需要使用uglifyjs-webpack-plugin插件肴楷,首先進(jìn)行安裝:

npm i uglifyjs-webpack-plugin -D

新建一個(gè)名為webpack.prod.js的文件作為生產(chǎn)環(huán)境配置水由,寫入以下內(nèi)容:

const merge = require('webpack-merge');
const common = require('./webpack.common');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');

const config = merge(common, {
  devtool:false,
  module: {
    rules: [
      {
        test: /\.(js|jsx)/,
        use:[
          'babel-loader'
        ]
      },{
        test: /\.(sass|scss|css)/,
        use: [
        "style-loader",
        "css-loader",
        "resolve-url-loader",
        "sass-loader?sourceMap"
        ]
      },{
        test: /\.(png|jpg|svg|gif)/,
        use:[
          "file-loader"
        ]
      }
    ]
  },
  plugins:[
    new UglifyJSPlugin()
  ]
});

module.exports = config;

因?yàn)樵陂_發(fā)時(shí)我們需要使用的命令是

webpack-dev-server --open --config webpack.dev.js

而在生產(chǎn)中我們需要使用的命令是

webpack --config webpack.prod.js

為了精簡(jiǎn)我們?cè)诿钚兄械妮斎胛覀儗⑦@些命令寫在package.json中

"scripts": {
    "dev": "webpack-dev-server --open --colors --progress --inline --config webpack.dev.js",
    "build": "webpack --colors --progress --config webpack.prod.js"
  }

此時(shí)我們只要在命令行中輸入npm run dev即可開啟開發(fā)環(huán)境,使用npm run build即可自動(dòng)生成用于生產(chǎn)環(huán)境的文件赛蔫。

使用clean-webpack-plugin

現(xiàn)在還有一個(gè)問(wèn)題是我們修改文件之后再次使用npm run build命令則會(huì)出現(xiàn)多個(gè)js文件砂客,這是因?yàn)槲覀兪褂昧薶ash占位符泥张,這個(gè)占位符可以保證用戶訪問(wèn)網(wǎng)站時(shí)始終保持最新的js文件,因此我們使用clean-webpack-plugin幫助我們每次刪除dist文件夾的內(nèi)容

npm i clean-webpack-plugin -D

在webpack.prod.js中引用:

const merge = require('webpack-merge');
const common = require('./webpack.common');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');

const config = merge(common, {
  // ......
  plugins:[
    new CleanWebpackPlugin(['./dist']),
    new UglifyJSPlugin()
  ]
});

module.exports = config;

開發(fā)src目錄劃分

雖然目前一個(gè)簡(jiǎn)易的React開發(fā)環(huán)境已經(jīng)搭建好了鞠值,但是還是需要對(duì)src目錄進(jìn)行劃分以保證良好的開發(fā)體驗(yàn)媚创,以下是劃分的目錄:

└───Components
      └───......
      └───......
└───Containers
      └───......
      └───......
└───static
      └───sass
      └───img
└───index.html
└───main.js

目錄功能相信一眼就能看出來(lái)了。這時(shí)一個(gè)簡(jiǎn)易的環(huán)境就已經(jīng)搭建好了彤恶。

最后是一個(gè)廣告貼钞钙,最近新開了一個(gè)分享技術(shù)的公眾號(hào),歡迎大家關(guān)注??

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末声离,一起剝皮案震驚了整個(gè)濱河市芒炼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌抵恋,老刑警劉巖焕议,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件宝磨,死亡現(xiàn)場(chǎng)離奇詭異弧关,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)唤锉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門世囊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人窿祥,你說(shuō)我怎么就攤上這事株憾。” “怎么了晒衩?”我有些...
    開封第一講書人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵嗤瞎,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我听系,道長(zhǎng)贝奇,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任靠胜,我火速辦了婚禮掉瞳,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘浪漠。我一直安慰自己陕习,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開白布址愿。 她就那樣靜靜地躺著该镣,像睡著了一般。 火紅的嫁衣襯著肌膚如雪响谓。 梳的紋絲不亂的頭發(fā)上拌牲,一...
    開封第一講書人閱讀 51,573評(píng)論 1 305
  • 那天俱饿,我揣著相機(jī)與錄音,去河邊找鬼塌忽。 笑死拍埠,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的土居。 我是一名探鬼主播枣购,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼擦耀!你這毒婦竟也來(lái)了棉圈?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤眷蜓,失蹤者是張志新(化名)和其女友劉穎分瘾,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體吁系,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡德召,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了汽纤。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片上岗。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蕴坪,靈堂內(nèi)的尸體忽然破棺而出肴掷,到底是詐尸還是另有隱情,我是刑警寧澤背传,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布呆瞻,位于F島的核電站,受9級(jí)特大地震影響径玖,放射性物質(zhì)發(fā)生泄漏痴脾。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一挺狰、第九天 我趴在偏房一處隱蔽的房頂上張望明郭。 院中可真熱鬧,春花似錦丰泊、人聲如沸薯定。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)话侄。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間年堆,已是汗流浹背吞杭。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留变丧,地道東北人芽狗。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像痒蓬,于是被迫代替她去往敵國(guó)和親童擎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

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