webpack 4.0使用指南

<h1>WebPack4.X 使用指南</h1>

<h2>一、简介:</h2>

webpack是一个前端自动化打包工具,根据它的名字也很好理解,web-pack顾名思义就是前端打包工具;它的使用是基于Node和NPM的,所以在安装使用webpack之前,需要安装nodejs,nodejs的版本过低也不行,所以推荐安装nodejs版本为v8.11.2以上,npm版本为v5.6.0以上;

如何查看node和npm版本?

答:安装完毕nodejs之后,在命令行输入node -v和npm -v查看。

<h2>二、项目建立:</h2>

第一步:新建一个文件夹,命名为wp。

第二步:在cmd命令行中使用cd命令切入到wp文件夹中,输入npm init或npm init -y,初始化package.json文件;<b>需要注意的是如果package.json的name为webpack可能会引起错误,所以name尽量避免输入为webpack。</b>

如图:

<img src="./image/1.png">

第三步:将wp文件夹拖入到sublime等编辑工具中,并在wp根目录下新建一个webpack.config.js的文件。

<img src="./image/2.png">

webpack.config.js里面应该配置的项目如下:

module.exports = {
    entry: '',               // 入口文件
    output: {},              // 出口文件
    module: {},              // 处理对应模块
    plugins: [],             // 对应的插件
    devServer: {},           // 开发服务器配置
    mode: 'development'      // 模式配置
}

我们先做一个默认配置:

const path = require('path');   
module.exports = {
    entry: './src/index.js',    // 入口文件
    output: {
        filename: 'bundle.js',      // 打包后的文件名称
        path: path.resolve('dist')  // 打包后的目录,必须是绝对路径
    }
}   

及将上述所谓的默认配置代码粘贴到webpack.config.js文件中

<img src="./image/3.png">

解释:
所谓的入口文件entry和出口文件output指的都是.js文件,当前的配置是单个入口文件和出口文件,后面我们在配置多页面的时候回有多入口和出口文件。

第四步:根据第三步中的配置内容需要注意到两个路径和文件:

 entry: './src/index.js',
 filename: 'bundle.js'
 path: path.resolve('dist')

'./src/index.js'的意思是在当前wp根目录下要新建一个src文件夹,里面,并且在里面新建一个index.js文件。

filename: 'bundle.js'和path: path.resolve('dist')的意思是最终打包完毕后会在wp根目录下自动创建一个叫dist的文件夹,里面包含一个bundle.js文件

打包前目录结构和代码:

<img src="./image/4.png">

第五步:接下来我们将根据第四步的内容进行打包,要想使用webpack打包,需要使用npm安装webpack 和 webpack-cli,在cmd命令行中输入:

npm install webpack webpack-cli --save-dev

如图:

<img src="./image/5.png">
<img src="./image/6.png">

安装完毕后修改package.json文件中的scripts,如下:

{
  "name": "wp",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev" : "webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.20.2",
    "webpack-cli": "^3.1.2"
  }
}

然后在cmd命令行中输入npm run dev进行打包。

如下图:

<img src="./image/7.png">

打包后目录结构和代码:

<img src="./image/8.png">

其中增加了一个dist文件夹,里面增加了一个bundle.js文件;这就是之前我们说的输出文件。

第六步:在src目录下新建一个index.html文件,里面引入打包后的bundle.js文件作为测试。

<img src="./image/9.png">

运行后的结果如下:

<img src="./image/10.png">

至此,基于webpack的项目建立好了,接下来我们准备安装一些常用模块和插件。

<h2>三、模块和插件配置安装:</h2>

<h3>1、配置HTML模板</h3>

简介

刚才我们建立的index.html文件是在src下面的,但实际打包后的文件是在dist目录下的,我们可以安装一个 html-webpack-plugin 插件,来打包html模板,并将该模板指向对应的入口文件。

安装

npm i html-webpack-plugin -D

<img src="./image/11.png">

配置

修改webpack.config.js后如下:

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

module.exports = {
    entry: './src/index.js',    // 入口文件
    output: {
        filename: 'bundle.js',      // 打包后的文件名称
        path: path.resolve('dist')  // 打包后的目录,必须是绝对路径
    },
    plugins: [
        // 通过new一下这个类来使用插件
        new HtmlWebpackPlugin({
            // 在src目录下创建一个index.html页面当做模板来用
            template: './src/index.html',
        })
    ]
}

增加了插件引入和插件的配置,仔细对比前面的设置就能知道。

运行

运行前修改一下src目录下的index.html代码,取消bundle.js的引用;

<img src="./image/14.png">

再次运行 npm run dev 结果如下:

<img src="./image/12.png">

在dist目录下自动新增了一个index.html文件,并且里面自动引用了bundle.js,这是因为我们新建的index.html文件是自动指向到index.js入口的;而index.js作为入口文件又最终编译生成为bundle.js。

<img src="./image/13.png">

<h3>2、引用CSS</h3>

简介

css文件在打包完成之后也会输出到dist目录下,所以引用css仍然需要模块支持,我们现在讨论的并不是拆分后的css,而是内部样式表;也就是说,css在自动引入到html文件中的时候是以内部样式表的形式出现的。关于拆分css我们后面会讲到。

安装

引用css需要安装两个模块:style-loader和css-loader

npm i style-loader css-loader -D

<img src="./image/15.png">

其中css-loader是负责解析css的,而style-loader则负责将css以内部样式表的形式嵌入到html中,当使用插件拆分css的时候就不再需要style-loader了,因为那是以外部样式表link到html文件中的。

