深入淺出webpack

第一章入門(mén)

1.1 前端的發(fā)展

1.1.1模塊化

模塊化是指將一個(gè)復(fù)雜的系統(tǒng)分解為多個(gè)模塊 以方便編碼
1、 CommonJS 是一種被廣泛使用的JavaScript 模塊化規(guī)范,其核心思想是通過(guò)require方法來(lái)同步加載依賴的其他模塊,通過(guò)module.exports導(dǎo)出需要暴露的接口

  • 優(yōu)點(diǎn)
    • 代碼可復(fù)用于Node.js 環(huán)境下并運(yùn)行,例如做同構(gòu)應(yīng)用(前后端通用的代碼)
    • 通過(guò)Npm 發(fā)布的很多第三方模塊都采用了CommonJS 規(guī)范
  • 缺點(diǎn)
    • 這樣的代碼無(wú)法直接運(yùn)行在瀏覽器環(huán)境下,必須通過(guò)工具轉(zhuǎn)換成標(biāo)準(zhǔn)的ES5

2、 AMD 也是一種JavaScript模塊化規(guī)范,與CommonJS 最大的不同在于,它采用了異步的方式去加載依賴的模塊。AMD規(guī)范主要用于解決針對(duì)瀏覽器環(huán)境的模塊化問(wèn)題,最具代表性的實(shí)現(xiàn)是requirejs,使用 define定義模塊,使用require導(dǎo)入模塊

  • AMD優(yōu)點(diǎn)
    • 可在不轉(zhuǎn)換代碼的情況下直接在瀏覽器中運(yùn)行
    • 可異步加載依賴
    • 可并行加載多個(gè)依賴
    • 代碼可運(yùn)行在瀏覽器環(huán)境和Node.js環(huán)境下
  • AMD缺點(diǎn)
    • JavaScript 運(yùn)行環(huán)境沒(méi)有原生支持AMD,需要先導(dǎo)入實(shí)現(xiàn)了AMD 的庫(kù)后才能正常使用

3、ES6 模塊化

  • ES6 模塊化是國(guó)際標(biāo)準(zhǔn)化組織ECMA 提出的JavaScript 模塊化規(guī)范,它在語(yǔ)言層面上實(shí)現(xiàn)了模塊化。瀏覽器廠商和Node都宣布要原生支持該規(guī)范。它將逐漸取代CommonJS 和AMD 規(guī)范,成為瀏覽器和服務(wù)器通用的模塊解決方案。使用import導(dǎo)入模塊, export導(dǎo)出模塊
    • 缺點(diǎn)
      • 目前無(wú)法直接運(yùn)行在大部分JavaScript運(yùn)行環(huán)境下,必須通過(guò)工具轉(zhuǎn)換成標(biāo)準(zhǔn)的ES5 后才能正常運(yùn)行

4、樣式文件中的模塊化

