拉勾教育07-08训练营-前端包管理整理

文章内容输出来源:拉勾教育高薪前端训练营

来拉勾教育学习了有一个多月了,感觉学的还是提不错的,引导作用感很强,相比之前自己一个人忙忙碌碌的却又很难提高效率,甚是困惑,有些知识概念就是很难深入理解,学习之后感觉就好很多。

以下呢就是一些关于前端包管理的一些整理点,简单分享下。。

1. npm、yarn、cnpm安装

  • 只要安装node一般都会自带安装npm
  • 安装 yarn:npm install yarn -g
  • 安装 cnpm:npm install -g cnpm --registry=https://registry.npm.taobao.org

2. npm 发布包

2.1 npm 包文件准备

步骤1: 在 github 上新建一个项目(选择 MIT 证书类型的开源协议,并勾选新建一个 README.md 文件)

步骤2: 把 github 上的该项目克隆到本地。

步骤3: 在该项目根目录下执行 npm init 初始化 package.json 文件,见下面第5点

# 初始化 package.json
npm init

示例如下:

{
  "name": "xxx",
  "version": "1.0.0",
  "description": "Some common methods are summarized",
  "main": "index.js",
  "author": "xxx <yyy@163.com>",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "homepage": "https://github.com/xxx/yyy",
  "bugs": "https://github.com/xxx/yyy/issues",
  "repository": {
    "type": "git",
    "url": "https://github.com/xxx/yyy"
  },
  "keywords": [
    "common",
    "functions",
    "tool"
  ],
  "license": "MIT"
}

步骤4: 添加一些过滤文件

  • 添加 .gitignore 文件。
.DS_Store
node_modules/
  • 添加 npm 包过滤上传文件 .npmignore

    当你上传包到npm库时,有一些本地的依赖文件和测试demo等不想上到npm库里,这时就要用到.npmignore过滤文件了

步骤5: 修改 README.md 文件,里面的首行图标可以在 https://shields.io/ 上制作。