配置

修改webpack.config.js,增加内容如下:

module: {
         rules: [
        {
            test: /\.css$/,     // 解析css
            use: ['style-loader', 'css-loader'] // 从右向左解析
            /* 
                也可以这样写,这种方式方便写一些配置参数
                use: [
                    {loader: 'style-loader'},
                    {loader: 'css-loader'}
                ]
            */
        }
    ]
}

修改后的webpack.config.js全部内容如下:

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

module.exports = {
    entry: './src/index.js',    // 入口文件
    output: {
        filename: 'bundle.js',      // 打包后的文件名称
        path: path.resolve('dist')  // 打包后的目录,必须是绝对路径
    },
    plugins: [
        // 通过new一下这个类来使用插件
        new HtmlWebpackPlugin({
            // 在src目录下创建一个index.html页面当做模板来用
            template: './src/index.html',
        })
    ],
    module: {
        rules: [
            {
                test: /\.css$/,     // 解析css
                use: ['style-loader', 'css-loader'] // 从右向左解析
                /* 
                    也可以这样写,这种方式方便写一些配置参数
                    use: [
                        {loader: 'style-loader'},
                        {loader: 'css-loader'}
                    ]
                */
            }
        ]
    }
}

运行

在运行前我们需要在src目录下新建一个css目录,并新建index.css,目录代码如下:

<img src="./image/16.png">

修改index.js,增加:

import "./css/index.css";

<img src="./image/17.png">

运行 npm run dev后的目录代码如下:

<img src="./image/18.png">

目录中并没有增加css文件夹和任何css文件,但是运行dist里面的index.html文件会得到下图效果。

页面效果如下:

<img src="./image/19.png">

这是使用style-loader打包的结果,内部样式表。

<h3>3、拆分CSS</h3>

简介

通过使用extract-text-webpack-plugin插件将刚才的内部样式表拆分为外部样式表

安装

npm i extract-text-webpack-plugin@next -D

<img src="./image/20.png">

配置

修改webpack.config.js里面的module:

module: {
        rules: [
            {
                test: /\.css$/,
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    use: 'css-loader'       
                })
            }
        ]
    },

新增:

const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin');

新增:

plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html',
        }),
        // 拆分后会把css文件放到dist目录下的css/style.css
        new ExtractTextWebpackPlugin('css/style.css')  
    ]

新增new ExtractTextWebpackPlugin('css/style.css') 后,会在dist目录下生产一个css文件夹,且src目录下的css最终会合并到这个style.css文件中,如果不想叫style.css,可以修改。

修改完毕后的webpack.config.js如下:

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

module.exports = {
    entry: './src/index.js',    // 入口文件
    output: {
        filename: 'bundle.js',      // 打包后的文件名称
        path: path.resolve('dist')  // 打包后的目录,必须是绝对路径
    },
     plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html',
        }),
        // 拆分后会把css文件放到dist目录下的css/style.css
        new ExtractTextWebpackPlugin('css/style.css')  
    ],
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    use: 'css-loader'       
                })
            }
        ]
    }
}

运行

运行 npm run dev后的目录代码如下:

<img src="./image/21.png">
<img src="./image/22.png">

<h3>4、引用Less</h3>

简介

less作为前端css编译工具广受欢迎,它在前端的使用方式有两种,一种是引入less.js文件来动态编译less代码,这必然是降低了程序的响应时间;第二种就是使用工具或lessc来手动编译转换less代码为css;我们现在要做的事情是在webpack这个自动化工具中配置less,让它变得自动起来。

安装

npm install less less-loader --save-dev

<img src="./image/23.png">

配置

修改webpack.config.js,增加:

{
    test:/\.less$/,
    use:ExtractTextPlugin.extract({
        fallback:"style-loader",
        use:[{
            loader:"css-loader"
        },{
            loader:"less-loader"
        }]
    })
}

修改完毕后的webpack.config.js如下:

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

module.exports = {
    entry: './src/index.js',    // 入口文件
    output: {
        filename: 'bundle.js',      // 打包后的文件名称
        path: path.resolve('dist')  // 打包后的目录,必须是绝对路径
    },
    plugins: [
        // 通过new一下这个类来使用插件
        new HtmlWebpackPlugin({
            // 在src目录下创建一个index.html页面当做模板来用
            template: './src/index.html',
        }),
        new ExtractTextWebpackPlugin('css/style.css') 
    ],
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    use: 'css-loader'       
                })
            },
            {
                test:/\.less$/,
                use:ExtractTextWebpackPlugin.extract({
                    fallback:"style-loader",
                    use:[{
                        loader:"css-loader"
                    },{
                        loader:"less-loader"
                    }]
                })
            }
        ]
    }
}

运行

运行前需要做的修改如下:

修改src目录下的index.html文件,新增一个class为less的div

<img src="./image/24.png">

在src目录下新建一个less文件夹,并新建index.less文件

<img src="./image/25.png">

在index.js中引入less文件夹下的index.less文件

<img src="./image/26.png">

运行npm run dev后的目录代码如下:

<img src="./image/27.png">

这里的style.css是将index.css和index.less的内容合并后的结果,至于如何拆分开,我们在多入口文件的时候再说。

<h3>5、引用Sass</h3>

简介

sass引入同less,不再多述。

安装

npm install --save-dev node-sass sass-loader

<img src="./image/28.png">

