從零一步步實(shí)現(xiàn)一個(gè)前端腳手架

前言

目前前端發(fā)展蒸蒸日上珍德,工程化也越來越成熟。在這期間出現(xiàn)了很多優(yōu)秀的框架和工具矗漾。與此同時(shí)伴隨著與框架搭配使用的腳手架也呼之欲出锈候。前端腳手架工具發(fā)展的日益強(qiáng)大,比如vue-cli敞贡,create-react-app等等是在vue泵琳,react開發(fā)搭建項(xiàng)目常用的腳手架。小編在看了vue-cli3誊役,vue-cli2的腳手架實(shí)現(xiàn)之后获列,心血來潮自己實(shí)現(xiàn)一個(gè)簡(jiǎn)易版的腳手架,下邊我們一起來學(xué)習(xí)一下腳手架的實(shí)現(xiàn)流程蛔垢。

小編福利推薦击孩,更多精彩內(nèi)容請(qǐng)點(diǎn)擊鏈接,點(diǎn)擊這里

實(shí)現(xiàn)思路

我認(rèn)為vue-cli3vue-cli2的實(shí)現(xiàn)區(qū)別有如下幾點(diǎn)

  • 就是vue-cli3不在從git倉庫下載模板啦桌,而是自己生成代碼和創(chuàng)建文件和文件夾溯壶。
  • vue-cli3webpack的配置內(nèi)置了,不在暴露出來甫男,提供用戶自定義的配置文件來自定義自己的配置且改;而vue-cli2則是把配置完全暴露出來,可以任意修改板驳。

本文我們這里是基于vue-cli2的實(shí)現(xiàn)思路來一步步實(shí)現(xiàn)一個(gè)簡(jiǎn)單的react版本腳手架又跛。下邊是小編整體的實(shí)現(xiàn)過程

1、添加自己腳手架的命令(lbs)
2若治、使用commander工具為自己的lbs命令添加解析參數(shù)慨蓝,解析參數(shù),添加自定義命令端幼;附上官方文檔 commander文檔
3礼烈、使用inquirer實(shí)現(xiàn)命令行和用戶的交互(用戶輸入,選擇)婆跑;附上官方文檔 inquirer文檔
4此熬、根據(jù)用戶輸入的項(xiàng)目名稱,模板來下載滑进,解壓模板
5犀忱、修改模板里邊的文件(package.json,index.html等)
6扶关、為項(xiàng)目安裝依賴阴汇,結(jié)束

開始擼代碼

本文實(shí)現(xiàn)一個(gè) lbs init [projectName] --force命令

projectName: 輸入的項(xiàng)目名稱
--force: 定義的選項(xiàng)(當(dāng)前目錄存在輸入的[projectName]文件夾時(shí)候,是否強(qiáng)制覆蓋)

添加腳手架命令(lbs)

創(chuàng)建項(xiàng)目這一步省略
利用package.jsonbin項(xiàng)來指定自己定義的命令對(duì)應(yīng)的可執(zhí)行文件的位置节槐,我們?cè)?code>package.json搀庶,添加如下代碼

"bin":{
  "lbs": "./bin/lbs.js"
},

然后創(chuàng)建bin/lbs.js文件,添加測(cè)試代碼:

#!/usr/bin/env node

console.log("hello lbs-cli")

第一行是必須添加的疯淫,是指定這里用node解析這個(gè)腳本地来。默認(rèn)找/usr/bin目錄下,如果找不到去系統(tǒng)環(huán)境變量查找熙掺。

然后我們?cè)谌我饽夸浵麓蜷_cmd窗口未斑,輸入lbs命令,你會(huì)發(fā)現(xiàn)找不到命令币绩。其實(shí)我們還需要做一步操作蜡秽,就是把本地項(xiàng)目全局安裝一下,在當(dāng)前項(xiàng)目下執(zhí)行npm install . -g缆镣,然后在cmd下執(zhí)行lbs命令芽突,你會(huì)發(fā)現(xiàn)會(huì)輸出我們打印的字符串。

QQ截圖20200918130913.png

