webpack@3.5.5使用手册-v1.0.0

目录

开始使用

mkdir webpack-demo && cd webpack-demo
npm init -y
npm install --save-dev webpack@3.5.5

管理依赖

为什么要?
如果导入模块时requrie 含有表达式﴾expressions﴿,会创建一个上下文﴾context﴿,因为在编译时﴾compile time﴿并不清楚具体是哪一个模块被导入。这会导致所有可能用到的模块都包含在 bundle 中。
require("./template/" + name + ".ejs");
方法选择?
可以使用 require.context() 方法来创建自己的(模块)上下文。给这个方法传 3 个参数:要搜索的文件夹目录,是否还应该搜索它的子目录,以及一个匹配文件的正则表达式。
require.context(directory, useSubdirectories = false, regExp = /^.//)
使用 require.context() 方法来创建自己的(模块)上下文,每个模块上下文有 3 个属性: resolve , keys , id 。 resolve 是一个函数,它返回请求被解析后得到的模块 id。 keys 也是一个函数,它返回一个数组,由所有可能被上下文模块处理的请求组成。id 是上下文模块里面所包含的模块 id. 可能在你使用 module.hot.accept 的时候被用到。
如何进行?
准备收集需要创建的模块上下文

//inex.js
var cache = {};
function importAll(r) {
        r.keys().forEach(key => cache[key] = r(key));
}

使用require.context()创建上下文

//index.js
importAll(require.context('../components/', true, /\.js$/));
// 在构建时,所有被 require 的模块都会被存到cache 里面。

管理资源

为什么要?
动态打包 (dynamically bundle)所有依赖项(创建所谓的依赖图﴾dependency graph﴿)。这是极好的创举,因为现在每个模块都可以明确表述它自身的依赖,我们将避免打包未使用的模块。
可以以更直观的方式将模块和资源组合在一起。无需依赖于含有全部资源的 /assets 目录,而是将资源与代码组合在一起。会使代码更具备可移植性。
方法选择?
加载样式:style‐loader 、css‐loader
加载图片:file‐loader、url-loader
加载字体:file‐loader、url-loader
加载数据:file‐loader、csv‐ loader、xml‐loader
如何进行?
通过加载器在js模块引入非js文件。从 JavaScript 模块中 import一个 CSS 文件,使用style‐loader 和 css‐loader。在依赖于此样式的文件中 import './style.css'(声明依赖) 。现在,当该模块运行时,含有 CSS 字符串的<style>标签会注入到html文件的head中(资源嵌入)。
假想,现在我们正在下载 CSS,但是我们的背景和图标这些图片,要如何处理呢?使用file‐loader,我们可以轻松地将这些内容混合到 CSS 中。当你 import MyImage from './my‐image.png'(声明依赖),该图像将被处理并添加到 output 目录,并且 MyImage变量将包含该图像在处理后的最终 url。当使用 css‐loader 时,如上所示,你的 CSS 中的 url('./my‐image.png') 会使用 类似的过程去处理(资源嵌入)。loader 会识别这是一个本地文件,并将 './my‐image.png' 路径,替换为 输出 目录中图像的最终路径。html‐loader 以相同的方式处理(资源嵌入)。
通过配置好 loader 并将字体文件放在合适的地方,你可以通过一个 @font‐face 声明引入。本地的 url(...) 指令 会被 webpack 获取处理,就像它处理图片资源一样。
可以加载的有用资源还有数据,如 JSON 文件,CSV、TSV 和 XML。类似于 NodeJS,JSON 支持实际上是内置 的,也就是说 import Data from './data.json' 默认将正常运行。要导入 CSV、TSV 和 XML,你可以使用 csv‐ loader 和 xml‐loader。
安装依赖到开发环境中
npm install ‐‐save‐dev style‐loader css‐loader
npm install ‐‐save‐dev file‐loader
在配置文件中用加载器

module: {
    rules: [{
        test: /\.css$/,
        use: [
            'style‐loader',
            'css‐loader'
        ]
    },
    {
        test:/\.(png|svg|jpg|gif)$/,
        use: [
            'file‐loader'
        ]
    },
    {
        test:/\.(woff|woff2|eot|otf)$/,
        use: [
            'file‐loader'
        ]
    }
]
 }

在文件中声明依赖

//index.js
import './style.css';

管理输出

为什么要?
问题01:到目前为止,我们在 index.html 文件中手动引入所有资源,然而随着应用程序增长,并且一旦开始对文件名使用哈 希﴾hash﴿]并输出多个 bundle,手动地对 index.html 文件进行管理,一切就会变得困难起来。——内容注入
问题02:假如输出文件都是输出到/dist目录,用多了总会遗留下来,导致我们的 /dist 文件夹相当杂乱。webpack 会生成文件,然后将这些文件放置在 /dist 文件夹中,但是 webpack 无法追踪到哪些文件是实际在项目中用到的。 通常,在每次构建前清理 /dist 文件夹,是比较推荐的做法,因此只会生成用到的文件。让我们完成这个需求。——目录清理
问题03:有时候,我们希望webpack 能够对「我们的模块映射到输出 bundle 的过程」保持追踪。比如收集静态资源的依赖关系、打包关系,以便实现模块化和组件化开发。——文件清单
方法选择?
问题01:可以用 HtmlWebpackPlugin 来解决对html文件注入内容:。
问题02:clean‐webpack‐plugin插件清除输出目录。
问题03:用WebpackManifestPlugin将模块映射到输出的关系提取到一个 json 文件,以供使用。
如何进行?
步骤01:安装依赖到开发环境中