同时安装了node-sass和sass-loader,其中node-sass安装过程可能会因为国外镜像原因或网络原因出错,但请单独安装node-sass和sass-loader;node-sass安装失败的解决办法主要推荐两个:

第一:

在项目根目录创建.npmrc文件,复制下面代码到该文件。

创建.npmrc文件需要在wp目录下输入命令: type nul>.npmrc

phantomjs_cdnurl=http://cnpmjs.org/downloads
sass_binary_site=https://npm.taobao.org/mirrors/node-sass/
registry=https://registry.npm.taobao.org

<img src="./image/29.png">

保存后 删除之前安装失败的包(第一次安装请跳过此步)

npm uninstall node-sass

重新安装

npm install node-sass

第二:

设置变量 sass_binary_site,指向淘宝镜像地址。示例:

npm i node-sass --sass_binary_site=https://npm.taobao.org/mirrors/node-sass/

// 也可以设置系统环境变量的方式。示例
// linux、mac 下
SASS_BINARY_SITE=https://npm.taobao.org/mirrors/node-sass/ npm install node-sass

// window 下
set SASS_BINARY_SITE=https://npm.taobao.org/mirrors/node-sass/ && npm install node-sass

配置

修改webpack.config.js,新增配置:

{
    test: /\.scss$/,     // 解析less
    // use: ['style-loader', 'css-loader','sass-loader'] // 从右向左解析
    use: ExtractTextWebpackPlugin.extract({
        // 将css用link的方式引入就不再需要style-loader了
        use:[{
            loader:"css-loader"
            },{
                loader:"sass-loader"
            }]      
        })
}

修改后的完整webpack.config.js代码如下:

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

module.exports = {
    entry: './src/index.js',    // 入口文件
    output: {
        filename: 'bundle.js',      // 打包后的文件名称
        path: path.resolve('dist')  // 打包后的目录,必须是绝对路径
    },
    plugins: [
        // 通过new一下这个类来使用插件
        new HtmlWebpackPlugin({
            // 在src目录下创建一个index.html页面当做模板来用
            template: './src/index.html',
        }),
        new ExtractTextWebpackPlugin('css/style.css') 
    ],
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    use: 'css-loader'       
                })
            },
            {
                test:/\.less$/,
                use:ExtractTextWebpackPlugin.extract({
                    fallback:"style-loader",
                    use:[{
                        loader:"css-loader"
                    },{
                        loader:"less-loader"
                    }]
                })
            },
            {
                test: /\.scss$/,     // 解析less
                // use: ['style-loader', 'css-loader','sass-loader'] // 从右向左解析
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    use:[{
                        loader:"css-loader"
                        },{
                            loader:"sass-loader"
                        }]      
                    })
            },
        ]
    }
}

运行

运行前需要做的修改如下:

修改src目录下的index.html文件,新增一个class为sass的div

<img src="./image/30.png">

在src目录下新建一个sass文件夹,并新建index.scss文件

<img src="./image/31.png">

在index.js中引入sass文件夹下的index.scss文件

<img src="./image/32.png">

运行npm run dev后的目录代码如下:

<img src="./image/33.png">

这里的style.css是将index.css、index.less和index.scss的内容合并后的结果,至于如何拆分开,我们在多入口文件的时候再说。

<h3>6、CSS3自动增加前缀</h3>

简介

我们在css或less、sass文件中常常会编写一些CSS3代码,有些时候这些css3代码需要指明私有前缀,这无疑增加了很多工作,可以使用 postcss-loader 插件来帮我们自动增加。

安装

npm install --save-dev postcss-loader autoprefixer

<img src="./image/34.png">

配置

postcss-loader的配置不同于前面的几个文件,它需要在wp根目录下新建一个postcss.config.js文件,并在里面添加如下代码:

module.exports = {
    plugins: [require('autoprefixer')]  // 引用该插件即可了
}

<img src="./image/35.png">

然后对需要的css或less、sass模块做出修改,比如你需要在css中增加css3前缀的功能,那就在css模块中增加postcss-loader,如下:

{
   test: /\.css$/,     // 解析css
   use: ExtractTextWebpackPlugin.extract({
        use:[{
            loader:"css-loader"
            },{
                loader:"postcss-loader"
            }],   
    })
},

less模块和sass模块操作同理。

修改后的webpack.config.js代码如下:

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

module.exports = {
    entry: './src/index.js',    // 入口文件
    output: {
        filename: 'bundle.js',      // 打包后的文件名称
        path: path.resolve('dist')  // 打包后的目录,必须是绝对路径
    },
    plugins: [
        // 通过new一下这个类来使用插件
        new HtmlWebpackPlugin({
            // 在src目录下创建一个index.html页面当做模板来用
            template: './src/index.html',
        }),
        new ExtractTextWebpackPlugin('css/style.css') 
    ],
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    // use: 'css-loader'   
                    use:[{
                        loader:"css-loader"
                    },{
                        loader:"postcss-loader"
                    }],   

                })
            },
            {
                test:/\.less$/,
                use:ExtractTextWebpackPlugin.extract({
                    fallback:"style-loader",
                    use:[{
                        loader:"css-loader"
                    },{
                        loader:"less-loader"
                    }]
                })
            },
            {
                test: /\.scss$/,     // 解析less
                // use: ['style-loader', 'css-loader','sass-loader'] // 从右向左解析
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    use:[{
                        loader:"css-loader"
                        },{
                            loader:"sass-loader"
                        }]      
                    })
            },
        ]
    }
}

运行