到這里我們已經(jīng)成功在系統(tǒng)里添加了自己定義的lbs命令董瞻,那么我們?cè)趺礊閘bs添加init寞蚌,create田巴,--version等等參數(shù)呢?

使用commander豐富我們的lbs命令

不熟悉commander的使用請(qǐng)看commander文檔

我們首先要安裝一下插件挟秤,然后初步嘗試一下為我們的lbs命令添加版本查看的選項(xiàng)

const { program } = require("commander")
const pkg = require("./../package.json")

program.version(pkg.version,'-v --version')

program.parse(process.argv)

此時(shí)我們?cè)谌我饷钚袌?zhí)行lbs -v或者lbs --version壹哺,可以看到在控制臺(tái)輸出版本信息

QQ截圖20200918133907.png

接下來為lbs命令添加一個(gè)命令:

// projectName 是一個(gè)可選參數(shù)

program.command('init [projectName]')
.description("初始化項(xiàng)目")   
// 添加一個(gè)選項(xiàng)     
.option('-f --force','如果存在輸入的項(xiàng)目目錄,強(qiáng)制刪除項(xiàng)目目錄') 
.action((projectName,cmd)=>{ 
     // projectName 是我們輸入的參數(shù)艘刚,
     console.log(projectName) 
     // cmd是Command對(duì)象
     console.log(cmd.force)  
})

這里我們添加了一個(gè)init命令管宵,支持一個(gè)可選參數(shù)和一個(gè)-f的可選選項(xiàng)
這時(shí)候我們執(zhí)行一下

lbs init test -f

可以在控制臺(tái)查看到我們輸入的testcmd對(duì)象∨噬酰可以在cmd中查找到存在force屬性箩朴。

QQ截圖20200918135820.png

如果執(zhí)行lbs init,輸出如下

QQ截圖20200918135905.png

如果執(zhí)行lbs init test秋度,輸出如下

QQ截圖20200918135917.png

這里我們主要是獲取這兩個(gè)數(shù)據(jù)炸庞,如果你的命令還有其它的復(fù)雜功能,還可以擴(kuò)展其它參數(shù)和選項(xiàng)荚斯。

這里只是command的一種使用方式燕雁,當(dāng)我們?yōu)?code>command添加第二個(gè)描述參數(shù),就意味著使用獨(dú)立的可執(zhí)行文件作為子命令鲸拥,比如你的命令是init那么你就需要?jiǎng)?chuàng)建一個(gè)lbs-init腳本文件拐格,這個(gè)文件負(fù)責(zé)執(zhí)行你指定的命令,按照lbs-${command}的方式創(chuàng)建腳本刑赶,我們創(chuàng)建lbs-init.js文件

QQ截圖20200918141559.png

把命令修改如下捏浊,為command方法添加第二個(gè)參數(shù)

// projectName 是一個(gè)可選參數(shù)
program.command('init [projectName]','init project')  
.description("初始化項(xiàng)目")        
// 添加一個(gè)選項(xiàng)
.option('-f --force','如果存在輸入的項(xiàng)目目錄,強(qiáng)制刪除項(xiàng)目目錄') 
        .action((projectName,cmd)=>{ 
            console.log(projectName) // projectName 是我們輸入的參數(shù)撞叨,
            console.log(cmd.force)  // cmd是Command對(duì)象
        })

執(zhí)行lbs init金踪,你會(huì)發(fā)現(xiàn)什么也沒輸出。因?yàn)檫@里不會(huì)執(zhí)行到action方法牵敷,會(huì)去執(zhí)行我們創(chuàng)建的lbs-init.js這個(gè)空文件胡岔。所以什么也不會(huì)輸出。這時(shí)候lbs.js只需要定義init命令就可以了枷餐。只需要這一行就足夠了program.command('init [projectName]','init project')

然后在lbs-init.js添加解析代碼

const { program } = require("commander")

let projectName;
let force;

program.arguments('[projectName]') // 指定解析的參數(shù)
        .description("初始化項(xiàng)目")  
        .option('-f --force','如果存在輸入的項(xiàng)目目錄靶瘸,強(qiáng)制刪除項(xiàng)目目錄') 
        .action((name,cmd)=>{ 
            projectName = name;
            force = cmd.force;
        });