![https://img.shields.io/badge/version-1.0.0-blue.svg](https://img.shields.io/badge/version-1.0.0-blue.svg)
![https://img.shields.io/badge/license-MIT-brightgreen.svg](https://img.shields.io/badge/license-MIT-brightgreen.svg)

## Usage

1. `cd` to your project directory, and install the package, `npm i -S xxxx` or `yarn add xxx`.  
2. use the package in your project, `import Funs from 'xxx'`.

## Contribution

- [@defeng li](mailto:xxx@gmail.com) The main author.

## Questions

Feel free to [contact me](mailto:xxx@gmail.com) or [create an issue](https://github.com/xxx/xxx/issues/new)

步骤6: 添加主入口文件 index.js

function sayHelloWorld() {
  console.log("Hello world !");
}
module.exports = sayHelloWorld;

至此这个简单的项目基本写好了,大致目录结构如下

xxx
  ├── .git          // git隐藏文件
  ├── README.md     // 说明文档
  ├── index.js      // 项目主入口
  ├── .gitignore    // git过滤文件
  ├── package.json  // 包信息
  └── LICENSE       // github开源协议文件

2.2 登录并发布

注册 npm 账号: 在 npm 网上 https://link.jianshu.com?t=https://www.npmjs.com/signup 注册一个账号,注意注册邮箱有要求(可以使用 gmail 邮箱)。

# 使用 npm adduser 命令输入用户名(Username)、密码(Password)和邮箱(Email)登录刚才注册的 npm 账号
npm adduser
# 在包根目录下发布
npm publish --access=public --registry=https://registry.npmjs.org/
yarn publish --access=public --registry=https://registry.yarnpkg.com/
# 看看刚刚发布的包是否已成功发布,如果报404错误表示发布失败,否则表示发布成功,并在项目里安装使用下会不会有问题。
npm view some-name

注意:

  • 登录和发布 npm 包的时候不能使用淘宝镜像,必须使用 npm 地址,可以使用 nrm use npm 切换到 npm 的地址,或者添加--registry参数,如果不是用的 npm 的地址一般是报 no_perms Private mode enable, only admin can publish this module 的错。
  • Error: EPERM: operation not permitted, unlink 错时,自己是把 package.json 文件里的 test 键值对删除了,和把 export default funs 改成了 module.exports = funs 解决的,希望有所参考。

2.3 更新发布的 npm 包

  1. 修改包的版本(package.json里的version字段,可以直接修改改文件,或者使用上面的 npm version 命令修改)
  • 对于"version":"x.y.z"(major主版本 . minor次要版本 . patch小版本)
    • 修复bug,小改动,增加z
    • 增加了新特性,但仍能向后兼容,增加y
    • 有很大的改动,无法向后兼容,增加x
  1. 提交项目最新的代码到 github 上。
  2. 在项目根目录下执行 npm publish 命令发布更新最新的 npm 包。
  3. 在项目上更新包查看下。

2.4 撤销发布的 npm 包

在项目的根目录下使用上面的 npm unpublish 命令。

3. 版本定义

npm包 中的模块版本都需要遵循 SemVer规范——由 Github 起草的一个具有指导意义的,统一的版本号表示规则。实际上就是 Semantic Version(语义化版本)的缩写

3.1 版本命名规则

我们常见的版本命名格式为:[name].x.y.z-[state]

  • name 为可选字段,一般为 v,表示 version

  • x.y.z 为各版本的序号,遵循 语义化版本命名规范实际上基于此规范,不应该在版本前出现 name 字段.

    序号 格式要求 说明
    x 非负整数 主版本号(major),进行不向下兼容的修改时,递增主版本号
    y 非负整数 次版本号(minor),保持向下兼容,新增特性时,递增次版本号
    z 非负整数 修订号(patch),保持向下兼容,修复问题但不影响特性时,递增修订号
    • 0.y.z 表示开发阶段,一切可能随时改变,非稳定版。
    • 1.0.0 界定此版本为初始稳定版,后面的一切更新都基于此版本进行修改。
  • state 可选字段,表示版本状态,例如 b 表示 beta 测试版,其他常见状态,后有详述

    描述方式 说明 含义
    αa alpha 版 内测版本,内部测试的版本,bug 较多
    βb beta 版 公测版本,给外部进行测试的版本,有缺陷
    γg Gamma 版 相当成熟的测试版,于发行版相差无几
    rc Release Candidate 是前面三种测试版的进一步版本,实现了全部功能,清除了大部分 bug,接近发布倒计时,有时会进一步细分为 rc1,rc2

实际上大部分前端工具均遵守上述规则

在商业软件中还会见到如下字段.

描述方式 说明 含义
Demo 演示版 只集成了正式版部分功能,无法升级
SP SP1 是 service pack 的意思表示升级包
Trial 试用版 试用版
Unregistered 未注册 有功能或时间限制的版本
Lite 精简版 只含有正式版核心功能
enhance 增强版 属于正式版1
free 免费版 自由使用版本
release 发行版 有时间限制
upgrade 升级版 有功能增强或修复 bug
Retail 零售版 单独发售
Cardware 共享版 公用许可证

3.2 版本限定

  • 在进行包管理时,为了保证安装依赖的兼容性,必须对依赖包版本进行限定.参考 npm 限定描述,如下示例表示安装 0.13.22 版本的 karma。

    {
      "devDependencies": {
        "karma": "0.13.22"
      }
    }
    
  • 为了方便理解,版本限定的语法简述为为: [范围描述]<版本号描述> 其中范围描述可选

    范围描述:

    • < 小于某一版本号
    • <= 小于等于某一版本号
    • > 大于某一版本号
    • >= 大于等于某一版本号
    • = 等于某一版本号,没有意义和直接写该版本号一样
    • ~ 基于版本号描述的最新补丁版本
    • ^ 基于版本号描述的最新兼容版本
    • - 某个范围,他应该出现在两个版本描述中间,实际上语法应为: <版本描述>-<版本描述>,写在此处为了统一

    严格来讲对 ~^ 的表述需要结合具体的包管理工具和版本号规则来确定,但是对于一般使用记住如下原则:

    • ^ 是确保版本兼容性时,默认对次版本号的限定约束
    • ~ 是确保版本兼容性时,默认对补丁号的约束

    版本描述:

    • * 通配符,类似 glob 模式 *
    • x,X 约等于 * 号,通常用于次版本和补丁的通配.

0.x 警惕这种版本,说明该依赖还未稳定(如果它遵守语义化命名的话),此外由于 0.x 版本随时可能改变,此时 ^,~ 的都表示为对补丁版的限制。

相关举例如下:

< 1.2.3     小于1.2.3 的版本均可 
= 1.2.3     只支持等于1.2.3 的版本 
<= 1.2.3    只支持小于等于1.2.3 的版本
> 1.2.3     只支持大于 1.2.3 的版本
>= 1.2.3    只支持大于等于 1.2.3 的版本
1.2.3-2     支持 >=1.2.3 <3.0.0 的版本
1.x.1       支持 >=1.0.1 <1.1.0 的版本
*           支持 >= 0.0.0 的版本
""          同 *
1           表示 >=1.0.0 <2.0.0 其余任意位置为空相似
1.0         >= 1.0.0 < 1.1.0
~1.1.1      >=1.1.1 <1.2.0
~1.1        >=1.1.0 <1.2.0
~1          >=1.0.0 <2.0.0
^1.1.1      >=1.1.1 <2.0.0
^0.1.1      >=0.1.1 <0.2.0 注意这里,不要以为是 0.1.1-1.0.0 之间
^0.0.1      >=0.0.1 <0.0.2 同上,请注意
@latest     最新的稳定版本
@next       最新未发行版本

注意:大部分包管理工具均遵守上述规则,但是在进行版本限定时,请参考包管理工具的配置项说明,确定语法格式。

4. npm常用命令

npm 模块仓库提供了一个查询服务,叫做 registry,比如 npm 的查询服务网址是 https://registry.npmjs.org/,淘宝镜像的查询服务网址是 https://registry.npm.taobao.org/,yarn 的查询服务网址是 https://registry.yarnpkg.com/

registry + package-name 就会看到 package-name 模块所有版本的信息,比如 https://registry.npmjs.org/reacthttps://registry.npm.taobao.org/reacthttps://registry.yarnpkg.com/react

4.1 发布包常用命令

注:以下指令一般需要切换成 npm 地址再执行

# 如果报404错说明该 npm 包名可用,否则该包名已被占用(也表示已发布到 npm 上)
npm [view | v | show | info] some-name
# 搜索某一个模块
npm search [package-name]
# 查看某个 package 的最新版本
npm [view | v] [package-name] version
# 查看某个 package 在 npm 服务器上所有发布过的版本
npm [view | v] [package-name] versions
# 创建项目在模块根目录初始化 package.json
npm init [-y]
# 添加 npm 用户(第一次发布包)
npm adduser
# 登录 npm 用户(非第一次发布包)
npm login
# 发布 npm 包(--access=public设置使用权参数为公有的)
npm publish [--access=public]
# 更新 npm 包版本(如果项目最新内容没有git提交则会报 Git working directory not clean 错,可以先提交再更新版本,如果一定要更新也可以使用 --force 参数强制更新版本)其实 npm version 命令更新版本后还立即执行了一次git提交。
npm version <版本号|major|minor|patch> [--force]
# 安装或更新包,@表示指定版本,^表示该大版本下的最新次要版本,~表示该次要版本下的最新小版本,--latest 是用于 upgrade 命令的
yarn add/upgrade <package_name>|@1.0.0|@~1.0.0|@^1.0.0| [--lateset]
# 撤销发布的包(一般会有 I sure hope you know what you are doing. 警告,因为可能有些项目在使用这个包,如果需要强制撤销发布的包需要加上 --force 参数)
npm unpublish [--force]

4.2 查找帮助

# 查看 npm 版本 
npm -v
# 显示所有可用命令
npm -l
# 查看命令的简单使用帮助
npm [command] -h
# 查看命令的详细使用指南
npm help [command]

4.3 安装、卸载、更新模块

npm install 安装过程:

  1. 发出 npm install 命令
  2. npm 向 registry 查询模块压缩包的网址
  3. 下载压缩包,存放在 ~/.npm 目录
  4. 解压压缩包到当前项目的 node_modules 目录
# 根据 package.json 文件安装相关依赖
npm [install | i]
# 局部安装某个模块,并将模块依赖写入到 package.json 文件的 dependencies 或 devDependencies 中
npm [install | i] [package-name] [--save | --save-prod | -P | --save-dev | -D]
npm install gulp # 等同于安装最新版本
npm install gulp@latest # 安装最新版本
npm install gulp@3.9.1 # 安装指定版本
npm install vue@">=1.0.28 < 2.0.0" # 安装指定范围版本
npm install git://github.com/package/path.git # 通过仓库地址安装
# 全局安装依赖
npm [install | i] [package-name] -g
# 更新局部模块
npm update [package-name]
# 更细全局模块到指定版本
npm update [package-name@x.x.x] -g
# 局部卸载模块
npm [uninstall | un] [package-name] [--save | --save-prod | -P | --save-dev | -D]
# 全局卸载模块
npm [uninstall | un] [package-name] -g
# 列出当前项目安装的所有模块
npm [list | ls] [--json]
# 查看全局安装包
npm [list | ls] -g --depth=0 [--json]
# 查看 npm 全局安装的根目录
npm bin

4.4 镜像相关

# 临时使用镜像
npm install package-name --registry=https://registry.npm.taobao.org/
# 长期使用镜像
npm config set registry=https://registry.npm.taobao.org/

4.5 npm 设置类

# 设置一些变量
npm [config] set registry https://registry.npmjs.org/
npm [config] set registry=https://registry.npmjs.org/
# 获取配置
npm [config] get registry
# 删除配置
npm config delete registry
# 设置一些初始化变量
npm [config] set init-license 'MIT'
npm [config] set init-author-name 'my name jerry'
# 查看命令的绝对路径 /Users/tony/Desktop/web_front/npmtest/node_modules
npm root
# 查看配置
npm config list
# 获取 npm 本地的缓存目录(npm install 或 npm update 命令,从 registry 下载压缩包之后)
npm config get cache
# 查看 npm 缓存,储存结构是{cache}/{name}/{version}
ll ~/.npm # ~/.npm/node-sass/4.14.1/...
# 添加 npm 缓存
npm cache add <folder>
npm cache add <tarball url>
npm cache add <git url>
npm cache add <name>@<version>
# 清除 npm 缓存
npm cache clean
rm -rf ~/.npm/*
# 不指明 dir_path 则在 {prefix}/lib/node_modules 中新建一个当前目录的超链接
# 指明 dir_path 则在 ./node_modules 中新建一个 dir_path 目录的超链接
# 参考地址:https://www.jianshu.com/p/aaa7db89a5b2
npm link [dir_path]
# 列出所有环境变量
env

4.6 执行脚本

4.6.1 脚本执行原理
  • 每当执行npm run,就会自动新建一个 Shell,在这个 Shell 里面执行指定的脚本命令。因此,只要是 Shell(一般是 Bash)可以运行的命令,就可以写在 npm 脚本里面。
  • npm run新建的这个 Shell,会将当前目录的node_modules/.bin子目录加入PATH变量,执行结束后,再将PATH变量恢复原样。也就是说当前目录的node_modules/.bin子目录里面的所有脚本,都可以直接用脚本名调用,而不必加上路径。比如,当前项目的依赖里面有 Mocha,只要直接写mocha test就可以了。
  • npm 脚本可以使用Shell通配符*表示任意文件名,**表示任意一层子目录,如果要使用字符*,要将星号转义\*
  • 向 npm 脚本传入参数,要使用--标明,如 npm run lint -- --reporter checkstyle
  • npm 并行执行使用&符号,按顺序继发执行使用&&符号,如 npm run script1.js & npm run script2.jsnpm run script1.js && npm run script2.js
{
  "scripts": {
    "test": "mocha test",
    "lint": "jshint *.js",
    "lint": "jshint **/*.js",
    "test": "tap test/\*.js",
    "lint:checkstyle": "npm run lint -- --reporter checkstyle > checkstyle.xml"
  }
}
4.6.2 一些执行脚本命令
# 执行 package.json 文件中 scripts 里的脚本
npm run [script-key]
# 注意会默认执行指令的 pre 和 post 钩子。注:双重的pre和post无效,比如prepretest和postposttest是无效的
[npm run pretest]
npm run test
[npm run posttest]
4.6.3 一些简写命令
  • npm startnpm run start
  • npm stopnpm run stop的简写
  • npm testnpm run test的简写
  • npm restartnpm run stop && npm run restart && npm run start的简写
4.6.4 获取变量
  • 通过 process.env.npm_package_ + 前缀(如果是 bash 脚本则还可以通过 $npm_package_ + 前缀)npm 脚本可以拿到package.json里面的字段。
// === package.json ===
{
  "name": "foo", 
  "version": "1.2.5",
  "scripts": {
    "view": "node view.js",
    "view-name": "echo $npm_package_name",
    "view-version": "echo $npm_package_version",
    "view-scripts-view": "echo $npm_package_scripts_view"
  }
}

// === view.js ===
console.log(process.env.npm_package_name); // foo
console.log(process.env.npm_package_version); // 1.2.5
console.log(process.env.npm_package_scripts_view); // node view.js

// === 如果是 bash 脚本 ===
npm run view-name // foo
npm run view-version // 1.2.5
npm run view-scripts-view // node view.js
  • 通过 $npm_config_ + 前缀 脚本可以拿到 npm 的配置变量,即npm config get xxx命令返回的值。
// === package.json ===
{ 
 "name": "foo",
 // 注意, package.json 里面的 config 对象,可以被环境变量覆盖。
 "config": {
   "port": "8080"
 },
 "scripts": {
   "view": "echo $npm_config_registry"
 }
}

// === bash ===
npm run view // https://registry.npm.taobao.org/

上面代码中,npm_package_config_port变量返回的是8080。这个值可以用下面的方法覆盖。

npm config set foo:port 80

4.7 npm 与 npx

  • npm 是一个 node package 安装工具,安装的包是永久存在的。

  • npx 是临时安装,用完后删除,npx 的优势是可以执行未安装的包的命令。

  • npx 类似于 npm exec / npm x

    # 使用 npx 创建一个 test-app 在本地
    npx react-create-app test-app
    # npx 支持运行远程仓库的可执行文件
    npx github:piuccio/cowsay hello
    npx http-server # 开启一个静态服务器
    npx -p node@8 npm run build # 指定 node 版本运行
    # =======
    # npm 的话需要先 install
    npm install -g create-react-app
    create-react-app test-app
    

5. package.json相关

package.json 定义了这个项目所需要的各种模块,以及项目的配置信息(比如名称、版本、许可证等元数据)

{
  // 项目名称
  "name": "Hello World",
  
  // 项目版本号
  "version": "0.0.1",
  
  // 项目作者
  "author": "zhangsan",
  
  // 项目参与人
  "contributors":[{
    "name": "lisi",
    "email":"lisi@example.com",
    "url": "http://barnyrubble.tumblr.com/"
  }],
  
  // 项目描述,便于用户在npm上搜索到我们的项目
  "description": "第一个node.js程序",
  
  // 项目关键字,便于用户在npm上搜索到我们的项目
  "keywords":["node.js", "javascript"],
  
  // 项目主页地址
  "homepage": "https://github.com/owner/project#readme",
  
  // 项目许可证
  "license": "MIT",
  
  // 加载的入口文件,加载优先级是 browser = browser+mjs > module > browser+cjs > main
  "main": "lib/index.js",
  // ESM 规范的入口文件
  "module": "lib/index.mjs", // module
  // typescript 的入口文件
  "types": "lib/index.d.ts", // ts
  // 在 browser 环境下的入口文件,browser 可定义成和 main/module 字段一一对应的映射对象,也可以直接定义为字符串
  "browser": {
    "./lib/index.js": "./lib/index.browser.js", // browser+cjs
    "./lib/index.mjs": "./lib/index.browser.mjs"  // browser+mjs
  },
  // "browser": "./lib/index.browser.js" // browser
  
  // 用来指定内部命令对应的可执行文件的位置,如下 someTool.js 会建立符号链接 ./node_modules/.bin/someTool
  "bin": {
    "someTool": "./bin/someTool.js"
  },

  // 除了根目录下的文件外还有哪些目录也要发布(当前有 bin 目录和 lib 目录)
  "files": {
    "bin":,
    "lib"
  },

  // 代码仓库地址
  "repository": {
    "type": "git",
    "url": "https://github.com/tony0511/cli.git"
  },
  
  // 指明了该模块运行的平台
  "engines": {
    "node": ">=0.10.3 <0.12"
  },
  
  // 项目问题反馈的 url 或报告问题的 email 地址
  "bugs": {
    "url":"http://path/to/bug",
    "email":"bug@example.com"
  },
  
  // 运行脚本
  "scripts": {
    "start": "node index.js"
  },
  
  // 用于添加命令行的环境变量
  "config": {
    "port": "8080"
  },
  
  // 项目运行所需依赖
  "dependencies": {
    "express": "latest",
    "mongoose": "~3.8.3",
    "handlebars-runtime": "~1.0.12",
    "express3-handlebars": "~0.5.0",
    "MD5": "~1.2.0"
  },
  
  // 项目运行开发所需依赖
  "devDependencies": {
    "bower": "~1.2.8",
    "grunt": "~0.4.1",
    "grunt-contrib-concat": "~0.3.0",
    "grunt-contrib-jshint": "~0.7.2",
    "grunt-contrib-uglify": "~0.2.7",
    "grunt-contrib-clean": "~0.5.0",
    "browserify": "2.36.1",
    "grunt-browserify": "~1.3.0",
  },
  
  // 是否为私有包,如果设置为 true, 则 npm 会拒绝发布它
  "private": false,

  // 发布的地址
  "publishConfig": {
    "registry": "https://registry.npmjs.org"
  },
  
  // 指定项目运行在什么操作系统上
  "os": [
    "darwin",
    "linux",
    "!win32"
  ],
  
  // 指定项目运行在什么 cpu 架构上。
  "cpu": [
    "x64",
    "ia32",
    "!arm",
    "!mips"
  ]
}

6. yarn常用命令

# === 初始化,设置 ===
# 初始化 npm 项目,生成 package.json 文件
yarn init
# 使用淘宝镜像
yarn config set registry http://registry.npm.taobao.org
yarn config set sass_binary_site http://cdn.npm.taobao.org/dist/node-sass -g
# 查看 yarn 全局缓存目录
yarn cache dir
# 列出匹配指定模式的已缓存的包
yarn cache list [--pattern "gulp-(match|newer)"]
# 清除缓存
yarn cache clean
# 查看当前 yarn 的 bin 的位置
yarn global bin
# 查看 yarn 全局安装的根目录
yarn global dir
# 查看全局安装包
yarn list --depth=0
# 配置项
yarn config list # 显示所有配置项
yarn config get <key> # 显示某配置项
yarn config delete <key> # 删除某配置项
yarn config set <key> <value> [-g|--global] # 设置配置项
# === 安装包管理 ===
# 安装、卸载、升级局部依赖(未指明包名将升级所有依赖项)
yarn [install]
yarn [add | remove] [package-name]@[version] [--dev / -D]
yarn upgrade [package | package@tag | package@version | @scope/]... [--ignore-engines] [--pattern]
# 安装、卸载、升级全局依赖
yarn global [add | remove] [package-name]@[version]
# 查看包相关信息
yarn info package-name
# === 执行脚本 ===
yarn [run] [script] [<args>]

7. Tink

npm 已落伍,下一代包管理器 Tink 正在孵化

参考链接:https://www.infoq.cn/article/R*5JRVuOOHBRlw411PlZ

Tink 是很值得期待的项目,但现在还没做好准备与大家见面。谁要是下载了它开始用搞不好会惹出大事的,所以还是要多等一等。Tink 使用 Virtual node_modules 作为新的运行时,具备开箱即用的 TypeScript、ESM、JSX 和 Wasm 支持。它将随 npm 的第 8 版一同发布,将来会是 npm 的一个可选组件。此外,我们将来会加入一个新的包管理 API。

require查找规则

参考阮大哥地址: http://www.ruanyifeng.com/blog/2015/05/require.html

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

推荐阅读更多精彩内容