搭建前端工程化

搭建前端工程化

在我們?nèi)粘i_(kāi)發(fā)項(xiàng)目時(shí),基本上會(huì)采用官方腳手架進(jìn)行開(kāi)發(fā)。然后使用官方腳手架開(kāi)發(fā)也有缺點(diǎn):不能很好的自定義一些功能睛低。下面我將總結(jié)出來(lái)我是如何從零開(kāi)始搭建前端工程的,希望對(duì)大家有所幫助。

1. 工程化的目的

  • 前端工程化就是通過(guò)流程規(guī)范化钱雷、標(biāo)準(zhǔn)化提升團(tuán)隊(duì)協(xié)作效率
  • 通過(guò)組件化骂铁、模塊化提升代碼質(zhì)量
  • 使用構(gòu)建工具、自動(dòng)化工具提升開(kāi)發(fā)效率

2. 工程化開(kāi)發(fā)的流程

  • 編譯 => 打包(合并) => 壓縮 (webpack 或者 rollup)
  • 代碼檢查 => eslint
  • 測(cè)試 => jest
  • 發(fā)包
  • 持續(xù)繼承

3. 編譯工具的選擇

大的編譯工具主要包括兩種罩抗,分別時(shí)webpack 和 rollup拉庵,下面我們將講解如何配置。

3.1 webpack 配置

const webpack = require("webpack");
// html 的插件套蒂,可以指定一個(gè)index.html 將對(duì)應(yīng)的js文件插入到頁(yè)面中
const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path");
module.exports = {
  mode: "development",
  devtool:false,
  entry: "./src/index.tsx",
  output: {
    filename: "[name].[hash].js",
    path: path.join(__dirname, "dist"),
  },
  // webpack5 內(nèi)置了 webpack-dev-server名段, 如果5一下的需要單獨(dú)安裝
  devServer: {
    hot: true,
    contentBase: path.join(__dirname, "dist"),
    historyApiFallback: {
      index: "./index.html",
    },
  },
  resolve: {
    extensions: [".ts", ".tsx", ".js", ".json"],
    alias: {
      "@": path.resolve("src"), // 這樣配置后 @ 可以指向 src 目錄
    },
  },

  module: {
    rules: [
      {
        test: /\.tsx?$/,
        loader: "ts-loader"
      }
    ],
  },

  plugins: [
    new HtmlWebpackPlugin({
      template: "./src/index.html"
    }),
    // webpack 的內(nèi)置插件。熱更新使用
    new webpack.HotModuleReplacementPlugin()
  ],
};

注意: webpack5 內(nèi)置了 webpack-dev-server,可以直接使用 webpack server 命令啟動(dòng)泣懊。

3.2 rollup的配置

import ts from 'rollup-plugin-typescript2'; // 解析ts的插件
import {
  nodeResolve
} from '@rollup/plugin-node-resolve'; // 解析第三方模塊的插件
import commonjs from '@rollup/plugin-commonjs'; // 讓第三方非esm模塊支持編譯
import json from 'rollup-plugin-json'; // 支持編譯json
import serve from 'rollup-plugin-serve'; // 啟動(dòng)本地服務(wù)的插件
import path from 'path'

// 區(qū)分開(kāi)發(fā)環(huán)境
const isDev = process.env.NODE_ENV === 'development'
// rollup 支持es6語(yǔ)法
export default {
  input: 'packages/index.ts',
  output: {
    // amd iife commonjs umd..
    name:'hp',
    format: 'umd', // esm 模塊
    file: path.resolve(__dirname, 'dist/index.js'), // 出口文件
    sourcemap: true, // 根據(jù)源碼產(chǎn)生映射文件
  },
  plugins: [
    commonjs({
      include: 'node_modules/**', // Default: undefined
       extensions: ['.js','.ts']
      // exclude: ['node_modules/foo/**', 'node_modules/bar/**'], // Default: undefined
      
    }),
    json({
      // All JSON files will be parsed by default,
      // but you can also specifically include/exclude files
      include: 'node_modules/**',
      // preferConst: true, 
      // namedExports: true // Default: true
    }),
    nodeResolve({ // 第三方文件解析
      browser:true,
      extensions: ['.js', '.ts']
    }),
    ts({
      tsconfig: path.resolve(__dirname, 'tsconfig.json')
    }),
    isDev ? serve({
      openPage: '/public/index.html',
      contentBase: '',
      port: 3000
    }) : null
  ]
}