运行前修改src/css/index.css文件,增加了transform css3代码,如下:

<img src="./image/36.png">

运行 npm run dev 后的目录代码如下:

<img src="./image/37.png">

刚刚修改的css3代码,自动增加了私有前缀。

<h3>7、CSS中的图片引用处理</h3>

简介

css中引用图片主要引用file-loader和url-loader,其中file-loader主要解决引用路径问题,url-loader主要解决图片的加载优化问题,可以设置一个阈值,比如将8k以下的图片转换为data-url的形式直接引用到html文件中,从而减少请求次数,达到优化目的。

安装

npm install --save-dev file-loader url-loader

<img src="./image/38.png">

配置

修改webpack.config.js,增加如下代码:

{
    test: /\.(jpe?g|png|gif)$/,
    use: [
        {
            loader: 'url-loader',
            options: {
                limit: 8192,    // 小于8k的图片自动转成base64格式,并且不会存在实体图片
                outputPath: 'images/'   // 图片打包后存放的目录
            }
        }
    ]
},

并增加红框中的内容

<img src="./image/42.png">

修改后的webpack.config.js文件如下:

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

module.exports = {
    entry: './src/index.js',    // 入口文件
    output: {
        filename: 'bundle.js',      // 打包后的文件名称
        path: path.resolve('dist')  // 打包后的目录,必须是绝对路径
    },
    plugins: [
        // 通过new一下这个类来使用插件
        new HtmlWebpackPlugin({
            // 在src目录下创建一个index.html页面当做模板来用
            template: './src/index.html',
        }),
        new ExtractTextWebpackPlugin('css/style.css') 
    ],
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    // use: 'css-loader'   
                    use:[{
                        loader:"css-loader"
                    },{
                        loader:"postcss-loader"
                    }],   
                    publicPath: '../'

                })
            },
            {
                test:/\.less$/,
                use:ExtractTextWebpackPlugin.extract({
                    fallback:"style-loader",
                    use:[{
                        loader:"css-loader"
                    },{
                        loader:"less-loader"
                    }]
                })
            },
            {
                test: /\.scss$/,     // 解析less
                // use: ['style-loader', 'css-loader','sass-loader'] // 从右向左解析
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    use:[{
                        loader:"css-loader"
                        },{
                            loader:"sass-loader"
                        }]      
                    })
            },
            {
                test: /\.(jpe?g|png|gif)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 8192,    // 小于8k的图片自动转成base64格式,并且不会存在实体图片
                            outputPath: 'images/'   // 图片打包后存放的目录
                        }
                    }
                ]
            },
        ]
    }
}

运行

运行前在src目录下新建image文件夹,在文件夹当中放一个图片做测试,如图:

<img src="./image/39.png">

修改src目录下的index.html文件:

<img src="./image/40.png">

修改src/css/index.css文件

<img src="./image/41.png">

运行 npm run dev后的效果为:

<img src="./image/43.png">

<h3>8、HTML中的图片引用处理</h3>

简介

同css中的图片处理,在html文件中使用img标签引用图片同样存在类似问题,需要安装 html-withimg-loader 模块

安装

npm install --save-dev html-withimg-loader

<img src="./image/44.png">

配置

修改webpack.config.js文件,新增:

{
    test: /\.(htm|html)$/,
    use: 'html-withimg-loader'
}

运行

修改src目录下的 index.html文件新增img标签

<img src="./image/46.png">

运行 npm run dev 后的效果如图:

<img src="./image/45.png">

<h3>9、iconfont字体引用</h3>

简介

原理同上

安装

不需要安装,因为已经安装过file-loader了。

配置

修改webpack.config.js文件,新增:

{
    test: /\.(eot|ttf|woff|svg)$/,
    use: 'file-loader'
},

运行

拷贝一个iconfont字体图标库到src/css文件夹下,如图:

<img src="./image/47.png">

在src/index.html文件中新增 span标签如下:

<span class="iconfont">&#xe62c;</span>

在src/index.js文件新增 iconfont.css引入如下:

<img src="./image/48.png">

运行 npm run dev 后的效果如下:

<img src="./image/49.png">

页面中将增加一个麦当劳的M标志,证明成功使用了字体图标。

<h3>10、Babel安装</h3>

简介

ES6因为包含广泛,ES2015,2016,2017等,使用中对ES6的转码是必须的,所以我们采用了babel来转码。

安装

npm install --save-dev babel-core babel-loader babel-preset-react babel-preset-env

<img src="./image/50.png">

这个安装过程可能比较慢,也可能会出现一些关于Parse , Json等的解析错误,出现类似的错误请按照下面两个方法解决:

第一:

运行 : npm cache clean –force 之后再运行上面的安装命令。

第二:

如果问题没有顺利解决,运行:npm install --registry=https://registry.npm.taobao.org --loglevel=silly
之后再运行安装命令。

配置

修改webpack.config.js,新增:

{
    test:'/\.(js|jsx)$/',
    use: 'bable-loader',
    include: /src/,          // 只转化src目录下的js
    exclude: /node_modules/  // 排除掉node_modules,优化打包速度
}

运行

运行前,在wp根目录下新建.babelrc文件

type nul>.babelrc

并在里面新增如下代码:

{
    "presets": ["env", "stage-0"]   // 从右向左解析
}

目录代码如下:

<img src="./image/51.png">

运行 npm run dev后观察代码的变化,事实上没有安装babel的时候,webpack也可以解码es6,但考虑到es6代表广泛,所以还是安装了babel解码。

