Webpack 4.x 小白成神之路

前言

趁工作之余玩了下webpack,现在都出到4.8版本了,不得不感叹前端技术版本更新真的很快!如果你还不会webpack,那你绝不是一个合格的前端开发者。

what is webpack?

webpack可以看做一个模块化打包机,分析项目结构,处理模块化依赖,转换成为浏览器可运行的代码。

初始化项目

// 这里不做过多描述
npm init

新建src文件夹,并新建index.js,随便写几行js。

安装webpack

webpack4.0以上抽离出了webpack-cli,所以我们需要下载2个依赖。

npm install webpack webpack-cli -D   
  • npm i -D 是 npm install --save-dev 的简写,是指安装模块并保存到 package.json 的 devDependencies中,主要在开发环境中的依赖包。

webpack4可以支持0配置打包,不过在实际开发中,0配置是根本无法满足需求的。不过我们看看到底0配置了什么?

// node v8.2版本以上会有npx

npx webpack     // 不设置mode的情况下 打包出来的文件自动压缩

npx webpack --mode development  // 设置mode为开发模式,打包后的文件不被压缩

当执行npx webpack命令时,webpack会自动寻找项目中src目录下的index.js文件,然后进行打包,生成一个dist目录并生成一个打包好的main.js文件

  • 启动devServer需要安装一下webpack-dev-server
npm i webpack-dev-server -D

定制化配置webpack

webpack需要在项目根目录下创建一个webpack.config.js来导出webpack的配置,配置多样化,可以自行定制。

// webpack.config.js

const path = require('path');

module.exports = {
    entry: './src/index.js',    // 入口文件
    output: {
        filename: 'bundle.js',      // 打包后的文件名称
        path: path.resolve('dist')  // 打包后的目录,必须是绝对路径
    }
}
  • entry代表入口
  • output输出文件配置
  • path输出的文件地址
  • filename输出文件的名字
    接下来我们执行命令webpack,此时我们可以看到目录下多出了一个dist文件,并生成了bundle.js。
    实际开发中我们打包编译的时候一般都通过npm执行的命令,所以我们找到package.json里的执行脚本去配置一下命令,这里如下图所示:
    image.png

npm run build 执行打包命令
rimraf dist 每次打包前 删除dist文件
set NODE_ENV=buildset NODE_ENV=dev 设置环境变量来区分开发环境和生成环境
--open 自动打开默认浏览器
npm run dev 开发环境下打包的文件,但是devServer帮我们把文件放到内存中,所以并不会输出打包后的dist文件夹

多文件入口

  • 实际开发中基本都是spa单页面,但是我们这里还是简单说一下多入口配置
const path = require('path');

module.exports = {
    // 1.写成数组的方式就可以打出多入口文件,但是打包后会合成一个
    // entry: ['./src/index.js', './src/index2.js'],
    entry: {
        index: './src/index.js',
        index2: './src/index2.js'
    },
    output: {
        // 1. filename: 'bundle.js',
        // 2. [name]就可以将出口文件名和入口文件名一一对应
        filename: '[name].[hash:6].js',      // 打包后会生成index.js和index2.js文件
        path: path.resolve('dist')
    }
}

hash 打包文件后自动加上hash值,避免缓存,取前6位。
执行npm run build后,dist目录下生成打包好的两个js文件:index.js 和 index2.js

压缩js

实际开发中,我们的js一般都很大,所以需要压缩;需要用到uglifyjs-webpack-plugin插件

npm i uglifyjs-webpack-plugin -D

接下来配置下:

const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
    plugins: [
        new UglifyJsPlugin()
    ]
}

这样就实现了js的压缩

HTML文件的发布

js文件都打包好了,但是我们不能每次都手动创建一个index.html去加载你的js,这样肯定是不切实际的。
这时候需要一个html-webpack-plugin的插件来帮助我们

  npm i html-webpack-plugin -D

