webpack学习笔记

一、Webpack简介

Webpack是一种前端资源构建工具,一个静态模块打包器。
在webpack 看来, 前端的所有资源文件(js/json/css/img/less/...)都会作为模块处理。
它将根据模块的依赖关系进行静态分析,打包生成对应的静态资源(bundle)。

1.1核心概念

Entry

入口指示Webpack以哪个文件为入口起点开始打包,分析内部依赖。

Output

输出指示Webpack打包后的资源bundles输出到哪里去。

Loader

Loader让Webpack能够去处理那些非js文件。

Plugins

插件可以用于执行范围更广的任务。从打包优化和压缩到重新定义环境中的变量等。

Mode

(1) development 能让代码本地调试运行的环境
源代码→webpack(打包、自动化)→bundle
(2) production 能让代码优化上线运行的环境(要做的事多,拖累开发环境的构建速度,打包慢)
css→js(大,闪) 提取出css;压缩;兼容...

1.2运行指令:

开发环境:webpack .src/index.js -o ./build --mode=development
    webpack会以 ./src/index.js 为入口文件开始打包,然后输出到 ./build/built.js,整体打包环境是开发环境
生产环境:webpack .src/index.js -o ./build --mode=production
  • 结论:
    1. webpack能处理js/json资源,不能处理css/img等其他资源。
    2. 生产环境和开发环境将ES6模块化编译成浏览器能识别的模块化。
    3. 生产环境比开发环境多一个压缩js代码。

二、配置

2.1 开发环境配置

2.1.1 打包样式资源

webpack.config.js

/* 
  webpack的配置文件
    作用:指示webpack干哪些活(当运行webpack指令时会加载里面的配置)
*/

// resolve用来拼接绝对路径的方法
const { resolve } = require('path')

module.exports = {
  // webpack配置
  // 入口起点
  entry: './src/index.js',

  // 输出
  output: {
    // 输出文件名
    filename: 'built.js',
    // 输出路径
    // __dirname 表示当前文件目录的绝对路径
    path: resolve(__dirname, 'build')
  },

  // loader配置
  module: {
    rules: [
      {
        // 匹配哪些文件
        test: /\.css$/,
        // 使用哪些loader
        use: [
          // use数组中loader执行顺序:从右到左,从下到上
          // 创建style标签,将js中的样式资源插入进行,添加到head中生效
          'style-loader',
          // 将css文件变成commonjs模块加载js中,里面的内容是样式字符串
          'css-loader'
        ]
      }
    ]
  },

  // plugins配置
  plugins: [

  ],

  // 模式
  mode: 'development'
  //mode: 'production'
}

2.1.2 打包html资源

webpack.config.js

/* 
  loader: 1. 下载 2. 使用
  plugin: 1. 下载 2. 引入 3. 使用
*/
const { resolve } = require('path')
//引入plugin
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  entry: "./src/index.js",
  output: {
    filename: 'built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [

    ]
  },
  plugins:[
    // 功能:默认创建一个空的html,自动引入打包输出的所有资源
    // 需要:需要有结构的html文件
    new HtmlWebpackPlugin({
      // 复制'./src/index.html‘文件,并自动引入打包输出的所有资源
      template: './src/index.html'
    })
  ],
  mode: 'development'
}

2.1.3 打包图片资源

webpack.config.js

const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'built.js',
    path: resolve(__dirname, 'build'),
    publicPath: './'

  },
  module: {
    rules: [
      {
        test: /\.less$/,
        use: [
          'style-loader',
          'css-loader',
          'less-loader'
        ]
      },
      // 处理图片资源
      {
        // 问题:处理不了html中的图片
        test: /\.(JPG|png|gif)$/,
        // 使用一个loader
        // 下载url-loader file-loader
        loader: 'url-loader',
        options: {
          // 图片大小小于8kb就会被base64处理
          // 优点:减少请求数量(减轻服务器压力)
          // 缺点:图片体积变大(文件请求速度变慢)
          limit: 8 * 1024,
          // 问题:因为url-loader默认使用es6模块化解析,而html-loader引入图片是commonjs
          // 解决:关闭url-loader的es6模块化,使用commonjs解析
          esModule: false,
          // 图片重命名
          // [hash:10]取图片的hash前十位
          // [ext]取文件原扩展名
          name: '[hash:10].[ext]'
        }
      },
      {
        test: /\.html$/,
        // 处理html文件的图片(负责引入图片,从而能被url-loader处理)
        loader: 'html-withimg-loader'
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  mode: 'development'
}

2.1.4 打包其他资源

webpack.config.js

const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          'css-loader'
        ]
      },
      // 打包其他资源
      {
        // 排除css/js/html资源
        exclude: /\.(css|js|html|less)$/,
        loader: 'file-loader',
        options: {
          name: '[hash:10].[ext]'
        }
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  mode: 'development'
}