<h3>11、JS代码压缩</h3>

在webpack.config.js中新增:

mode: 'development'

表示开发环境,不压缩代码。

mode: 'production'

表示生产环境,压缩代码。

<img src="./image/52.png">

<h3>12、CSS代码压缩</h3>

简介

CSS代码压缩需要安装插件:

optimize-css-assets-webpack-plugin

安装

npm install optimize-css-assets-webpack-plugin --save-dev

<img src="./image/54.png">

配置

在webpack.config.js中新增

const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');

new OptimizeCssAssetsPlugin({
      assetNameRegExp: /\.css$/g,
      cssProcessor: require('cssnano'),
      cssProcessorOptions: { safe: true, discardComments: { removeAll: true } },
      canPrint: true
    })

目录代码如图:

<img src="./image/53.png">

运行

运行 npm run dev 后的目录代码如下:

<img src="./image/55.png">

<h3>13、HTML代码压缩</h3>

html代码压缩不用再安装额外的插件和模块,修改webpack.config.js中的html插件为:

new HtmlWebpackPlugin({
        template: './src/index.html',   
        //filename: 'index.html',
        //chunks: ['index'],   // 对应关系,index.js对应的是index.html
        minify: {
            removeAttributeQuotes:true,
            removeComments: true,
            collapseWhitespace: true,
            removeScriptTypeAttributes:true,
            removeStyleLinkTypeAttributes:true
        }
    }),

目录代码如图:

<img src="./image/56.png">

运行 npm run dev后可见dist目录下的index.html已经压缩了。

<h3>14、安装第三方类库Jquery</h3>

简介

jquery作为前端必需的第三方类库,安装是它是一个示范作用,其他的第三方类库安装可以参考jquery 的安装。

安装

npm install jquery --save-dev

<img src="./image/57.png">

配置

jquery的引用要用到webpack,所以修改webpack.config.js,新增:

const Webpack = require('webpack');

还要新增:

new Webpack.ProvidePlugin({
        $:'jquery'
    }),

备注:如果项目还引用了Bootstrap,那jquery的配置还需要修改为如下:

new Webpack.ProvidePlugin({
        $:'jquery',
        jQuery:'jquery'
    }),

修改后的webpack.config.js代码如下:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const Webpack = require('webpack');

module.exports = {
    mode: 'development',//production
    entry: './src/index.js',    // 入口文件
    output: {
        filename: 'bundle.js',      // 打包后的文件名称
        path: path.resolve('dist')  // 打包后的目录,必须是绝对路径
    },
    plugins: [
        // 通过new一下这个类来使用插件
        // new HtmlWebpackPlugin({
        //     // 在src目录下创建一个index.html页面当做模板来用
        //     template: './src/index.html',
        // }),
        new HtmlWebpackPlugin({
            template: './src/index.html',   
            //filename: 'index.html',
            //chunks: ['index'],   // 对应关系,index.js对应的是index.html
            minify: {
                removeAttributeQuotes:true,
                removeComments: true,
                collapseWhitespace: true,
                removeScriptTypeAttributes:true,
                removeStyleLinkTypeAttributes:true
            }
        }),
        new ExtractTextWebpackPlugin('css/style.css'),
        new OptimizeCssAssetsPlugin({
          assetNameRegExp: /\.css$/g,
          cssProcessor: require('cssnano'),
          cssProcessorOptions: { safe: true, discardComments: { removeAll: true } },
          canPrint: true
        }),
        new Webpack.ProvidePlugin({
            $:'jquery'
        })
    ],
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    // use: 'css-loader'   
                    use:[{
                        loader:"css-loader"
                    },{
                        loader:"postcss-loader"
                    }],   
                    publicPath: '../'
                })
            },
            {
                test:/\.less$/,
                use:ExtractTextWebpackPlugin.extract({
                    fallback:"style-loader",
                    use:[{
                        loader:"css-loader"
                    },{
                        loader:"less-loader"
                    }]
                })
            },
            {
                test: /\.scss$/,     // 解析less
                // use: ['style-loader', 'css-loader','sass-loader'] // 从右向左解析
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    use:[{
                        loader:"css-loader"
                        },{
                            loader:"sass-loader"
                        }]      
                    })
            },
            {
                test: /\.(jpe?g|png|gif)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 8192,    // 小于8k的图片自动转成base64格式,并且不会存在实体图片
                            outputPath: 'images/'   // 图片打包后存放的目录
                        }
                    }
                ]
            },
            {
                test: /\.(htm|html)$/,
                use: 'html-withimg-loader'
            },
            {
                test: /\.(eot|ttf|woff|svg)$/,
                use: 'file-loader'
            },
            {
                test:'/\.(js|jsx)$/',
                use: 'bable-loader',
                include: /src/,          // 只转化src目录下的js
                exclude: /node_modules/  // 排除掉node_modules,优化打包速度
            }

        ]
    },
}

运行

运行前修改src目录下的index.js文件,新增:

$('div').css('border', '10px solid white');

目录代码如下:

<img src="./image/58.png">

运行npm run dev后的效果如下:

<img src="./image/59.png">

<h3>15、多页面多入口打包</h3>

在实际的开发中,我们不可能只有一个页面,常常需要很多页面,那打包多页面就很实际了,多页面就需要多入口,也就是需要多个.js文件;所以在src目录下新建:login.html和login.js,其中login.js作为login.html页面的入口文件。

在src/css下新建login.css文件作为修饰login.html的css,目录代码如图:

login.html

<img src="./image/60.png">

login.css

<img src="./image/61.png">

login.js

<img src="./image/62.png">

新增完毕页面后,还需要修改webpack.config.js文件:

修改入口文件为:

<img src="./image/63.png">

修改出口文件为:

<img src="./image/64.png">

修改html插件为:

<img src="./image/65.png">

修改css插件为:

<img src="./image/66.png">

修改后的webpack.config.js代码如下:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const Webpack = require('webpack');

module.exports = {
    mode: 'development',//production
    // entry: './src/index.js',    // 入口文件
    entry: {
        index: './src/index.js',
        login: './src/login.js'
    },
    // output: {
    //     filename: 'bundle.js',      // 打包后的文件名称
    //     path: path.resolve('dist')  // 打包后的目录,必须是绝对路径
    // },
    output: {                       
        filename: '[name].js',
        path: path.resolve('dist')
    },
    plugins: [
        // 通过new一下这个类来使用插件
        // new HtmlWebpackPlugin({
        //     // 在src目录下创建一个index.html页面当做模板来用
        //     template: './src/index.html',
        // }),
        // new HtmlWebpackPlugin({
        //     template: './src/index.html',   
        //     // filename: 'index.html',
        //     // chunks: ['index'],   // 对应关系,index.js对应的是index.html
        //     minify: {
        //         removeAttributeQuotes:true,
        //         removeComments: true,
        //         collapseWhitespace: true,
        //         removeScriptTypeAttributes:true,
        //         removeStyleLinkTypeAttributes:true
        //     }
        // }),
        new HtmlWebpackPlugin({
            template: './src/index.html',   
            filename: 'index.html',
            chunks: ['index'],   // 对应关系,index.js对应的是index.html
            minify: {
                removeAttributeQuotes:true,
                removeComments: true,
                collapseWhitespace: true,
                removeScriptTypeAttributes:true,
                removeStyleLinkTypeAttributes:true
            }
        }),
        new HtmlWebpackPlugin({
            template: './src/login.html',
            filename: 'login.html',
            chunks: ['login'],   // 对应关系,login.js对应的是login.html
            minify: {
                removeAttributeQuotes:true,
                removeComments: true,
                collapseWhitespace: true,
                removeScriptTypeAttributes:true,
                removeStyleLinkTypeAttributes:true
            }
        }),
        // new ExtractTextWebpackPlugin('css/style.css'),
        new ExtractTextWebpackPlugin('css/[name].css'),
        new OptimizeCssAssetsPlugin({
          assetNameRegExp: /\.css$/g,
          cssProcessor: require('cssnano'),
          cssProcessorOptions: { safe: true, discardComments: { removeAll: true } },
          canPrint: true
        }),
        new Webpack.ProvidePlugin({
            $:'jquery'
        })
    ],
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    // use: 'css-loader'   
                    use:[{
                        loader:"css-loader"
                    },{
                        loader:"postcss-loader"
                    }],   
                    publicPath: '../'
                })
            },
            {
                test:/\.less$/,
                use:ExtractTextWebpackPlugin.extract({
                    fallback:"style-loader",
                    use:[{
                        loader:"css-loader"
                    },{
                        loader:"less-loader"
                    }]
                })
            },
            {
                test: /\.scss$/,     // 解析less
                // use: ['style-loader', 'css-loader','sass-loader'] // 从右向左解析
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    use:[{
                        loader:"css-loader"
                        },{
                            loader:"sass-loader"
                        }]      
                    })
            },
            {
                test: /\.(jpe?g|png|gif)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 8192,    // 小于8k的图片自动转成base64格式,并且不会存在实体图片
                            outputPath: 'images/'   // 图片打包后存放的目录
                        }
                    }
                ]
            },
            {
                test: /\.(htm|html)$/,
                use: 'html-withimg-loader'
            },
            {
                test: /\.(eot|ttf|woff|svg)$/,
                use: 'file-loader'
            },
            {
                test:'/\.(js|jsx)$/',
                use: 'bable-loader',
                include: /src/,          // 只转化src目录下的js
                exclude: /node_modules/  // 排除掉node_modules,优化打包速度
            }

        ]
    },
}

运行 npm run dev 后的 dist目录结构如下:

<img src="./image/67.png">

<h3>16、优化多页面多入口</h3>

由于每次新增一个页面都需要修改webpack.config.js这很麻烦,所以修改后的webpack.config.js如下:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin');
const Webpack = require('webpack');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');

const glob = require("glob");