program.parse(process.argv);

console.log(projectName,force)

重新執(zhí)行lbs init test -f發(fā)現(xiàn)數(shù)據(jù)都能獲取。到這里我們已經(jīng)可以為我們的lbs init命令自定義參數(shù)和選項(xiàng)了毛肋,那么當(dāng)用戶只執(zhí)行lbs init命令怨咪,這時(shí)候我們就獲取不到項(xiàng)目名稱,我們?cè)趺崔k呢润匙?請(qǐng)往下看

使用inquirer實(shí)現(xiàn)命令行和用戶的交互(用戶輸入诗眨,選擇,問答)

這里我們需要安裝chalk孕讳,inquirer插件
chalk:主要是自定義顏色控制臺(tái)輸出

創(chuàng)建一個(gè)logger.js工具類匠楚,主要是輸出控制臺(tái)信息

const chalk = require('chalk');

exports.warn = function(message){
    console.log(chalk.yellow(message));
}

exports.error = function(message){
    console.log(chalk.red(message))
}

exports.info = function(message){
    console.log(chalk.white(message))
}

exports.infoGreen = function(message){
    console.log(chalk.green(message))
}

exports.exit = function(error){
    if(error && error instanceof Error){
        console.log(chalk.red(error.message))
    }
    process.exit(-1);
}