2.1.5 开发服务器devServer

用来自动化(自动编译,自动打开浏览器,自动刷新浏览器。。。)
特点:只会在内存中编译打包,不会有任何输出

devServer: {
  contentBase: resolve(__dirname, 'build'),
  // 启动gzip压缩
  compress: true,
  port: 3000,
  // 自动打开浏览器
  open: true
}

2.2 生产环境配置

2.2.1 提取css成单独文件

MiniCssExtractPlugin

module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          // 'style-loader',
          MiniCssExtractPlugin.loader,
          'css-loader'
        ]
      }
    ],
  },

2.2.2 css兼容性处理

postcss --> postcss-loader postcss-preset-env

const HtmlWebpackPlugin = require('html-webpack-plugin')
const { resolve } = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')


// 设置nodejs环境变量
// process.env.NODE_ENV = 'development'

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.js',
    path: resolve(__dirname, 'build'),
    publicPath: '/'
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          // 'style-loader',
          MiniCssExtractPlugin.loader,
          'css-loader',
          /* 
            css兼容性处理:postcss --> post-loader postcss-preset

            帮postcss找到package.json中的browserslist里面的配置,通过配置加载指定的css兼容性样式
            "browserslist": {
              // 开发环境 --> 设置环境变量:process.env.NODE_ENV = development
              "development": [
                "last 1 chrome version"
              ],
              // 生产环境(默认)
              "production": [
                ">0.2%",
                "not dead",
                "not op_mini all"
              ]
            }
          */
          // 1. 使用loader的默认配置
          // 'postcss-loader',
          // 2. 修改loader的配置
          {
            loader: 'postcss-loader',
            options: {
              postcssOptions: {
                plugins: [ require('postcss-preset-env')() ]
              }
            }
          }
        ]
      }
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    new MiniCssExtractPlugin({
      filename: 'css/built.css'
    })
  ],
  mode: 'development'
}

2.2.3 压缩css

CssMinizerWebpackPlugin插件

2.2.4 js语法检查

  • 语法检查: eslint-loader eslint
  • 注意:只检查自己的代码,第三方库不检查
    exclude: /node_modules/,
  • 设置检查规则:
    package.json中eslintConfig中设置
    aribnb --> eslint-config-airbnb-base eslint eslint-plugin-import

package.json中的配置

"eslintConfig": {
  "extends": "airbnb-base"
}

webpack.config.js

module: {
  rules: [
    {
      test: /\.js$/,
      exclude: /node_modules/,
      loader: 'eslint-loader',
      options: {
        // 自动修复
        fix: true,
      },
    },
  ],
},
// 下一行eslint所有规则都失效
// eslint-disable-next-line

2.2.5 js兼容性处理

  • 基本js兼容性处理
    babel-loader @babel/preset-env
    问题:只能转换基本语法,如promse等不能转换

  • 全部js兼容性处理
    @babel/polyfill(非插件,只需引入)
    问题:只需解决部分兼容性问题,但将所有兼容性代码引入,体积过大

  • 按需加载兼容性处理
    core-js

module: {
  rules: [
    {
      test: /\.js$/,
      exclude: /node_modules/,
      loader: 'babel-loader',
      options: {
        // 预设:指示babel做怎么样的兼容性处理

        // 1. 基本js兼容性处理
        // presets: [
        //   '@babel/preset-env'
        // ]

        // 3. 按需加载兼容性处理
        presets: [
          [
            '@babel/preset-env',
            {
              // 按需加载
              useBuiltIns: 'usage',
              corejs: {
                // 指定corejs版本
                version: 2
              },
              // 指定兼容性做到哪个版本浏览器
              targets: {
                chrome: '60',
                firefox: '50',
                ie: '9',
                safari: '10',
                edge: '17'
              }
            }
          ]
        ]
      }
    }
  ],
},

正常来讲,一个文件只能被一个loader处理,当一个文件要被多个loader处理时,那么一定要知道loader执行的先后顺序,先执行eslint再执行babel
enforce: 'pre'