npm install ‐‐save‐dev html‐webpack‐plugin
npm install ‐‐save‐dev clean‐webpack‐plugin
npm install ‐‐save‐dev WebpackManifestPlugin 

步骤02:在配置文件中使用插件

const HtmlWebpackPlugin = require('html‐webpack‐plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const ManifestPlugin = require('webpack-manifest-plugin');
plugins: [
  new CleanWebpackPlugin(['dist']),
  new HtmlWebpackPlugin({title: 'Output Management'}),
  new ManifestPlugin()
]

选项参考:内容注入清除目录文件清单

代码分离

为什么要?
把代码分离到不同的 bundle 中。可以按需加载或并行加载这些文件;可以用于获取更小的 bundle,以及控制资源加载优先级,如果使用合理,会极大影响加载时间。
分离方法?
入口起点:使用 entry 配置手动地分离代码。
防止重复:使用 CommonsChunkPlugin 去重和分离 chunk。
动态导入:通过模块的内联函数调用来分离代码。
怎么分离?
通过设置多个入口进行分离,是迄今为止最简单、最直观的分离代码的方式。

entry: {
    index: './src/index.js',
    another: './src/another‐module.js'
}

如果入口 chunks 之间包含重复的模块,那些重复模块都会被引入到各个 bundle 中。接着,我们通过使用 CommonsChunkPlugin插件来移除重复的模块到一个公共文件中。这常用于提取公共类库,三方类库异步类库,文件清单

plugins: [
    new webpack.optimize.CommonsChunkPlugin({
        name: 'common' // 指定公共 bundle 的名称。
    })
]

但是,通过设置多个入口进行分离,还有一不足。这种方法不够灵活,不能将核心应用程序逻辑进行动态拆分代码。为此,引入动态分离。

//index.js
async function getComponent() {
    var element = document.createElement('div');
    const _ = await
    import( /* webpackChunkName: "lodash" */ 'lodash');
    element.innerHTML = _.join(['Hello', 'webpack'], ' ');
    return element;
}
//webpack.config.js
output: {
    filename: '[name].bundle.js',
    //决定非入口文件的名称
    chunkFilename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist')
}

除了上述对脚本的分离,ExtractTextPlugin插件用于将 CSS 从主应用程序中分离。

分析输出

如果我们以分离代码作为开始,那么就以检查模块作为结束,分析输出结果是很有用处的。webpack‐visualizer: 可视化并分析你的 bundle,检查哪些模块占用空间,哪些可能是重复使用的。

//step01:运行命令
webpack --json --profile > stats.json

//step02:开浏览器
http://chrisbateman.github.io/webpack-visualizer/

or use in nodejs:
https://npm.taobao.org/package/webpack-visualizer-plugin

管理缓存

为什么要?
问题01:使用 webpack 来打包我们的模块化后的应用程序,webpack 会生成一个可部署的 /dist 目录,然后把打包后的内容放置在此目录中。只要 /dist 目录中的内容部署到服务器上,客户端(通常是浏览器)就能够访问网站此 服务器的网站及其资源。而最后一步获取资源是比较耗费时间的,这就是为什么浏览器使用一种名为缓存的技术。可以通过命中缓存,以降低网络流量,使网站加载速度更快,然而,如果我们在部署新版本时不更改资源的文件名,浏 览器可能会认为它没有被更新,就会使用它的缓存版本。由于缓存的存在,当你需要获取新的代码时,就会显得很棘手。
我们需要确保 webpack 编译生成的文件能够被客户端缓存,而在文件内容变化后,能够请求到新的文件。——文件指纹
什么方法?
改文件名法:
通过使用 output.filename 进行文件名替换,可以确保浏览器获取到修改后的文件。 [hash] 替换可以用于在文件名中包含一个构建相关﴾build‐specific﴿的 hash,但是更好的方式是使用基于文件内容摘要的[chunkhash] 替换。
提取样板法:CommonsChunkPlugin 可以用于将模块分离到单独的文件中。然而 CommonsChunkPlugin 有一个较少有人知道的功能是,能够在每次修改后的构建结果中,将 webpack的样板 ﴾boilerplate﴿和 manifest 提取出来。通过指定 entry 配置中未用到的名称,此插件会自动将我们需要的内容提取到单独的包中。将第三方库﴾library﴿(例如 lodash 或 react )提取到单独的 vendor chunk 文件中,是比较推荐的做法,这是因为,它们很少像本地的源代码那样频繁修改。因此通过实现以上步骤,利用客户端的长效缓存机制,可以通过命中缓 存来消除请求,并减少向服务器获取资源,同时还能保证客户端代码和服务器端代码版本一致。
模块标识法:向项目中再添加一个模块,每个 module.id 会基于默认的解析顺序﴾resolve order﴿进行增量(模块的id基于数字标识)。也就是说,当解析顺序发生变化,ID 也会随之改变。会造成第三方类库的hash也跟着改变。插件NamedModulesPlugin ,将使用模块的路径,而不是数字标识符。虽然此插件有助于在开发过程中输出结果的可读性,然而执行时间会长一些。第二个选择是使用 HashedModuleIdsPlugin ,推荐用于生产环境构建。
如何操作?
(文件名法)

//webpack.config.js
output: {
filename: '[name].[chunkhash].js',
}

bundle 的名称是它内容(通过 hash)的映射。如果我们不做修改,然后再次运行构建,我们以为文件名会 保持不变。然而,如果我们真的运行,可能会发现情况并非如此——如果不做修改,文件名可能会变,也可能不会。这是因为 webpack 在入口 chunk 中,包含了某些样板﴾boilerplate﴿,特别是 runtime 和 manifest。
(提取样板)

const webpack = require('webpack');
module.exports = {
    entry: {
        main: './src/index.js',
        vendor: [
            'lodash'
        ]
},
plugins: [
//提取第三方的包
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor'
}),
//提取 manifest
        new webpack.optimize.CommonsChunkPlugin({
            name: 'manifest'
        })
    ],
    output: {
        filename: '[name].[chunkhash].js',
        path: path.resolve(__dirname, 'dist')
    }
};