這個(gè)庫是我們可以和用戶交互的工具巍膘;第一個(gè)問題是輸入項(xiàng)目名稱,第二個(gè)問題是讓用戶選擇一個(gè)模板芋簿,這里的模板需要在github上準(zhǔn)備好典徘,我這里只準(zhǔn)備了一個(gè)lb-react-apps-template,這個(gè)模板是基于react-apps-template這個(gè)項(xiàng)目重新建了一個(gè)git倉庫益咬。這個(gè)模板的具體實(shí)現(xiàn)可以可以看之前`webpack的系列文章:react+webpack4搭建前端項(xiàng)目,后邊兩個(gè)模板是是不存在的

// 設(shè)置用戶交互的問題
const questions = [
    {
        type: 'input',
        name:'projectName',
        message: chalk.yellow("輸入你的項(xiàng)目名字:")
    },
    {
        type:'list',
        name:'template',
        message: chalk.yellow("請(qǐng)選擇創(chuàng)建項(xiàng)目模板:"),
        choices:[
            {name:"lb-react-apps-template",value:"lb-react-apps-template"},
            {name:"template2",value:"tempalte2"},
            {name:"template3",value:"tempalte3"}
        ]
    }
];

// 如果用戶命令參數(shù)帶projectName,只需要詢問用戶選擇模板
if(projectName){
    questions.splice(0,1);
}

// 執(zhí)行用戶交互命令
inquirer.prompt(questions).then(result=>{
    if(result.projectName) {
        projectName = result.projectName;
    }
    const templateName = result.template;
    // 獲取projectName templateName
    console.log("項(xiàng)目名稱:" + projectName)
    console.log("模板名稱:" + templateName)
    if(!templateName || !projectName){
        // 退出
        logger.exit();
    }
    // 往下走
    checkProjectExits(projectName,templateName); // 檢查目錄是否存在
}).catch(error=>{
    logger.exit(error);
})

這里的checkProjectExits下邊會(huì)實(shí)現(xiàn)帜平,可以先忽略幽告。這時(shí)候我們執(zhí)行lbs init,可以看到成功獲取到projectNametemplateName

QQ截圖20200918173924.png

接下來我們還需要判斷用戶輸入的項(xiàng)目名稱在當(dāng)前目錄是不是存在裆甩,在存在的情況下
1冗锁、如果用戶執(zhí)行的命令包含--force,那么直接把存在的目錄刪除嗤栓,
2冻河、如果命令不包含 --force,那么需要詢問用戶是否需要覆蓋茉帅。如果用戶需要覆蓋叨叙,那就直接刪除存在的文件夾,不過用戶不允許堪澎,那就直接退出

添加checkProjectExits檢查目錄存在的方法擂错,代碼如下

function checkProjectExits(projectName,templateName){
    const currentPath = process.cwd();
    const filePath = path.join(currentPath,`${projectName}`); // 獲取項(xiàng)目的真實(shí)路徑
    if(force){ // 強(qiáng)制刪除
        if(fs.existsSync(filePath)){
            // 刪除文件夾
            spinner.logWithSpinner(`刪除${projectName}...`)
            deletePath(filePath)
            spinner.stopSpinner(false);
        }
        startDownloadTemplate(projectName, templateName) // 開始下載模板
        return;
    }
    if(fs.existsSync(filePath)){ // 判斷文件是否存在 詢問是否繼續(xù)
        inquirer.prompt( {
            type: 'confirm',
            name: 'out',
            message: `${projectName}文件夾已存在,是否覆蓋樱蛤?`
        }).then(data=>{
            if(!data.out){ // 用戶不同意
                exit();
            }else{
                // 刪除文件夾
                spinner.logWithSpinner(`刪除${projectName}...`)
                deletePath(filePath)
                spinner.stopSpinner(false);
                startDownloadTemplate(projectName, templateName) // 開始下載模板
            }
        }).catch(error=>{
            exit(error);
        })
    }else{
        startDownloadTemplate(projectName, templateName) // 開始下載模板
    }
}

function startDownloadTemplate(projectName,templateName){
    console.log(projectName,templateName)
}

我們這里用到了一個(gè)spinner的工具類钮呀,新建lib/spinner.js,主要是一個(gè)轉(zhuǎn)菊花的動(dòng)畫提示昨凡,代碼如下

const ora = require('ora')
const chalk = require('chalk')

const spinner = ora()
let lastMsg = null

exports.logWithSpinner = (symbol, msg) => {
  if (!msg) {
    msg = symbol
    symbol = chalk.green('?')
  }
  if (lastMsg) {
    spinner.stopAndPersist({
      symbol: lastMsg.symbol,
      text: lastMsg.text
    })
  }
  spinner.text = ' ' + msg
  lastMsg = {
    symbol: symbol + ' ',
    text: msg
  }
  spinner.start()
}

exports.stopSpinner = (persist) => {
  if (!spinner.isSpinning) {
    return
  }

  if (lastMsg && persist !== false) {
    spinner.stopAndPersist({
      symbol: lastMsg.symbol,
      text: lastMsg.text
    })
  } else {
    spinner.stop()
  }
  lastMsg = null
}

我們新建lib/io.js爽醋,實(shí)現(xiàn)deletePath刪除目錄方法,如下

function deletePath (filePath){
    if(fs.existsSync(filePath)){
        const files = fs.readdirSync(filePath);
        for(let index=0; index<files.length; index++){
            const fileNmae = files[index];
            const currentPath = path.join(filePath,fileNmae);
            if(fs.statSync(currentPath).isDirectory()){
                deletePath(currentPath)
            }else{
                fs.unlinkSync(currentPath);
            }
        }
        fs.rmdirSync(filePath);
    }
}

可以創(chuàng)建my-app文件夾便脊,這時(shí)候可以測(cè)試一下lbs init my-app -flbs init -f命令蚂四,查看my-app是否刪除,

執(zhí)行lbs init哪痰,根據(jù)一步步提示证杭,輸入已經(jīng)存在的目錄名稱作為項(xiàng)目名稱;選擇模板妒御,檢查是否my-app文件夾被刪除解愤,如下

QQ截圖20200918190201.png
下載,解壓模板

下載模板乎莉,需要我們根據(jù)選擇的模板名稱拼接github倉庫相對(duì)應(yīng)的zip壓縮包的url送讲,然后執(zhí)行node的下載代碼奸笤,(注意這里是把下載的zip壓縮包下載到系統(tǒng)的臨時(shí)目錄)下載成功后把zip壓縮包解壓到用戶輸入項(xiàng)目名稱的目錄,解壓成功后刪除已下載的壓縮包哼鬓。這一個(gè)流程就結(jié)束了

這其中下載利用request插件监右,解壓用到了decompress插件,這兩個(gè)插件需要提前安裝一下异希,這兩個(gè)插件有不熟悉使用的小伙伴可以提前熟悉一下相關(guān)使用

重寫上邊的startDownloadTemplate方法

function startDownloadTemplate(projectName,templateName){
    // 開始下載模板
    downloadTemplate(templateName, projectName , (error)=>{
        if(error){
            logger.exit(error);
            return;
        }
        // 替換解壓后的模板package.json, index.html關(guān)鍵內(nèi)容
        replaceFileContent(projectName,templateName)
    })
}

function replaceFileContent(projectName,templateName){
    console.log(projectName,templateName);
}

新建lib/download.js健盒,實(shí)現(xiàn)downloadTemplate下載模板的方法,代碼如下

const request = require("request")
const fs = require("fs")
const path = require("path")
const currentPath = process.cwd();
const spinner = require("./spinner")
const os = require("os")
const { deletePath , unzipFile } = require("./io")

exports.downloadTemplate = function (templateName,projectName,callBack){

    // 根據(jù)templateName拼接github對(duì)應(yīng)的壓縮包url
    const url = `https://github.com/liuboshuo/${templateName}/archive/master.zip`;

    // 壓縮包下載的目錄称簿,這里是在系統(tǒng)臨時(shí)文件目錄創(chuàng)建一個(gè)目錄
    const tempProjectPath = fs.mkdtempSync(path.join(os.tmpdir(), `${projectName}-`));

    // 壓縮包保存的路徑
    const file = path.join(tempProjectPath,`${templateName}.zip`);

    // 判斷壓縮包在系統(tǒng)中是否存在
    if(fs.existsSync(file)){
        fs.unlinkSync(file); // 刪除本地系統(tǒng)已存在的壓縮包
    }
    
    spinner.logWithSpinner("下載模板中...")
    let stream = fs.createWriteStream(file);
    request(url,).pipe(stream).on("close",function(err){  
        spinner.stopSpinner(false)

        if(err){
            callBack(err);
            return;
        }

        // 獲取解壓的目錄
        const destPath = path.join(currentPath,`${projectName}`);

        // 解壓已下載的模板壓縮包
        unzipFile(file,destPath,(error)=>{
            // 刪除創(chuàng)建的臨時(shí)文件夾
            deletePath(tempProjectPath);
            callBack(error);
        });
    })
}

