AntDesignPro中臺(tái)項(xiàng)目遷移Typescript,并接入Eslint+Prettier代碼格式化

前言

在一家小公司實(shí)習(xí)了一段時(shí)間,接手的項(xiàng)目代碼格式及規(guī)范化不可描述,為了保證項(xiàng)目的可維護(hù)性,決定接入Typescript,同時(shí)采用EslintPrettier進(jìn)行代碼規(guī)范化,為下一步的CodeReview

Typescript是強(qiáng)類型語言,接入Typescript一開始會(huì)有很大的痛點(diǎn),但是過了一陣子就可以享受到Typescript帶來的好處,bug減少了,代碼易讀了,也可維護(hù)了,好處網(wǎng)上一大把就不累贅了。

常用的代碼格式化工具主要有ESlintTSLintStandardJS。TS官方已經(jīng)決定棄用TSLint,全面擁抱ESLint。因此在技術(shù)選型方面將采用ESlint

Eslint的主要功能包含代碼格式的校驗(yàn),代碼質(zhì)量的校驗(yàn),JS規(guī)范,如用===而不是==判斷相等、用駝峰命名變量而不是用下劃線。而 Prettier 是美麗的意思,只是代碼格式的校驗(yàn)(并格式化代碼),不會(huì)對代碼質(zhì)量進(jìn)行校驗(yàn),如單行代碼長度、tab長度、空格、逗號表達(dá)式等問題。

一、安裝相關(guān)依賴

1.1 安裝 Typescript

推薦使用全局安裝,可以在其他項(xiàng)目中也使用TS。

npm install -g typescript

1.2 安裝聲明文件

所需的 react, react-dom 的聲明文件, 以及 加載TS的ts-loader

npm install --save-dev @types/react @types/react-dom ts-loader

1.3 配置 tsconfig.json

在使用Typescript時(shí)需要根據(jù)實(shí)際項(xiàng)目的需要進(jìn)行相關(guān)規(guī)則的配置,具體配置根據(jù)項(xiàng)目而異、可參考官網(wǎng),具體看這里TS官網(wǎng)。我的配置項(xiàng)如下所示:

{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "noUnusedParameters": true,
    "outDir": "build/dist",
    "baseUrl": ".",
    "strict": true,
    "noImplicitAny": true,
    "removeComments": true,
    "preserveConstEnums": true,
    "sourceMap": true,
    "forceConsistentCasingInFileNames": true,
    "strictPropertyInitialization": true,
    "experimentalDecorators": true,
    "noImplicitReturns": true,
    "moduleResolution": "node",
    "strictNullChecks": true,
    "esModuleInterop": true,
    "noUnusedLocals": true,
    "importHelpers": true,
    "noImplicitThis": false,
    "suppressImplicitAnyIndexErrors": false,
    "skipLibCheck": true,
    "noResolve": false,
    "module": "es2015",
    "allowJs": true,
    "target": "es5",
    "jsx": "react",
    "lib": [
      "es5",
      "es2015",
      "dom",
      "es7",
      "es2018"
    ],
    "paths": {
      "@/*": [
        "./src/*"
      ]
    }
  },
  "exclude": [
    "node_modules",
    "build",
    "scripts",
    "acceptance-tests",
    "webpack",
    "jest",
    "src/setupTests.ts",
    "tslint:latest",
    "tslint-config-prettier"
  ]
}

二、ESLint+Prettier代碼規(guī)范

針對JS項(xiàng)目遷移到TS的項(xiàng)目,主要有兩種選擇ESLintTSLintTSLint僅針對TS代碼,因此如果采用TSLint規(guī)范TS代碼,JS代碼需要采用其他工具。而ESLint不僅能規(guī)范js代碼,通過配置解析器,也能規(guī)范TS代碼。此外由于性能問題,TypeScript 官方?jīng)Q定全面采用ESLint。因此本項(xiàng)目采用ESLint配合Prettier規(guī)范化TSJS代碼。

2.1 ESLint規(guī)范TS代碼

2.1.1 安裝ESLint依賴

npm i eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin --save-dev
  • eslint: ESLint的核心代碼

  • @typescript-eslint/parser:ESLint的解析器,用于解析Typescript文件,從而檢查和規(guī)范Typescript代碼

  • @typescript-eslint/eslint-plugin:這是一個(gè)ESLint插件,包含了各類定義好的檢測Typescript代碼的規(guī)范