2.2.6 html压缩

plugins: [
  new HtmlWebpackPlugin({
    template: './src/index.html',
    minify: {
      // 移除空格
      collapseWhitespace: true,
      // 移除注释
      removeComments: true
    }
  }),
],

2.2.7 生产环境基本配置

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerWebpackPlugin = require('css-minimizer-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { resolve } = require('path');

// 定义node.js环境变量 决定使用browserlist的哪个环境
process.env.NODE_ENV = 'production';

// 服用css配置
const commonCssLoader = [
  // 'style-loader',
  MiniCssExtractPlugin.loader,
  'css-loader',
  // 兼容性处理
  {
    loader: 'postcss-loader',
    // 修改默认配置
    options: {
      postcssOptions: {
        plugins: [ require('postcss-preset-env')() ]
      }
    }
    // 还需在package.json中定义browserslist
  //   "browserslist": {
  //   "development": [
  //     "last 1 chrome version",
  //     "last 1 firefox version",
  //     "last 1 safari version"
  //   ],
  //   "production": [
  //     ">0.2%",
  //     "not dead",
  //     "not op_mini all"
  //   ]
  //  },
  },
];

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.js',
    path: resolve(__dirname, 'build'),
  },
  module: {
    rules: [
      // css
      {
        test: /\.css$/,
        use: [...commonCssLoader],
      },
      // less
      {
        test: /\.less$/,
        ues: [...commonCssLoader, 'less-loader'],
      },

      /*
        正常来讲,一个文件只能被一个loader处理
        当一个文件要被多个loader处理,那么一定要知道loader执行的先后顺序
          先执行eslint再执行babel
      */
      // js语法检查
      {
        test: /\.js$/,
        exclude: /node_modules/,
        enforce: 'pre',
        loader: 'eslint-loader',
        options: {
          fix: true,
        },
        // package.json
        // "eslintConfig": {
        //   "extends": "airbnb-base"
        // }
      },
      // js兼容性处理
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
        options: {
          presets: [
            [
              '@babel/preset-env',
              {
                useBuiltIns: 'usage',
                corejs: {
                  version: 2,
                },
                targets: {
                  chrome: '60',
                  firefox: '59',
                },
              },
            ],
          ],
        },
      },
      // 图片
      {
        test: /\.(jpg|png|gif)/,
        loader: 'url-loader',
        options: {
          limit: 8 * 1024,
          name: '[hash:10].[ext]',
          outputPath: 'img',
          esModule: false,
        },
      },
      // html图片
      {
        test: /\.html/,
        loader: 'html-loader',
      },
      // 其他文件
      {
        exclude: /\.(js|css|less|html|jpg|png|gif)/,
        loader: 'file-loader',
        options: {
          outputPath: 'media',
        },
      },
    ],
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/built.css',
    }),
    new CssMinimizerWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: './src/index.html',
      minify: {
        collapseWhitespace: true,
        removeComments: true,
      },
    }),
  ],
  // js压缩
  mode: 'production',
};

三、webpack性能优化

3.1 开发环境性能优化

  • 优化打包构建速度
  • 优化代码调试

HMR 功能

  • 作用:一个模块发生变化,只会重新打包这一个模块(而不是所有模块)
  • 注意:
    ① 样式文件可以使用HMR功能,因为style-loader内部实现了
    ② html文件默认不能使用HMR功能(不用做HMR功能)
    ③ js文件默认不能使用HMR功能,需要修改js代码(webpack配置target: 'web')
if (module.hot) {
  // 一旦module.hot为true,说明开启了HMR功能,需要让HMR代码功能生效
  module.hot.accept('./print.js', function () {
    // 方法监听print.js文件的变化,一旦发生变化,其他默认不会重新打包构建
    // 会执行后面的回调函数
    print()
  })
}

source-map

一种提供源代码到构建后代码的映射技术(如果构建后代码出错了,通过映射可以追踪到源代码作物)