var webpackConfig = {
    mode: 'development',//production
    // entry: './src/index.js',    // 单页面入口文件
    // 多页面配置
    entry: {
        index: './src/index.js',
        login: './src/login.js'
    },
    // 出口文件  
    output: {                       
        filename: '[name].js',
        path: path.resolve('dist')
    },
    plugins: [
        new ExtractTextWebpackPlugin('css/[name].css'),

        new Webpack.ProvidePlugin({
            $:'jquery'
        }),
        new Webpack.HotModuleReplacementPlugin(),//调用webpack的热更新插件
        new OptimizeCssAssetsPlugin({
          assetNameRegExp: /\.css$/g,
          cssProcessor: require('cssnano'),
          cssProcessorOptions: { safe: true, discardComments: { removeAll: true } },
          canPrint: true
        })
    ],
    module: {
        rules: [
            {
                test: /\.css$/,     // 解析css
                // use: ['style-loader', 'css-loader'] // 从右向左解析
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    // use: 'css-loader',
                    use:[{
                        loader:"css-loader"
                        },{
                            loader:"postcss-loader"
                        }],
                    publicPath: '../'      
                })
            },
            {
                test: /\.less$/,     // 解析less
                // use: ['style-loader', 'css-loader','less-loader'] // 从右向左解析
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    use:[{
                        loader:"css-loader"
                        },{
                            loader:"less-loader"
                        }]      
                    })
            },
            {
                test: /\.scss$/,     // 解析less
                // use: ['style-loader', 'css-loader','sass-loader'] // 从右向左解析
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    use:[{
                        loader:"css-loader"
                        },{
                            loader:"sass-loader"
                        }]      
                    })
            },
            {
                test: /\.(jpe?g|png|gif)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 8192,    // 小于8k的图片自动转成base64格式,并且不会存在实体图片
                            outputPath: 'images/'   // 图片打包后存放的目录
                        }
                    }
                ]
            },
            {
                test: /\.(htm|html)$/,
                use: 'html-withimg-loader'
            },
            {
                test: /\.(eot|ttf|woff|svg)$/,
                use: 'file-loader'
            },
            {
                test:'/\.(js|jsx)$/',
                use: 'bable-loader',
                include: /src/,          // 只转化src目录下的js
                exclude: /node_modules/  // 排除掉node_modules,优化打包速度
            }
        ]
    }
}

function getView(globPath){
    let files = glob.sync(globPath);

    let entries = {},
    entry, dirname, basename, pathname, extname;

    files.forEach(item => {
        entry = item;
        dirname = path.dirname(entry);//当前目录
        extname = path.extname(entry);//后缀
        basename = path.basename(entry, extname);//文件名
        pathname = path.join(dirname, basename);//文件路径
        if (extname === '.html') {
            entries[pathname] = './' + entry;
        } else if (extname === '.js') {
            entries[basename] = entry;
        }
    });

    return entries;
}

let pages = Object.keys(getView('./src/*html'));

pages.forEach((pathname) => {
    let htmlname = pathname.split('src/')[1];
    let conf = {
        filename: `${htmlname}.html`,
        template: `${pathname}.html`,
        // hash: true,
        chunks:[htmlname],
        minify: {
            removeAttributeQuotes:true,
            removeComments: true,
            collapseWhitespace: true,
            removeScriptTypeAttributes:true,
            removeStyleLinkTypeAttributes:true
        }
    }

    webpackConfig.plugins.push(new HtmlWebpackPlugin(conf));
});

module.exports = webpackConfig;

除此之外不用修改其他任何文件。

<h3>17、热更新</h3>

简介

每次运行和更新代码都输入npm run dev命令太麻烦,安装热更新来解决该问题,每次改动代码后,只需要保存代码并刷新页面即可,不用再执行命令。

安装

npm install webpack-dev-server --save-dev

配置

修改webpack.config.js 新增插件:

new Webpack.HotModuleReplacementPlugin(),//调用webpack的热更新插件

新增热更新配置:

devServer: {
    // 设置服务器访问的基本目录
    contentBase:path.resolve(__dirname,'dist'), //最好设置成绝对路径
    // 设置服务器的ip地址,可以是localhost
    host:'localhost',
    // 设置端口
    port:8090,
    // 设置自动打开浏览器
    open:true,
    // 设置热更新
    hot:true
}

修改后的webpack.config.js如下:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin');
const Webpack = require('webpack');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');

const glob = require("glob");

var webpackConfig = {
    mode: 'development',//production
    // entry: './src/index.js',    // 单页面入口文件
    // 多页面配置
    entry: {
        index: './src/index.js',
        login: './src/login.js'
    },
    // 出口文件  
    output: {                       
        filename: '[name].js',
        path: path.resolve('dist')
    },
    plugins: [
        new ExtractTextWebpackPlugin('css/[name].css'),

        new Webpack.ProvidePlugin({
            $:'jquery'
        }),
        new Webpack.HotModuleReplacementPlugin(),//调用webpack的热更新插件
        new OptimizeCssAssetsPlugin({
          assetNameRegExp: /\.css$/g,
          cssProcessor: require('cssnano'),
          cssProcessorOptions: { safe: true, discardComments: { removeAll: true } },
          canPrint: true
        })
    ],
    module: {
        rules: [
            {
                test: /\.css$/,     // 解析css
                // use: ['style-loader', 'css-loader'] // 从右向左解析
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    // use: 'css-loader',
                    use:[{
                        loader:"css-loader"
                        },{
                            loader:"postcss-loader"
                        }],
                    publicPath: '../'      
                })
            },
            {
                test: /\.less$/,     // 解析less
                // use: ['style-loader', 'css-loader','less-loader'] // 从右向左解析
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    use:[{
                        loader:"css-loader"
                        },{
                            loader:"less-loader"
                        }]      
                    })
            },
            {
                test: /\.scss$/,     // 解析less
                // use: ['style-loader', 'css-loader','sass-loader'] // 从右向左解析
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    use:[{
                        loader:"css-loader"
                        },{
                            loader:"sass-loader"
                        }]      
                    })
            },
            {
                test: /\.(jpe?g|png|gif)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 8192,    // 小于8k的图片自动转成base64格式,并且不会存在实体图片
                            outputPath: 'images/'   // 图片打包后存放的目录
                        }
                    }
                ]
            },
            {
                test: /\.(htm|html)$/,
                use: 'html-withimg-loader'
            },
            {
                test: /\.(eot|ttf|woff|svg)$/,
                use: 'file-loader'
            },
            {
                test:'/\.(js|jsx)$/',
                use: 'bable-loader',
                include: /src/,          // 只转化src目录下的js
                exclude: /node_modules/  // 排除掉node_modules,优化打包速度
            }
        ]
    },
    devServer: {
        // 设置服务器访问的基本目录
        contentBase:path.resolve(__dirname,'dist'), //最好设置成绝对路径
        // 设置服务器的ip地址,可以是localhost
        host:'localhost',
        // 设置端口
        port:8090,
        // 设置自动拉起浏览器
        open:true,
        // 设置热更新
        hot:true
    }
}