webpack配置插件都需要在plugins中完成,ok 我们配置下:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin'); //打包html

module.exports = {
    // 1.写成数组的方式就可以打出多入口文件,但是打包后会合成一个
    // entry: ['./src/index.js', './src/index2.js'],
    entry: {
        index: './src/index.js',
        index2: './src/index2.js'
    },
    output: {
        // 1. filename: 'bundle.js',
        // 2. [name]就可以将出口文件名和入口文件名一一对应
        filename: '[name].[hash:6].js',      // 打包后会生成index.js和index2.js文件
        path: path.resolve('dist')
    },
    plugins: [
        // 通过new一下这个类来使用插件
         new HtmlWebpackPlugin({
            template: './src/index.html',
            hash: true, // 会在打包好的bundle.js后面加上hash串
            minify: {
                minifyCSS: true, // 压缩 HTML 中出现的 CSS 代码
                minifyJS: true, // 压缩 HTML 中出现的 JS 代码
                removeAttributeQuotes: true
            },
        }),
    ]
}
  • template 在src目录下创建一个index.html页面当做模板来用
  • hash 会在打包好的bundle.js后面加上hash串
  • minify 是对html文件进行压缩
  • removeAttributeQuotes 去掉属性的双引号
  • minifyCSS 压缩 HTML 中出现的 CSS 代码
  • minifyCSS 压缩 HTML 中出现的 JS代码
    ok 执行npm run build,此时dist目录下自动生成index.html,并自动引入了js文件

CSS文件发布

在webpack中打包css、less需要单独的loader去解析

npm i style-loader css-loader less less-loader -D

接下来我们配置下:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin'); //打包html

module.exports = {
    // 1.写成数组的方式就可以打出多入口文件,但是打包后会合成一个
    // entry: ['./src/index.js', './src/index2.js'],
    entry: {
        index: './src/index.js',
        index2: './src/index2.js'
    },
    output: {
        // 1. filename: 'bundle.js',
        // 2. [name]就可以将出口文件名和入口文件名一一对应
        filename: '[name].[hash:6].js',      // 打包后会生成index.js和index2.js文件
        path: path.resolve('dist')
    },
    module: {
        rules: [
            {
                test: /\.css/,
                exclude: /node_modules/, // 取消匹配node_modules里面的文件
                use: ['style-loader', 'css-loader']
            },
            {
                test: /\.less$/,
                exclude: /node_modules/, // 取消匹配node_modules里面的文件
                use: ['style-loader', 'css-loader', 'less-loader']
            },
        ]
    },   
    plugins: [
        // 通过new一下这个类来使用插件
         new HtmlWebpackPlugin({
            template: './src/index.html',
            hash: true, // 会在打包好的bundle.js后面加上hash串
            minify: {
                minifyCSS: true, // 压缩 HTML 中出现的 CSS 代码
                minifyJS: true, // 压缩 HTML 中出现的 JS 代码
                removeAttributeQuotes: true
            },
        }),
    ]
}
  • test 正则表达式,匹配文件名
  • use 数组,里面放需要执行的loader,倒序执行,从右至左。(小坑:style-loader最后执行)
  • exclude 取消匹配node_modules里面的文件
    ok 执行npm run build,此时我们发现并没有看到css文件生成,这是为什么呢?因为webpack默认把我们的css合并到bundle.js中了,如下图:
    image.png

实际开发中,我们一般都吧css 和 js分离。

拆分CSS

在webpack3.x版本中可以用extract-text-webpack-plugin插件进行拆分,但这里不做过多描述,如果感兴趣的同学可以去官网查看文档。因为webpack4.x新出了mini-css-extract-plugin插件, 我们就用最新的。让我们安装一下

npm i mini-css-extract-plugin -D

接下来我们加入配置:(为了方便观看,只显示当前配置项)

const path = require('path');
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); // 提取出来css