(模块标识)

const webpack = require('webpack');
module.exports = {
    entry: {
        main: './src/index.js',
        vendor: [
            'lodash'
        ]
},
plugins: [
//模块基于路径标识
new webpack.HashedModuleIdsPlugin(),//生产环境
// new webpack.NamedModulesPlugin(),//开发环境
//提取第三方的包
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor'
}),
//提取 manifest
        new webpack.optimize.CommonsChunkPlugin({
            name: 'manifest'
        })
    ],
    output: {
        filename: '[name].[chunkhash].js',
        path: path.resolve(__dirname, 'dist')
    }
};

模块刷新

为什么要?
问题01:有时候在运行时更新各种模块,而无需进行完全刷新。——自动刷新
刷新方法?
内置刷新服务器法:webpack‐dev‐server
自建刷新服务器法:webpack‐dev‐middleware + webpack‐hot‐middleware +express
怎么刷新?
(使用内置刷新服务器)
安装依赖

npm install ‐‐save‐dev NamedModulesPlugin
npm install ‐‐save‐dev HotModuleReplacementPlugin

配置文件

// built-in-hot-dev-server.config.js
entry: {
 app: './src/index.js'
},
devServer: {
    contentBase: './dist',
    hot: true
},
plugins: [
    new CleanWebpackPlugin(['dist']),
    new HtmlWebpackPlugin({
        title: 'Hot Module Replacement'
    }),
    //以便更容易查看要修补﴾patch﴿的依赖
    new webpack.NamedModulesPlugin(),
    new webpack.HotModuleReplacementPlugin()
]