3.3 編譯typescript文件伸辟。

比你ts 兩種方案,一種時(shí)基于babel 編譯馍刮,一種是基于 tsc 編譯信夫。

基于tsc 編譯

// webpack 中 
// cnpm i typescript ts-loader -D
module: {
    rules: [
      {
        test: /\.tsx?$/,
        loader: "ts-loader"
      }
    ],
},
  
 // rollup 中
 // cnpm i rollup-plugin-typescript2 -D
  
ts({
      tsconfig: path.resolve(__dirname, 'tsconfig.json')
})
  

基于babel 編譯

分別在 webpack 和 rollup 引入babel 插件

babel 的配置文件

const presets = [
    ['@babel/preset-env', { // 一個(gè)預(yù)設(shè)集合
        // chrome, opera, edge, firefox, safari, ie, ios, android, node, electron
        // targets 和 browerslist 合并取最低版本
        // 啟用更符合規(guī)范的轉(zhuǎn)換,但速度會(huì)更慢卡啰,默認(rèn)為 `false`静稻,從目前來(lái)看,是更嚴(yán)格的轉(zhuǎn)化匈辱,包括一些代碼檢查振湾。
        spec: false,

        // 有兩種模式:normal, loose。其中 normal 更接近 es6 loose 更接近 es5
        loose: false,

        // "amd" | "umd" | "systemjs" | "commonjs" | "cjs" | false, defaults to "commonjs"
        modules: false, // 代表是esm 模塊

        // 打印插件使用情況
        debug: false,
        useBuiltIns: 'usage', // 按需引入
        corejs: { version: 3, proposals: true } // 考慮使用2亡脸,還是3
    }],
    ['@babel/preset-typescript', { // ts的配置
        'isTSX': true,
        'allExtensions': true
    }],
    '@vue/babel-preset-jsx'
];
const plugins = [
    '@babel/plugin-syntax-jsx',
    '@babel/plugin-transform-runtime',
    '@babel/plugin-syntax-dynamic-import',
    // ['@babel/plugin-transform-modules-commonjs'], 支持tree sharking 必須是esm 模塊押搪, 所以刪除此插件
    //  支持裝飾器模式開(kāi)發(fā)  
    ['@babel/plugin-proposal-decorators', { 'legacy': true }],
    ['@babel/plugin-proposal-class-properties', { 'loose': true }],
];

module.exports = {
    presets,
    plugins
};

建議: webpack 在業(yè)務(wù)中開(kāi)發(fā)推薦使用babel 編譯。 編輯js庫(kù)使用tsc編譯浅碾。

3.4 ts 配置文件梳理

基本參數(shù)

參數(shù) 解釋
target 用于指定編譯之后的版本目標(biāo)
module 生成的模塊形式:none大州、commonjs、amd垂谢、system厦画、umd、es6滥朱、es2015 或 esnext 只有 amd 和 system 能和 outFile 一起使用 target 為 es5 或更低時(shí)可用 es6 和 es2015
lib 編譯時(shí)引入的 ES 功能庫(kù)根暑,包括:es5 、es6徙邻、es7排嫌、dom 等。如果未設(shè)置鹃栽,則默認(rèn)為: target 為 es5 時(shí): ["dom", "es5", "scripthost"] target 為 es6 時(shí): ["dom", "es6", "dom.iterable", "scripthost"]
allowJs 是否允許編譯JS文件躏率,默認(rèn)是false,即不編譯JS文件
checkJs 是否檢查和報(bào)告JS文件中的錯(cuò)誤民鼓,默認(rèn)是false
jsx 指定jsx代碼用于的開(kāi)發(fā)環(huán)境 preserve指保留JSX語(yǔ)法,擴(kuò)展名為.jsx,react-native是指保留jsx語(yǔ)法薇芝,擴(kuò)展名js,react指會(huì)編譯成ES5語(yǔ)法 詳解
declaration 是否在編譯的時(shí)候生成相應(yīng)的.d.ts聲明文件
declarationDir 生成的 .d.ts 文件存放路徑,默認(rèn)與 .ts 文件相同
declarationMap 是否為聲明文件.d.ts生成map文件
sourceMap 編譯時(shí)是否生成.map文件
outFile 是否將輸出文件合并為一個(gè)文件,值是一個(gè)文件路徑名丰嘉,只有設(shè)置module的值為amdsystem模塊時(shí)才支持這個(gè)配置
outDir 指定輸出文件夾
rootDir 編譯文件的根目錄夯到,編譯器會(huì)在根目錄查找入口文件
composite 是否編譯構(gòu)建引用項(xiàng)目
removeComments 是否將編譯后的文件中的注釋刪掉
noEmit 不生成編譯文件
importHelpers 是否引入tslib里的輔助工具函數(shù)
downlevelIteration 當(dāng)target為ES5ES3時(shí),為for-of饮亏、spreaddestructuring中的迭代器提供完全支持
isolatedModules 指定是否將每個(gè)文件作為單獨(dú)的模塊耍贾,默認(rèn)為true