module.exports = {
    module: {
        rules: [
            {
                test: /\.css/,
                exclude: /node_modules/, // 取消匹配node_modules里面的文件
                use: ['style-loader', MiniCssExtractPlugin.loader, 'css-loader']
            },
            {
                test: /\.less$/,
                exclude: /node_modules/, // 取消匹配node_modules里面的文件
                use: ['style-loader', MiniCssExtractPlugin.loader, 'css-loader', 'less-loader']
            },
        ]
    },   
    plugins: [
        // 把css从bundle.js中分离出来
        new MiniCssExtractPlugin({
            filename: "static/css/[name].[chunkhash:8].css",
        }),
    ]
}

ok 执行npm run build,我们可以看到dist目录下生成了static/css/xxx.css文件,bundle.js文件里已没有css,这样我们就做到了css的拆分!

图片发布(css中的img)

同样处理图片也需要相应的loader。

  npm i file-loader url-loader -D

接下来我们加入配置:(为了方便观看,只显示当前配置项)

const path = require('path');

// 解决css 分离后图片引入路径不正确问题
if (process.env.type == 'build') { // 判断package.json里面是build还是dev命令
    // 开发
    var website ={
        publicPath:"/"
    }
} else {
    // 生产
    var website ={
        publicPath:"/"
    }
}

module.exports = {
    output: {
        filename: 'bundle.[chunkhash:6].js',
        path: path.resolve('dist'),
        publicPath: website.publicPath // 解决css 分离后图片引入路径不正确问题
    },    
    module: {
        rules: [
            {
                test: /\.(png|jpe?g|gif|svg)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 10000, // limit:是把小于xxx(也就是xxxk)的文件打成Base64的格式,写入JS。否则就写入路径
                            name: '[name]_[hash:7].[ext]', // 打包图片的名字
                            outputPath:'static/images/' // 打包后放到images路径下
                        }
                    }
                ]
            },
        ]
    },   
}

需要注意如果是在css文件里引入的如背景图之类的图片,就需要指定一下相对路径!

  • limit 阈值 单位byte 大于设置值不进行base64压缩,否则下雨此值压缩成base64
  • name 打包图片的名字
  • outputPath 打包图片路径
    ok 执行npm run build,我们可以看到dist目录下生成了static/images/xxx.png, 或者直接在css已base64码引入

图片发布(页面中的img)

在实际开发中,我们经常用的<img src="xxxx.png"/>的方式引入图片,同样也有相应的loader去处理。

npm i html-withimg-loader -D

接下来我们加入配置:(为了方便观看,只显示当前配置项)

module.exports = {
    module: {
        rules: [
            {
                test: /\.(htm|html)$/,
                use: 'html-withimg-loader'
            }
        ]
    }
}

ok,这样我们html和css中的img都可以打包成功了!

自动处理CSS3属性前缀

为了浏览器的兼容性,有时候我们必须加入-webkit,-ms,-o,-moz这些前缀。目的就是让我们写的页面在每个浏览器中都可以顺利运行

PostCSS是一个CSS的处理平台,它可以帮助你的CSS实现更多的功能。

npm i postcss-loader autoprefixer -D

安装后,在项目根目录下创建一个postcss.config.js文件,配置如下:

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

这样我们就实现了css前缀自动补齐了。

babel-loader(解析ES6、ES7)

在实际开发中基本都开始使用ES6的语法了,可以提高前端开发速度,但是有一些低版本的浏览器不支持语法,所以我们需要转成es5。于是就需要Babel。执行下面命令:

npm i babel-core babel-loader babel-preset-env babel-preset-react babel-plugin-transform-runtime babel-preset-stage-0 -D

安装完成后,我们可以新建.babelrc文件来配置一下:

{
  "presets": ["react", "env", "stage-0"], 
  "plugins": ["transform-runtime"],
}

我们再在webpack里配置一下babel-loader既可以做到代码转成ES5了

