Webpack初学者使用教程

本文基于原文阅读整理,做的读书笔记
原文:Webpack 初學者教學課程 Part 1 - Webpack 簡介

前提条件:
你已经了解基本的node.js和npm知识,并已安装且使用过。

编码环境:
系统:OS X EI Capitan
版本:10.11.6

webpack-bundle.png

为什么要Webpack

之前我是因为跟着潮流学习react,第一次接触到webpack。每次做项目的时候,也总是有合并js、压缩js、合并css、转换less、sass等需求。一开始我是用glup、grunt,现在也用起了webpack实现这些功能。至于具体选择哪一种工具,还是根据具体需求。

阅读相关资料,我们发现webpack可以实现:

  • 将多个js文件打包合并成单一的js文件,也就是所说的Bundle
  • Minify压缩或优化代码
  • 将Less或scss转化成css(并可以合并成一个css文件,需要ExtractTextPlugin)
  • 使用HMR(Hot Module Replacement)
  • 包含任何类型的文件到你的js中
  • 在前端程序代码中使用npm packages
  • 使用Javascript ES6 或 ES7(需要babel)
  • 还有更多...

每个功能的好处,也就是为什么要这么做,可以去查询资料了解一下。有时候我也会使用webpack只做前面几点的工作:打包、合并、压缩。

安装使用

你需要全局安装使用webpack大部分功能

$ npm install -g webpack

然后有些功能,是需要安装到项目的,例如一些优化的plugins,这种情况下就需要:

$ npm install --save-dev webpack

命令

如何执行webpack,只需要:

$ webpack

如果你要在webpack每次build的时候查看改变,需要:

$ webpack --watch

如果你要在webpack进行build的时候,使用某个配置文档,需要:

$ webpack --config myconfig.js

demo准备

我们一般用webpack的时候,都会先使用npm init创建一个package.json文件。打开终端,先创建一个demo文件夹,进入执行init命令。全部命令如下:

$ mkdir webpack-demo
$ cd webpack-demo
$ npm init

命令行中会有一系列的配置,你可以暂时‘回车’跳过,后面要修改的话可以直接编辑package.json文件。文件内容大致如下:

{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo "Error: no test specified" && exit 1"
},
"author": "",
"license": "ISC"
}

例子1:打包合并JS(bundle)

首先创建如下所示的文件目录列表,并创建一个webpack.config.js。目录列表如下:

webpack-demo
| - dist
| - src
  | - index.js
  | - component.js
| - webpack.config.js

各文件代码如下:

// index.js
var component = require('./component.js');
component();

// component.js
module.exports = function(){
  alert('component');
}

// webpack.config.js
var path = require('path')
module.exports = {
  // bundle入口
  entry: ['./src/index'], // 在index 檔案後的 .js 副檔名是可選的
  // bundle输出
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'bundle.js'  // 入口那里不变,这里如果写成[name].js,最后输出的文件为main.js
  }
}

执行命令webpack进行打包

$ webpack

看到的结果大致如下:

Hash: 288342e723b9c46b09a4
Version: webpack 1.13.3
Time: 100ms
  Asset    Size    Chunks    Chunk Names
  bundle.js  1.69 kB   0 [emitted]  main
[0] multi main 28 bytes {0}** [built]**
[1] ./src/index.js 55 bytes {0}** [built]**
[2] ./src/component.js 52 bytes {0}** [built]**

** 多个入口怎么写? **

我们刚刚看到的webpack.config.js配置是针对一个入口的,如果多个要怎么写呢?下面我们修改一下这个文件。

// webpack.config.js
var path = require('path')
module.exports = {
  // bundle入口
  entry: {
    // ***********改动***************** //
    name1: ['./src/index'], // 在index 檔案後的 .js 副檔名是可選的
    name2: ['./src/component']
  },
  // bundle输出
  output: {
    path: path.join(__dirname, 'dist'),
    // ***********改动***************** //
    filename: '[name].js'  // 入口那里不变,这里如果写成[name].js,最后输出的文件为main.js
  }
}

重新执行命令webpack进行打包,得到的输出如下:

Hash: ca24ca8a293dadbd2371
Version: webpack 1.13.3
Time: 75ms
  Asset    Size    Chunks    Chunk Names
  name1.js  1.69 kB   0 [emitted]  name1
  name2.js  1.57 kB   0 [emitted]  name2