嚴(yán)格檢查
**

參數(shù) 解釋
strict 是否啟動(dòng)所有類型檢查
noImplicitAny 不允許默認(rèn)any類型
strictNullChecks 當(dāng)設(shè)為true時(shí),null和undefined值不能賦值給非這兩種類型的值
strictFunctionTypes 是否使用函數(shù)參數(shù)雙向協(xié)變檢查
strictBindCallApply 是否對(duì)bind路幸、call和apply綁定的方法的參數(shù)的檢測(cè)是嚴(yán)格檢測(cè)的
strictPropertyInitialization 檢查類的非undefined屬性是否已經(jīng)在構(gòu)造函數(shù)里初始化
noImplicitThis 不允許this表達(dá)式的值為any類型的時(shí)候
alwaysStrict 指定始終以嚴(yán)格模式檢查每個(gè)模塊

額外檢查
**

參數(shù) 解釋
noUnusedLocals 檢查是否有定義了但是沒(méi)有使用的變量
noUnusedParameters 檢查是否有在函數(shù)體中沒(méi)有使用的參數(shù)
noImplicitReturns 檢查函數(shù)是否有返回值
noFallthroughCasesInSwitch 檢查switch中是否有case沒(méi)有使用break跳出

模塊解析檢查
**

參數(shù) 解釋
moduleResolution 選擇模塊解析策略荐开,有nodeclassic兩種類型,詳細(xì)說(shuō)明
baseUrl 解析非相對(duì)模塊名稱的基本目錄
paths 設(shè)置模塊名到基于baseUrl的路徑映射
rootDirs 可以指定一個(gè)路徑列表,在構(gòu)建時(shí)編譯器會(huì)將這個(gè)路徑列表中的路徑中的內(nèi)容都放到一個(gè)文件夾中
typeRoots 指定聲明文件或文件夾的路徑列表
types 用來(lái)指定需要包含的模塊
allowSyntheticDefaultImports 允許從沒(méi)有默認(rèn)導(dǎo)出的模塊中默認(rèn)導(dǎo)入
esModuleInterop 為導(dǎo)入內(nèi)容創(chuàng)建命名空間,實(shí)現(xiàn)CommonJS和ES模塊之間的互相訪問(wèn)
preserveSymlinks 不把符號(hào)鏈接解析為其真實(shí)路徑

sourcemap檢查
**

參數(shù) 解釋
sourceRoot 調(diào)試器應(yīng)該找到TypeScript文件而不是源文件位置
mapRoot 調(diào)試器找到映射文件而非生成文件的位置简肴,指定map文件的根路徑
inlineSourceMap 指定是否將map文件的內(nèi)容和js文件編譯在一個(gè)同一個(gè)js文件中
inlineSources 是否進(jìn)一步將.ts文件的內(nèi)容也包含到輸出文件中

**
試驗(yàn)選項(xiàng)
**

參數(shù) 解釋
experimentalDecorators 是否啟用實(shí)驗(yàn)性的裝飾器特性
emitDecoratorMetadata 是否為裝飾器提供元數(shù)據(jù)支持

試驗(yàn)選項(xiàng)