lib/io.js添加解壓zip壓縮包的方法扣癣,代碼如下

const decompress = require("decompress");
exports.unzipFile = function(file,destPath,callBack){
    decompress(file,destPath,{
        map: file => {
            // 這里可以修改文件的解壓位置, 
            // 例如壓縮包中文件的路徑是 ${destPath}/lb-react-apps-template/src/index.js   =》  ${destPath}/src/index.js
            const outPath = file.path.substr(file.path.indexOf('/') + 1)
            file.path = outPath
            return file
        }}
    ).then(files => {
        callBack()
    }).catch(error=>{
        callBack(error)
    })
}

這里可以執(zhí)行以下lbs init my-app測(cè)試一下

修改項(xiàng)目中的模板文件(package.json憨降,index.html等)

重寫replaceFileContent方法父虑,這一步是把模板中的一些文件的內(nèi)容修改以下,比如package.json的name授药,index.html的title值

function replaceFileContent(projectName,templateName){
    const currentPath = process.cwd();
    try{
        // 讀取項(xiàng)目的package.json
        const pkgPath = path.join(currentPath,`${projectName}/package.json`);
        // 讀取內(nèi)容
        const pkg = require(pkgPath);
        // 修改package.json的name屬性為項(xiàng)目名稱
        pkg.name = projectName;
        fs.writeFileSync(pkgPath,JSON.stringify(pkg,null,2));

        const indexPath = path.join(currentPath, `${projectName}/index.html`);
        let html = fs.readFileSync(indexPath).toString();
        // 修改模板title為項(xiàng)目名稱
        html = html.replace(/<title>(.*)<\/title>/g,`<title>${projectName}</title>`)
        fs.writeFileSync(indexPath,html);
    }catch(error){
        exit(error)
    }
    // 安裝依賴
    install(projectName)
}

