Webpack学习笔记

Webpack 是一个前端资源加载/打包工具。它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源。找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其打包为合适的格式以供浏览器使用。
Webpack的工作方式是:把你的项目当做一个整体,通过一个给定的主文件(如:index.js),Webpack将从这个文件开始找到你的项目的所有依赖文件,使用loaders处理它们,最后打包为一个浏览器可识别的JavaScript文件。

Webpack

安装Webpack

webpack是建立在node.js环境下的,所以要使用它我们需要先安装node和npm,其相关知识这里将不介绍。

安装node.js

在终端输入以下命令即可

$ sudo apt-get install nodejs

安装npm

在终端输入以下命令即可

$ sudo apt-get install npm

为了保证下载速度,我们直接永久设置为淘宝源为npm的registry地址。在终端里输入

npm config set registry https://registry.npm.taobao.org
  • 配置成功后输入以下命令来查看是否成功
npm config get registry

如图所示即为成功


设置npm为淘宝源

安装webpack

  1. 全局安装
    在终端输入
sudo npm install -g webpack
  1. 局部安装
    进入项目目录,并在终端中输入
npm install --save-dev webpack

使用Webpack

  1. 创建一个工作目录,并进入这个目录创建一个项目,在终端输入以下命令,会自动生成一个package.json文件,这是一个标准的npm说明文件,里面包含了一些信息,包含了项目的依赖模块,自定义脚本任务等。
npm init

输入这个命令后,终端会问你一系列诸如项目名称,项目描述,作者等信息,不过不用担心,如果你不准备在npm中发布你的模块,这些问题的答案都不重要,回车默认即可。

  1. 在本项目中安装Webpack作为依赖包,在终端输入以下命令
npm install --save-dev webpack
  1. 创建app和public文件夹

    • app文件夹用来存放原始数据和我们将写的JavaScript模块
    • public文件夹用来存放准备给浏览器读取的数据(包括使用webpack生成的打包后的js文件以及一个index.html文件)
  2. 创建几个html和js文件做一个简单的例子

    • public下创建index.html文件,加载通过webpack打包之后的bundle.js文件
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="utf-8">
        <title>Webpack Sample Project</title>
    </head>
    <body>
        <div id='root'>
        </div>
        <script src="bundle.js"></script>
    </body>
    </html>
    
    • app目录下创建Greeter.js,用来返回一个简单的文字信息的html元素的函数
    module.exports = function() {
        var greet = document.createElement('div');
        greet.textContent = "Hi there and greetings!";
        return greet;
        };
    
    • app目录下创建main.js,用来把Greeter模块返回的结点插入页面
    var greeter = require('./Greeter.js');
    document.getElementById('root').appendChild(greeter());
    
  3. 使用webpack进行打包
    基本命令为

webpack {entry file/入口文件} {destination for bundled file/存放bundle.js的地方}

只需要指定一个入口文件,webpack将自动识别项目所依赖的其它文件,不过需要注意的是如果你的webpack没有进行全局安装,那么当你在终端中使用此命令时,需要额外指定其在node_modules中的地址,继续上面的例子,在终端中属于如下命令

node_modules/.bin/webpack app/main.js public/bundle.js

执行结果如下,可以看到帮我们打包了两个文件


webpack命令打包

打开浏览器访问index.html可以看到如下结果


打包后index结果
  • webpack还有许多功能,通过命令行都可以实现,但是命令多了不好记也容易出错,所以webpack也提供了配置文件方式,在项目根目录下创建webpack.config.js文件,在其中编写我们所需要的配置。

    module.exports = {
        //唯一入口文件
        entry: __dirname + "/app/main.js",
        output: {
            //打包后的文件存放的地方
            path: __dirname + "/public",
            //打包后输出文件的文件名
            filename: "bundle.js"
        }
    }
    

    注:__dirname是node.js中的一个全局变量,它指向当前执行脚本所在的目录。
    接下来指定打包命令只需要在终端中输入webpack即可。执行的结果和用命令一致。

  • 打包操作还可以更简单,为了解决命令复杂且多的问题,npm还提供了引导任务执行的功能。对其进行配置后可以使用简单的npm start命令来代替这些繁琐的命令。在package.json中对npm的脚本部分进行相关设置即可,设置方法如下。

{
  "name": "first_webpack_project",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    //配置start命令
    "start": "webpack"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^3.4.1"
  }
}