1.1.2 新框架

  1. React
    React框架引入了JSX 語(yǔ)法到JavaScript 語(yǔ)言層面中,可以更靈活地控制視圖的渲染邏輯。
  2. Vue
    Vue ( https: //vuejs.org )框架將與一個(gè)組件相關(guān)的HTML模板、JavaScript 邏輯代碼、css樣式代碼都寫(xiě)在一個(gè)文件里,這非常直觀。

3 . Angular2
Angular2 推崇采用Typescript 語(yǔ)言開(kāi)發(fā)應(yīng)用,并且可以通過(guò)注解的語(yǔ)法描述組件的各種屬性。

1.1.3 新語(yǔ)言

  1. ES6
    ECMAScript 6.0(簡(jiǎn)稱ES6 )是JavaScript 語(yǔ)言的下一代標(biāo)準(zhǔn)。它在語(yǔ)言層面為JavaScript引入了很多新語(yǔ)法和API ,使得JavaScript 語(yǔ)言可以用來(lái)編寫(xiě)復(fù)雜的大型應(yīng)用程序
  2. Typescript
    TypeScript 是JavaScript 的一個(gè)超集,由Microsoft 開(kāi)發(fā)并開(kāi)源,除了支持ES6 的所有功能,還提供了靜態(tài)類(lèi)型檢查
    3 . Flow
    Flow也是JavaScript 的一個(gè)超集,它的主要特點(diǎn)是為JavaScript 提供靜態(tài)類(lèi)型檢查,和Typescript 相似但更靈活,可以讓我們只在需要的地方加上類(lèi)型檢查。
    4 . scss
    SCSS ( http ://s ass-lang .com )可以讓我們用程序員的方式寫(xiě)css 。它是一種css 預(yù)處理器,其基本思想是用和css 相似的編程語(yǔ)言寫(xiě)完后再編譯成正常的css 文件。

1.2常見(jiàn)的構(gòu)建工具及對(duì)比

概述

構(gòu)建就是將源代碼轉(zhuǎn)換成可執(zhí)行的JavaScript 、css 、html代碼,包括如下內(nèi)容。

  • 代碼轉(zhuǎn)換:將TypeScript 編譯成JavaScript 、將scss 編譯成css 等。
  • 文件優(yōu)化:壓縮JavaScript 、css 、html代碼,壓縮合并圖片等。
  • 代碼分割:提取多個(gè)頁(yè)面的公共代碼,提取首屏不需要執(zhí)行部分的代碼讓其異步加載。
  • 模塊合并:在采用模塊化的項(xiàng)目里會(huì)有很多個(gè)模塊和文件,需要通過(guò)構(gòu)建功能將模塊分類(lèi)合并成一個(gè)文件。
  • 自動(dòng)刷新:監(jiān)昕本地源代碼的變化,自動(dòng)重新構(gòu)建、刷新瀏覽器。
  • 代碼校驗(yàn):在代碼被提交到倉(cāng)庫(kù)前需要校驗(yàn)代碼是否符合規(guī)范,以及單元測(cè)試是否通過(guò)。
  • 自動(dòng)發(fā)布:更新代碼后,自動(dòng)構(gòu)建出線上發(fā)布代碼井傳輸給發(fā)布系統(tǒng)。

構(gòu)建其實(shí)是工程化、自動(dòng)化思想在前端開(kāi)發(fā)中的體現(xiàn),將一系列流程用代碼去實(shí)現(xiàn),讓代碼自動(dòng)化地執(zhí)行這一系列復(fù)雜的流程。構(gòu)建為前端開(kāi)發(fā)注入了更大的活力,解放了我們的生產(chǎn)力。

常用的構(gòu)建工具

  • webpack、grunt、gulp、browserify、yeoman、FIS3、Rollup、Parcel

Webpack是一個(gè)打包模塊化JavaScript 的工具,在Webpack 里一切文件皆模塊,通過(guò)Loader 轉(zhuǎn)換文件,通過(guò)Plugin 注入鉤子,最后輸出由多個(gè)模塊組合成的文件。Webpack 專注于構(gòu)建模塊化項(xiàng)目。

1.3安裝與使用

1.3.3 使用webpack

構(gòu)建一個(gè)最簡(jiǎn)單的webpack項(xiàng)目步驟如下:

1、新建一個(gè)web項(xiàng)目
在node環(huán)境下,新建一個(gè)目錄,再進(jìn)入項(xiàng)目根目錄,初始化最簡(jiǎn)單的采用了模塊化開(kāi)發(fā)的項(xiàng)目

npm init -y

2、安裝webpack

npm i webpack@4.44 -D

運(yùn)行安裝在項(xiàng)目中的webpack,有以下兩種方式

  • 在項(xiàng)目根目錄下對(duì)應(yīng)的命令行里通過(guò)node rnodules/.bin/webpack 運(yùn)行
    Webpack 的可執(zhí)行文件
  • 在Npm Script 里定義的任務(wù)會(huì)優(yōu)先使用本項(xiàng)目下的Webpack,在package.json文件中
scripts: {
  start: webpack --config webpack.config.js
}

3、實(shí)例:構(gòu)建一個(gè)采用了CommonJS 模塊化編寫(xiě)的項(xiàng)目,該項(xiàng)目中的某個(gè)網(wǎng)頁(yè)會(huì)通過(guò)JavaScript 顯示Hello Webpack 。
詳見(jiàn) F:\學(xué)習(xí)\webpack\allDemo\demo1.3.3

1.4使用Loader

1、在demo1.3.3項(xiàng)目中加入css文件
詳見(jiàn) F:\學(xué)習(xí)\webpack\allDemo\demo1.4
2、步驟

  • 新建main.css
  • 將main.css引入main.js
require('./main.css)
  • 修改配置文件
 module: {
        rules: [
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader']
            }
        ]
    }
  • 安裝style-loader,css-loader

1.5使用Plugin

1、在demo1.4項(xiàng)目中單獨(dú)提取css,并且對(duì)css進(jìn)行壓縮
詳見(jiàn) F:\學(xué)習(xí)\webpack\allDemo\demo1.5
2、詳細(xì)步驟

  • 安裝單獨(dú)提取css的插件mini-css-extract-plugin和壓縮css文件插件optimize-css-assets-webpack-plugin
  • 修改配置文件
const miniCssExtractPlugin = require('mini-css-extract-plugin')
const optimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
 module: {
        rules: [
            {
                test: /\.css$/,
                use: [miniCssExtractPlugin.loader, 'css-loader']
            }
        ]
    },
plugins: [
     new miniCssExtractPlugin(
            {
                filename: `./css/[name].css?v=[contenthash:4]`
            }
     ),
    new optimizeCssAssetsWebpackPlugin(
            {
            assetNameRegExp: /\.css(.*)$/,
            cssProcessor: require('cssnano'),
            cssProcessorOptions: {
              safe: true,
              discardComments: {
                removeAll: true
              }
            },
            canPrint: true
          }
        )
    ]

1.6使用DevServer

1、步驟

  • 安裝webpack-dev-server
  • 啟動(dòng) webpack-dev-server --config webpack.config.js
  • 訪問(wèn)localhost
    2、注意點(diǎn)
    webpack-dev-server與webpack-cli最新版不兼容,要安裝webpack-cli@3
    3、配置模塊熱替換和source map
  • 模塊熱替換: 在不重新加載整個(gè)網(wǎng)頁(yè)的情況下,通過(guò)將被更新過(guò)的模塊替換老的模塊,再重新執(zhí)行一次來(lái)實(shí)現(xiàn)實(shí)時(shí)預(yù)覽
  • source Map:查看源碼
  • 具體配置
devtool: 'source-map', // 可選模式有七種,常用source-map和eval-source-map
devServer: {
        hot: true
    }
  • 查看源碼:控制臺(tái)sources下面的webpack文件夾下面有個(gè).文件夾中

第二章配置

2.1 entry

2.1.1 context

Webpack 在尋找相對(duì)路徑的文件時(shí)會(huì)以context 為根目錄, context 默認(rèn)為執(zhí)行啟動(dòng)Webpack 時(shí)所在的當(dāng)前工作目錄,通常為'',也可以自定義

const path = require('path')
module.exports = {
    context: path.resolve(__dirname,'app'),
}

2.1.2 entry的類(lèi)型

     // entry的屬性值可以是string\array\Object
    entry: './main.js'
    // array 類(lèi)型,則搭配output.library 配置項(xiàng)使用時(shí),只有數(shù)組里的最后一個(gè)入口文件的模塊會(huì)被導(dǎo)出
    entry: ['./main.js', './entry.js']
    // 配置多個(gè)入口,每個(gè)入口生成一個(gè)Chunk
    entry: {
        a: './entry1.js',
        b: './entry2.js',
        c: './entry3.js'
    }

2.1.3 chunk的名稱

Webpack 會(huì)為每個(gè)生成的Chunk 取一個(gè)名稱, Chunk 的名稱和entry的配置有關(guān)。

  • 如果entry 是一個(gè)string 或array ,就只會(huì)生成一個(gè)Chunk ,這時(shí)Chunk 的名稱是main
  • 如果entry 是一個(gè)object ,就可能會(huì)出現(xiàn)多個(gè)Chunk ,這時(shí)Chunk 的名稱是object 鍵值對(duì)中鍵的名稱。

2.2 output

output: {
        //filename 配置輸出文件的名稱,為string 類(lèi)型
        filename: 'bundle.js' ,// 如果只有一個(gè)輸出文件,則可以將它寫(xiě)成靜態(tài)不變的:
        filename: '[name].js',// 在有多個(gè)Chunk 要輸出時(shí),就需要借助模板和變量了,內(nèi)置變量有name\id\hash\chunkhash
        // chunkFilename用于指定在運(yùn)行過(guò)程中生成的Chunk 在輸出時(shí)的文件名稱
        chunkFilename:'common.js', 
        // path 配置輸出文件存放在本地的目錄,必須是string 類(lèi)型的絕對(duì)路徑
        path: path.resolve(__dirname, 'dist'),
        // publicPath 配置發(fā)布到線上資源的URL 前綴
        publicPath: 'https://cdn.example.com/assets/',
        // libraryTarget 配置以何種方式導(dǎo)出庫(kù),支持var/commonjs2/this/window/global
        libraryTarget: '',
        //library 配置導(dǎo)出庫(kù)的名稱
        library: 'LibraryName',
        // libraryExport 配置要導(dǎo)出的模塊中哪些子模塊需要被導(dǎo)出
        libraryExport: 'a'
    }

2.3 module

配置處理模塊的規(guī)則

 module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    'style-loader',
                    {
                        loader: 'css-loader',
                        options:{
                            miniminze: true
                        },
                        /**
                         * 一組Loader 的執(zhí)行順序默認(rèn)是從右到左執(zhí)行的
                         * 通過(guò)enforce 選項(xiàng)可以將其中一個(gè)Loader 的執(zhí)行順序放到最前或者最后
                         * post的含義是將該Loader 的執(zhí)行順序放到最后
                         * pre代表將Loader 的執(zhí)行順序放到最前面
                         */
                        enforce: 'post'
                    }
                ],
                // 只命中src目錄里的JavaScript文件,加快Webpack 的搜索速度
                include: path.resolve(__dirname, 'src'),
                // 排除node modules目錄下的文件
                exclude:path.resolve(__dirname, 'node modules')
            }
        ],
        /**
         * 1、noParse 配置項(xiàng)可以讓W(xué)ebpack 忽略對(duì)部分沒(méi)采用模塊化的文件的遞歸解析和處理
         * 這樣做的好處是能提高構(gòu)建性能
         * 2、noParse 是可選的配置項(xiàng),類(lèi)型需要是RegExp 、[ RegExp )、fun ction 中的一種
         */
        noParse: /jquery|chartjs/,
        // parser 屬性可以更細(xì)粒度地配置哪些模塊語(yǔ)法被解析、哪些不被解析
        parser: {
            amd: false, //禁用AMD
            commonjs : false, //禁用CommonJS
            system : false, //禁用SystemJS
            harmony : false, //禁用ES6 import/export
            requireinclude: false, //禁用require .in cl ude
            requireEnsure: false, //禁用require . ens ur e
            requireContext: false, //禁用require.context
            browserify: false, //禁用browserify
            requireJs : false, //禁用requirejs
        }
    }