module.exports = {
    module: {
        rules: [
            {
                test:/\.(jsx|js)$/,
                include: [ 
                    path.resolve(__dirname, 'src'), 
                    // 限定只在 src 目录下的 js/jsx 文件需要经 babel-loader 处理
                    // 通常我们需要 loader 处理的文件都是存放在 src 目录
                ],
                use:['babel-loader'],
                exclude:/node_modules/ // 去除掉node_modules文件夹的js 不然node_modules也都转换了
            },
        ]
    }
}

细心的同学可以发现,我加了一个jsx,这样就可以写react代码啦···

resolve解析

在webpack的配置中,resolve我们常用来配置别名和省略后缀名

module.exports = {
    resolve: {
        // 别名
        alias: {
            $: './src/jquery.js'
        },
        // 省略后缀
        extensions: ['.js', '.json', '.css']
    },
}

优化黑科技

webpack给我们提供了很多优化的配置,接下来我们看看:

拆分JS 抽离公共代码

在webpack4之前,提取公共代码都是通过一个叫CommonsChunkPlugin的插件来完成的,但是webpack4.x以后内置了一个更好的配置项去完成这份工作:

// 提取公共代码
module.exports = {
    optimization: {
        splitChunks: {
            cacheGroups: {
                vendor: {   // 抽离第三方插件
                    test: /node_modules/,   // 指定是node_modules下的第三方包
                    chunks: 'initial',
                    name: 'vendor',  // 打包后的文件名,任意命名    
                    // 设置优先级,防止和自定义的公共代码提取时被覆盖,不进行打包
                    priority: 10    
                },
                utils: { // 抽离自己写的公共代码,utils这个名字可以随意起 (css/js公用的都会单独抽离出来生成一个单独的文件)
                   chunks: 'initial',
                   name: 'utils',  // 任意命名
                   minSize: 0    // 只要超出0字节就生成一个新包
                }
            }
        }
    },  
}

备注信息代码已注释的很详细,这里就不多解释了,

  • vendor 开发中我们经常用到vue.min.js、reacr.min.js ....等很多源码库,因为我们每次发布的时候变得只是业务逻辑,源码是不变的,所以我们单独抽离出来,这样也有利于浏览器缓存,提高页面加载速度,增加用户体验。
  • utils 这个配置项指的是平常开发中,我们经常会写一些公共的util,配置此项也可以单独打包出来,但是我不建议这么做,因为本身util一般也不会很大,没有这个必要。

HappyPack

HappyPack 允许 Webpack 使用 Node 多线程进行构建来提升构建的速度。
HappyPack支持对css loader 和 babel loader的加速。对url-loader 和 file-loader 的支持度的问题
首先安装:

npm i -D happypack

接下来我们加入配置:(为了方便观看,只显示当前配置项)

const HappyPack = require('happypack'); // 多线程构建
const happyThreadPool = HappyPack.ThreadPool({ size: 5 });  // 构造出共享进程池,进程池中包含5个子进程
module.exports = {
    module: {
        rules: [
            {
                test:/\.(jsx|js)$/,
                // 开启多线程进行构建 匹配下面注释的插件
                use:['happypack/loader?id=js'], 
                exclude:/node_modules/ 
            },
        ]
    },   
    plugins: [
        // 多线程构建 匹配上面的loader
        new HappyPack({
            id: 'js',
            loaders: ['babel-loader'],
            threadPool: happyThreadPool, // 使用共享进程池中的子进程去处理任务
        }),
    ]
}

其实很简单,我们看奥下面的happypack插件里面的id去匹配上面loader等于js的配置

  • threadPool 开启5个子进程去处理任务

minimizer

