熟悉 webpack 與 webpack4 配置

熟悉 webpack 與 webpack4 配置。

webpack4 相對于 3 的最主要的區別是所謂的零配置,但是為了滿足我們的項目需求還是要自己進行配置,不過我們可以使用一些 webpack 的預設值。同時 webpack 也拆成了兩部分,webpack 和 webpack-cli,都需要本地安裝。

我們通過實現一個 vue 的開發模板(vue init webpack 模板,其實跟 vue 關系不太大)來進行一次體驗。在配置過程中會盡量使用 webpack4 的相關內容。

本文不做 webpack 配置的完整介紹,著重介紹配置過程中需要注意的地方。查看代碼注釋閱讀效果更佳,完整配置與詳細注釋可見源代碼。配置位于 build 文件夾下。

與版本 4 相關的章節會添加符號 ④

需要注意的一點是,我們的 webpack 代碼是運行在node環境下的,這部分代碼可以使用 node api,但是我們的業務代碼(src下)是無法使用 node api 的。

基本公用配置

由于 webpack 配置中的如 context,entry(chunk入口),output(輸出)和 module.rules 中 loaders 的配置在開發模式和生產模式基本都是公用的,所以我們提取到 webpack.base.js 文件內,供復用。其中 output 部分如下:

output: {

  path: path.resolve(__dirname, '../dist/'), // 資源文件輸出時寫入的路徑
  filename: 'static/js/[name].[chunkhash].js', // 使用 chunkhash 加入文件名做文件更新和緩存處理
  chunkFilename: 'static/js/[name].[chunkhash].js'
}

需要注意的有:

文件名 hash

hash 是用在文件輸出的名字中的,如 [name].[hash].js,總的來說,webpack 提供了三種 hash:

  1. [hash]:此次打包的所有內容的 hash。
  2. [chunkhash]:每一個 chunk 都根據自身的內容計算而來。
  3. [contenthash]:由 css 提取插件提供,根據自身內容計算得來。

三種 hash 的使用,我們在優化部分再講,先優先使用 [chunkhash]

loader 優先級

loader 優先級需要注意兩點,

  1. 同 test 配置內優先級:在同一個 test 下配置多個 loader ,優先處理的 loader 放在配置數組的后面,如對 less 處理,則:

    {
      test: /\.less$/,
      use: [
        'style-loader', 
        'css-loader', 
        'postcss-loader', 
        'less-loader'
      ]
    }
    
  2. 不同 test 內優先級:如對 js 文件的處理需要兩個 test 分別配置,使用 eslint-loaderbabel-loader ,但是又不能配置在一個配置對象內,可使用 enforce: 'pre' 強調優先級,由 eslint-loader 優先處理。

    {
      test: /\.(js|vue)$/,
      loader: 'eslint-loader',
      enforce: 'pre',
    },
    {
      test: /\.js$/,
      loader: 'babel-loader'
    }
    

css 預處理器配置

我們以 less 文件的 loader 配置 ['vue-style-loader', 'css-loader', 'postcss-loader', 'less-loader'],使用 @import url(demo.less)為例:

  1. less-loader 先處理 less 語法
  2. postcss-loader 進行前綴添加等其他處理
  3. css-loader 將內容引入 @import 所在的 css 文件內
  4. vue-style-loader 將生成 style 標簽,將 css 內容插入 HTML

vue-style-loader 功能類似 style-loader

但是由于 vue 中的單文件組件,又分為兩種情況:

  • .vue 文件內的 style:
    vue-loader 會對 .vue 單文件組件進行處理,對 .vue 單文件組件內的各種 lang="type" 我們可以在 vue-loader 的 options 配置不同的 loader,由于 vue-loader 內置了 postcss 對 css 進行處理,所以此處我們不需要再配置 postcss-loader

    {
      test: /\.vue$/,
      loader: 'vue-loader',
      options: {
        loaders: {
          less: ['// xxx-loaders'],
          scss: ['// xxx-loaders'],
        }
      }
    }
    
  • js 直接引入中引入樣式文件:
    如 main.js 中 import 'demo.less',這種方式引入的樣式文件,在 vue-loader 處理范圍置之外,所以仍然需要配置 postcss-loader

由于這種差異我們將 對 css 預處理器文件的配置封裝為函數,由 usePostCss 參數生成對應配置,將文件放入 utils.js 文件內,將 vue-loader 配置放在 vue-loader.js 文件內。

也就是對 css 預處理器的配置我們需要在 vue-loader 內和 webpack 內配置兩遍。