2.4 resolve

Webpack 在啟動(dòng)后會(huì)從配置的入口模塊出發(fā)找出所有依賴的模塊, Resolve 配置Webpack如何尋找模塊所對(duì)應(yīng)的文件。

resolve: {
        /**
         * alias 配置項(xiàng)通過(guò)別名來(lái)將原導(dǎo)入路徑映射成一個(gè)新的導(dǎo)入路徑
         * alias 還支持通過(guò)$符號(hào)來(lái)縮小范圍到只命中以關(guān)鍵字結(jié)尾的導(dǎo)入語(yǔ)句
         */
        alias: {
            components: './src/components/',
            'react$': '/path/react.min.js'
        },
        /**
         * 有一些第三方模塊會(huì)針對(duì)不同的環(huán)境提供幾份代碼
         * Webpack 會(huì)根據(jù)mainFields 的配置去決定優(yōu)先采用哪份代碼
         */
        mainFields: ['jsnext:main', 'browser', 'main'],
        /**
         * 在導(dǎo)入語(yǔ)句沒(méi)帶文件后綴時(shí), Webpack 會(huì)自動(dòng)帶上后綴后去嘗試訪問(wèn)文件是否存在。
         * resolve.extensions 用于配置在嘗試過(guò)程中用到的后綴列表            
         */
        extensions: ['.js', '.json'],
        // 配置Webpack 去哪些目錄下尋找第三方模塊,默認(rèn)只會(huì)去node modules 目錄下尋找
        modules: ['./ src/cornponents', 'node modules'],
        // 配置描述第三方模塊的文件名稱
        descriptionFiles: ['package.json'],
        // 是否所有的導(dǎo)入語(yǔ)句都帶后綴
        enforceExtension: false,
        // 功能與enforceExtension類(lèi)似,只對(duì)node_modules下的模塊生效,通常與enforceExtension配合使用
        enforceModuleExtension: false
    }

2.5 plugin

const miniCssExtractPlugin = require('mini-css-extract-plugin')
 plugins: [
        new miniCssExtractPlugin(
            {
                filename: `./css/[name].css?v=[contenthash:4]`
            }
        )   
    ]

2.6 Devserver

2.6.6 host

devServer.host 配置項(xiàng)用于配置DevServer 服務(wù)監(jiān)聽(tīng)的地址,只能通過(guò)命令行參數(shù)傳入。例如,若想讓局域網(wǎng)中的其他設(shè)備訪問(wèn)自己的本地服務(wù),則可以在啟動(dòng)Dev Server 時(shí)帶上--host 0.0.0 。host 的默認(rèn)值是127.0.0.1 ,即只有本地可以訪問(wèn)Dev Server 的HTTP服務(wù)。

2.6.9 disableHostCheck