注:npm的start是一个特殊的脚本名称,它的特殊性表现在,在命令行中使用npm start就可以执行相关命令,如果对应的此脚本名称不是start,想要在命令行中运行时,需要这样用npm run {script name}npm run build,以下是执行npm start后命令行的输出显示

npm start结果

Webpack功能

生成Source Maps

开发总是离不开调试,如果可以更加方便的调试当然就能提高开发效率,不过打包后的文件有时候你是不容易找到出错了的地方对应的源代码的位置的,Source Maps就是来帮我们解决这个问题的。

通过简单的配置后,Webpack在打包时可以为我们生成的source maps,这为我们提供了一种对应编译文件和源文件的方法,使得编译后的代码可读性更高,也更容易调试。

devtool选项 配置结果
source-map 在一个单独的文件中产生一个完整且功能完全的文件。这个文件具有最好的source map,但是它会减慢打包文件的构建速度
cheap-module-source-map 在一个单独的文件中生成一个不带列映射的map,不带列映射提高项目构建速度,但是也使得浏览器开发者工具只能对应到具体的行,不能对应到具体的列(符号),会对调试造成不便
eval-source-map 使用eval打包源文件模块,在同一个文件中生成干净的完整的source map。这个选项可以在不影响构建速度的前提下生成完整的sourcemap,但是对打包后输出的JS文件的执行具有性能和安全的隐患。不过在开发阶段这是一个非常好的选项,但是在生产阶段一定不要用这个选项
cheap-module-eval-source-map 这是在打包文件时最快的生成source map的方法,生成的Source Map 会和打包后的JavaScript文件同行显示,没有列映射,和eval-source-map选项具有相似的缺点

在webpack的配置文件中配置source maps,需要配置devtool,它有以下四种不同的配置选项,各具优缺点,描述如下:

devtool选项 配置结果
source-map 在一个单独的文件中产生一个完整且功能完全的文件。这个文件具有最好的source map,但是它会减慢打包文件的构建速度
cheap-module-source-map 在一个单独的文件中生成一个不带列映射的map,不带列映射提高项目构建速度,但是也使得浏览器开发者工具只能对应到具体的行,不能对应到具体的列(符号),会对调试造成不便
eval-source-map 使用eval打包源文件模块,在同一个文件中生成干净的完整的source map。这个选项可以在不影响构建速度的前提下生成完整的sourcemap,但是对打包后输出的JS文件的执行具有性能和安全的隐患。不过在开发阶段这是一个非常好的选项,但是在生产阶段一定不要用这个选项
cheap-module-eval-source-map 这是在打包文件时最快的生成source map的方法,生成的Source Map 会和打包后的JavaScript文件同行显示,没有列映射,和eval-source-map选项具有相似的缺点

按照说明选择一种你希望的生成方式,在webpack.config.js中进行配置

module.exports = {
    //配置生成Source Maps,选择合适的选项
    devtool: "eval-source-map",
    //唯一入口文件
    entry: __dirname + "/app/main.js",
    output: {
        //打包后的文件存放的地方
        path: __dirname + "/public",
        //打包后输出文件的文件名
        filename: "bundle.js"
    }
}

使用webpack构建本地服务器

Webpack提供一个可选的本地开发服务器,这个本地服务器基于node.js构建,可以实现监测你的代码的修改,并自动刷新修改后的结果,不过它是一个单独的组件,在webpack中进行配置之前需要单独安装它作为项目依赖。安装命令如下

npm install --save-dev webpack-dev-server

devserver作为webpack配置选项中的一项,具有以下配置选项