參數(shù) 解釋
files 配置一個(gè)數(shù)組列表晃听,里面包含指定文件的相對(duì)或絕對(duì)路徑,編譯器在編譯的時(shí)候只會(huì)編譯包含在files中列出的文件
include include也可以指定要編譯的路徑列表砰识,但是和files的區(qū)別在于能扒,這里的路徑可以是文件夾,也可以是文件
exclude exclude表示要排除的辫狼、不編譯的文件初斑,他也可以指定一個(gè)列表
extends extends可以通過(guò)指定一個(gè)其他的tsconfig.json文件路徑,來(lái)繼承這個(gè)配置文件里的配置
compileOnSave 在我們編輯了項(xiàng)目中文件保存的時(shí)候膨处,編輯器會(huì)根據(jù)tsconfig.json的配置重新生成文件
references 一個(gè)對(duì)象數(shù)組,指定要引用的項(xiàng)目

tsconfig.json 的基本配置

{
  "compilerOptions": {
    "outDir": "./dist",
    "sourceMap": true,
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "module": "commonjs",
    "target": "es5",
    "jsx": "react",
    "baseUrl": ".",
    "paths": {
      "@/*": [
        "src/*"
      ]
    }
  },
  "include": [
    "./src/**/*"
  ]
}

ts配置文件梳理完畢见秤。

4. 代碼校驗(yàn)

4.1 代碼檢查的目的:

  • 規(guī)范的代碼可以促進(jìn)團(tuán)隊(duì)合作
  • 規(guī)范的代碼可以降低維護(hù)成本
  • 規(guī)范的代碼有助于 code review(代碼審查)

4.2 常見(jiàn)的代碼規(guī)范文檔

4.3 代碼與檢查插件eslint(vscode)

在vscode 商店中搜索 eslint, 然后安裝


image.png

配置生效方式一:(修改vscode 配置)

{
  "eslint.options": { "configFile": "C:/mydirectory/.eslintrc.json" }
}

方式二:給每個(gè)單獨(dú)的工程增加配置文件


image.png

4.4 安裝模塊

cnpm i eslint typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin --save-dev

4.5 基本配置

module.exports = {
    "parser":"@typescript-eslint/parser",
    "plugins":["@typescript-eslint"],
    "rules":{
        "no-var":"error",
        "no-extra-semi":"error",
        "@typescript-eslint/indent":["error",2]
    },
    "parserOptions": {
        "ecmaVersion": 6,
        "sourceType": "module",
        "ecmaFeatures": {
          "modules": true
        }
    }
}

// package.json
"scripts": {
+  "lint": "eslint --fix  --ext .js,.vue src",
 }

4.6 代碼與檢查

cnpm i husky lint-staged --save-dev

// package.json 

"husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "src/**/*.js": [
      "eslint --fix",
      "git add"
    ],
    "src/**/*.less": [
      "stylelint --fix",
      "git add"
    ]
  },

5. 單元測(cè)試

5.1 安裝與配置

cnpm i jest @types/jest ts-jest jest -D // 依賴包
npx ts-jest config:init // 生成配置文件

// package.json
 "scripts": {
 +  "jest-test": "jest -o",
 +  "jest-coverage": "jest --coverage"
  },

5.2 配置文件展示

module.exports = {
  roots: [
    "<rootDir>/packages"
  ],
  testRegex: 'test/(.+)\\.test\\.(jsx?|tsx?)$',
  transform: {
    "^.+\\.tsx?$": "ts-jest"
  },
  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
};

注意: 這里只是簡(jiǎn)單的列舉了下需要的東西,和一個(gè)夠用的配置真椿。如果要按照具體需求配置的話秦叛,需要查看文檔。

6. git提交規(guī)范與changelog (發(fā)包)

6.1 優(yōu)點(diǎn)

  1. 良好的git commit好處
  • 可以加快code review 的流程
  • 可以根據(jù)git commit 的元數(shù)據(jù)生成changelog
  • 可以讓其它開(kāi)發(fā)者知道修改的原因