安裝好依賴后,需要在項(xiàng)目根目錄中的.eslintrc.js中配置,包括解析器、繼承的代碼規(guī)范、插件和環(huán)境:

module.exports = {
   parser:  '@typescript-eslint/parser', //定義ESLint的解析器
   extends: ['plugin:@typescript-eslint/recommended'],//定義文件繼承的子規(guī)范
   plugins: ['@typescript-eslint'],//定義了該eslint文件所依賴的插件
   env:{                          //指定代碼的運(yùn)行環(huán)境
       browser: true,
       node: true,
   }                                
}

2.2 規(guī)范React代碼

項(xiàng)目是以依賴于React的AntDesignPro為基礎(chǔ),因此需要安裝規(guī)范React代碼的Eslint插件。

2.2.1安裝插件

npm i eslint-plugin-react --save-dev

2.2.2 配置React規(guī)范

然后修改.eslintrc.js的配置,如下所示:

module.exports = {
   parser:  '@typescript-eslint/parser',
   extends: [
    'plugin:react/recommended',
    'plugin:@typescript-eslint/recommended'
   ],//使用推薦的React代碼檢測規(guī)范
   plugins: ['@typescript-eslint'],
   env:{                          
       browser: true,
       node: true,
   },
   settings: {//自動(dòng)發(fā)現(xiàn)React的版本,從而進(jìn)行規(guī)范react代碼
       "react": {
           "pragma": "React",
           "version": "detect"
       }
   },  
   parserOptions: {//指定ESLint可以解析JSX語法
       "ecmaVersion": 2019,
       "sourceType": 'module',
       "ecmaFeatures":{
           jsx:true
       }
   }
   rules: {
   //在Rules中可以自定義你的React代碼編碼規(guī)范。
   }
}

2.3接入Prettier

2.3.1 安裝依賴

npm install prettier eslint-config-prettier eslint-plugin-prettier -g
  • prettier:prettier插件的核心代碼

  • eslint-config-prettier:解決ESLint中的樣式規(guī)范和prettier中樣式規(guī)范的沖突,以prettier的樣式規(guī)范為準(zhǔn),使ESLint中的樣式規(guī)范自動(dòng)失效

  • eslint-plugin-prettier:將prettier作為ESLint規(guī)范來使用

2.3.2 配置規(guī)則

在項(xiàng)目的根目錄下創(chuàng)建.prettierrc.js文件并配置prettier代碼檢查規(guī)則

module.exports = {
    //最大長度80個(gè)字符
    printWidth: 80,
    //行末分號
    semi: false,
    //單引號
    singleQuote: true,
    //盡可能使用尾隨逗號(包括函數(shù)參數(shù))
    trailingComma: 'all',
    //在對象文字中打印括號之間的空格。
    bracketSpacing: true,
    // > 標(biāo)簽放在最后一行的末尾,而不是單獨(dú)放在下一行
    jsxBracketSameLine: false,
    //箭頭圓括號
    arrowParens: 'avoid',
    //在文件頂部插入一個(gè)特殊的 @format 標(biāo)記,指定文件格式需要被格式化。
    insertPragma: false,
    //縮進(jìn)
    tabWidth: 4,
    //使用tab還是空格
    useTabs: false,
}

2.3.3 結(jié)合Prettier配置Eslint

修改.eslintrc.js文件,引入prettier
最終配置為:

module.exports = {
    parser: '@typescript-eslint/parser',
    extends: [
        'plugin:react/recommended',
        'plugin:@typescript-eslint/recommended',
        'prettier/@typescript-eslint',
        'plugin:prettier/recommended',
    ],
    plugins: ['@typescript-eslint', 'react'],
    env: {
        browser: true,
        node: true,
        es6: true,
    },
    rules: {
        quotes: ['error', 'single'], //強(qiáng)制使用單引號
        semi: ['error', 'never'], // 要求或禁止使用分號而不是 ASI
        camelcase: 0, // 雙峰駝命名格式
        eqeqeq: 2, //必須使用全等
        yoda: [2, 'never'], //禁止尤達(dá)條件
        strict: [2, 'never'], // 禁用嚴(yán)格模式,禁止在任何地方出現(xiàn) 'use strict'
        'no-extra-boolean-cast': 2, //禁止不必要的bool轉(zhuǎn)換
        'no-lone-blocks': 2, //禁止不必要的嵌套塊
        'no-plusplus': 0, //禁止使用++,--
        'no-proto': 2, //禁止使用__proto__屬性
        'no-self-compare': 2, //不能比較自身
        'no-undef': 2, //不能有未定義的變量
        'no-unreachable': 2, //不能有無法執(zhí)行的代碼
        'no-unused-expressions': 2, //禁止無用的表達(dá)式
        'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
        'no-alert': 2, //禁止使用alert
        'no-caller': 1, //禁止使用arguments.caller或arguments.callee
        'no-inline-comments': 2, //禁止行內(nèi)備注
        'no-func-assign': 2, //禁止重復(fù)的函數(shù)聲明
        'no-eval': 2, //禁止使用eval,
        'no-empty': 2, //塊語句中的內(nèi)容不能為空
        'no-const-assign': 2, //禁止修改const聲明的變量
        'no-var': 2, //禁止使用var
        'no-multiple-empty-lines': [1, { max: 2 }], //空行最多不能超過2行
        'no-extra-semi': 'error', // 禁止不必要的分號
        'array-bracket-spacing': [2, 'never'], //是否允許非空數(shù)組里面有多余的空格
        'linebreak-style': ['error', 'unix'], // 強(qiáng)制使用一致的換行風(fēng)格
        'brace-style': [2, '1tbs', { allowSingleLine: true }], // if while function 后面的{必須與if在同一行,java風(fēng)格。
        'comma-dangle': 0, // 數(shù)組和對象鍵值對最后一個(gè)逗號, never參數(shù):不能帶末尾的逗號, always參數(shù):必須帶末尾的逗號,
        'comma-spacing': [2, { before: false, after: true }], // 控制逗號前后的空格
        'computed-property-spacing': [2, 'never'], // 以方括號取對象屬性時(shí),[ 后面和 ] 前面是否需要空格, 可選參數(shù) never, always
        'use-isnan': 2, //禁止比較時(shí)使用NaN,只能用isNaN()
        'default-case': 2, //switch語句最后必須有default
        'newline-after-var': 2, //變量聲明后是否需要空一行
        'max-depth': [2, 4], //嵌套塊深度最多四層
        'max-params': [2, 4], //函數(shù)最多只能有4個(gè)參數(shù)
        'no-else-return': 2, //如果if語句里面有return,后面不能跟else語句,禁止出現(xiàn) if (cond) { return a } else { return b },應(yīng)該寫為 if (cond) { return a } return b
        'no-eq-null': 2, //禁止對null使用==或!=運(yùn)算符
        'no-iterator': 2, //禁止使用__iterator__ 屬性
        'no-mixed-spaces-and-tabs': [2, false], //禁止混用tab和空格
        'no-new-func': 1, //禁止使用new Function
        'no-new-object': 2, //禁止使用new Object()
        'no-self-compare': 2, //不能比較自身
        'no-unused-vars': [2, { vars: 'all', args: 'after-used' }], //不能有聲明后未被使用的變量或參數(shù)
        'no-use-before-define': 0, //未定義前不能使用
        'valid-typeof': 2, //無效的類型判斷
        'wrap-iife': [2, 'inside'], //立即執(zhí)行函數(shù)表達(dá)式的小括號風(fēng)格
        // 注釋的斜線和星號后要加空格
        'spaced-comment': [
            2,
            'always',
            {
                block: {
                    exceptions: ['*'],
                    balanced: true,
                },
            },
        ],
        // new, delete, typeof, void, yield 等表達(dá)式前后必須有空格,-, +, --, ++, !, !! 等表達(dá)式前后不許有空格
        'space-unary-ops': [
            2,
            {
                words: true,
                nonwords: false,
            },
        ],
        'prefer-rest-params': 2, // 必須使用解構(gòu) ...args 來代替 arguments
        'consistent-this': [2, 'self', 'that'], // this 的別名規(guī)則,只允許 self 或 that
        curly: [2, 'multi-line', 'consistent'], // if 后必須包含 { ,單行 if 除外
        'for-direction': 2, // for 循環(huán)不得因方向錯(cuò)誤造成死循環(huán)
        'getter-return': [2, { allowImplicit: true }], // getter 必須有返回值,允許返回 undefined
        'keyword-spacing': 2, // 關(guān)鍵字前后必須有空格
        // new關(guān)鍵字后類名應(yīng)首字母大寫
        'new-cap': [
            2,
            {
                capIsNew: false, // 允許大寫開頭的函數(shù)直接執(zhí)行
            },
        ],
        'no-await-in-loop': 2, // 禁止將 await 寫在循環(huán)里
        'no-class-assign': 2, // class定義的類名不得與其它變量重名
        'no-dupe-args': 2, // 函數(shù)參數(shù)禁止重名
        'no-duplicate-case': 2, // 禁止 switch 中出現(xiàn)相同的 case
        'no-duplicate-imports': 2, // 禁止重復(fù) import
        'no-empty-function': 0, // 禁止空的 function,包含注釋的情況下允許
        'no-empty-pattern': 2, // 禁止解構(gòu)中出現(xiàn)空 {} 或 []
        'no-ex-assign': 2, // catch 定義的參數(shù)禁止賦值
        'no-extend-native': [2, { exceptions: ['Array', 'Object'] }], // 禁止擴(kuò)展原生對象
        'no-extra-parens': [2, 'functions'], // 禁止額外的括號,僅針對函數(shù)體
        'no-floating-decimal': 2, // 不允許使用 2. 或 .5 來表示數(shù)字,需要用 2、2.0、0.5 的格式
        'no-func-assign': 2, // 禁止對函數(shù)聲明重新賦值
        'no-implied-eval': 2, // 禁止在 setTimeout 和 setInterval 中傳入字符串,因會(huì)觸發(fā)隱式 eval
        'no-multi-assign': 2, // 禁止連等賦值
        '@typescript-eslint/explicit-function-return-type': [
            'off',
            {
                allowExpressions: true,
                allowTypedFunctionExpressions: true,
            },
        ],
        '@typescript-eslint/no-explicit-any': 0, // 特殊情況可將類型顯示設(shè)置為any
        '@typescript-eslint/interface-name-prefix': 0, // 允許接口命名以I開頭
        '@typescript-eslint/no-var-requires': 0, // antd中引用style需要用require
        '@typescript-eslint/no-use-before-define': 0, // mapStateToProps在之前就用到(typeof推斷類型)
        '@typescript-eslint/camelcase': 0, // 駝峰命名格式
        '@typescript-eslint/no-empty-function': 0, // 給函數(shù)默認(rèn)值可以為空
        'react/display-name': 0, // 一個(gè)莫名其妙的Bug
        'react/no-find-dom-node': 0,
        '@typescript-eslint/no-non-null-assertion': 0, // 允許用!斷言不為空
    },
    settings: {
        //自動(dòng)發(fā)現(xiàn)React的版本,從而進(jìn)行規(guī)范react代碼
        react: {
            pragma: 'React',
            version: 'detect',
        },
    },
    parserOptions: {
        //指定ESLint可以解析JSX語法
        ecmaVersion: 2019,
        sourceType: 'module',
        ecmaFeatures: {
            jsx: true,
        },
    },
}
  • prettier/@typescript-eslint:使得@typescript-eslint中的樣式規(guī)范失效,遵循prettier中的樣式規(guī)范。

  • plugin:prettier/recommended:使用prettier中的樣式規(guī)范,且如果使得ESLint會(huì)檢測prettier的格式問題,同樣將格式問題以error的形式拋出。