在production模式,该配置会默认为我们压缩混淆代码,但这显然满足不了我们对于优化代码的诉求。下面是最优化配置:

 optimization: {
    minimizer: [
       // 自定义js优化配置,将会覆盖默认配置 最大化压缩成js
        new UglifyJsPlugin({
            exclude: /\.min\.js$/, // 过滤掉以".min.js"结尾的文件,我们认为这个后缀本身就是已经压缩好的代码,没必要进行二次压缩
            cache: true,
            parallel: true, // 开启并行压缩,充分利用cpu
            sourceMap: false,
            extractComments: false, // 移除注释
            uglifyOptions: {
              compress: {
                unused: true,
                warnings: false,
                drop_debugger: true
              },
              output: {
                comments: false
              }
            }
        }),
        // 用于优化css文件 最大化压缩css 并且去掉注释掉的css
        new OptimizeCssAssetsPlugin({
            assetNameRegExp: /\.css$/g,
            cssProcessorOptions: {
              safe: true,
              autoprefixer: { disable: true },
              mergeLonghand: false,
              discardComments: {
                removeAll: true // 移除注释
              }
            },
            canPrint: true
        })
    ],
}

最后

最终代码

const path = require('path');
const webpack = require('webpack');
// 插件都是一个类,所以我们命名的时候尽量用大写开头
const HtmlWebpackPlugin = require('html-webpack-plugin'); //打包html
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); // 提取出来css
const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); // 压缩打包后的js 
const HappyPack = require('happypack'); // 多线程构建
const happyThreadPool = HappyPack.ThreadPool({ size: 5 });  // 构造出共享进程池,进程池中包含5个子进程
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')// 最大化压缩css

console.log('process.env.NODE_ENV------->',  process.env.NODE_ENV)
// 解决css 分离后图片引入路径不正确问题
if (process.env.type == 'build') { // 判断package.json里面是build还是dev命令
    // 开发
    var website ={
        publicPath:"/"
    }
} else {
    // 生产
    var website ={
        publicPath:"/"
    }
}