[0] multi name1 28 bytes {0}** [built]**
[0] multi name2 28 bytes {1}** [built]**
[1] ./src/index.js 55 bytes {0}** [built]**
[2] ./src/component.js 52 bytes {0} {1}** [built]**

那么,多个入口我们也会写了。


这里,我有一个疑问?如果有人阅读这个文章,如果能解答,就感谢大神指导了。🙏
当文件大于一个的时候,很自然的就写成
entry:['./src/index','./src/index2']
但是,当文件就一个的时候,以下两种写法都可以
entry:['./src/index']
entry:'./src/index'
问题来了,两种写法打包出来的文件大小是不一样的?哪种写法才是正确的?


例子2:优化压缩代码插件(plugins)

先执行命令,将webpack安装到本地项目,才能使用一些plugins

$ npm install --save-dev webpack

安装后package.json会有所变化,新增内容如下:

...

"devDependencies": {
"webpack": "^1.13.3"
}
...

接着,我们要使用UglifyJsPlugin来实现优化压缩代码。修改webpack.config.js,内容如下:

// webpack.config.js
var path = require('path')
var webpack = require('webpack')
module.exports = {
  // bundle入口
  entry: ['./src/index'],
  // bundle输出
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  // ***********新增***************** //
  // 插件
  plugins: [
    // Minify你的程序吗,并显示警告
    new webpack.optimize.UglifyJsPlugin({
      compressor: {
        warnings: false, //设置不显示
      },
    })
  ]
  // ***********新增结束***************** //
}

执行命令webpack进行打包

$ webpack

用sublime或者其他编辑器打开/dist/bundle.js,可以看到代码已被压缩,文件大小也从1.69kB减少到322bytes

原文作者还用了另外一个插件OccurrenceOrderPlugin,作用是透过发生次数分配module和chunk的id,一些常用的id取得较短的id长度,从而达到文件大小进一步变小(似乎感觉这个作用不明显)。

那如果使用它,我们需要修改webpack.config.js的内容,如下:

// webpack.config.js
var path = require('path')
var webpack = require('webpack')
module.exports = {
  // bundle入口
  entry: ['./src/index'],
  // bundle输出
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  // 插件
  plugins: [
    // Minify你的程序吗,并显示警告
    new webpack.optimize.UglifyJsPlugin({
      compressor: {
        warnings: false, //设置不显示
      },
    }),
    // ***********新增***************** //
    // 透过发生次数分配module和chunk的id,一些常用的id取得较短的id长度。
    new webpack.optimize.OccurrenceOrderPlugin()
  ]
}

在你实际的开发使用中,js变得更复杂,你可以去留意一下这个插件OccurrenceOrderPlugin所起的作用。这里例子的js过于简单,看不出效果。略

例子3:编译css\sass\less(modules)

先来看看如何将css编译打包,执行命令安装一下loader:

$ npm install --save-dev style-loader css-loader

新建一个index.css文件、一个index.scss文件,目录列表如下:

webpack-demo
| - dist
| - src
  | - index.js
  | - component.js
  | - index.css
  | - index.scss
| - webpack.config.js

修改index.js和webpack.config.js的相应代码,如下:

// index.js
// ***********新增***************** //
require('./index.css') 
// ***********新增结束***************** //
var component = require('./component.js');
component();

// webpack.config.js
var path = require('path')
var webpack = require('webpack')
module.exports = {
  // bundle入口
  entry: ['./src/index'],
  // bundle输出
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  // 插件
  plugins: [
    // Minify你的程序吗,并显示警告
    new webpack.optimize.UglifyJsPlugin({
      compressor: {
        warnings: false, //设置不显示
      },
    }),
    // 透过发生次数分配module和chunk的id,一些常用的id取得较短的id长度。
    new webpack.optimize.OccurrenceOrderPlugin()
  ],
  // ***********新增***************** //
  // 组件模块
  module: {
    // 转换器
    loaders: [{
       // css转换
       test: /\.css$/,  // test是一个正则表达式,来匹配loader
       loaders: ['style', 'css']
    }]
  }
  // ***********新增结束***************** //
}

执行命令webpack进行打包

$ webpack

没有报错,则说明css编译打包成功。接着我们看一下sass的,首先执行命令安装sass需要的loader:

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

接着,修改代码内容如下:

// index.js
require('./index.scss') 
var component = require('./component.js');
component();