devServer.disableHostCheck 配置項(xiàng)用于配置是否關(guān)閉用于DNS 重新綁定的HTTP請(qǐng)求的HOST 檢查。
DevServer 默認(rèn)只接收來(lái)自本地的請(qǐng)求, 關(guān)閉后可以接收來(lái)自任意HOST的請(qǐng)求。
它通常用于搭配-- host 0.0.0 使用, 因?yàn)橄胱屍渌O(shè)備訪問(wèn)自己的本地服務(wù),但訪問(wèn)時(shí)是直接通過(guò)IP 地址訪問(wèn)而不是通過(guò)HOST 訪問(wèn),所以需要關(guān)閉HOST 檢查。

  devServer: {
        hot: true,// 開(kāi)啟模塊熱替換
        // inline 用于配置是否將這個(gè)代理客戶端自動(dòng)注入將運(yùn)行在頁(yè)面中的Chunk 里,默認(rèn)自動(dòng)注入
        inline: true,
        // historyApiFallback用于方便地開(kāi)發(fā)使用了HTML5 History API的單頁(yè)應(yīng)用
        historyApiFallback: true,
        // contentBase 配置DevServer HTTP 服務(wù)器的文件根目錄
        contentBase : path.join( __dirname,'public'),
        // headers 配置項(xiàng)可以在HTTP 響應(yīng)中注入一些HTTP 響應(yīng)頭
        headers: {
            'X-foo':  'bar'
        },
        // 端口號(hào)
        port: '8081',
        allowedHosts: [
            'host . com',
            'sub.host.com',
            // host2.com 和所有的子域名*.host2.com 都將匹配
            '.host2 . com'
        ],
        // 搭配--host 0.0.0使用
        disableHostCheck: true,
        // 使用https
        https: true,
        // 配置客戶端的日志等級(jí),這會(huì)影響到我們?cè)跒g覽器開(kāi)發(fā)者工具控制臺(tái)里看到的日志內(nèi)容
        clientloglevel: 'warning',
        // compress 配置是否啟用Gzip 壓縮,為boolean 類(lèi)型,默認(rèn)為false
        compress: true,
        // open 用于在Dev Server 啟動(dòng)且第一次構(gòu)建完時(shí),自動(dòng)用我們的系統(tǒng)的默認(rèn)瀏覽器去打開(kāi)要開(kāi)發(fā)的網(wǎng)頁(yè)
        open: true
    }

2.7 其他配置項(xiàng)

module.exports = {
   // target 配置項(xiàng)可以讓W(xué)ebpack 構(gòu)建出針對(duì)不同運(yùn)行環(huán)境的代碼,可選值:node/web/async-node/webworker/electron-main/electron-renderer
    target: 'node',
    devtool: 'source-map',
    watch: true,
    externals : {
        // 將導(dǎo)入語(yǔ)句里的jquery替換成運(yùn)行環(huán)境里的全局變量jQuery
        jquery: 'jQuery'
    },
    // ResolveLoader 用來(lái)告訴Webpack如何去尋找Loader
    resolveLoader: {
        // 去哪個(gè)目錄下尋找Loader
        modules: ['node modules'] ,
        // 入口文件的后綴
        extensions :['.js','. json'] ,
        // 指明入口文件位置的字段
        mainFields: ['loader','main']
    }
}

2.8 整體配置結(jié)構(gòu)

第三章實(shí)戰(zhàn)

3.1 使用ES6語(yǔ)言

概述

將es6轉(zhuǎn)換成es5做了以下兩件事情

  • 將新的ES6 語(yǔ)法用ES5 實(shí)現(xiàn)
  • 為新的API 注入polyfill(polyfill本意是聚酯纖維填充,這里用作補(bǔ)丁或者兼容插件講,用來(lái)兼容原本一些不支持的屬性和方法)

3.1.3 認(rèn)識(shí)babel

在Babel 執(zhí)行編譯的過(guò)程中,會(huì)從項(xiàng)目根目錄下的.babelrc文件中讀取配置

/**
        1、presets屬性告訴Babel要轉(zhuǎn)換的源碼使用了哪些新的語(yǔ)法特性,一個(gè)Presets對(duì)一組
            新語(yǔ)法的特性提供了支持,多個(gè)Presets 可以疊加。Presets 其實(shí)是一組P lugins 的集合,每個(gè)
            Plugin 完成一個(gè)新語(yǔ)法的轉(zhuǎn)換工作
        2、可選值: 
            1)  es2015/es2016/es2017/env(包含當(dāng)前所有ECMAScript 標(biāo)準(zhǔn)里的最新特性)
            2)  被社區(qū)提出來(lái)的但還未被寫(xiě)入ECMAScript 標(biāo)準(zhǔn)里的特性: stage0/stage1/stage2/stage3/stage4
            3))用于支持一些特定應(yīng)用場(chǎng)景下的語(yǔ)法的特性,和ECMAScript 標(biāo)準(zhǔn)沒(méi)有關(guān)系
    */
    "presets": [
        "env",
        [
            "es2015",
            {
                "modules": false
            }
        ],
        "stage-2",
        "react"
    ],
    /** 
       * plugins屬性告訴Babel要使用哪些插件,這些插件可以控制如何轉(zhuǎn)換代碼
    */
    "plugins": [
        [
            "transform-runtime", // Babel官方提供的一個(gè)插件,作用是減少冗余的代碼
            {
                "polyfill": false
            }
        ]
    ]
}

實(shí)現(xiàn)步驟

  1. 新建.babelrc文件,內(nèi)容如下
{
    "presets": ["env"]
}
  1. 安裝插件
  npm i -D babel-core@6 babel-loader@7 babel-preset-env

注釋:

  • babel-loader 8.x對(duì)應(yīng)babel-core 7.x
  • babel-loader 7.x對(duì)應(yīng)babel-core 6.x
  1. 通過(guò)loader接入Babel
module.exports = {
  module: {
      rules: [
        {
            test: /\.js$/,
            use: ['babel-loader'],
            exclude:path.resolve(__dirname, 'node modules')
        }
      ]  
}
}

3.4 使用sass

實(shí)現(xiàn)步驟

  1. 安裝loader
  npm i node-sass sass-loader@10 style-loader css-loader

注釋:sass-loader的版本不能太高,依賴于node-sass
2.修改配置文件,增加loader配置