6.2 良好的commit

  • commitizen是一個(gè)格式化commit message的工具

  • validate-commit-msg 用于檢查項(xiàng)目的 Commit message 是否符合格式

  • conventional-changelog-cli可以從git metadata生成變更日志

  • 統(tǒng)一團(tuán)隊(duì)的git commit 標(biāo)準(zhǔn)

  • 可以使用angulargit commit日志作為基本規(guī)范

    • 提交的類型限制為 feat瀑粥、fix挣跋、docs、style狞换、refactor避咆、perf、test修噪、chore查库、revert等
    • 提交信息分為兩部分,標(biāo)題(首字母不大寫黄琼,末尾不要加標(biāo)點(diǎn))樊销、主體內(nèi)容(描述修改內(nèi)容)
  • 日志提交友好的類型選擇提示 使用commitize工具

  • 不符合要求格式的日志拒絕提交 的保障機(jī)制

    • 需要使用validate-commit-msg工具
  • 統(tǒng)一changelog文檔信息生成

    • 使用conventional-changelog-cli工具
cnpm i commitizen  validate-commit-msg conventional-changelog-cli -D
commitizen init cz-conventional-changelog --save --save-exact
git cz

使用 git cz 命令:可以很方便的操作。


image.png

6.3 提交的格式

<type>(<scope>):<subject/>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
  • 代表某次提交的類型,比如是修復(fù)bug還是增加feature
  • 表示作用域围苫,比如一個(gè)頁(yè)面或一個(gè)組件
  • 主題 裤园,概述本次提交的內(nèi)容
  • 詳細(xì)的影響內(nèi)容
  • 修復(fù)的bug和issue鏈接
    | 類型 | 含義 |
    | :--- | :--- |
    | feat | 新增feature |
    | fix | 修復(fù)bug |
    | docs | 僅僅修改了文檔,比如README剂府、CHANGELOG拧揽、CONTRIBUTE等 |
    | style | 僅僅修改了空格、格式縮進(jìn)腺占、偏好等信息淤袜,不改變代碼邏輯 |
    | refactor | 代碼重構(gòu),沒(méi)有新增功能或修復(fù)bug |
    | perf | 優(yōu)化相關(guān)衰伯,提升了性能和體驗(yàn) |
    | test | 測(cè)試用例铡羡,包括單元測(cè)試和集成測(cè)試 |
    | chore | 改變構(gòu)建流程,或者添加了依賴庫(kù)和工具 |
    | revert | 回滾到上一個(gè)版本 |
    | ci | CI 配置意鲸,腳本文件等更新 |

6.4 升級(jí)package.json 版本

安裝依賴 cnpm install standard-version inquirer shelljs -D

執(zhí)行腳本:

const inquirer = require('inquirer'); // 命令行交互模塊
const shell = require('shelljs');

if (!shell.which('git')) {
    shell.echo('Sorry, this script requires git');
    shell.exit(1);
}

const getVersion = async() => {
    return new Promise((resolve, reject) => {
        inquirer.prompt([
            {
                type: 'list',
                name: 'version',
                choices: ['patch', 'minor', 'major'],
                message: 'please choose argument [major|minor|patch]: '
            }
        ]).then(answer => {
            resolve(answer.version);
        }).catch(err => {
            reject(err);
        });
    });
};

const main = async() => {
    const version = await getVersion();
    shell.echo(`\nReleasing ${version} ...\n`);
    await shell.exec(`npm run standard-version -- --release-as ${version}`);
};

main();

major:升級(jí)主要版本
minor: 升級(jí)次要版本
patch:升級(jí)補(bǔ)丁版本

6.5 生成CHANGELOG.md

  • conventional-changelog-cli 默認(rèn)推薦的 commit 標(biāo)準(zhǔn)是來(lái)自angular項(xiàng)目
  • 參數(shù)-i CHANGELOG.md表示從 CHANGELOG.md 讀取 changelog
  • 參數(shù) -s 表示讀寫 CHANGELOG.md 為同一文件
  • 參數(shù) -r 表示生成 changelog 所需要使用的 release 版本數(shù)量蓖墅,默認(rèn)為1,全部則是0
cnpm i conventional-changelog-cli -D
"scripts": {
    "changelogs": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0"
}

彩蛋:

你是否在github上見(jiàn)過(guò)這樣的release文檔

image.png

如果你感興趣临扮,下面會(huì)教你怎么配置

安裝 cnpm install gh-release -D

// package.json
 "scripts": {
    "rel": "gh-release"
  },

操作步驟:

  1. 使用 git cz 提交代碼论矾。
  2. 使用 standard-version 升級(jí)版本
  3. 使用 changelogs 生成md (注意:這個(gè)時(shí)候不要提交代碼了)
  4. 執(zhí)行 npm run rel。