function install(projectName){
    console.log(projectName)
}
安裝依賴

重寫install方法士嚎,這里利用child_process包創(chuàng)建一個(gè)node的子進(jìn)程來執(zhí)行npm install任務(wù)。注意這里要執(zhí)行的命令npm在不同系統(tǒng)有區(qū)別悔叽,在window下執(zhí)行的是npm.cmd命令莱衩,在linuxmac執(zhí)行的是npm命令
有不熟悉child_process使用的小伙伴可以深入學(xué)習(xí)一下,這是nodejs自帶的一個(gè)包娇澎,非常有用膳殷,這里貼一下文檔地址 child_process官方文檔,這里利用spawn方法執(zhí)行系統(tǒng)命令九火,還可以使用execFileSync方法來執(zhí)行文件等等

const currentPath = process.cwd();
    const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm'
    // 創(chuàng)建一個(gè)子進(jìn)程執(zhí)行npm install 任務(wù)
    const nodeJob = child_process.spawn(npm , ['install'], {
        stdio: 'inherit', // 指定父子進(jìn)程通信方式
        cwd: path.join(currentPath,projectName)
    });
    // 監(jiān)聽任務(wù)結(jié)束赚窃,提示用戶創(chuàng)建成功,接下來的操作
    nodeJob.on("close",()=>{
        logger.info(`創(chuàng)建成功! ${projectName} 項(xiàng)目位于 ${path.join(currentPath,projectName)}`)
        logger.info('')
        logger.info('你可以執(zhí)行以下命令運(yùn)行開發(fā)環(huán)境')
        logger.infoGreen(` cd ${projectName}       `);
        logger.infoGreen(` npm run dev             `);
    })

執(zhí)行lbs init測(cè)試一下

1600428938(1).jpg

那么到這里一個(gè)簡(jiǎn)易版的腳手架已經(jīng)完成岔激!

有什么疑問可以關(guān)注公眾號(hào)私信哦~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末勒极,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子虑鼎,更是在濱河造成了極大的恐慌辱匿,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件炫彩,死亡現(xiàn)場(chǎng)離奇詭異匾七,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)江兢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門昨忆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人杉允,你說我怎么就攤上這事邑贴∠铮” “怎么了?”我有些...
    開封第一講書人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵拢驾,是天一觀的道長(zhǎng)奖磁。 經(jīng)常有香客問我,道長(zhǎng)繁疤,這世上最難降的妖魔是什么咖为? 我笑而不...
    開封第一講書人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮稠腊,結(jié)果婚禮上躁染,老公的妹妹穿的比我還像新娘。我一直安慰自己麻养,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開白布诺舔。 她就那樣靜靜地躺著鳖昌,像睡著了一般。 火紅的嫁衣襯著肌膚如雪低飒。 梳的紋絲不亂的頭發(fā)上许昨,一...
    開封第一講書人閱讀 52,441評(píng)論 1 310
  • 那天,我揣著相機(jī)與錄音褥赊,去河邊找鬼糕档。 笑死,一個(gè)胖子當(dāng)著我的面吹牛拌喉,可吹牛的內(nèi)容都是我干的速那。 我是一名探鬼主播,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼尿背,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼端仰!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起田藐,我...
    開封第一講書人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤荔烧,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后汽久,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鹤竭,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年景醇,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了臀稚。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡三痰,死狀恐怖烁涌,靈堂內(nèi)的尸體忽然破棺而出苍碟,到底是詐尸還是另有隱情,我是刑警寧澤撮执,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布微峰,位于F島的核電站,受9級(jí)特大地震影響抒钱,放射性物質(zhì)發(fā)生泄漏蜓肆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一谋币、第九天 我趴在偏房一處隱蔽的房頂上張望仗扬。 院中可真熱鬧,春花似錦蕾额、人聲如沸早芭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽退个。三九已至,卻和暖如春调炬,著一層夾襖步出監(jiān)牢的瞬間语盈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來泰國打工缰泡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留刀荒,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓棘钞,卻偏偏與公主長(zhǎng)得像缠借,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子宜猜,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

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