// webpack.config.js
var path = require('path')
var webpack = require('webpack')
module.exports = {
  // bundle入口
  entry: ['./src/index'],
  // bundle输出
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  // 插件
  plugins: [
    // Minify你的程序吗,并显示警告
    new webpack.optimize.UglifyJsPlugin({
      compressor: {
        warnings: false, //设置不显示
      },
    }),
    // 透过发生次数分配module和chunk的id,一些常用的id取得较短的id长度。
    new webpack.optimize.OccurrenceOrderPlugin()
  ],
  // 组件模块
  module: {
    // 转换器
    loaders: [
      // css转换
      // {
      //  test: /\.css$/,  // test是一个正则表达式,来匹配loader
      //  loaders: ['style', 'css']
      // },
      // ***********新增***************** //
      // sass转换 
      {
       test: /\.scss$/,
       // 注意这里,这些被指定的loader是有顺序的,是从右到左的,也就是说sass loader是第一个作用在你的.scss档案,然后是css 
       loaders: ["style", "css", "sass"]
      }
    ]
  }
}

执行命令webpack进行打包

$ webpack

没有报错,则说明sass编译打包成功。less这里略。

上面的webpack.config.js的代码中,我们在loaders那里也可以换种方法写,如下:

loaders: ["style","css","sass"]
// 也可以简写成:
loader: "style!css!sass"

我们发现css/sass/less编译是可以了,如果说一点点css代码混在js文件里我们可以接受,但是整个网站的css代码呢?我们不想让一大堆css样式和js混在一起,这可怎么办?

例子4:抽离css,与js分开

将页面的css抽离出来,我们用到另一个插件Extract Text Plugin。先执行命令安装一下:

$ npm install --save-dev extract-text-webpack-plugin

我们去修改一下webpack.config.js的内容,如下:

// webpack.config.js
var path = require('path')
var webpack = require('webpack')
// ***********新增***************** //
var ExtractTextPlugin = require('extract-text-webpack-plugin')
module.exports = {
  // bundle入口
  entry: ['./src/index'],
  // bundle输出
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  // 插件
  plugins: [
    // Minify你的程序吗,并显示警告
    new webpack.optimize.UglifyJsPlugin({
      compressor: {
        warnings: false, //设置不显示
      },
    }),
    // 透过发生次数分配module和chunk的id,一些常用的id取得较短的id长度。
    new webpack.optimize.OccurrenceOrderPlugin(),
    // ***********新增***************** //
    new ExtractTextPlugin("styles.css")
  ],
  // 组件模块
  module: {
    // 转换器
    loaders: [
      // css转换
      // {
      //  test: /\.css$/,
      //  loader: ExtractTextPlugin.extract('style-loader', 'css-loader')
      // },
      // sass转换 
      {
       test: /\.scss$/,
       // ***********修改***************** //
       // 注意这里是loader,不是loaders
       loader: ExtractTextPlugin.extract('style-loader', 'css-loader', 'sass-loader')
      }
    ]
  }
}

执行命令webpack进行打包

$ webpack

没有报错,并显示打包出了bundle.js和styles.css共2个文件,实现分离。

例子5:生成html页面

基于一个html页面,在打包的过程中动态生成html页面,我们需要一个插件html-webpack-plugin来实现。执行命令

$ npm install --save-dev html-webpack-plugin@2

新增一个index.html文件,内容如下:

// index.html
<html>
<head>
  <title>Webpack Demo</title>
<body>
  <h1>Hello world</h1>
</body>
</html>

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

// webpack.config.js
var path = require('path')
var webpack = require('webpack')
var ExtractTextPlugin = require('extract-text-webpack-plugin')
// ***********新增***************** //
var HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
  // bundle入口
  entry: ['./src/index'],
  // bundle输出
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  // 插件
  plugins: [
    // Minify你的程序吗,并显示警告
    new webpack.optimize.UglifyJsPlugin({
      compressor: {
        warnings: false, //设置不显示
      },
    }),
    // 透过发生次数分配module和chunk的id,一些常用的id取得较短的id长度。
    new webpack.optimize.OccurrenceOrderPlugin(),
    new ExtractTextPlugin("styles.css"),
    // ***********新增***************** //
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  // 组件模块
  module: {
    // 转换器
    loaders: [
      // css转换
      // {
      //  test: /\.css$/,
      //  loader: ExtractTextPlugin.extract('style-loader', 'css-loader')
      // },
      // sass转换 
      {
       test: /\.scss$/,
       loader: ExtractTextPlugin.extract('style-loader', 'css-loader', 'sass-loader')
      }
    ]
  }
}

执行命令webpack进行打包

$ webpack