/* webpack.config.js */
devtool: 'source-map'
参数 内/外 作用
source-map 外部生成source-map文件 错误代码准确信息和源代码的错误位置
inline-source-map 内嵌source-map,构建速度快 错误代码准确信息和源代码的错误位置
hidden-source-map 外部生成source-map文件 错误代码原因,但是没有错误位置,不能追踪源代码错误,只能提示到构建后代码位置
eval-source-map 内嵌(每一个文件都生成一个source-map) 错误代码准确信息和源代码的错误位置
nosources-source-map 外部 错误代码准确信息,但是没有任何源代码信息
cheap-source-map 外部 错误代码准确信息和源代码的错误位置,只能精确到行
cheap-module-source-map 外部 错误代码准确信息和源代码的错误位置,会将loader的source map加入
  • 开发环境:速度快、调试友好

    • 速度快(eval>inline>cheap>...)
      eval-cheap-source-map
      eval-source-map(推荐)
    • 调试更友好
      source-map
      cheap-module-source-map
      cheap-source-map
  • 生产环境:源代码要不要隐藏?调试要不要更友好?
    内嵌会让代码体积变大,所以生产环境不用内嵌
    nosources-source-map 全部隐藏
    hidden-source-map 只隐藏源代码

    source-map/cheap-module-source-map (推荐)

3.2 生产环境性能优化

3.2.1 优化打包构建速度

oneOf

oneOf:匹配到 loader 后就不再向后进行匹配,优化生产环境的打包构建速度

module: {
  rules: [
    {
      // js 语法检查
      test: /\.js$/,
      exclude: /node_modules/,
      // 优先执行
      enforce: 'pre',
      loader: 'eslint-loader',
      options: {
        fix: true
      }
    },
    {
      // oneOf 优化生产环境的打包构建速度
      // 以下loader只会匹配一个(匹配到了后就不会再往下匹配了)
      // 注意:不能有两个配置处理同一种类型文件(所以把eslint-loader提取出去放外面)
      oneOf: [
        {
          test: /\.css$/,
          use: [...commonCssLoader]
        },
        {
          test: /\.less$/,
          use: [...commonCssLoader, 'less-loader']
        },
        {
          // js 兼容性处理
          test: /\.js$/,
          exclude: /node_modules/,
          loader: 'babel-loader',
          options: {
            presets: [
              [
                '@babel/preset-env',
                {
                  useBuiltIns: 'usage',
                  corejs: {version: 3},
                  targets: {
                    chrome: '60',
                    firefox: '50'
                  }
                }
              ]
            ]
          }
        },
        {
          test: /\.(jpg|png|gif)/,
          loader: 'url-loader',
          options: {
            limit: 8 * 1024,
            name: '[hash:10].[ext]',
            outputPath: 'imgs',
            esModule: false
          }
        },
        {
          test: /\.html$/,
          loader: 'html-loader'
        },
        {
          exclude: /\.(js|css|less|html|jpg|png|gif)/,
          loader: 'file-loader',
          options: {
            outputPath: 'media'
          }
        }
      ]
    }
  ]
},

缓存

  • babel缓存
    配置cacheDirectory: true
    让第二次打包构建速度更快
  • 文件资源缓存
    • hash:每次webpack打包时会生成一个唯一的hash值
      问题:因为js和css同时使用一个hash值如果重新打包会导致所有缓存失效。
    • chunkhash:根据chunk生成的hash值,如果打包来源于同一个chunk,那么hash值就一样
      问题:js和css的hash值还是一样,因为css是在js中被引入的,同属一个chunk
    • contenthash:根据文件的内容生成hash值
      让代码上线运行缓存更好使用

多进程打包

优化打包速度
问题: 进程启动大概为600ms,进程通信也有开销.
只有打包工作消耗时间比较长,才需要多进程打包

// 再某个loader后(数组前)使用thread-loader可对相应loader进行多进程打包
/* 
  多进程打包
*/
{
  loader: "thread-loader",
  options: {
    workers: 2 // 进程数
  }
},

externals

防止将某些方法打包到最终输出的bundle中

// webpack.config.js中配置
externals: {
  // 忽略库名 npm包名
  // 拒绝jquery被打包
  jquery: 'jQuery'
}
再将需要的包在html中引入

dll

动态链接库
类似externals,指示哪些库不需要打包,不同在于dll会将某些库进行单独打包成chunk.

  • webpack.dll.js 配置:(将 jquery 单独打包)
/*
  node_modules的库会打包到一起,但是很多库的时候打包输出的js文件就太大了
  使用dll技术,对某些库(第三方库:jquery、react、vue...)进行单独打包
  当运行webpack时,默认查找webpack.config.js配置文件
  需求:需要运行webpack.dll.js文件
    --> webpack --config webpack.dll.js(运行这个指令表示以这个配置文件打包)
*/
const { resolve } = require('path');
const webpack = require('webpack');