function getView(globPath){
    let files = glob.sync(globPath);

    let entries = {},
    entry, dirname, basename, pathname, extname;

    files.forEach(item => {
        entry = item;
        dirname = path.dirname(entry);//当前目录
        extname = path.extname(entry);//后缀
        basename = path.basename(entry, extname);//文件名
        pathname = path.join(dirname, basename);//文件路径
        if (extname === '.html') {
            entries[pathname] = './' + entry;
        } else if (extname === '.js') {
            entries[basename] = entry;
        }
    });

    return entries;
}

let pages = Object.keys(getView('./src/*html'));

pages.forEach((pathname) => {
    let htmlname = pathname.split('src/')[1];
    let conf = {
        filename: `${htmlname}.html`,
        template: `${pathname}.html`,
        // hash: true,
        chunks:[htmlname],
        minify: {
            removeAttributeQuotes:true,
            removeComments: true,
            collapseWhitespace: true,
            removeScriptTypeAttributes:true,
            removeStyleLinkTypeAttributes:true
        }
    }

    webpackConfig.plugins.push(new HtmlWebpackPlugin(conf));
});

module.exports = webpackConfig;

修改wp根目录下的package.json文件:

<img src="./image/68.png">

修改后的package.json如下:

{
  "name": "wp",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "webpack --mode development",
    "dev": "webpack-dev-server --mode development"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "autoprefixer": "^9.1.5",
    "babel-core": "^6.26.3",
    "babel-loader": "^8.0.4",
    "babel-preset-env": "^1.7.0",
    "babel-preset-stage-0": "^6.24.1",
    "css-loader": "^1.0.0",
    "extract-text-webpack-plugin": "^4.0.0-beta.0",
    "file-loader": "^2.0.0",
    "html-webpack-plugin": "^3.2.0",
    "html-withimg-loader": "^0.1.16",
    "jquery": "^3.3.1",
    "less-loader": "^4.1.0",
    "node-sass": "^4.9.3",
    "optimize-css-assets-webpack-plugin": "^5.0.1",
    "postcss-loader": "^3.0.0",
    "sass-loader": "^7.1.0",
    "style-loader": "^0.23.1",
    "url-loader": "^1.1.2",
    "webpack": "^4.20.2",
    "webpack-cli": "^3.1.2",
    "webpack-dev-server": "^3.1.9"
  }
}

运行

运行 npm run dev 后的cmd命令行效果如下:

<img src="./image/69.png">

<h3>18、安装Vue</h3>

简介

vue是在使用中,我们对组件模板的引用有一种单文件模板的使用形式,这种模板的引用就需要用到ES6的模块技术,所以将vue打包到webpack里面。

安装

安装vue:

npm install vue --save-dev

安装vue-loader和vue-template-compiler

npm install vue-loader vue-template-compiler --save-dev

配置

修改webpack.config.js:

新增:

...
const VueLoaderPlugin = require('vue-loader/lib/plugin');
...
new VueLoaderPlugin(),
...
{ test: /\.vue$/, use: 'vue-loader' },
...
resolve: {
    alias: {
        'vue': 'vue/dist/vue.js'
    }
}
...

修改后的代码示例如下:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const Webpack = require('webpack');

module.exports = {
    entry: './src/index.js',    // 入口文件
    output: {
        filename: 'bundle.js',      // 打包后的文件名称
        path: path.resolve('dist')  // 打包后的目录,必须是绝对路径
    },
    plugins: [
        // 通过new一下这个类来使用插件
        new HtmlWebpackPlugin({
            // 在src目录下创建一个index.html页面当做模板来用
            template: './src/index.html',
        }),
        new VueLoaderPlugin(),
        new Webpack.HotModuleReplacementPlugin(),//调用webpack的热更新插件
    ],
    module: {
        rules: [
            {
                test:'/\.(js|jsx)$/',
                use: 'bable-loader',
                include: /src/,          // 只转化src目录下的js
                exclude: /node_modules/  // 排除掉node_modules,优化打包速度
            },
            { test: /\.vue$/, use: 'vue-loader' },
        ]
    },
    devServer: {
        // 设置服务器访问的基本目录
        contentBase:path.resolve(__dirname,'dist'), //最好设置成绝对路径
        // 设置服务器的ip地址,可以是localhost
        host:'localhost',
        // 设置端口
        port:8090,
        // 设置自动打开浏览器
        open:true,
        // 设置热更新
        hot:true
    },
    resolve: {
        alias: {
            'vue': 'vue/dist/vue.js'
        }
    }
}

运行

输入npm run dev运行查看效果,这里不再列出.vue的编写和vue相关的引入了。直接查看示例即可。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,245评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,749评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,960评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,575评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,668评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,670评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,664评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,422评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,864评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,178评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,340评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,015评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,646评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,265评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,494评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,261评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,206评论 2 352