module: {
        rules: [
           ......
            {
                test: /\.scss/,
                use: ['style-loader', 'css-loader', 'sass-loader']
            }
          .......
        ]
    }

3.5 認(rèn)識(shí)PostCss

概述

PostCSS 是一個(gè)用 JavaScript 工具和插件轉(zhuǎn)換 CSS 代碼的工具,和scss 的不同之處在于它可以通過(guò)插件機(jī)制靈活地?cái)U(kuò)展其支持的特性,而不像scss 那樣語(yǔ)法是固定的。PostCSS 的用處非常多,包括向css 自動(dòng)加前綴、使用下一代css 語(yǔ)法等

常用插件

  • postcss-import: 合并樣式表
  • postcss-url: 用于轉(zhuǎn)換 url ( ),inline 或者復(fù)制資產(chǎn)
  • cssnano : 壓縮代碼

使用步驟

1.安裝loader

npm i -D postcss-loader@4 style-loader css-loader

2.使用autoprefixer,需要在package.json中添加browserslist配置項(xiàng)

 "browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 8"
  ]

3.安裝需要的插件,以autoprefixer為例

npm i -D autoprefixer

4.兩種配置postcss的方案

  • 新建postcss.config.js,內(nèi)容如下
module.exports = {
    plugins: [
        [
            'autoprefixer'
        ]
    ]
}
  • 修改webpack.config.js配置項(xiàng)
    有postcss.config.js文件時(shí)
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    'style-loader', 
                    'css-loader',
                    'postcss-loader'
                ]
            }
        ]
         
    }

沒(méi)有postcss.config.js文件時(shí)

rules: [
            {
                test: /\.css$/,
                use: [
                    'style-loader', 
                    {
                        loader: 'css-loader',
                        options: { importLoaders: 1 },
                    },
                    {
                        loader: 'postcss-loader',
                        options: {
                            postcssOptions:{
                                plugins: [
                                    [
                                        'autoprefixer'
                                    ]
                                ]
                            }
                        }
                    }
                ]
            }
        ]

3.7 使用vue框架

步驟

1.安裝loader

npm i -S vue
npm i -D vue-loader css-loader vue-tamplate-compiler

2.配置webpack

  module: {
        rules: [
            {
                test: /\.vue$/,
                use: ['vue-loader']
            }
        ]
    }

3.實(shí)例:vue單文件組件使用方法如下
index.html

<body>
    <div id="app"></div>
    <script src="./dist/bundle.js"></script>
</body>

App.vue

<template>
    <h1>{{ msg }}</h1>
</template>
<script>
export default {
    data() {
        return {
            msg: 'Hello App'
        }
    }
}
</script>
<style>
h1 {
    color: red;
}
</style>

main.js

import Vue from 'vue'
import App from './App.vue'

new Vue({
    el: '#app',
    render: h => h(App)
})

3.9 為單頁(yè)應(yīng)用生成html

步驟

在上述實(shí)例中添加html-webpack-plugin
1.安裝

npm i html-webpack-plugin@4

注意:html-webpack-plugin最新版本不兼容webpack4
2、修改配置文件

const HtmlPlugin = require('html-webpack-plugin')
 plugins: [
        new HtmlPlugin({
            filename: 'index.html',
            template: './template.html'
        })
    ]

3.13 構(gòu)建npm模塊

3.13.1 認(rèn)識(shí)npm