2.4 在VSCode中集成ESLint配置

當(dāng)在項(xiàng)目中有了如上配置,其他開發(fā)人員需要在自己的VSCode中進(jìn)行ESLint和Prettier插件的安裝配置。VScode的ESLint和Prettier會(huì)讀取項(xiàng)目的配置文件,從而達(dá)到對代碼的檢查。踩坑如下:

  • 需要注意的是如果是通過工作機(jī)進(jìn)行遠(yuǎn)程工作的,一定要記得遠(yuǎn)程的VScode安裝插件才生效,本地安裝并沒用。
  • 同時(shí)在團(tuán)隊(duì)協(xié)作過程中,插件的版本有可能不同,如穩(wěn)定版本和非穩(wěn)定版本對于eslint規(guī)則的解析不同,因此團(tuán)隊(duì)直接盡可能安裝相同版本的插件.

2.4.1 配置setting,保存自動(dòng)校驗(yàn)

prettier和eslint可以在保存時(shí)自動(dòng)檢查并自動(dòng)格式化一部分問題,在settings.json文件中修改其配置文件如下:

{
    "eslint.enable": true, //是否開啟vscode的eslint
    "eslint.options": { //指定vscode的eslint所處理的文件的后綴
        "extensions": [
            ".js",
            ".vue",
            ".ts",
            ".tsx"
        ]
    },
    "editor.formatOnSave": true,
    "editor.codeActionsOnSave": {
        "source.fixAll.eslint": true
    },
    "eslint.validate": [ //確定校驗(yàn)準(zhǔn)則
        "javascript",
        "javascriptreact",
        {
            "language": "html",
            "autoFix": true
        },
        {
            "language": "vue",
            "autoFix": true
        },
        {
            "language": "typescript",
            "autoFix": true
        },
        {
            "language": "typescriptreact",
            "autoFix": true
        }
    ]
}