module.exports = {
  entry: {
    // 最终打包生成的[name] --> jquery
    // ['jquery] --> 要打包的库是jquery
    jquery: ['jquery']
  },
  output: {
    // 输出出口指定
    filename: '[name].js', // name就是jquery
    path: resolve(__dirname, 'dll'), // 打包到dll目录下
    library: '[name]_[hash]', // 打包的库里面向外暴露出去的内容叫什么名字
  },
  plugins: [
    // 打包生成一个manifest.json --> 提供jquery的映射关系(告诉webpack:jquery之后不需要再打包和暴露内容的名称)
    new webpack.DllPlugin({
      name: '[name]_[hash]', // 映射库的暴露的内容名称
      path: resolve(__dirname, 'dll/manifest.json') // 输出文件路径
    })
  ],
  mode: 'production'
};
  • webpack.config.js 配置:(告诉 webpack 不需要再打包 jquery,并将之前打包好的 jquery 跟其他打包好的资源一同输出到 build 目录下)
// 引入插件
const webpack = require('webpack');
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');

// plugins中配置:
plugins: [
  new HtmlWebpackPlugin({
    template: './src/index.html'
  }),
  // 告诉webpack哪些库不参与打包,同时使用时的名称也得变
  new webpack.DllReferencePlugin({
    manifest: resolve(__dirname, 'dll/manifest.json')
  }),
  // 将某个文件打包输出到build目录下,并在html中自动引入该资源
  new AddAssetHtmlWebpackPlugin({
    filepath: resolve(__dirname, 'dll/jquery.js')
  })
],

3.2.2 优化代码运行性能

tree shaking

去除无用代码,减少打包体积

  • 前提

    1. 必须使用ES6模块化
    2. production环境
  • 在package.json中配置
    "sideEffects": false 所有代码都没有副作用(都可以进行tree shaking)
    问题:可能会把css/@babel/polyfill 文件干掉
    解决:"sideEffects": ["*.css"]

代码分割 code split

打包成一个代码体积大,需要分隔开

方法
  1. 多入口
    多个entry
  2. splitChunks
    可以将node_modules中的代码单独打包成一个chunk最终输出(比如多入口文件中有重复的依赖,使用该方法单独加载依赖避免重复加载)
optimization: {
  splitChunks: {
    chunks: 'all'
  }
},
  1. 通过js代码让某个文件单独打包成一个chunk(常用)
    import动态导入语法,能将某个文件单独打包
import(/* webpackChunkName: 'test' */'./test')
  .then(({ mul, count }) => {
    console.log(mul(2, 5));
  })
  .catch(() => {
    console.log('err');
  })

懒加载

// 懒加载
import(/* webpackChunkName: 'test', webpackPrefetch: true */'.test')
  .then(({ mul })=> {
    console.log(mul(4, 6));
  })

正常加载:可以认为是并行加载(同时加载多个文件)
懒加载:文件需要用时加载
预加载webpackPrefetch:会在使用之前提前加载js文件,等其他资源加载完毕空闲时加载该资源

PWA

渐进式网络开发应用程序(离线可访问)
workbox --> workbox-webpack-plugin

// webpack.config.js插件
// PWA
new WorkboxWebpackPlugin.GenerateSW({
  // 1. 帮助serviceworker快速启动
  // 2. 删除旧的serviceworker
  // 生成一个serviceworker配置文件
  clientsClaim: true,
  skipWaiting: true
})
// js文件配置
/* 
  问题1: eslint不认识window,navigator全局变量
  解决: 需要修改package.json中eslintConfig的配置
  "env": {
    "browser": true // 支持浏览器端全局变量
  }

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

推荐阅读更多精彩内容

  • 命令窗口运行初始化eslint切换到./node_modules/.bin/文件夹下运行 eslint --ini...
    BigTooth_3611阅读 307评论 0 0
  • 安装开发服务器webpack-dev-server避免开发过程中重复的打包操作,自动编译打包、自动刷新浏览器,开发...
    coder勇阅读 249评论 0 0
  • Webpack 是一个前端资源加载/打包工具。它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成...
    EarthChen阅读 389评论 0 1
  • webpack学习笔记 注意本笔记只能作为参考,如有错误希望大家指正一下。 基础属性例子 入口(entry) 描述...
    Demonskp阅读 228评论 0 0
  • 1、HTML、CSS和JS代码压缩 JS文件的压缩webpack4内置了uglifyjs-webpack-plug...
    wayne1125阅读 243评论 0 1