Npm (https://www.npmjs.com)是目前最大的JavaScript 模塊倉(cāng)庫(kù),里面有全世界的開(kāi)發(fā)者上傳的可復(fù)用模塊。雖然在大多數(shù)情況下我們都是這些開(kāi)放模塊的使用者,但我們也許會(huì)成為貢獻(xiàn)者,會(huì)開(kāi)發(fā)一個(gè)模塊上傳到Npm 倉(cāng)庫(kù)。
發(fā)布到Npm 倉(cāng)庫(kù)的模塊有以下幾個(gè)特點(diǎn):

  • 在每個(gè)模塊根目錄下都必須有一個(gè)描述該模塊的package.json 文件。該文件描述了模塊的入口文件是哪個(gè),該模塊又依賴哪些模塊等
  • 模塊中的文件以JavaScript 文件為主,但不限于JavaScript 文件
  • 模塊中的代碼大多采用模塊化規(guī)范,,目前支持比較廣泛的是CommonJS 模塊化規(guī)范,上傳到Npm 倉(cāng)庫(kù)的代碼最好遵守該規(guī)范。

3.14.2 認(rèn)識(shí)Service Workers

3.16 檢查代碼

3.16.1 代碼檢查具體是做什么的

3.16.2 怎么做代碼檢查

1 . 檢查JavaScript
ESlint C https: //eslint.org )
2、檢查T(mén)ypescript
TSLint ( https://palantir.github . io/tslint/)
3.檢查css
style lint ( https://stylelint.io

3.16.3 結(jié)合Webpack 檢查代碼

1.eslint-loader ( https://github.com/MoOx/eslint-loader

module.exports = {
    module: {
        rules: [
              {
                  test: /\.js$/,
                   use: ['eslint-loader'],
 // 將eslint-loader 的執(zhí)行順序放在最前面,防止其他Loader將處理后的代碼交給es lint-loader去檢查
                    enforce: 'pre'  
              }
         ]
    }
}

3.17 通過(guò)Node.js API 啟動(dòng)Webpack

3.18 使用Webpack DevMiddleware

通過(guò)webpack-dev-middleware 能夠?qū)evServer 集成到現(xiàn)有的HTTP 服務(wù)器中,讓現(xiàn)有的HTTP 服務(wù)器能返回Webpack構(gòu)建出的內(nèi)容,而不是在開(kāi)發(fā)時(shí)啟動(dòng)多個(gè)HTTP 服務(wù)器。這特別適用于后端接口服務(wù)采用Node.js 編寫(xiě)的項(xiàng)目

3.19 加載圖片

步驟

1.安裝loader

npm i -D file-loader

2.修改配置文件

  {
                test: /\.png$/,
                use: [ {
                    loader: 'file-loader',
                    options: {
                        esModule: false
                    }
                }]
            }

或者使用url-loader(小圖)結(jié)合file-loader(大圖)

 {
                test: /\.png$/,
                use: [ {
                    loader: 'url-loader',
                    options: {
                        limit: 1024 * 30,
                        fallback: 'file-loader',
                        esModule: false
                    }
                }]
            }

3.21 加載Source Map

第四章優(yōu)化

概述

1.優(yōu)化開(kāi)發(fā)體驗(yàn)

  • 優(yōu)化構(gòu)建速度
  • 優(yōu)化使用體驗(yàn)

2.優(yōu)化輸出質(zhì)量

  • 減少用戶感知到的加載時(shí)間
  • 提升流暢度

4.1 縮小文件的搜索范圍

4.1.1 優(yōu)化Loader 配置

在使用Loader 時(shí),可以通過(guò)test 、include 、exclude 三個(gè)配置項(xiàng)來(lái)命中Loader 要應(yīng)用規(guī)則的文件

4 .1.2 優(yōu)化resolve.modules、resolve.mainFields、resolve.alias、resolve.extensions、module. noParse配置

 module.exports = {
      resolve : {
        // 使用絕對(duì)路徑指明第三方模塊存放的位置,以減少搜索步驟
          modules: [path.resolve( __dirname ,'node modules ')],
          mainFields: ['main'],
          alias: {
            'react': path.resolve( __dirname,’./nodemodules/react/dist/react.min.js ’),
          'src': path.resolve(__dirname, 'src')
          },
        extensions:[ '.js', '.json']
      },
    module: {
        noParse: [/react\.min\.js$/]
    }
}

4.2 使用DllPlugin

4.2.1 認(rèn)識(shí)DLL

以.dll為后綴名的文件,叫做動(dòng)態(tài)鏈接庫(kù),在一個(gè)動(dòng)態(tài)鏈接庫(kù)中可以包含為其他模塊調(diào)用的函數(shù)和數(shù)據(jù)要給Web 項(xiàng)目構(gòu)建接入動(dòng)態(tài)鏈接庫(kù)的思想,需要完成以下事情。

  • 將網(wǎng)頁(yè)依賴的基礎(chǔ)模塊抽離出來(lái),打包到一個(gè)個(gè)單獨(dú)的動(dòng)態(tài)鏈接庫(kù)中,一個(gè)動(dòng)態(tài)鏈接庫(kù)中可以包含多個(gè)模塊。
  • 當(dāng)需要導(dǎo)入的模塊存在于某個(gè)動(dòng)態(tài)鏈接庫(kù)中時(shí),這個(gè)模塊不能被再次打包,而是去動(dòng)態(tài)鏈接庫(kù)中獲取。
  • 頁(yè)面依賴的所有動(dòng)態(tài)鏈接庫(kù)都需要被加載。

4.2.2 接入Webpack

Webpack 己經(jīng)內(nèi)置了對(duì)動(dòng)態(tài)鏈接庫(kù)的支持,需要通過(guò)以下兩個(gè)內(nèi)置的插件接入。

  • DllPlugin 插件: 用于打包出一個(gè)個(gè)單獨(dú)的動(dòng)態(tài)鏈接庫(kù)文件
  • DllReferencePlugin 插件:用于在主要的配置文件中引入DllP!ugin 插件打包好的動(dòng)態(tài)鏈接庫(kù)文件。

具體實(shí)現(xiàn)方式

1.構(gòu)建出動(dòng)態(tài)鏈接庫(kù)文件

const path = require('path')
const dllPlugin = require('webpack/lib/DllPlugin')
module.exports = {
    entry: {
        // 將React 相關(guān)的模塊放到一個(gè)單獨(dú)的動(dòng)態(tài)鏈接庫(kù)中
        react: ['react', 'react-dom'],
        // 將項(xiàng)目需要所有的polyfill 放到一個(gè)單獨(dú)的動(dòng)態(tài)鏈接庫(kù)中
        polyfill: ['core-js/fn/object/assign', 'core-js/fn/promise', 'whatwg-fetch']
    },
    output: {
        // 輸出的動(dòng)態(tài)鏈接庫(kù)的文件名稱,[name]代表當(dāng)前動(dòng)態(tài)鏈接庫(kù)的名稱
        filename: '[name].dll.js',
        path: path.resolve(__dirname, 'dist'),
        // 存放動(dòng)態(tài)鏈接庫(kù)的全局變量名稱,例如對(duì)于react 來(lái)說(shuō)就是_dll_react,之所以在前面加上dll ,是為了防止全局變量沖突
        library: '_dll_[name]'
    },
    plugins: [
        new dllPlugin({
            name: '_dll_[name]',
            path: path.join(__dirname, 'dist', '[name].manifest.json')
        })
    ]
}

2.使用動(dòng)態(tài)鏈接庫(kù)文件

const path = require('path')
const DllReferencePlugin = require('webpack/lib/DllReferencePlugin')
module.exports = {
    entry: {
        main: './main.js'
    },
    output: {
        // 輸出的動(dòng)態(tài)鏈接庫(kù)的文件名稱,[name]代表當(dāng)前動(dòng)態(tài)鏈接庫(kù)的名稱
        filename: '[name].js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                use: ['babel-loader'],
                exclude: path.resolve(__dirname, 'node_modules')
            }
        ]
    },
    plugins: [
        new DllReferencePlugin({
            manifest: require('./dist/react.manifest.json')
        }),
        new DllReferencePlugin({
            manifest: require('./dist/polyfill.manifest.json')
        })
    ]
}

3.執(zhí)行構(gòu)建

  • 第一步
webpack --config webpack dll.config.js
  • 第二步:在確保動(dòng)態(tài)鏈接庫(kù)存在時(shí),才能正常編譯入口執(zhí)行文件。方法是執(zhí)行webpack 命令

4.3.1 使用HappyPack

webpack自帶插件,用于分解任務(wù)和管理線程

4.4 使用ParallelUglifyPlugin

概述

由于壓縮JavaScript 代碼時(shí),需要先將代碼解析成用Object 抽象表示的AST 語(yǔ)法樹(shù),再去應(yīng)用各種規(guī)則分析和處理AST,所以導(dǎo)致這個(gè)過(guò)程的計(jì)算量巨大, 耗時(shí)非常多。

實(shí)現(xiàn)方式

當(dāng)Webpack 有多個(gè)JavaScript 文件需要輸出和壓縮時(shí),原本會(huì)使用uglifyJS 去一個(gè)一個(gè)壓縮再輸出,但是ParallelUglifyPlugin 會(huì)開(kāi)啟多個(gè)子進(jìn)程,將對(duì)多個(gè)文件的壓縮工作分配給多個(gè)子進(jìn)程去完成,每個(gè)子進(jìn)程其實(shí)還是通過(guò)UglifyJS 去壓縮代碼,但是變成了并行執(zhí)行。所以ParallelUglifyPlugin 能更快地完成對(duì)多個(gè)文件的壓縮工作。
注意:webpack4的js壓縮,設(shè)置mode或者使用terser-webpack-plugin插件

4.5 使用自動(dòng)刷新

4.5. 1 文件監(jiān)昕

有以下兩種方式

  • 在webpack.config.js中設(shè)置watch:true
  • 使用命令webpack --watch

4.5.2 自動(dòng)刷新瀏覽器

使用webpack-dev-server模塊去自動(dòng)刷新頁(yè)面
在使用webpack-dev-server 模塊去啟動(dòng)webpack 模塊時(shí), webpack模塊的監(jiān)聽(tīng)模式默認(rèn)會(huì)被開(kāi)啟。webpack 模塊會(huì)在文件發(fā)生變化時(shí)通知webpack-de v-server模塊。

1.自動(dòng)刷新的原理

  • 借助瀏覽器擴(kuò)展去通過(guò)瀏覽器提供的接口刷新
  • 向要開(kāi)發(fā)的網(wǎng)頁(yè)中注入代理客戶端代碼,通過(guò)代理客戶端去刷新整個(gè)頁(yè)面
  • 將要開(kāi)發(fā)的網(wǎng)頁(yè)裝進(jìn)一個(gè)iframe 中,通過(guò)刷新iframe 去看到最新效果
    DevServer 支持第2 、3 種方法, 第2 種是DevServer 默認(rèn)采用的刷新方法
  1. 優(yōu)化自動(dòng)刷新的性能
    devServer.inline 配置項(xiàng),它用來(lái)控制是否向Chunk 中注入代理客戶端,默認(rèn)會(huì)注入

4.6 開(kāi)啟模塊熱替換

webpack-dev-server --hot

4.7 區(qū)分環(huán)境

module.exports = {
    plugins: [
         new webpack.DefinePlugin({
                'process.env': {
// 注意,在定義環(huán)境變量的值時(shí)用JSON.stringify 包裹字符串的原因是,環(huán)境變量的值需要是一個(gè)由雙引號(hào)包裹的字符串,而JSON.stringify('production')的值正好等于'"pro duction "'
                      NODE_ENV: JSON.stringify ( 'production')
            }
        })
    ]
}

4.8 壓縮代碼

4.8.1壓縮js

optimization: {
        minimizer: [ // 用于配置 minimizers 和選項(xiàng)
            new UglifyJsPlugin({
                cache: true,
                parallel: true,
                sourceMap: true // set to true if you want JS source maps
            }),
            new OptimizeCSSAssetsPlugin({})
        ]
    }

4.8.2壓縮es6

4.8.3壓縮css

4.9CDN加速

4.9.1 什么是CDN

CDN(內(nèi)容分發(fā)網(wǎng)絡(luò))的作用就是加速網(wǎng)絡(luò)傳輸,通過(guò)將資源部署到世界各地,使用戶在訪問(wèn)時(shí)按照就近原則從離其最近的服務(wù)器獲取資源,來(lái)加快資源的獲取速度。CDN 其實(shí)是通過(guò)優(yōu)化物理鏈路層傳輸過(guò)程中的光速有限、丟包等問(wèn)題來(lái)提升網(wǎng)速

4.9.2 接入CDN

要為網(wǎng)站接入CDN,需要將網(wǎng)頁(yè)的靜態(tài)資源上傳到CDN 服務(wù)上,在服務(wù)這些靜態(tài)資源時(shí)需要通過(guò)CDN 服務(wù)提供的URL 地址去訪問(wèn)。
為了讓文件及時(shí)更新,成熟做法如下:

  • 針對(duì)HTML 文件:不開(kāi)啟緩存,將HTML 放到自己的服務(wù)器上,而不是CDN 服務(wù)上,同時(shí)關(guān)閉自己服務(wù)器上的緩存。自己的服務(wù)器只提供HTML 文件和數(shù)據(jù)接口
  • 針對(duì)靜態(tài)的JavaScript 、css 、圖片等文件:開(kāi)啟CDN 和緩存,上傳到CDN 服務(wù)上,同時(shí)為每個(gè)文件名帶上由文件內(nèi)容算出的Hash值,例如上面的appa6976b6d.css 文件。帶上Hash值的原因是文件名會(huì)隨著文件的內(nèi)容而變化,只要文件的內(nèi)容發(fā)生變化,其對(duì)應(yīng)的hash值也就會(huì)變化,它就會(huì)被重新下載,無(wú)論緩存時(shí)間有多長(zhǎng)
    注意:
    1.對(duì)于瀏覽器限制:在同一時(shí)刻針對(duì)同一個(gè)域名的資源的并行請(qǐng)求有限制(大概4 個(gè)左右,不同的瀏覽器可能不同),可以將靜態(tài)資源分散到不同的CDN 服務(wù)上
  1. 多域名解析會(huì)增加域名解析的時(shí)間,解決方法是在HTML HEAD 標(biāo)簽中加入<link rel="dns-prefetch ” href = ”//js.cdn.com ”>預(yù)解析域名
    延遲。

4.9.3 用Webpack 實(shí)現(xiàn)CDN的接入

構(gòu)建需要實(shí)現(xiàn)以下幾點(diǎn):

  • 靜態(tài)資源的導(dǎo)入U(xiǎn)RL需要變成指向CDN 服務(wù)的絕對(duì)路徑的URL,而不是相對(duì)于HTML 文件的URL
  • 靜態(tài)資源的文件名需要帶上由文件內(nèi)容算出來(lái)的Hash 值,以防止被緩存
  • 將不同類(lèi)型的資源放到不同域名的CDN 服務(wù)上,以防止資源的并行加載被阻塞

核心設(shè)置publicPath

  • 在output . publicPath 中設(shè)置JavaScript 的地址
  • 在css-loader.publicPath 中設(shè)置被css 導(dǎo)入的資源的地址
  • 在WebPlugin.stylePublicPath 中設(shè)置css 文件的地址

4.10 使用Tree Shaking

4 . 10.1 認(rèn)識(shí)Tree Shaking

Tree Shaking 可以用來(lái)剔除JavaScript 中用不上的死代碼,它依賴靜態(tài)的ES6 模塊化語(yǔ)法,例如通過(guò)import 和export 導(dǎo)入、導(dǎo)出

4.10. 2 接入Tree Shaking

首先,為了將采用ES6 模塊化的代碼提交給Webpack ,需要配置Babel 以讓其保留ES6模塊化語(yǔ)句。修改.babelrc 文件如下:

  {
    "presets": [
        [
            "env",
            {
                "modules": false  // 關(guān)閉Babel的模塊轉(zhuǎn)換功能,保留原有的ES6模塊化語(yǔ)法
            }
        ]
        
    ]
}

執(zhí)行命令

wabpack --display -used -exports --optimize-minimize

4.11 提取公共代碼

4 . 11.2 如何提取公共代碼

  • 根據(jù)網(wǎng)站所使用的技術(shù)攏,找出網(wǎng)站的所有頁(yè)面都需要用到的基礎(chǔ)庫(kù),將它們提取到一個(gè)單獨(dú)的文件base.js 中,該文件包含了所有網(wǎng)頁(yè)的基礎(chǔ)運(yùn)行環(huán)境。
  • 在剔除了各個(gè)頁(yè)面中被base.js 包含的部分代碼后, 再找出所有頁(yè)面都依賴的公共部分的代碼,將它們提取出來(lái)并放到common.js 中。
  • 再為每個(gè)網(wǎng)頁(yè)都生成一個(gè)單獨(dú)的文件,在這個(gè)文件中不再包含base.js 和common.js 中包含的部分,而只包含各個(gè)頁(yè)面單獨(dú)需要的部分代碼。
    注意:提取公共代碼webpack4使用vendors或者commons參數(shù)設(shè)置

4 .12 分割代碼以按需加載

在為單頁(yè)應(yīng)用做按需加載優(yōu)化時(shí), 一般采用以下原則

  • 將整個(gè)網(wǎng)站劃分成一個(gè)個(gè)小功能,再按照每個(gè)功能的相關(guān)程度將它們分成幾類(lèi)
  • 將每一類(lèi)合并為一個(gè)Chunk ,按需加載對(duì)應(yīng)的Chunk
  • 按需加載用戶首次打開(kāi)網(wǎng)站時(shí)需要看到的畫(huà)面所對(duì)應(yīng)的功能,不要將其放到執(zhí)行入口所在的Chunk 中,以減少用戶能感知的網(wǎng)頁(yè)加載時(shí)間。
  • 對(duì)于不依賴大量代碼的功能點(diǎn),例如依賴Cha rt.js 去畫(huà)圖表、依賴flv .js 去播放視頻的功能點(diǎn),可再對(duì)其進(jìn)行按需加載。

4.12.3 用Webpack 實(shí)現(xiàn)按需加載

import(/* webpackChunkName :”show " */ ’./show’) . then ((show) => {
    show ( ’ Webpack ’)
})

4.13 使用Prepack

4.13.1 認(rèn)識(shí)Prepack

Prepack 由Facebook 開(kāi)源,采用了較為激進(jìn)的方法:在保持運(yùn)行結(jié)果一致的情況下,改變?cè)创a的運(yùn)行邏輯,輸出性能更好的JavaScript 代碼。實(shí)際上, Prepack 就是一個(gè)部分求值器,編譯代碼時(shí)提前將計(jì)算結(jié)果放到編譯后的代碼中, 而不是在代碼運(yùn)行時(shí)才去求值。
注意:暫時(shí)不推薦用于生產(chǎn)環(huán)境,不成熟