2.5 husky規(guī)范工作流

在項(xiàng)目遷移和規(guī)范化的過程中,我們不可能一次性將所有已經(jīng)存在的代碼遷移到TS,因此在實(shí)際過程中我們是采用JS和TS混合開發(fā),在實(shí)際做業(yè)務(wù)需求過程中將改動(dòng)的文件遷移成TS,對尚未碰見的代碼不做改動(dòng),保證項(xiàng)目的正常運(yùn)行。同樣,對Eslint的格式化也是主要集中在新開發(fā)的頁面。在開發(fā)的過程中,為了保證團(tuán)隊(duì)所有成員都能嚴(yán)格執(zhí)行Eslint規(guī)范,采用husky構(gòu)建工作流,eslint將檢查做了修改,存在stage階段尚未commit階段的代碼,在commit前進(jìn)行校驗(yàn),校驗(yàn)無誤即通過,否則不通過。

2.5.1 安裝依賴

    npm install husky --save-dev

2.5.2 配置

在package.json的script中配置:

 "scripts": {
   "lint": "npm run lint:js && npm run lint:style && npm run lint:prettier",
    "lint-staged": "lint-staged",
    "lint-staged:js": "eslint --ext .js,.jsx,.ts,.tsx ",
    "lint:fix": "eslint --fix --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src && npm run lint:style",
    "lint:js": "eslint --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src",
    "lint:prettier": "check-prettier lint",
    "lint:style": "stylelint --fix \"src/**/*.less\" --syntax less",
}

接著需要在package.json的husky中配置如下:

 "husky": {
   "hooks": {
      "pre-commit": "npm run lint"
    }
},

在pre-commit這個(gè)hook也就是在提交之前進(jìn)行l(wèi)int的檢測。

上述我們通過在husky的pre-comit這個(gè)hook中執(zhí)行一個(gè)npm命令來做lint校驗(yàn)。其實(shí)一般情況,我們會(huì)定義一個(gè)lint-staged,來在提交前檢測代碼的規(guī)范。使用lint-staged來規(guī)范代碼的方式如下,我們修改package.json文件為:

{
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "**/*.{js,jsx,ts,tsx}": [
      "eslint --fix",
      "prettier --write",
      "git add ."
    ]
  }
}

注意:這里有個(gè)需要注意,如果發(fā)現(xiàn)文件eslint還報(bào)錯(cuò),居然還能提交成功,也就是husky沒有生效,那么可以cd進(jìn)入到.git/hooks文件夾,查看一下有沒有pre-commit文件(不是pre-commit.sample文件),如果沒有,那么就是git版本的原因,需要升級到2.13.0以上。

在本項(xiàng)目中采用cicd進(jìn)行持續(xù)集成,因此也可以將eslint加入到ci中,在這里不在詳細(xì)介紹。

總結(jié)

項(xiàng)目的Typescript遷移和Eslint+Prettier的代碼格式化,目前已經(jīng)上線幾個(gè)月運(yùn)行良好,至今項(xiàng)目已經(jīng)遷移一半,基本無痛點(diǎn),很爽。


qrcode.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,556評論 3 418
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,463評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,009評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,778評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,218評論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,436評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,969評論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,795評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,993評論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,229評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,659評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,917評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,687評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,990評論 2 374