入口文件

//./src/index.js
import printMe from './print.js';
if(module.hot) {
    module.hot.accept('./print.js', function() {
        console.log('Accepting the updated printMe module!');
        printMe();
    })
}

包的配置

    //package.json
"scripts": {
    "start": "webpack --config built-in-hot-dev-server.config.js"
}

运行命令

npm run start
(使用自建刷新服务器)

开发环境

为什么要?
问题01:使用错误追踪功能。为了更容易地追踪错误和警告,将编译后的代码映射回原始源代码。如果一个错误来自于 b.js ,source map 就会明确的告诉你。——资源映射
问题02:使用自动编译功能。每次要编译代码时,手动运行 npm run build 就会变得很麻烦。工具可以帮助你在代码发生变化后自动编译代码。——文件监控+自动刷新

  1. webpack's Watch Mode——解决自刷脚本的问题
  2. webpack‐dev‐server ——解决了自刷脚本+自刷样式+自刷内容的问题
  3. webpack‐dev‐middleware ——解决了自刷脚本+自刷样式+自刷内容的问题

如何进行?
(错误追踪)

//step01:设置配置文件
devtool: 'inline‐source‐map',

//step02:编译及打开浏览器

//step03:在控制台查看错误

(自动编译)
方案1:webpack的监控模式实现自动编译

"scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "watch": "webpack ‐‐watch",
        "build": "webpack"
},

方案2:webpack‐dev‐server实现自动编译

//step01:安装依赖
npm install ‐‐save‐dev webpack‐dev‐server
//step02:设置配置
devServer: {
        //告诉开发服务器﴾dev server﴿,在哪里查找文件
        contentBase: './dist'
}
//step03:包的配置
"scripts": {
"start": "webpack‐dev‐server ‐‐open"
}

方案3:webpack-dev-middleware实现自动编译
webpack‐dev‐middleware是一个容器,它可以把 webpack 处理后的文件传递给一个服务器 ﴾server﴿。 webpack‐dev‐server 在内部就是使用了它,同时,它也可以作为一个单独的包来使用,以便进行更多自定义设置来实现更多的需求。