4.14 開(kāi)啟Scope Hoisting

4.14.1 認(rèn)識(shí)Scope Hoisting

Scop e Hoisting 可以讓W(xué)ebpack 打包出來(lái)的代碼文件更小、運(yùn)行更快,它又被譯作“作用域提升”,是在Webpack 3 中新推出的功能
webpack4的實(shí)現(xiàn)方法
https://www.cnblogs.com/cherryvenus/p/9808320.html

4.15 輸出分析

4.15.2webpack-bundle-analyzer

4.16 優(yōu)化總結(jié)

第五章原理

5.1 工作原理概括

5.1.1 基本概念

5.1.2 流程概括

5. 1.3 流程細(xì)節(jié)

5.2 輸出文件分析

5.3 編寫(xiě)Loader

5.3.1 Loader 的職責(zé)

5.3.2 Loader 基礎(chǔ)

5.3.3 Loader 進(jìn)階

5.3.5 加載本地Loader

5.3.6 實(shí)戰(zhàn)

5.4 編寫(xiě)Plugin

Webpack 通過(guò)Plugin 機(jī)制讓其更靈活,以適應(yīng)各種應(yīng)用場(chǎng)景。在webpack 運(yùn)行的生命周期中會(huì)廣播許多事件, Plugin 可以監(jiān)昕這些事件,在合適的時(shí)機(jī)通過(guò)Webpack 提供的API改變輸出結(jié)果。

5.4.4 實(shí)戰(zhàn)

5.5 調(diào)試Webpack

附錄

小技巧

1、vscode展開(kāi)壓縮代碼
需要首先打開(kāi)(ctrl+shift+p)命令行面板,選擇format selection with,
然后里面選擇Prettier -code formatter
2、linix命令

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

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