就可以得到上面好看的文檔了杆勇。

7. 持續(xù)集成

繼續(xù)集成有很多中不同的方案贪壳,實(shí)現(xiàn)方式也各有不同,方式:1.Travis CI 蚜退。2 jenkins 等闰靴。 由于配置比較不復(fù)雜這里就不展開(kāi)說(shuō)了,具體的可以根據(jù)公司的情況钻注,和運(yùn)維一起進(jìn)行配置蚂且。

結(jié)束!7怠P铀馈!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末捆交,一起剝皮案震驚了整個(gè)濱河市淑翼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,607評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件衡载,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡杯活,警方通過(guò)查閱死者的電腦和手機(jī)狰腌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門柳畔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)鼎姐,“玉大人哪雕,你說(shuō)我怎么就攤上這事船殉。” “怎么了热监?”我有些...
    開(kāi)封第一講書人閱讀 164,960評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)饮寞。 經(jīng)常有香客問(wèn)我孝扛,道長(zhǎng),這世上最難降的妖魔是什么幽崩? 我笑而不...
    開(kāi)封第一講書人閱讀 58,750評(píng)論 1 294
  • 正文 為了忘掉前任苦始,我火速辦了婚禮,結(jié)果婚禮上慌申,老公的妹妹穿的比我還像新娘陌选。我一直安慰自己,他們只是感情好蹄溉,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布咨油。 她就那樣靜靜地躺著,像睡著了一般柒爵。 火紅的嫁衣襯著肌膚如雪役电。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,604評(píng)論 1 305
  • 那天棉胀,我揣著相機(jī)與錄音法瑟,去河邊找鬼。 笑死唁奢,一個(gè)胖子當(dāng)著我的面吹牛霎挟,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播麻掸,決...
    沈念sama閱讀 40,347評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼酥夭,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了脊奋?” 一聲冷哼從身側(cè)響起采郎,我...
    開(kāi)封第一講書人閱讀 39,253評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎狂魔,沒(méi)想到半個(gè)月后蒜埋,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,702評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡最楷,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評(píng)論 3 336
  • 正文 我和宋清朗相戀三年整份,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了待错。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,015評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡烈评,死狀恐怖火俄,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情讲冠,我是刑警寧澤瓜客,帶...
    沈念sama閱讀 35,734評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站竿开,受9級(jí)特大地震影響谱仪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜否彩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評(píng)論 3 330
  • 文/蒙蒙 一疯攒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧列荔,春花似錦敬尺、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,934評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至崎溃,卻和暖如春呜舒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背笨奠。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,052評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工袭蝗, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人般婆。 一個(gè)月前我還...
    沈念sama閱讀 48,216評(píng)論 3 371
  • 正文 我出身青樓到腥,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親蔚袍。 傳聞我的和親對(duì)象是個(gè)殘疾皇子乡范,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評(píng)論 2 355

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

  • 一、新建項(xiàng)目 1啤咽、先安裝腳手架vue-cli晋辆,已集成webpack cnpm install vue-cli -g...
    chqqq閱讀 1,393評(píng)論 0 0
  • 1. TypeScript工程化開(kāi)發(fā) 前端工程化就是通過(guò)流程規(guī)范化、標(biāo)準(zhǔn)化提升團(tuán)隊(duì)協(xié)作效率 通過(guò)組件化宇整、模塊化提升...
    張Piers閱讀 1,033評(píng)論 0 0
  • 前言 web應(yīng)用復(fù)雜度的增加瓶佳,特別是單頁(yè)面應(yīng)用的風(fēng)靡。組件化鳞青,工程化霸饲,自動(dòng)化成了前端發(fā)展的趨勢(shì)为朋。每個(gè)前端團(tuán)隊(duì)都在打...
    前端的爬行之旅閱讀 533評(píng)論 0 1
  • 1.webpack與grunt、gulp的不同厚脉? Grunt习寸、Gulp是基于任務(wù)運(yùn)行的工具: 它們會(huì)自動(dòng)執(zhí)行指定的...
    北冥有魚_425c閱讀 2,166評(píng)論 0 4
  • 夜鶯2517閱讀 127,720評(píng)論 1 9