devserver配置选项 功能描述
contentBase 默认webpack-dev-server会为根文件夹提供本地服务器,如果想为另外一个目录下的文件提供本地服务器,应该在这里设置其所在目录(本例设置到“public"目录)
port 设置默认监听端口,如果省略,默认为”8080“
inline 设置为true,当源文件改变时会自动刷新页面
colors 设置为true,使终端输出的文件为彩色的
historyApiFallback 在开发单页应用时非常有用,它依赖于HTML5 history API,如果设置为true,所有的跳转将指向index.html

webpack.config.js中进行配置devserver:

module.exports = {
    //配置生成Source Maps,选择合适的选项
    devtool: "eval-source-map",
    //唯一入口文件
    entry: __dirname + "/app/main.js",
    output: {
        //打包后的文件存放的地方
        path: __dirname + "/public",
        //打包后输出文件的文件名
        filename: "bundle.js"
    },

    devServer: {
        //本地服务器所加载的页面所在的目录
        contentBase: "./public",
        //终端中输出结果为彩色
        colors: true,
        //不跳转
        historyApiFallback: true,
        //实时刷新
        inline: true
    }
}

Loaders

通过使用不同的loader,webpack通过调用外部的脚本或工具可以对各种各样的格式的文件进行处理,比如说分析JSON文件并把它转换为JavaScript文件,或者说把下一代的JS文件(ES6,ES7)转换为现代浏览器可以识别的JS文件。

Loaders需要单独安装并且需要在webpack.config.js下的modules关键字下进行配置,Loaders的配置选项包括以下几方面:

|选项|描述|是否必须|
|test|一个匹配loaders所处理的文件的拓展名的正则表达式|是|
|loader|loader的名称|是|
|include/exclude|手动添加必须处理的文件(文件夹)或屏蔽不需要处理的文件(文件夹)|否|
|query|为loaders提供额外的设置选项|否|

我们把Greeter.js里的问候消息放在一个单独的JSON文件里,并通过合适的配置使Greeter.js可以读取该JSON文件的值,配置方法如下:

  1. 首先安装可以读取json文件的值的loader
npm install --save-dev json-loader
  1. webpack.config.js中进行配置json-loader:
module.exports = {
    ...
    ...
    ...

    //在配置文件里添加JSON loader
    module: {
        loaders: [
            {
                test: /\.json$/,
                loader: "json-loader"
            }
        ]
    },
}
  1. 创建带有问候信息的JSON文件(在app下创建config.json文件)
{
  "greetText": "Hi there and greetings from JSON!"
}
  1. 更新app/Greeter.js的内容为:
//从config.json读取
var config = require('./config.json');

module.exports = function() {
    var greet = document.createElement('div');
    greet.textContent = config.greetText;
    return greet;
};

Babel

Babel其实是一个编译JavaScript的平台,它的强大之处表现在可以通过编译帮你达到以下目的:

  • 下一代的JavaScript标准(ES6,ES7),这些标准目前并未被当前的浏览器完全的支持
  • 使用基于JavaScript进行了拓展的语言,比如React的JSX
  1. 安装所有Babel所有的依赖包
npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react
  1. webpack.config.js中进行配置babel
module.exports = {
    ...
    ...
    ...

    //在配置文件里添加JSON loader
    module: {
        loaders: [
            {
                test: /\.json$/,
                loader: "json-loader"
            },
            {
                test: /\.js$/,
                exclude: /node_modules/,
                //在webpack的module部分的loaders里进行配置即可
                loader: 'babel-loader',
                query: {
                    presets: ['es2015', 'react']
                }
            }
        ]
    },
}

现在你的webpack的配置已经允许你使用ES6以及JSX的语法了。

现在使用React进行测试,先安装 React 和 React-DOM,在终端中输入

npm install --save react react-dom
  1. 更新app/Greeter.js的内容为:
//Greeter,js
//导入React
import React, {Component} from 'react'
//从config.json读取
import config from './config.json';

class Greeter extends Component{
  render() {
    return (
      <div>
        {config.greetText}
      </div>
    );
  }
}

export default Greeter
  1. 更新app/main.js内容为:
import React from 'react';
import {render} from 'react-dom';
import Greeter from './Greeter';

render(<Greeter />, document.getElementById('root'));
Babel的配置选项

Babel可以在webpack.config.js中进行配置页可以分块单独配置,当配置较多时,最好单独配置创建一个.babelrc的babel配置文件,webpack会自动调用.babelrc其中的配置选项。

  1. 更新webpack.config.js内容为:
module.exports = {
    ...
    ...
    ...

    //在配置文件里添加JSON loader
    module: {
        loaders: [
            {
                test: /\.json$/,
                loader: "json-loader"
            },
            {
                test: /\.js$/,
                exclude: /node_modules/,
                //在webpack的module部分的loaders里进行配置即可
                loader: 'babel-loader',
            }
        ]
    },
}
  1. 创建.babelrc文件并添加内容如下:
{
  "presets": ["react", "es2015"]
}

模块

Webpack有一个不可不说的优点,它把所有的文件都可以当做模块处理,包括你的JavaScript代码,也包括CSS和fonts以及图片等等等,只有通过合适的loaders,它们都可以被当做模块被处理。

CSS

webpack提供两个工具处理样式表,css-loaderstyle-loader,二者处理的任务不同,css-loader使你能够使用类似@importurl(...)的方法实现 require()的功能,style-loader将所有的计算后的样式加入页面中,二者组合在一起使你能够把样式表嵌入webpack打包后的JS文件中。

  1. 安装css-loaderstyle-loader模块,在终端输入以下命令
npm install --save-dev style-loader css-loader
  1. 更新webpack.config.js内容,使其能够使用css-loaderstyle-loader
module.exports = {
    ...
    ...
    ...

    //在配置文件里添加JSON loader
    module: {
        loaders: [
            {
                test: /\.json$/,
                loader: "json-loader"
            },
            {
                test: /\.js$/,
                exclude: /node_modules/,
                //在webpack的module部分的loaders里进行配置即可
                loader: 'babel-loader',
            },
            {
                test: /\.css$/,
                //添加对样式表的处理
                loader: 'style-loader!css-loader'
            }
        ]
    },
}
>注:感叹号的作用在于使同一文件能够使用不同类型的loader
  1. app文件夹下创建main.css的文件,设置某些元素的样式
html {
  box-sizing: border-box;
  -ms-text-size-adjust: 100%;
  -webkit-text-size-adjust: 100%;
}

*, *:before, *:after {
  box-sizing: inherit;
}

body {
  margin: 0;
  font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}

h1, h2, h3, h4, h5, h6, p, ul {
  margin: 0;
  padding: 0;
}
  1. 由于webpack只有单一的入口,其它的模块需要通过 import, require, url等导入相关位置,为了让webpack能找到”main.css“文件,我们把它导入”main.js “中,更新后的main.js文件内容为:
import React from 'react';
import {render} from 'react-dom';
import Greeter from './Greeter';

//使用require导入css文件
import './main.css';

render(<Greeter/>, document.getElementById('root'));

CSS module

CSS modules 的技术就意在把JS的模块化思想带入CSS中来,通过CSS模块,所有的类名,动画名默认都只作用于当前模块。Webpack从一开始就对CSS模块化提供了支持,在CSS loader中进行配置后,你所需要做的一切就是把”modules“传递都所需要的地方,然后就可以直接把CSS的类名传递到组件的代码中,且这样做只对当前组件有效,不必担心在不同的模块中具有相同的类名可能会造成的问题.

  1. 更新webpack.config.js内容,使其能使用CSS module
module.exports = {
    ...
    ...
    ...

    //在配置文件里添加JSON loader
    module: {
        loaders: [
            {
                test: /\.json$/,
                loader: "json-loader"
            },
            {
                test: /\.js$/,
                exclude: /node_modules/,
                //在webpack的module部分的loaders里进行配置即可
                loader: 'babel-loader',
            },
            {
                test: /\.css$/,
                //添加对样式表的处理
                //仅仅添加了?modules-loader
                loader: 'style-loader!css-loader?modules-loader'
            }
        ]
    },
}
  1. app文件夹下创建Greeter.css并增加内容为:
.root {
  background-color: #eee;
  padding: 10px;
  border: 3px solid #ccc;
}
  1. 导入.rootGreeter.js中,更新Greeter.js内容为:
import React, {Component} from 'react';
import config from './config.json';
import styles from './Greeter.css';//导入

class Greeter extends Component{
  render() {
    return (
      <div className={styles.root}>//添加类名
        {config.greetText}
      </div>
    );
  }
}

export default Greeter

CSS预处理器

Sass 和 Less之类的预处理器是对原生CSS的拓展,它们允许你使用类似于variables, nesting, mixins, inheritance等不存在于CSS中的特性来写CSS,CSS预处理器可以这些特殊类型的语句转化为浏览器可识别的CSS语句,

常用的CSS处理器loaders:

  • Less Loader
  • Sass Loader
  • Stylus Loader
  1. 安装postcss-loaderautoprefixer(自动添加前缀的插件)
npm install --save-dev postcss-loader autoprefixer
  1. 更新webpack.config.js内容,使其能使用postcss-loaderautoprefixer,只需要新建一个postcss关键字,并在里面申明依赖的插件
module.exports = {
    ...
    ...
    ...

    //在配置文件里添加JSON loader
    module: {
        loaders: [
            {
                test: /\.json$/,
                loader: "json-loader"
            },
            {
                test: /\.js$/,
                exclude: /node_modules/,
                //在webpack的module部分的loaders里进行配置即可
                loader: 'babel-loader',
            },
            {
                test: /\.css$/,
                //添加对样式表的处理
                //仅仅添加了?modules
                loader: 'style-loader!css-loader?modules-loader!postcss-loader'
            }
        ]
    },
}
  1. webpack.config.js同级目录下创建postcss.config.js文件,配置内容如下;
module.exports = {
  plugins: [
    require('autoprefixer')
  ]
}

插件

插件(Plugins)是用来拓展Webpack功能的,它们会在整个构建过程中生效,执行相关的任务。

如何使用插件

要使用某个插件,我们需要通过npm安装它,然后要做的就是在webpack配置中的plugins关键字部分添加该插件的一个实例(plugins是一个数组)

  1. 添加一个显示版权声明的插件,在webpack.config.js中更新内容如下
var webpack = require('webpack');

module.exports = {
    ...
    ...
    ...

    plugins: [
        //在这个数组中new一个就可以了
        new webpack.BannerPlugin("Copyright Flying Unicorns inc.")
  ],
}

HtmlWebpackPlugin

这个插件的作用是依据一个简单的模板,帮你生成最终的Html5文件,这个文件中自动引用了你打包后的JS文件。每次编译都在文件名中插入一个不同的哈希值。

这个插件自动完成了我们之前手动做的一些事情,在正式使用之前需要对一直以来的项目结构做一些改变:

  1. 移除public文件夹,利用此插件,HTML5文件会自动生成,此外CSS已经通过前面的操作打包到JS中了,public文件夹里。

  2. 在app目录下,创建一个Html文件模板,这个模板包含title等其它你需要的元素,在编译过程中,本插件会依据此模板生成最终的html页面,会自动添加所依赖的 css, js,favicon等文件,在本例中我们命名模板文件名称为index.tmpl.html,模板源代码如下

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Webpack Sample Project</title>
  </head>
  <body>
    <div id='root'>
    </div>
  </body>
</html>
  1. 更新webpack的配置文件,方法同上,新建一个build文件夹用来存放最终的输出文件
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
    ...
    ...
    ...

    output: {
        //打包后的文件存放的地方
        path: __dirname + "/build",
        //打包后输出文件的文件名
        filename: "bundle.js"
    },
    ...
    ...
    ...

    plugins: [
         new HtmlWebpackPlugin({
            template: __dirname + "/app/index.tmpl.html"//new 一个这个插件的实例,并传入相关的参数
        })
  ],
}