1.安装依赖
npm install ‐‐save‐dev express webpack‐dev‐middleware
2.设置配置
output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/'
}
3.建服务器dev-server.js
const express = require('express');
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack‐dev‐middleware');
const app = express();
const config = require('./webpack.config.js');
const compiler = webpack(config);
// Tell express to use the webpack‐dev‐middleware and use the webpack.config.js
// configuration file as a base.
app.use(webpackDevMiddleware(compiler, {
    publicPath: config.output.publicPath
}));
// Serve the files on port 3000.
app.listen(3000, function() {
    console.log('Example app listening on port 3000!\n');
});
4.包的配置
"scripts": {
    "start": "node dev-server.js"
}

生产环境

为什么要?
开发环境(development)和生产环境(production)的构建目标差异很大。在开发环境中,我们需要具有强大的、具有实时 重新加载﴾live reloading﴿或热模块替换﴾hot module replacement﴿能力的 source map 和 localhost server。而在生产环境 中,我们的目标则转向于关注更小的 bundle,更轻量的 source map,以及更优化的资源,以改善加载时间。由于要遵 循逻辑分离,我们通常建议为每个环境编写彼此独立的 webpack 配置。
如何构建?
遵循不重复原则﴾Don't repeat yourself ‐ DRY﴿,保留一个“通用”配置。为了将这些配置合并在一起,我们将使用一个名为 webpack‐merge 的工具。 通过“通用”配置,我们不必在环境特定﴾environment‐specific﴿的配置中重复代码。——代码压缩

step01:配置文件
//webpack.common.js 通用配置文件
//webpack.pro.js 产品环境文件
//webpack.dev.js 开发环境文件

step02:安装依赖
npm install ‐‐save‐dev webpack‐merge

step03:包的配置
"scripts": {
 "start": "webpack‐dev‐server ‐‐open ‐‐config webpack.dev.js",
 "build": "webpack ‐‐config webpack.pro.js"
}

step04:运行命令
# 开发时
Npm run start
# 构建时
Npm run build

环境变量

为什么要?
问题01:要在开发和生产构建之间,消除 webpack.config.js 的差异,可能需要环境变量。
什么方法?
怎么设置?
运行命令时传入变量:webpack 命令行环境配置中,通过设置 ‐‐env 可以使你根据需要,传入尽可能多的环境变量。

webpack ‐‐env.NODE_ENV=local ‐‐env.production ‐‐progress –config webpack.config.pro.js

配置文件中访问变量:在 webpack.config.js 文件中可以访问到这些环境变量。

//webpack.config.pro.js
module.exports = env => {
// Use env.<YOUR VARIABLE> here:
    console.log('NODE_ENV: ', env.NODE_ENV) // 'local'
    console.log('Production: ', env.production) // true
    return {
        entry: './src/index.js',
        output: {
            filename: 'bundle.js',
            path: path.resolve(__dirname, 'dist')
        }
    }
}

公共路径

为什么要?
问题01:在开发模式中,我们通常有一个 assets/ 文件夹,它往往存放在和首页一个级别的目录下。这样是挺方便;但是如果在生产环境下,你想把这些静态文件统一使用CDN加载,那该怎么办?——公共路径
什么方法?
环境变量法:设置了一个名为 ASSET_PATH 的变量。
即时设置法:webpack 提供一个全局变量供你设置,它名 叫 webpack_public_path
怎么设置?
(环境变量法)

step01:配置文件
//webpack.config.js
import webpack from 'webpack';
// 设置变量
const ASSET_PATH = process.env.ASSET_PATH || '/';
export default {
    output: {
        publicPath: ASSET_PATH
    },
    plugins: [
        // 该插件帮助我们安心地使用环境变量
        new webpack.DefinePlugin({
            'process.env.ASSET_PATH': JSON.stringify(ASSET_PATH)
        })
    ]
};
step02:运行命令

(即时设置法)

step01:入口文件
//index.js
__webpack_public_path__ = process.env.ASSET_PATH;

step02:运行命令

构建性能

为什么要?