module.exports = {
    // devtool:'eval-source-map',
    mode: 'development', // 模式配置
    entry: {
        main: './src/index.js',
    },             
    output: {
        filename: 'bundle.[chunkhash:6].js',
        path: path.resolve(__dirname, 'dist'),
        publicPath: website.publicPath, // 解决css 分离后图片引入路径不正确问题
    },             
    module: {
        rules: [
            {
                test: /\.css/,
                exclude: /node_modules/,
                use: ['style-loader', MiniCssExtractPlugin.loader, 'css-loader'],
            },
            {
                test: /\.less$/,
                exclude: /node_modules/,
                use: ['style-loader', MiniCssExtractPlugin.loader, 'css-loader', 'less-loader'],
            },
            {
                test: /\.(png|jpe?g|gif|svg)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 10000,
                            name: '[name]_[hash:7].[ext]', 
                            outputPath:'static/images/'
                        }
                    }
                ]
            },
            {
                test: /\.(htm|html)$/,
                use: 'html-withimg-loader'
            },
            // babel 解析es7 es6 jsx
            {
                test:/\.(jsx|js)$/,
                include: [ 
                    path.resolve(__dirname, 'src'),
                ],
                use:['babel-loader'],
                /*
                    如果开启多线程进行构建
                    use:['happypack/loader?id=js'], 
                    loader这样写 匹配下面注释的插件
                */
                exclude:/node_modules/
            },
        ]
    },              
    plugins: [
        // 打包html
        new HtmlWebpackPlugin({
            template: './src/index.html',
            hash: true,
            minify: {
                minifyCSS: true,
                minifyJS: true, 
                removeAttributeQuotes: true
            },
        }),
        new MiniCssExtractPlugin({
            filename: "static/css/[name].[chunkhash:8].css",
            chunkFilename: "[id].css"
        }),
        new UglifyJsPlugin({
            parallel: true, 
        }),
        new webpack.DefinePlugin({
            NODE_ENV: JSON.stringify('DEV')
        }),
        // 多线程构建 匹配上面的loader
        // new HappyPack({
        //     id: 'js',
        //     //threads: 4,
        //     loaders: ['babel-loader'],
        //     threadPool: happyThreadPool, // 使用共享进程池中的子进程去处理任务
        // }),
    ],   
    // 提取公共代码
    optimization: {
        minimizer: [
           // 自定义js优化配置,将会覆盖默认配置 最大化压缩成js
            new UglifyJsPlugin({
                exclude: /\.min\.js$/, // 过滤掉以".min.js"结尾的文件,我们认为这个后缀本身就是已经压缩好的代码,没必要进行二次压缩
                cache: true,
                parallel: true, // 开启并行压缩,充分利用cpu
                sourceMap: false,
                extractComments: false, // 移除注释
                uglifyOptions: {
                  compress: {
                    unused: true,
                    warnings: false,
                    drop_debugger: true
                  },
                  output: {
                    comments: false
                  }
                }
            }),
            // 用于优化css文件 最大化压缩成css 并且去掉注释掉的css
            new OptimizeCssAssetsPlugin({
                assetNameRegExp: /\.css$/g,
                cssProcessorOptions: {
                  safe: true,
                  autoprefixer: { disable: true },
                  mergeLonghand: false,
                  discardComments: {
                    removeAll: true // 移除注释
                  }
                },
                canPrint: true
            })
        ],
        splitChunks: {
            cacheGroups: {
                vendor: {   // 抽离第三方插件
                    test: /node_modules/,   // 指定是node_modules下的第三方包
                    chunks: 'initial',
                    name: 'vendor',  // 打包后的文件名,任意命名    
                    // 设置优先级,防止和自定义的公共代码提取时被覆盖,不进行打包
                    priority: 10    
                },
                // utils: { // 抽离自己写的公共代码,utils这个名字可以随意起 (css/js公用的都会单独抽离出来生成一个单独的文件)
                //     chunks: 'initial',
                //     name: 'utils',  // 任意命名
                //     minSize: 0    // 只要超出0字节就生成一个新包
                // }
            }
        }
    },        
    devServer: {
        historyApiFallback: true,
        inline: true
    },   
    // externals: {
    //     jquery: "jQuery",
    // },
    resolve: {
        // alias 别名配置,它能够将导入语句里的关键字替换成你需要的路径
        alias: {
            // 比如我们就可以直接写 import Nav from '@/Nav'
            '@': './app/component'
        },
        // 省略后缀
        extensions: ['.js', '.jsx', '.less', '.json', '.css'],
    },     
    performance: {
        hints: false // 选项可以控制 webpack 如何通知「资源(asset)和入口起点超过指定文件限制」
    }
}
同学你都读到这里了,还不点赞加关注吗?

webpack其实还有很多优化项,很多plugins And loader等着我们去挖掘.
小编也是萌新一枚,哪里写的不好,提出意见!我也会不断更新文章的...请大家持续关注!
辛苦大家了.......下班回家了............

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

推荐阅读更多精彩内容

  • 版权声明:本文为博主原创文章,未经博主允许不得转载。 webpack介绍和使用 一、webpack介绍 1、由来 ...
    it筱竹阅读 11,056评论 0 21
  • GitChat技术杂谈 前言 本文较长,为了节省你的阅读时间,在文前列写作思路如下: 什么是 webpack,它要...
    萧玄辞阅读 12,679评论 7 110
  • 一、webpack的基本概念 webpack 本质上是一个打包工具,它会根据代码的内容解析模块依赖,帮助我们把多个...
    cilla123阅读 1,536评论 0 8
  • webpack 介绍 webpack 是什么 为什么引入新的打包工具 webpack 核心思想 webpack 安...
    yxsGert阅读 6,458评论 2 71
  • 1:感恩老公清明小长假带全家旅游渡假,享受幸福生活。 2:感恩金钱让我筹备烧烤的材料,享受美食 3:感恩闹钟提醒我...
    吕永敏阅读 168评论 2 3