寫這篇 README.md 期間 vue-loader 發布了 v15 版,需要配合插件使用,不用再進行兩遍配置

postcss-loader

postcss-loader 是一個強大的 css 處理工具,我們將 postcss 的配置拆分出去,新建 postcss.config.js 配置文件

module.exports = {
  plugins: {
    // 處理 @import
    'postcss-import': {},
    // 處理 css 中 url
    'postcss-url': {},
    // 自動前綴
    'autoprefixer': {
      "browsers": [
        "> 1%",
        "last 2 versions"
      ]
    }
  }
}

除了注釋中列出的需要的功能插件,我們還可能會用到 nextcss(新的css語法的處理),px2rem/px-to-viewport 移動端適配相關的插件。

babel-loader

我們使用 babel 編譯瀏覽器不能識別的 js、類 js 語法,如轉義 ES6+、JSX等。同樣將 babel-loader 的配置拆分出去,需要創建 .babelrc 并配置:

{
  "presets": [
    [
      /* *
       *  babel-preset-env
       *  可以根據配置的目標運行環境自動啟用需要的 babel 插件。
       */
      "env", {
        "modules": false, // 關閉 babel 對 es module 的處理
        "targets": { // 目標運行環境
          "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
        }
      }
    ]
  ],
  "plugins": [
    "syntax-dynamic-import" // 異步加載語法編譯插件
  ]
}

媒體資源 loader

我們還需要對圖片、視頻、字體等文件進行 loader 配置,以字體文件為例子,主要用到的是 url-loader

{
  /**
   * 末尾 \?.* 匹配帶 ? 資源路徑
   * 我們引入的第三方 css 字體樣式對字體的引用路徑中可能帶查詢字符串的版本信息
   */
  test: /\.(woff2|woff|eot|ttf|otf)(\?.*)?$/,
  /**
   * url-loader
   * 會配合 webpack 對資源引入路徑進行復寫,如將 css 提取成獨立文件,可能出現 404 錯誤可查看 提取 js 中的 css 部分解決
   * 會以 webpack 的輸出路徑為基本路徑,以 name 配置進行具體輸出
   * limit 單位為 byte,小于這個大小的文件會編譯為 base64 寫進 js 或 html
   */
  loader: 'url-loader',
  options: {
    limit: 10000,
    name: 'static/fonts/[name].[hash:7].[ext]',
  }
}

靜態文件拷貝

直接引用(絕對路徑)和代碼執行時確定的資源路徑應該是以靜態文件存在的,這些資源文件不會經過 webpack 編譯處理,所以我們將它們放在獨立的文件夾(如 static)中,并在代碼打包后拷貝到我們的輸出目錄,我們使用 copy-webpack-plugin 自動完成這個工作:

const CopyWebpackPlugin = require('copy-webpack-plugin')

// 在開發模式下,會將文件寫入內存
new CopyWebpackPlugin([
  {
    from: path.resolve(__dirname, '../static'),
    to: 'static',
    ignore: ['.*']
  }
])

此插件在拷貝文件過多時會崩潰,不知道解決了沒有。

生產模式 production

我們先進行生產模式的配置。

添加 script 腳本命令

在 package.json 下添加