如何进行?
使用最新的 webpack 稳定版本。我们会经常进行性能优化。
保持最新的 Node.js稳定版本
保证最新的包管理工具稳定版本。(npm/yarn)
将 loaders 应用于最少数的必要模块中。因为范围太广,查找耗时。
尽量少使用不同的工具。因为每个额外的 loader/plugin 都有启动时间。
尽量减少resolve.modules , resolve.extensions , resolve.mainFiles , resolve.descriptionFiles 中类目的数量,因为他们会增加文件系统调用的次数。
提高解析速度。如果你不使用 symlinks ,可以设置 resolve.symlinks: false ﴾例如 npm link 或者 yarn link ﴿.如果你使用自定义解析 plugins ,并且没有指定 context 信息,可以设置 resolve.cacheWithContext: false 。
减少编译的整体大小,以提高构建性能。尽量保持 chunks 小巧。使用 更少/更小 的库。 在多页面应用程序中使用 CommonsChunksPlugin 。 在多页面应用程序中以 async 模式使用 CommonsChunksPlugin 。 移除不使用的代码。 只编译你当前正在开发部分的代码。

开发环境时:
增量编译。使用 webpack 的监听模式。不要使用其他工具来监听你的文件和调用 webpack 。在监听模式下构建会记录时间戳并将信息传递给编译让缓存失效。 在某些设置中,监听会回退到轮询模式。有许多监听文件会导致 CPU 大量负载。在这些情况下,你可以使 用 watchOptions.poll 来增加轮询的间隔。
在内存中编译。以下几个实用工具通过在内存中进行代码的编译和资源的提供,但并不写入磁盘来提高性能: webpack‐dev‐server webpack‐hot‐middleware webpack‐dev‐middleware
产品环境时:
某些实用工具, plugins 和 loaders 都只能在构建生产环境时才有用。例如,在开发时使用 UglifyJsPlugin 来压缩和修改代码是没有意义的。
UglifyJsPlugin
ExtractTextPlugin
[hash] / [chunkhash]
AggressiveSplittingPlugin
AggressiveMergingPlugin
ModuleConcatenationPlugin
多个编译时 当进行多个编译时,以下工具可以帮助到你: parallel‐webpack : 它允许编译工作在 worker 池中进行。 cache‐loader : 缓存可以在多个编译时之间共享。

离线应用

(渐进式的网络应用程序)
为什么要?
我们应该要实现的是,停止服务器然后刷新,仍然可以查看应用程序 正常运行。
如何进行?
搭建一个服务器

1.安装依赖
npm install http‐server ‐‐save‐dev
2.包的配置
"scripts": {
    "start": " http‐server dist"
}
3.启动服务
启动 http‐server,服务目录是 dist

如果你打开浏览器访问 http://localhost:8080 ﴾即 http://127.0.0.1 ﴿,你应该会看到在 dist 目录创建出服务, 并可以访问 webpack 应用程序。如果停止服务器然后刷新,则 webpack 应用程序不再可访问。

//1.安装依赖
npm install workbox‐webpack‐plugin ‐‐save‐dev
//2.配置文件
const path = require('path');
const HtmlWebpackPlugin = require('html‐webpack‐plugin');
const CleanWebpackPlugin = require('clean‐webpack‐plugin');
const WorkboxPlugin = require('workbox‐webpack‐plugin');
plugins: [
    new CleanWebpackPlugin(['dist']),
    new WorkboxPlugin({
        // 这些选项帮助 ServiceWorkers 快速启用
        // 不允许遗留任何“旧的” ServiceWorkers
        clientsClaim: true,
        skipWaiting: true
    })
]
//3.使用
import _ from 'lodash';
import printMe from './print.js';
if('serviceWorker' in navigator) {
    window.addEventListener('load', () => {
        navigator.serviceWorker.register('/sw.js').then(registration => {
            console.log('SW registered: ', registration);
        }).catch(registrationError => {
            console.log('SW registration failed: ', registrationError);
        });
    });
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容