好了,你看到在dist文件夹下出现了一个index.html页面。并且看一下生成的这个index.html的代码,你发现打包的bundle.js和styles.css都自动填进去了。没错,插件帮你做了这个。

// index.html(dist文件夹下打包生成的index.html)
<html>
<head>
  <title>Webpack Demo</title>
<link href="styles.css" rel="stylesheet"></head>
<body>
  <h1>Hello world</h1>
<script type="text/javascript" src="bundle.js"></script></body>
</html>

例子6:跑起一个服务

如果我们想要在浏览器上预览我们的网页,我们需要一个服务器来实现这个功能。webpack自带了方便的webpack-dev-server,它可以帮我们实现。
执行命令,安装

$ npm install -g webpack-dev-server
$ npm install --save-dev webpack-dev-server

默认跑起来的地址是http://localhost:8080。然而跑起来之前我们还要设置一下。
在实际中,我们都会把webpack.config.js变成2个文件:

webpack.config.dev.js // 用于开发过程
webpack.config.prod.js // 用于实际生产

先看看webpack.config.dev.js的内容,为了看的清楚,我把多余的注释都删除了,需要注释请查看文章前面的内容。如下:

// webpack.config.dev.js
var path = require('path')
var webpack = require('webpack')
var ExtractTextPlugin = require('extract-text-webpack-plugin')
var HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
  devtool: 'cheap-eval-source-map',
  entry: [
    'webpack-dev-server/client?http://localhost:8080',
    'webpack/hot/dev-server',
    './src/index'
  ],
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new ExtractTextPlugin("styles.css"),
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  module: {
    loaders: [
      {
       test: /\.scss$/,
       loader: ExtractTextPlugin.extract('style-loader', 'css-loader', 'sass-loader')
      }
    ]
  },
  devServer: {
    contentBase: './dist',
    hot: true
  }
}

其中,修改:

  • 开发过程中我们不需要代码优化,开发不断rebuild时,优化既耗时又影响我们开发快速定位错误。所以不需要 webpack.optimize plugins。
  • 对 dev server 做了一些设定,你可以到这里了解更多。

总的来说

  • entry:两个新入口将服务器关联浏览器,方便HMR。
  • devServer:其中contentBase指定文件路径,hot指定是否开启HMR。

接着,再看看webpack.config.prod.js的内容,如下:

// webpack.config.prod.js
var path = require('path')
var webpack = require('webpack')
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
  devtool: 'source-map',
  entry: ['./src/index'],
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  plugins: [
    new webpack.optimize.UglifyJsPlugin({
      compressor: {
        warnings: false,
      },
    }),
    new webpack.optimize.OccurrenceOrderPlugin(),
    new ExtractTextPlugin("styles.css"),
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  module: {
    loaders: [{
       test: /\.scss$/,
       loader: ExtractTextPlugin.extract('style-loader', 'css-loader', 'sass-loader')
    }]
  }
}

其中,修改:

  • devtool是协助debug的工具,快速定位。source-map用于prodution,cheap-eval-source-map用于development。不纠结这个问题。

那么,执行dev server的命令是

$ webpack-dev-server --config webpack.config.dev.js

执行build production的命令是

$ webpack --config webpack.config.prod.js

上面的命令很长,如果每次都输入这么长的话,很难受。为了简化,我们在package.json中设定2个简单的script。如下:

  ...
  "scripts": {
    "build": "webpack --config webpack.config.prod.js",
    "dev": "webpack-dev-server --config webpack.config.dev.js"
  },
  ...

之后,只要通过下面的命令就可以执行这些命令:

$ npm run dev  (跑dev server)
$ npm run build  (跑build production)

OK,看看现在还有什么问题。我们发现我们修改index.html代码之后,我们还要手动刷新浏览器才显示变化,还没有实现浏览器自动更新。下面我们来实现这个。

例子7:热加载(hot reload)

要实现这个功能,我们需要一个新的loader来实现(raw-loader),但是我们还需要另一个plugin来阻止它影响production,只是影响dev就好了。

要让webpack可以热加载html,我们需要require它,让它变成我们依赖树(dependency tree)中的一部分。为了实现这个,我们用raw-loader这个loader,它可以将html变成字符串到我们的javascript中。我们真正做的是要html进入到依赖树中。

首先,我们来安装一下raw-loader,执行命令

$ npm install --save-dev raw-loader

修改index.js的内容,如下:

// 这里我们放了一个判断条件,如果不是production,就引入index.html
// 目的就是为了dev时引入,produciton时不引入
if (process.env.NODE_ENV !== 'production') {
  require('./index.html')
}
require('./index.scss') 
var component = require('./component.js');
component();

修改webpack.config.dev.js的内容,如下:

// webpack.config.dev.js
var path = require('path')
var webpack = require('webpack')
var ExtractTextPlugin = require('extract-text-webpack-plugin')
var HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
  devtool: 'cheap-eval-source-map',
  entry: [
    'webpack-dev-server/client?http://localhost:8080',
    'webpack/hot/dev-server',
    './src/index'
  ],
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new ExtractTextPlugin("styles.css"),
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  module: {
    loaders: [
      {
       test: /\.scss$/,
       loader: ExtractTextPlugin.extract('style-loader', 'css-loader', 'sass-loader')
      },
      // ***********新增***************** //
      {
        test: /\.html$/,
        loader: "raw-loader" // loaders: ['raw-loader'],這個方式也是可以被接受的。
      }
    ]
  },
  devServer: {
    contentBase: './dist',
    hot: true
  }
}

修改webpack.config.prod.js的内容,如下:

// webpack.config.prod.js
var path = require('path')
var webpack = require('webpack')
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
  devtool: 'source-map',
  entry: ['./src/index'],
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  plugins: [
    new webpack.optimize.UglifyJsPlugin({
      compressor: {
        warnings: false,
      },
    }),
    new webpack.optimize.OccurrenceOrderPlugin(),
    new ExtractTextPlugin("styles.css"),
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    // ***********新增***************** //
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('production')
    })
  ],
  module: {
    loaders: [{
       test: /\.scss$/,
       loader: ExtractTextPlugin.extract('style-loader', 'css-loader', 'sass-loader')
    }]
  }
}

现在我们执行命令,跑起一个服务

$ npm run dev

然后去修改/src/index.html,随便改一下'Hello, my friend',查看一下网页,确实不需要手动刷新就更新成新的内容了。

例子8:npm package的使用

npm是一个非常大的open source生态系统,可以储存和发布你自己的代码。还可以找到非常多你可能需要的组件,直接拿来用。

那如何使用呢?
比如说,这里,我们去用一个pleasejs,它是一个随机色彩的生成器,我们给按钮绑定一个事件调用pleasejs去随便变色。

先执行命令安装pleasejs,如下

$ npm install --save pleasejs

修改index.html,index.js代码如下:

// index.html
<html>
<head>
  <title>Webpack Tutorial</title>
</head>
<body>
  <h1>Hello world</h1>
  <section id="color"></section>
  <button id="button">Such Button</button>
</body>
</html>

// index.js
if (process.env.NODE_ENV !== 'production') {
  require('./index.html')
}
// 接受 hot module reloading
if (module.hot) {
  module.hot.accept()
}
require('./index.scss') 
var Please = require('pleasejs')
var div = document.getElementById('color')
var button = document.getElementById('button')
function changeColor() {
  div.style.backgroundColor = Please.make_color()
}
button.addEventListener('click', changeColor)

然后我们执行命令,跑起一个服务

$ npm run dev

点击按钮,就可以成功的调用pleasejs变换颜色。


这里似乎出现了一个问题,因为这段判断代码,热加载失败了,不知道原作者的教程这里是否正确。

// 接受 hot module reloading
if (module.hot) {
module.hot.accept()
}


在前面,我们有使用到css\sass\less\html的loader,那么还有好多其他类似的,这里简单列一下(代码中用了正则):

{ test: /bootstrap-sass\/assets\/javascripts\//, loader: 'imports?jQuery=jquery' },
{ test: /\.jsx?$/, exclude: /node_modules/, loaders: ["babel"]},
// loads bootstrap's css.
{ test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,   loader: "url?limit=10000&mimetype=application/font-woff" },
{ test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,  loader: "url?limit=10000&mimetype=application/font-woff2" },
{ test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,    loader: "url?limit=10000&mimetype=application/octet-stream" },
{ test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,    loader: "file" },
{ test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,    loader: "url?limit=10000&mimetype=image/svg+xml" },
{ test: /\.json$/, loader: 'json' },
{ test: /\.(jpe?g|png|gif|svg)$/, loader: 'url', query: {limit: 10240} },
{ test: /\.(webm|mp4)$/, loader: "file" }

到这里,就先结束了。


学习是一条漫漫长路,每天不求一大步,进步一点点就是好的。

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

推荐阅读更多精彩内容