优化插件

webpack提供了一些在发布阶段非常有用的优化插件,它们大多来自于webpack社区,可以通过npm安装,通过以下插件可以完成产品发布阶段所需的功能

  • OccurenceOrderPlugin :为组件分配ID,通过这个插件webpack可以分析和优先考虑使用最多的模块,并为它们分配最小的ID
  • UglifyJsPlugin:压缩JS代码;
  • ExtractTextPlugin:分离CSS和JS文件
  1. 安装插件,在终端中输入
npm install --save-dev extract-text-webpack-plugin
  1. 在在webpack.config.js中更新配置内容如下
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
    .
    ...
    ...

    plugins: [
         new HtmlWebpackPlugin({
            template: __dirname + "/app/index.tmpl.html"//new 一个这个插件的实例,并传入相关的参数
            new webpack.optimize.OccurenceOrderPlugin(),
            new webpack.optimize.UglifyJsPlugin(),
            new ExtractTextPlugin("style.css")
        })
  ],
}

注:

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

推荐阅读更多精彩内容

  • 无意中看到zhangwnag大佬分享的webpack教程感觉受益匪浅,特此分享以备自己日后查看,也希望更多的人看到...
    小小字符阅读 8,134评论 7 35
  • 这是我第二次学习webpack了,初见他时,我是一脸懵逼的,这次再见时,稍微轻松了一点,现在写下这份学习笔记,用来...
    ruby0922阅读 306评论 0 0
  • 最近在学习 Webpack,网上大多数入门教程都是基于 Webpack 1.x 版本的,我学习 Webpack 的...
    My_Oh_My阅读 8,160评论 40 247
  • GitChat技术杂谈 前言 本文较长,为了节省你的阅读时间,在文前列写作思路如下: 什么是 webpack,它要...
    萧玄辞阅读 12,669评论 7 110
  • 出发,去机场了,早上八点半的飞机,结束一周的出差旅途,奔波数个地方,换过很多维也纳酒店,一直都没有休息好,主要是睡...
    OO碰到OO阅读 201评论 0 1