"scripts": {
  "build": "node build/build.js"`
}

那么使用 npm run build 命令就可執行 node build/build.js,我們不直接使用 webpack webpack.prod.config.js 命令去執行配置文件,而是在 build.js 中,做一些文件刪除的處理,再啟動 webpack。

創建 build.js 邏輯

主要是兩個工作,引入 rimraf 模塊刪除 webpack 下之前產生的指定文件,啟動 webpack,并在不同階段給出不同的提示信息。

// 在第一行設置當前為 生產環境
process.env.NODE_ENV = 'production'

const webpack = require('webpack')
const rm = require('rimraf')
const webpackConfig = require('./webpack.prod')
// 刪除 webpack 輸出目錄下的內容,也可只刪除子文件如 static 等
rm(webpackConfig.output.path, err => {
  // webpack 按照生產模式配置啟動
  webpack(webpackConfig, (err, stats) => {
    // 輸出一些狀態信息
  })
}

更多細節見源代碼注釋

生產模式配置文件

新建 webpack.prod.js 文件,使用

const merge = require('webpack-merge') // 專用合并 webpack 配置的包
const webpackBaseConfig = require('./webpack.base')
module.exports = merge(webpackBaseConfig, {
  // 生產模式配置
})

合并基本配置和生產模式獨有配置,然后我們開始進行生產模式下的 webpack 的配置信息的填寫。

④ mode 預設

這是 webpack4 的新 api ,有三個預設值:developmentproductionnone,我們在生產模式選用mode: 'production',webpack4在此配置下默認啟用了:

  • 插件

    • FlagDependencyUsagePlugin:應該是刪除無用代碼的,其他插件依賴
    • FlagIncludedChunksPlugin:應該是刪除無用代碼的,其他插件依賴
    • ModuleConcatenationPlugin:作用域提升 webpack3的scope hosting
    • NoEmitOnErrorsPlugin:遇到錯誤代碼不跳出
    • OccurrenceOrderPlugin
    • SideEffectsFlagPlugin
    • UglifyJsPlugin:js代碼壓縮
    • process.env.NODE_ENV 的值設為 production

所以這些默認啟用的內容我們不需要再配置。

最后一點設置 process.env.NODE_ENV 的值設為 production 其實是使用 DefinePlugin 插件:

new webpack.DefinePlugin({
  "process.env.NODE_ENV": JSON.stringify("production") 
})

從而我們可以在業務代碼中通過 process.env.NODE_ENV,如進行判斷,使用開發接口還是線上接口。如果我們需要在 webpack 中判斷當前環境,還需要單獨的設置 process.env.NODE_ENV = 'production',這也是我們在 build.js 中第一行做的事情。

添加 webpack 打出的 bundles 到 HTML 文件

  • 我們使用 webpack 配置入口時只能配置 js 文件作為入口,webpack 打出的 bundles 并不能自動與我們項目的 HTML 文件發生關聯。
  • 需要我們手動添加<script src="./bundles.js"></script>(還可能包括后面提取出來的 css 文件)到 HTML 文件。
  • 我們可以使用 html-webpack-plugin 插件自動完成這個工作。
  • 當僅使用 webpack 對 js 進行打包,而沒有 HTML文件需求時,不需要這一步。
const HtmlWebpackPlugin = require('html-webpack-plugin')
plugins: [
  new HtmlWebpackPlugin({
    filename: path.join(__dirname, '../dist/index.html'),// 文件寫入路徑
    template: path.join(__dirname, '../src/index.html'),// 模板文件路徑
    inject: true // js 等 bundles 插入 html 的位置 head/body等
  })
]

如果不對 HtmlWebpackPlugin 進行配置,則其會創建一個 HTML 文件,其中 filename 在開發模式下還是比較重要的。

④ 提取 js 中的 css 部分到單獨的文件

使用過 webpack3 的同學應該對 extract-text-webpack-plugin 插件(以舊插件代稱)比較熟悉,為了嘗試webpack4,我并不想使用這個插件的 @next 版本,所以選擇了新的替代插件 mini-css-extract-plugin(以新插件代稱)。
與舊插件相同,同樣需要在 webpack 的 loader 部分和 plugin 部分都進行配置,不同的是新插件提供了單獨的 loader,在 loader 部分與舊插件的配置方式不太相同。配置如下:

  • loader 部分

    const MiniCssExtractPlugin = require("mini-css-extract-plugin")
    // 
    [
      {
        loader: MiniCssExtractPlugin.loader,
        options: {
          // (segmentfault 這兒的多行注釋渲染有點問題 ??,改成單行注釋形式)
          // 復寫 css 文件中資源路徑
          // webpack3.x 配置在 extract-text-webpack-plugin 插件中
          // 因為 css 文件中的外鏈是相對與 css 的,
          // 我們抽離的 css 文件在可能會單獨放在 css 文件夾內
          // 引用其他如 img/a.png 會尋址錯誤
          // 這種情況下所以單獨需要配置 publicPath,復寫其中資源的路徑
          //
          publicPath: '../' 
        }
      },
      {
        loader: 'css-loader',
        options: {}
      },
      {
        loader: 'less-loader',
        options: {}
      }
    ]
    
  • plugin 部分

    new MiniCssExtractPlugin({
      // 輸出到單獨的 css 文件夾下
      filename: "static/css/[name].[chunkhash].css"
    })
    

可以看到這個 loader 也配置在了 css 預處理器部分,在前面我們已經把 css 預處理器的配置提取到了 utils.js 文件的函數內,所以這里也是,我們使用 extract 參數決定是否需要提取。

回憶一下,之前使用的 style-loadervue-style-loader 的作用,它們會創建標簽將 css 的內容直接插入到 HTML中。而提取成獨立的 css 文件之后,插入到 HTML 的工作由 html-webpack-plugin 插件完成,兩者職責的這部分職責是重復的,所以我們需要使用 extract 參數做類似如下處理:

if (options.extract) {
  return [MiniCssExtractPlugin.loader, ...otherLoaders]
} else {
  return ['vue-style-loader', ...otherLoaders]
}

④ 拆分 js 代碼

這是 webpack 配置中很重要的一個環節,影響到我們使用瀏覽器緩存的合理性,影響頁面資源的加載速度,將 js 進行合理拆分,可以有效減小我們每次更新代碼影響到的文件范圍。
使用過 webpack3 的同學一定清楚,我們一般會提取出這么幾個文件 manifest.js(webpack 運行時,即webpack解析其他bundle的代碼等)、vendor.js(node_modules內的庫)、app.js(真正的項目業務代碼)。在 webpack3 中我們使用 webpack.optimize.CommonsChunkPlugin插件進行提取,webpack4 中我們可以直接使用 optimization 配置項進行配置(當然仍可使用插件配置):

/**
 * 優化部分包括代碼拆分
 * 且運行時(manifest)的代碼拆分提取為了獨立的 runtimeChunk 配置 
 */
optimization: {
  splitChunks: {
    chunks: "all",
    cacheGroups: {
      // 提取 node_modules 中代碼
      vendors: {
        test: /[\\/]node_modules[\\/]/,
        name: "vendors",
        chunks: "all"
      },
      commons: {
        // async 設置提取異步代碼中的公用代碼
        chunks: "async"
        name: 'commons-async',
        /**
         * minSize 默認為 30000
         * 想要使代碼拆分真的按照我們的設置來
         * 需要減小 minSize
         */
        minSize: 0,
        // 至少為兩個 chunks 的公用代碼
        minChunks: 2
      }
    }
  },
  /**
   * 對應原來的 minchunks: Infinity
   * 提取 webpack 運行時代碼
   * 直接置為 true 或設置 name
   */
  runtimeChunk: {
    name: 'manifest'
  }
}

也可將不會變的開發依賴配置到單獨的entry中,如:

entry: {
  app: 'index.js',
  vendor2: ['vue', 'vue-router', 'axios']
}

開發模式 development

開發模式與生產模式的不同是,在開發時會頻繁運行代碼,所以很多東西在開發模式是不推薦配置的,如css文件提取,代碼壓縮等。所以針對一些寫入公共配置文件,但是開發模式不需要的功能,我們需要做類似修改:process.env.NODE_ENV === 'production' ? true : false,如 css 預處理中是否需要配置提取 loader MiniCssExtractPlugin.loader。此外還有一些是只配置在生產模式下的,如 MiniCssExtractPlugin 和 js 代碼拆分優化。

開發模式我們需要一個開發服務,幫我們完成實時更新、接口代理等功能。我們使用 webpack-dev-server。需要 npm 安裝。

添加 script 腳本命令

同樣,在 package.json 下添加

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

使用 --config 指定配置文件,由于命令直接調用 webpack-dev-server 運行,所以我們直接寫配置就好,可以不像生產模式一樣去編寫調用邏輯。

開發模式配置文件

新建 webpack.dev.js 文件,同樣使用:

// 在第一行設置當前環境為開發環境
process.env.NODE_ENV = 'development'
const merge = require('webpack-merge') // 專用合并webpack配置的包
const webpackBaseConfig = require('./webpack.base')
module.exports = merge(webpackBaseConfig, {
  // 開發模式配置
})

④ mode 預設

同樣,在開發模式下我們可以將 mode 配置為 development,同樣默認啟用了一些功能:

  • 插件

    • NamedChunksPlugin:使用 entry 名做 chunk 標識
    • NamedModulesPlugin:使用模塊的相對路徑非自增 id 做模塊標識
  • process.env.NODE_ENV 的值設為 development

開發服務配置 devServer

文檔

devServer: {
  clientLogLevel: 'warning',
  inline: true,
  // 啟動熱更新
  hot: true,
  // 在頁面上全屏輸出報錯信息
  overlay: {
    warnings: true,
    errors: true
  },
  // 顯示 webpack 構建進度
  progress: true,
  // dev-server 服務路徑
  contentBase: false,
  compress: true,
  host: 'localhost',
  port: '8080',
  // 自動打開瀏覽器
  open: true,
  // 可以進行接口代理配置
  proxy: xxx,
  // 跟 friendly-errors-webpack-plugin 插件配合
  quiet: true,
  publicPath: '/'
}

其他插件

devServer 使用熱更新 hot 時需要使用插件:

plugins: [
  new webpack.HotModuleReplacementPlugin()
]

優化 webpack 輸出信息,需要配置:

const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
plugins: [
  new FriendlyErrorsPlugin()
]

注意事項

  • 熱更新:在使用熱更新時,我們的 chunk 名中不能使用 [hash] 做標識,文件名變化無法熱更新,所以需要將原來配置在公共配置中的 output 中的文件名配置分別寫入生產和開發模式配置中,開發模式去掉 [hash]

    filename: 'static/[name].js', 
    chunkFilename: 'static/[id].js'
    
  • HtmlWebpackPlugin:在生產模式下,我們將 html 文件寫入到 dist 下,但是在開發模式下,并沒有實際的寫入過程,且 devServer 啟動后的服務內容與 contentBase 有關,兩者需要一致,所以我們將 HtmlWebpackPlugin 的配置也分為 生產和開發模式,開發模式下使用:

    new HtmlWebpackPlugin({
      filename: 'index.html', // 文件寫入路徑,前面的路徑與 devServer 中 contentBase 對應
      template: path.resolve(__dirname, '../src/index.html'),// 模板文件路徑
      inject: true
    })
    

優化

配置提取

  • 開發模式和生產模式的一些功能啟用,如 css 是否提取。
  • 路徑配置,如文件輸出路徑和文件名、output 中的 publicPath(代碼 output 中只配置了 path,沒配置 publicPath,將這部分路徑的 static 寫到了各個資源的輸出name中,可參考Webpack中publicPath詳解)、服務配置如端口等。

我們可以提取到獨立的 config 文件中(本代碼沒做)。

拆分 js 代碼

在生產模式的 拆分 js 代碼 部分我們已經講了如何拆分,那么為了更好的分析我們的拆分是否合理,我們可以配置一個 bundle 組成分析的插件。

const BundleAnalyzer = require('webpack-bundle-analyzer')
plugins: [
  new BundleAnalyzer.BundleAnalyzerPlugin()
]

hash 固化

我們使用文件名中的 hash 變化來進行資源文件的更新,那么合理利用緩存時,就要求我們合理的拆分文件,在內容更新時最小限度的影響文件名中的 hash。這里就用到了[hash][chunkhash][contenthash]。然而 webpack 對 hash 的默認處理并不盡如人意,這一部分的優化可以參考基于 webpack 的持久化緩存方案

多頁面

多頁面配置代碼位于 muilt-pages 分支。我們只需做少量修改,以目前有 entry 頁和 index 頁為例。

entry 改動

將兩個頁面的 js 入口都配置在 webpackentry中:

entry: {
  /**
    * 入口,chunkname: 路徑
    * 多入口可配置多個
    */
  main: './src/main.js',
  entry: './src/entry.js'
}

也可以自己設置項目結構,使用 node api 動態讀取的方式獲取目前的多頁面入口。

HtmlWebpackPlugin 改動

需按照頁面個數配置多個 HtmlWebpackPlugin

new HtmlWebpackPlugin({
  filename: path.join(__dirname, '../dist/main.html'),// 文件寫入路徑
  template: path.join(__dirname, '../src/index.html'),// 模板文件路徑
  inject: true, // 插入位置
  chunks: ['manifest', 'vendors', 'common', 'main']
}),
new HtmlWebpackPlugin({
  filename: path.join(__dirname, '../dist/entry.html'),// 文件寫入路徑
  template: path.join(__dirname, '../src/index.html'),// 模板文件路徑
  inject: true, // 插入位置
  chunks: ['manifest', 'vendors', 'common', 'entry']
}),

其中需手動指定每個頁面的插入的 chunks(同步的),否則會將其他頁面的文件也一同插入當前頁面。

④ 公共js提取

在單頁面下,一般不存在提取非異步 js 文件的公共代碼(非 node_modules)的問題,在多頁面下我們的頁面間可能會公用 api、配置等文件,此時可以增加:

'common': {
  // initial 設置提取同步代碼中的公用代碼
  chunks: 'initial',
  // test: 'xxxx', 也可使用 test 選擇提取哪些 chunks 里的代碼
  name: 'common',
  minSize: 0,
  minChunks: 2
}

提取同步代碼中的公用代碼

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,316評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,481評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,241評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,939評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,697評論 6 409
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,182評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,247評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,406評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,933評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,772評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,973評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,516評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,638評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,866評論 1 285
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,644評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,953評論 2 373

推薦閱讀更多精彩內容