你必定喜欢看的 Webpack 2.× 入门实战(转载)

 最近在学习 Webpack,网上大多数入门教程都是基于 Webpack 1.x 版本的,我学习 Webpack 的时候是看了 zhangwang<<入门 Webpack,看这篇就够了>> 写的很是好,不过是基于 Webpack 1.x 版本的,语法上和 Webpack 2.x 有一点不一样.我学习时是使用 Webpack 2.6.1 版本,因此我就寻思着基于 zhangwang<<入门 Webpack,看这篇就够了>> 写下这篇 Webpack 2.x 的入门实战,是我学习 Webpack 的记录.据说 Webpack 3.x 版本快要出了,不得不感叹前端领域发展的真是太快了!javascript

Webpack 是什么?

Webpack 是前端资源模块化管理和打包工具。
Webpack 能够将许多松散的模块按照依赖和规则打包成符合生产环境部署的前端资源。
Webpack 能够将按需加载的模块进行代码分隔,等到实际须要的时候再异步加载。
Webpack 经过 loader 的转换,任何形式的资源均可以视做模块,好比 CommonJs 模块、 AMD 模块、 ES6 模块、CSS、图片、 JSON、Coffeescript、 LESS、 SASS 等。

一图胜千言,下图足够说明上面巴巴拉拉一大堆是啥了!css

对于模块的组织,一般有以下几种方法:html

  • 分开写几个 js 文件,使用 script 标签加载.
  • CommonJS 进行同步加载, Node.js 就使用这种方式.
  • AMD进行异步加载, require.js 使用这种方式.
  • 新的 ES6 模块.

Webpack 的特色

  • 丰富的插件,流行的插件都有,方便进行开发工做.
  • 大量的加载器,便于处理和加载各类静态资源.
  • 将按需加载的模块进行代码分隔,等到实际须要的时候再异步加载.

Webpack 的优点

  • Webpack 以 commonJS 的形式来书写脚本,但对 AMD / CMD / ES6 模块 的支持也很全面,方便旧项目进行代码迁移。
  • 全部资源都能模块化。
  • 开发便捷,能替代部分 Grunt / Gulp 的工做,好比打包、压缩混淆、图片转 base6四、SASS 解析成 CSS 等。
  • 扩展性强,插件机制完善,特别是支持模块热替换(见 模块热替换 )的功能让人眼前一亮。

Webpack 与 Grunt / Gulp

在没有学习 Webpack 以前我对 Webpack、Grunt、Gulp 的认识很模糊,只知道好像这三个东西都是前端自动化工具,都是用来使前端自动化、模块化、工程化的,这三者是能够替代彼此的前端工具.前端

其实 Webpack 和 Gulp / Grunt 并无太多的可比性,Gulp / Grunt 是一种可以优化前端开发流程的自动化工具,而 Webpack 是一种模块化的解决方案,不过 Webpack 的优势使得 Webpack 能够替代 Gulp / Grunt 一部分工做。java

Grunt / Gulp 的工做方式是:在一个配置文件中,指明对某些文件须要进行哪些处理,例如:编译、组合、压缩等任务的具体步骤,Grunt / Gulp 以后能够自动替你完成这些任务。Grunt / Gulp的工做流程以下图:node

Webpack 的工做方式是:把你的项目当作一个总体,经过一个给定的主文件( 如:index.js ),Webpack 将从这个文件开始找到你的项目的全部依赖文件,使用 loaders 处理它们,最后打包为一个浏览器可识别的 JavaScript 文件。Webpack工做方式以下图:

 

Webpack

若是实在要进行比较,Webpack 的处理速度更快更直接,由于 Webpack 的历史包袱小.Webpack 还能打包更多不一样类型的文件。react

开始使用 Webpack

初步了解 Webpack 后,就能够开始学习使用 Webpack。这里会以一个小的 Demo 为例子来一步一步进行动手学习!webpack

新建 Webpack 项目

1. 新建一个文件夹,命名为 webpack-demo,webpack-demo 就是你的项目名,项目名建议使用小写字母,而且不带空格,不能含有大写字母.git

2. 安装 Webpack,Webpack 可使用 npm 安装,若是你还不知道 npm 为什么物,请 Google,也能够参考 Node.js 安装配置NPM 使用介绍快速了解、安装 npm.github

使用终端在该文件夹中执行下述指令就能够完成安装,因为网络缘由安装过程可能须要一些时间。

//全局安装
npm install -g webpack
//安装到你的项目目录
npm install --save-dev webpack

Webpack 能够全局安装,也能够安装到你的项目目录.刚开始学习 Webpack 为了方便,建议同时全局安装和安装到你的项目目录.

3. 在 webpack-demo 文件夹中建立一个 package.json 文件,这是一个标准的 npm 说明文件,里面蕴含了丰富的信息,包括当前项目的依赖模块,自定义的脚本任务等等。在终端中使用 npm init 命令能够自动建立这个 package.json 文件.

npm init

 

输入这个命令后,终端会问你一系列诸如项目名称,项目版本,项目描述,入口文件,做者等信息,不过不用担忧,若是你不许备在 npm 中发布你的模块,这些问题的答案都不重要,回车默认便可.这些信息从此均可以更改 package.json 来修改,因此不用担忧.

4. 在 webpack-demo 文件夹中建立两个文件夹 app 文件夹和 public 文件夹, app 文件夹用来存放原始数据,例如: SASS 文件、LESS 文件、JavaScript 模块等,public 文件夹用来存放通过 Webpack 处理过的 app 文件夹数据,这也是准备给浏览器读取的数据,其中包括使用 Webpack 打包后的 js 文件等。在这里还须要在 public 文件夹中建立 index.html 文件.在 app 文件夹中建立 Greeter.js 和 main.js 文件,此时项目结构以下图所示:

5. 在 public 文件夹中的 index.html 文件只有最基础的 html 代码,它惟一的目的就是加载打包后的 js 文件 bundle.js.

 

// index.html

<!DOCTYPE html>
<html lang="zh">

<head>
    <meta charset="UTF-8">
    <title>webpack-demo</title>
</head>

<body>
    <div id='root'>
    </div>
    <script type="text/javascript" src="bundle.js"></script>
</body>

</html>

6. 在 app 文件夹中的 Greeter.js 只包括一个用来返回问候信息的 html 元素的函数。

// Greeter.js

module.exports = function() {
    var greet = document.createElement('div');
    greet.textContent = "Hi there and greetings!";
    return greet;
}


7. 在 app 文件夹中的 main.js 用来把 Greeter 模块(其实能够简单的把它看做 Greeter.js)返回的节点插入页面。

// main.js

var greeting = require('./Greeter.js');
document.getElementById('root').appendChild(greeting());

Webpack 配置文件

Webpack 配置文件其实也是一个简单的 JavaScript 模块,能够把全部与项目构建相关的信息放在里面。在 webpack-demo 文件夹根目录下新建一个名为 webpack.config.js 的文件,并在其中进行最简单的配置.以下所示,它包含入口文件路径和存放打包后文件的地方路径。

// webpack.config.js

module.exports = {
    entry: __dirname + "/app/main.js", //入口文件路径
    output: {
        path: __dirname + "/public/", //存放打包后文件的地方路径
        filename: "bundle.js" //打包后的文件名
    }
}
注:__dirname 是 node.js 中的一个全局变量,它指向当前 js 文件所在的目录.

如今只须要在终端里运行 webpack 命令就能够了,这条命令会自动参考 webpack.config.js 文件中的配置选项打包你的项目,输出结果以下:

 

此时项目的 public 文件夹下也会出现打包好的 bundle.js 文件.此时项目结构以下图所示:

能够看出 webpack 同时编译了 main.js 和 Greeter.js,打开 public 目录下的 index.html 文件,就能够看到最终效果,以下图:

利用 npm 更快捷的执行打包任务

经过 Webpack 配置文件和执行 webpack 命令实际上是比较烦人且容易出错的,不过值得庆幸的是 npm 能够引导任务执行,对其进行配置后可使用简单的 npm start 命令来代替这些繁琐的命令。在 package.json 中对 npm 的脚本部分进行相关设置,至关于把 npm 的 start 命令指向 webpack 命令,设置方法以下:

// package.json

{
    "name": "webpack-demo",
    "version": "1.0.0",
    "description": "",
    "scripts": {
        "start": "webpack"
    },
    "author": "",
    "license": "ISC"
}

执行 npm start 后命令行的输出显示:

如今只须要使用 npm start 就能够打包文件了.打开 public 目录下的 index.html 文件,看到的最终效果是否是与以前的同样.

利用 Webpack 生成 Source Maps

简单说,Source Maps 就是一个信息文件,里面储存着位置信息。也就是说,转换后的代码的每个位置,所对应的转换前的位置.有了它,出错的时候,除错工具将直接显示原始代码,而不是转换后的代码。这无疑给开发者带来了很大方便.为了方便调试能够利用 Webpack 生成 Source Maps.

在 Webpack 的配置文件中配置 Source Maps,须要配置 devtool,它有如下四种不一样的配置选项,各有优缺点,描述以下:

  • source-map 在一个单独的文件中产生一个完整且功能彻底的文件。这个文件具备最方便调试的 Source Maps,可是这个文件会比较大,会减慢打包文件的构建速度.
  • cheap-module-source-map 在一个单独的文件中生成一个不带列映射的 Source Maps,不带列映射可以提升项目构建速度,但这也使得浏览器开发者工具只能对应到具体的行,不能对应到具体的列,会对调试形成不便.
  • eval-source-map 在同一个文件中生成干净的完整的 Source Maps。这个选项能够在不影响构建速度的前提下生成完整的 Source Maps,可是对打包后输出的 js 文件的执行具备性能和安全的隐患。不过在开发阶段这是一个很是好的选项,可是在生产阶段必定不要用这个选项.
  • cheap-module-eval-source-map 这是在打包文件时最快的生成 Source Maps 的方法,生成的Source Map 会和打包后的 js 文件同行显示,没有列映射,和 eval-source-map 选项具备类似的缺点,文件的执行具备性能和安全的隐患.

上述选项由上到下打包速度愈来愈快,不过同时也具备愈来愈多的负面做用,较快的构建速度的后果就是对打包的文件执行有必定影响。在学习阶段以及在小到中型的项目上,eval-source-map是一个很好的选项,不过记得只在开发阶段使用它.

编辑 webpack-demo 文件夹下的 webpack.config.js 文件配置 devtool 选项,生成 Source Maps 文件.配置 devtool 后的 webpack.config.js 文件以下:

// webpack.config.js

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

执行 npm start 命令后就能生成对应的 Source Maps,终端输出信息以下图:

 

此时项目中 public 文件夹下也生成了名为 bundle.js.map 的 Source Maps 文件.此时项目结构以下图所示:

使用 Webpack 构建本地服务器

想不想让你的浏览器监测你修改的代码,并自动刷新修改后的结果.其实 Webpack 提供一个可选的本地开发服务器,这个本地服务器基于 node.js 构建,能够实现你想要的这些功能,不过它是一个单独的组件,在 Webpack 中进行配置以前须要单独安装它做为项目依赖.在终端中输入下面的指令安装对应组件.建议同时全局安装和安装到你的项目目录.

//全局安装
npm install -g webpack-dev-server
//安装到你的项目目录
npm install --save-dev webpack-dev-server

devserver 做为 Webpack 配置选项中的一项,具备如下配置选项

  • contentBase 默认 webpack-dev-server 会为根文件夹提供本地服务器,若是想为另一个目录下的文件提供本地服务器,应该在这里设置其所在目录(本例设置到“public"文件夹下).
  • port 设置默认监听端口,若是省略,默认为"8080".
  • inline 设置为 true,当源文件改变时会自动刷新页面.
  • historyApiFallback 在开发单页应用时很是有用,它依赖于 HTML5 history API,若是设置为 true,全部的跳转将指向 index.html.

编辑 webpack-demo 文件夹下的 webpack.config.js 文件配置以上选项.

// webpack.config.js

module.exports = {
    devtool: "source-map", //配置生成 Source Maps 的选项
    entry: __dirname + "/app/main.js", //入口文件路径
    output: {
        path: __dirname + "/public/", //存放打包后文件的地方路径
        filename: "bundle.js" //打包后的文件名
    },
    devServer: {
        contentBase: "./public",
        port: "9000",
        inline: true,
        historyApiFallback: true,
    }
}

在终端中输入以下命令,构建本地服务器:

webpack-dev-server

终端输出信息以下图,表示 Webpack 构建的本地服务器已启动.

在浏览器中打开 http://localhost:9000/ 就能够看到像以前同样的问候语页面.

也可使用 npm 更快捷的执行任务,编辑 webpack-demo 文件夹下的 package.json 文件 scripts 选项.

 

// package.json

{
    "name": "webpack-demo",
    "version": "1.0.0",
    "description": "",
    "scripts": {
        "start": "webpack",
        "dev": "webpack-dev-server --devtool eval --progress --content-base build"
    },
    "author": "",
    "license": "ISC"
}

在终端中执行 npm run dev 命令,输出信息以下图,同样能够启动的本地服务器.

 

 

Ctrl + C 便可退出本地服务器.

一切皆模块

Webpack 有一个不可不说的优势,它把全部的文件均可以当作模块处理,包括你的 JavaScript 代码,也包括 CSS 和 fonts 以及图片等等,只要经过合适的 Loaders,它们均可以被当作模块被处理.

Loaders

webpack 可使用 loader 来预处理文件。这容许你打包除 JavaScript 以外的任何静态资源.经过使用不一样的 loader,Webpack 经过调用外部的脚本或工具能够对任何静态资源进行处理,好比说分析 JSON 文件并把它转换为 JavaScript 文件,或者说把 ES6 / ES7 的 JS 文件转换为现代浏览器能够识别的 JS 文件.对 React 开发而言,合适的 Loaders 能够把 React 的 JSX 文件转换为 JS 文件.

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

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

继续动手实践,修改 app 文件夹下的 Greeter.js 文件,把问候消息放在一个单独的 JSON 文件里,经过 loader 的使 Greeter.js 能够读取该 JSON 文件.

1. 在 app 文件夹下建立 config.json 文件,并输入以下代码:

//config.json

{
    "greetText": "Hi there and greetings from JSON!"
}

2. 编辑 app 文件夹下的 Greeter.js 文件,修改后以下:

// Greeter.js

var config = require('./config.json');

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

3. 安装支持导入 JSON 文件的 json-loader .因为 webpack 2.× 默认支持导入 JSON 文件.若是你使用自定义文件扩展名,可能仍然须要使用此 loader.在终端中运行以下命令,安装 json-loader 到你的项目中.

//安装到你的项目中
npm install --save-dev json-loader

由于 json-loader 安装到你的项目目录里了,因此 webpack-demo 项目下会新增一个 node_modules 文件夹用于存放安装的 json-loader.此时的项目结构以下:

                                                                                 

4. 编辑 webpack.config.js 文件配置 modules 选项,添加 json-loader,编辑后的文件以下:

 

// webpack.config.js

module.exports = {
    devtool: "source-map", //配置生成 Source Maps 的选项
    entry: __dirname + "/app/main.js", //入口文件路径
    output: {
        path: __dirname + "/public/", //存放打包后文件的地方路径
        filename: "bundle.js" //打包后的文件名
    },
    devServer: {
        contentBase: "./public",
        port: "9000",
        inline: true,
        historyApiFallback: true,
    },
    module: {
        loaders: [{
            test: /\.json$/,
            loader: "json-loader"
        }]
    }
}

在终端中输入 npm start 从新编译打包,再在浏览器中打开 public 文件夹下的 index.html 文件,若是看到和下图同样的,就说明 json-loader 配置成功了.

Babel

Babel 实际上是一个编译 JavaScript 的平台,它的强大之处表如今能够经过编译帮你达到如下目的:

  • 把 ES6 / ES7 标准的 JavaScript 转化为浏览器可以解析的 ES5 标准的 JavaScript.
  • 使用基于 JavaScript 进行了拓展的语言,好比 React 的 JSX.

Babel的安装与配置

Babel 实际上是几个模块化的包,其核心功能位于称为 babel-core 的 npm 包中,不过 Webpack 把它们整合在一块儿使用,可是对于每个你须要的功能或拓展,你都须要安装单独的包.用得最多的是解析 ES6 的 babel-preset-es2015 包和解析 JSX 的 babel-preset-react 包.

先来安装这些依赖包,输入以下命令,把这些依赖包安装到你的项目中.

// 利用 npm 一次性安装多个依赖模块,模块之间用空格隔开
npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react

//安装 React 和 React-DOM
npm install --save react react-dom

编辑 webpack.config.js 文件配置 modules 选项,添加 Babel 配置,编辑后的文件以下:

// webpack.config.js

module.exports = {
    devtool: "source-map", //配置生成 Source Maps 的选项
    entry: __dirname + "/app/main.js", //入口文件路径
    output: {
        path: __dirname + "/public/", //存放打包后文件的地方路径
        filename: "bundle.js" //打包后的文件名
    },
    devServer: {
        contentBase: "./public",
        port: "9000",
        inline: true,
        historyApiFallback: true,
    },
    module: {
        loaders: [{
            test: /\.json$/,
            loader: "json-loader"
        }, {
            test: /\.js$/,
            exclude: /node_modules/, //编译打包时须要排除 node_modules 文件夹
            loader: "babel-loader",
            query: {
                presets: ['es2015', 'react']
            }
        }]
    }
}

使用 ES6 的语法,更新 app 文件夹下的 Greeter.js 文件,并返回一个 React 组件,修改后的代码以下:

// Greeter.js

import React, { Component } from 'react';
import config from './config.json';

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

    export default Greeter;

使用 ES6 的模块定义和渲染 Greeter 模块,修改 app 文件夹下的 main.js 文件,修改后的代码以下:

// main.js

import React from 'react';
import {render} from 'react-dom';
import Greeter from './Greeter';

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

在终端中运行 npm start 命令从新编译打包,终端输出信息以下:

 

在浏览器中打开 public 文件夹下的 index.html 文件,若是看到和下图同样的,就说明已经成功配置了 Babel.

 

Babel的配置选项

Babel 其实能够彻底在 webpack.config.js 文件中进行配置,可是考虑到 babel 具备很是多的配置选项,在单一的 webpack.config.js 文件中进行配置每每使得这个文件显得太复杂,所以一些开发者支持把 babel 的配置选项放在一个单独的名为 ".babelrc" 的配置文件中。咱们如今的 babel 的配置并不算复杂,不过以后咱们会再加一些东西,所以如今咱们就提取出相关部分,分两个配置文件进行配置, Webpack 会自动调用 .babelrc 里的 babel 配置选项.

编辑 webpack.config.js 文件配置 modules 选项,添加 Babel 配置,编辑后的文件以下:

// webpack.config.js

module.exports = {
    devtool: "source-map", //配置生成 Source Maps 的选项
    entry: __dirname + "/app/main.js", //入口文件路径
    output: {
        path: __dirname + "/public/", //存放打包后文件的地方路径
        filename: "bundle.js" //打包后的文件名
    },
    devServer: {
        contentBase: "./public",
        port: "9000",
        inline: true,
        historyApiFallback: true,
    },
    module: {
        loaders: [{
            test: /\.json$/,
            loader: "json-loader"
        }, {
            test: /\.js$/,
            exclude: /node_modules/, //编译打包时须要排除 node_modules 文件夹
            loader: "babel-loader"
        }]
    }
}

 在 webpack-demo 文件夹下新建 .babelrc 文件,添加以下代码:

// .babelrc

{
    "presets": ['es2015', 'react']
}

在终端中运行 npm start 命令从新编译打包,终端输出信息以下:

在浏览器中打开 public 文件夹下的 index.html 文件,若是看到和下图同样的,就说明已经成功配置了 Babel.

CSS

Webpack 提供两个工具处理样式表,css-loader 和 style-loader.

  • css-loader 使你可以使用相似 @import 和 url(...) 的方法实现 require() 的功能
  • style-loader 将全部的计算后的样式加入页面中

两者组合在一块儿使你可以把样式表嵌入 Webpack 打包后的 JS 文件中。

先来安装 css-loader, style-loader,输入以下命令,把这些依赖包安装到你的项目中.

npm install --save-dev style-loader css-loader

编辑 webpack.config.js 文件配置 modules 选项,添加处理样式表配置,编辑后的文件以下:

// webpack.config.js

module.exports = {
    devtool: "source-map", //配置生成 Source Maps 的选项
    entry: __dirname + "/app/main.js", //入口文件路径
    output: {
        path: __dirname + "/public/", //存放打包后文件的地方路径
        filename: "bundle.js" //打包后的文件名
    },
    devServer: {
        contentBase: "./public",
        port: "9000",
        inline: true,
        historyApiFallback: true,
    },
    module: {
        loaders: [{
            test: /\.json$/,
            loader: "json-loader"
        }, {
            test: /\.js$/,
            exclude: /node_modules/, //编译打包时须要排除 node_modules 文件夹
            loader: "babel-loader"
        }, {
            test: /\.css$/,
            loader: 'style-loader!css-loader' //添加对样式表的处理,感叹号的做用在于使同一文件可以使用不一样类型的 loader
        }]
    }
}

接下来,在 app 文件夹里建立一个名为 main.css 的文件,在文件中添加以下代码,对一些元素设置样式.

// 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;
}
Webpack 只有单一的入口,其它的模块须要经过 import, require, url 等导入相关位置,为了让 Webpack 能找到 main.css 文件,咱们把它导入 app 文件夹下的 main.js 中.修改 app 文件夹下的 main.js 文件,修改后的代码以下:
// main.js

import React from 'react';
import {render} from 'react-dom';
import Greeter from './Greeter';
import './main.css'; //导入css文件

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

在终端中运行 npm start 命令从新编译打包,终端输出信息以下:

 

在浏览器中打开 public 文件夹下的 index.html 文件,若是看到和下图同样的,就说明已经配置成功了.

 

一般状况下,css 会和 js 打包到同一个文件中,并不会打包为一个单独的 css 文件,不过经过合适的配置 Webpack 也能够把 css 打包为单独的文件的。
不过这也只是 Webpack 把 css 当作模块而已,继续看一个真的 CSS 模块的实践.

CSS module

在过去的一些年里,JavaScript 经过一些新的语言特性、更好的工具、更好的实践方法(好比说模块化)发展得很是迅速。模块使得开发者把复杂的代码转化为小的、干净的、依赖声明明确的单元,且基于优化工具,依赖管理和加载管理能够自动完成。

不过前端的另一部分,CSS 的发展就相对慢一些,大多的样式表却依旧是巨大且充满了全局类名,这使得维护和修改都很是困难和复杂。

CSS modules 的技术就可以把 JS 的模块化思想带入 CSS 中来,经过 CSS 模块,全部的类名,动画名默认都只做用于当前模块.

Webpack 从一开始就对 CSS 模块化提供了支持,在 CSS loader 中进行配置后,你所须要作的一切就是把 modules 传递到须要的地方,而后就能够直接把 CSS 的类名传递到组件的代码中,且这样作只对当前组件有效,没必要担忧在不一样的模块中具备相同的类名可能会形成的问题。

编辑 webpack.config.js 文件配置 modules 选项,添加处理样式表配置,编辑后的文件以下:

// webpack.config.js

module.exports = {
    devtool: "source-map", //配置生成 Source Maps 的选项
    entry: __dirname + "/app/main.js", //入口文件路径
    output: {
        path: __dirname + "/public/", //存放打包后文件的地方路径
        filename: "bundle.js" //打包后的文件名
    },
    devServer: {
        contentBase: "./public",
        port: "9000",
        inline: true,
        historyApiFallback: true,
    },
    module: {
        loaders: [{
            test: /\.json$/,
            loader: "json-loader"
        }, {
            test: /\.js$/,
            exclude: /node_modules/, //编译打包时须要排除 node_modules 文件夹
            loader: "babel-loader"
        }, {
            test: /\.css$/,
            loader: 'style-loader!css-loader?modules' //跟前面相比就在后面加上了 ?modules
        }]
    }
}

接下来,在 app 文件夹里建立一个名为 Greeter.css 的文件,在文件中添加以下代码,对一些元素设置样式.

// Greeter.css

.root {
    background-color: #eee;
    padding: 10px;
    border: 3px solid #ccc;
}

导入 .root 到 Greeter.js 中,修改 app 文件夹下的 Greeter.js 文件,修改后的代码以下:

// Greeter.js

import React, { Component } from 'react';
import config from './config.json';
import styles from './Greeter.css'; //导入 .root 到 Greeter.js 中

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

    export default Greeter;

在终端中运行 npm start 命令从新编译打包,终端输出信息以下:

在浏览器中打开 public 文件夹下的 index.html 文件,若是看到和下图同样的,就说明已经配置成功了.

 

CSS modules 也是一个很大的主题,有兴趣的话能够去官方文档查看更多消息.下面两篇文章也能够看看:

CSS 预处理器

CSS 预处理器能够将 SASS、LESS 文件转化为浏览器可识别的 CSS 文件,如下是经常使用的CSS 预处理器 loaders.

  • Less Loader
  • Sass Loader
  • Stylus Loader

其实也存在一个 CSS 的处理平台 PostCSS,它能够帮助你的 CSS 实现更多的功能,能够看看<<PostCSS 是个什么鬼东西?>>.

举例来讲如何使用 PostCSS,咱们使用 PostCSS 来为 CSS 代码自动添加适应不一样浏览器,不一样版本的 CSS 前缀。首先安装 postcss-loader 和 autoprefixer(自动添加前缀的插件),安装到你的项目中.

npm install --save-dev postcss-loader autoprefixer

 

 编辑 webpack.config.js 文件配置 modules 选项,添加 postcss-loader 处理样式表配置,编辑后的文件以下:

// webpack.config.js

module.exports = {
    devtool: "source-map", //配置生成 Source Maps 的选项
    entry: __dirname + "/app/main.js", //入口文件路径
    output: {
        path: __dirname + "/public/", //存放打包后文件的地方路径
        filename: "bundle.js" //打包后的文件名
    },
    devServer: {
        contentBase: "./public",
        port: "9000",
        inline: true,
        historyApiFallback: true,
    },
    module: {
        loaders: [{
            test: /\.json$/,
            loader: "json-loader"
        }, {
            test: /\.js$/,
            exclude: /node_modules/, //编译打包时须要排除 node_modules 文件夹
            loader: "babel-loader"
        }, {
            test: /\.css$/,
            loader: 'style-loader!css-loader?modules!postcss-loader' //跟前面相比就在后面加上了 !postcss-loader
        }]
    }
}

在 webpack-demo 文件夹下新建 postcss.config.js 文件,添加以下代码:

// postcss.config.js

module.exports = {
    plugins: [
        //调用autoprefixer插件,还能够配置选项添加须要兼容的浏览器版本.
        require("autoprefixer")({ browsers: ['ie>=8', '>1% in CN'] })
    ]
}

如今你写的样式会自动根据 Can i use 里的数据添加不一样前缀了.在终端中运行 npm start 命令从新编译打包,终端输出信息以下:

 

在浏览器中打开 public 文件夹下的 index.html 文件,若是看到和下图同样的,就说明已经成功配置了 PostCSS.

 

 

 

插件(Plugins)

插件(Plugins)是用来拓展 Webpack 功能的,它会在整个构建过程当中生效,执行相关的任务。
Loaders 和 Plugins 经常被弄混,可是他们实际上是彻底不一样的东西,能够这么说,Loaders 是在打包构建过程当中用来处理源文件的(JSX,Scss,Less..),一次处理一个;插件并不直接操做单个文件,它直接对整个构建过程其做用。

Webpack 有不少内置插件,同时也有不少第三方插件,可让咱们完成更加丰富的功能。

使用插件的方法

要使用某个插件,咱们须要经过 npm 安装它,而后要作的就是在 Webpack 配置中的 Plugins 关键字部分添加该插件的一个实例.

编辑 webpack.config.js 文件配置 Plugins 选项,添加一个实现版权声明的 BannerPlugin 插件,BannerPlugin 是内置插件不须要使用 npm 安装.编辑后的文件以下:

// webpack.config.js

var webpack = require("webpack");
module.exports = {
    devtool: "source-map", //配置生成 Source Maps 的选项
    entry: __dirname + "/app/main.js", //入口文件路径
    output: {
        path: __dirname + "/public/", //存放打包后文件的地方路径
        filename: "bundle.js" //打包后的文件名
    },
    devServer: {
        contentBase: "./public",
        port: "9000",
        inline: true,
        historyApiFallback: true,
    },
    module: {
        loaders: [{
            test: /\.json$/,
            loader: "json-loader"
        }, {
            test: /\.js$/,
            exclude: /node_modules/, //编译打包时须要排除 node_modules 文件夹
            loader: "babel-loader"
        }, {
            test: /\.css$/,
            loader: 'style-loader!css-loader?modules!postcss-loader' //跟前面相比就在后面加上了 !postcss-loader
        }]
    },
    plugins: [
        new webpack.BannerPlugin("Copyright Flying Unicorns inc.")//在这个数组中new一个实例就能够了
    ]
}

在终端中运行 npm start 命令从新编译打包,终端输出信息以下:

在浏览器中打开 public 文件夹下的 index.html 文件,若是看到和下图同样的,就说明已经成功配置了 BannerPlugin 插件.

 

经常使用插件

给你们推荐几个经常使用的插件

HtmlWebpackPlugin

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

安装 HtmlWebpackPlugin 到你的项目中
npm install --save-dev html-webpack-plugin

在使用 HtmlWebpackPlugin 以前,须要对 webpack-demo 项目结构作一些改变.

1. 移除 public 文件夹.

2. 在 app 目录下,建立一个文件名为 index.tmpl.html 模板文件,在编译过程当中,HtmlWebpackPlugin 插件会依据此模板生成最终的 html 页面,会自动添加所依赖的 css、 js、favicon等文件.index.tmpl.html 模板文件代码以下:

// index.tmpl.html

<!DOCTYPE html>
<html lang="zh">

<head>
    <meta charset="UTF-8">
    <title>webpack-demo</title>
</head>

<body>
    <div id="root"></div>
</body>

</html>

3. 在 webpack-demo 文件夹下新建一个 build 文件夹用来存放最终的输出文件.

4. 编辑 webpack.config.js 文件配置 Plugins 选项,添加 HtmlWebpackPlugin 插件,修改 output 选项.编辑后的文件以下:

// webpack.config.js

var webpack = require("webpack");
var HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    devtool: "source-map", //配置生成 Source Maps 的选项
    entry: __dirname + "/app/main.js", //入口文件路径
    output: {
        path: __dirname + "/build/", //存放打包后文件的地方路径
        filename: "bundle.js" //打包后的文件名
    },
    devServer: {
        contentBase: "./public",
        port: "9000",
        inline: true,
        historyApiFallback: true,
    },
    module: {
        loaders: [{
            test: /\.json$/,
            loader: "json-loader"
        }, {
            test: /\.js$/,
            exclude: /node_modules/, //编译打包时须要排除 node_modules 文件夹
            loader: "babel-loader"
        }, {
            test: /\.css$/,
            loader: 'style-loader!css-loader?modules!postcss-loader' //跟前面相比就在后面加上了 !postcss-loader
        }]
    },
    plugins: [
        new webpack.BannerPlugin("Copyright Flying Unicorns inc."), //在这个数组中new一个实例就能够了
        new HtmlWebpackPlugin({
            template: __dirname + "/app/index.tmpl.html" //new一个插件的实例,并传入相关的参数
        })
    ]
}

此时项目结构以下图所示:


                                                         

 

在终端中运行 npm start 命令从新编译打包,终端输出信息以下:

 

此时项目结构已经发生改变,build 文件夹下存放了最终的输出的文件,项目结构以下图所示:

                               

 

在浏览器中打开 build 文件夹下的 index.html 文件,若是看到和下图同样的,就说明已经成功配置了 HtmlWebpackPlugin 插件.

Hot Module Replacement

Hot Module Replacement(HMR)也是 Webpack 里颇有用的一个插件,它容许你在修改组件代码后,自动刷新实时预览修改后的效果。
在 Webpack 中使用 HMR 也很简单,只须要作两项配置.

  • 在 Webpack 配置文件中添加 HMR 插件
  • 在 Webpack Dev Server 中添加 hot 参数

不过配置完这些后,JS 模块其实仍是不能自动热加载的,还须要在你的 JS 模块中执行一个 Webpack 提供的 API 才能实现热加载,虽然这个 API 不难使用,可是若是是 React 模块,使用咱们已经熟悉的 Babel 能够更方便的实现功能热加载。

整理下思路,具体实现方法以下

  • Babel 和 Webpack 是独立的工具,两者能够一块儿工做,两者均可以经过插件拓展功能.
  • HMR 是一个 Webpack 插件,它让你能浏览器中实时观察模块修改后的效果,可是若是你想让它工做,须要对模块进行额外的配额.
  • Babel 有一个叫作 react-transform-hrm 的插件,能够在不一样 React 模块进行额外的配置下让 HMR 正常工做.

编辑 webpack.config.js 文件配置 Plugins / devServer 选项,添加 Hot Module Replacement 插件.编辑后的文件以下:

// webpack.config.js

var webpack = require("webpack");
var HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    devtool: "source-map", //配置生成 Source Maps 的选项
    entry: __dirname + "/app/main.js", //入口文件路径
    output: {
        path: __dirname + "/build/", //存放打包后文件的地方路径
        filename: "bundle.js" //打包后的文件名
    },
    devServer: {
        port: "9000",
        inline: true,
        historyApiFallback: true,
        hot: true
    },
    module: {
        loaders: [{
            test: /\.json$/,
            loader: "json-loader"
        }, {
            test: /\.js$/,
            exclude: /node_modules/, //编译打包时须要排除 node_modules 文件夹
            loader: "babel-loader"
        }, {
            test: /\.css$/,
            loader: 'style-loader!css-loader?modules!postcss-loader' //跟前面相比就在后面加上了 !postcss-loader
        }]
    },
    plugins: [
        new webpack.BannerPlugin("Copyright Flying Unicorns inc."), //在这个数组中new一个实例就能够了
        new HtmlWebpackPlugin({
            template: __dirname + "/app/index.tmpl.html" //new一个插件的实例,并传入相关的参数
        }),
        new webpack.HotModuleReplacementPlugin() //热加载插件
    ]
}

安装 react-transform-hmr 插件

npm install --save-dev babel-plugin-react-transform react-transform-hmr

编辑在 webpack-demo 文件夹下的 .babelrc 文件,编辑后的文件以下:

// .babelrc

{
  "presets": ["react", "es2015"],
  "env": {
    "development": {
    "plugins": [["react-transform", {
       "transforms": [{
         "transform": "react-transform-hmr",
         "imports": ["react"],
         "locals": ["module"]
       }]
     }]]
    }
  }
}

编辑 webpack-demo 文件夹下的 package.json 文件 scripts 选项,添加 --hot 选项开启代码热替换.

// package.json

{
    "name": "webpack-demo",
    "version": "1.0.0",
    "description": "",
    "scripts": {
        "start": "webpack",
        "dev": "webpack-dev-server --devtool eval --progress --content-base build --hot"
    },
    "author": "",
    "license": "ISC"
}

在终端中执行 npm run dev 命令,输出信息以下图,同样能够启动自动热加载.

 

在浏览器中打开 http://localhost:9000/ 就能够看到像以前同样的问候语页面.

如今当你使用 React 时,就能够热加载模块了.按 Ctrl + C 便可退出自动热加载.

产品阶段的构建

咱们已经使用 Webpack 构建了一个完整的开发环境.可是在产品阶段,可能还须要对打包的文件进行额外的处理,好比说优化、压缩、缓存以及分离 CSS 和 JS.

对于复杂的项目来讲,须要复杂的配置,这时候分解配置文件为多个小的文件可使得事情层次分明,以 webpack-demo 项目来讲,咱们在 webpack-demo 文件夹下建立一个名为 webpack.production.config.js 的文件,在里面加上基本的配置代码,以下:

// webpack.production.config.js

var webpack = require("webpack");
var HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry: __dirname + "/app/main.js", //入口文件路径
    output: {
        path: __dirname + "/build/", //存放打包后文件的地方路径
        filename: "bundle.js" //打包后的文件名
    },
    module: {
        loaders: [{
            test: /\.json$/,
            loader: "json-loader"
        }, {
            test: /\.js$/,
            exclude: /node_modules/, //编译打包时须要排除 node_modules 文件夹
            loader: "babel-loader"
        }, {
            test: /\.css$/,
            loader: 'style-loader!css-loader?modules!postcss-loader' //跟前面相比就在后面加上了 !postcss-loader
        }]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: __dirname + "/app/index.tmpl.html" //new一个插件的实例,并传入相关的参数
        })
    ]
}

 

编辑 webpack-demo 文件夹下的 package.json 文件 scripts 选项,添加 build 选项,编辑后的文件以下:
// package.json

{
    "name": "webpack-demo",
    "version": "1.0.0",
    "description": "",
    "scripts": {
        "start": "webpack",
        "dev": "webpack-dev-server --devtool eval --progress --content-base build --hot",
        "build": "webpack --config ./webpack.production.config.js --progress"
    },
    "author": "",
    "license": "ISC"
}

在终端中执行 npm run build 命令,输出信息以下图:

说明分解配置文件为多个小的文件成功了.

优化插件

Webpack 提供了一些在发布阶段很是有用的优化插件,它们大多来自于 Webpack 社区,能够经过 npm 安装,经过如下插件能够完成产品发布阶段所需的功能.

  • OccurrenceOrderPlugin: 为组件分配 ID,经过这个插件 Webpack 能够分析和优先考虑使用最多的模块,并为它们分配最小的 ID.
  • UglifyJsPlugin:压缩JS代码.
  • ExtractTextPlugin:分离 CSS 和 JS 文件.

咱们来看看如何使用它们,OccurrenceOrderPlugin 和 UglifyJS plugins 都是内置插件,咱们只须要安装 ExtractTextPlugin 插件.

安装 ExtractTextPlugin 插件

npm install --save-dev extract-text-webpack-plugin

 

编辑 webpack.config.js 文件配置 Plugins 选项,添加这三个插件,由于要分离 css 因此还要配置 module 下的 loaders 选项.编辑后的文件以下:

 
// webpack.config.js

var webpack = require("webpack");
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
    devtool: "source-map", //配置生成 Source Maps 的选项
    entry: __dirname + "/app/main.js", //入口文件路径
    output: {
        path: __dirname + "/build/", //存放打包后文件的地方路径
        filename: "bundle.js" //打包后的文件名
    },
    devServer: {
        port: "9000",
        inline: true,
        historyApiFallback: true,
        hot: true
    },
    module: {
        loaders: [{
            test: /\.json$/,
            loader: "json-loader"
        }, {
            test: /\.js$/,
            exclude: /node_modules/, //编译打包时须要排除 node_modules 文件夹
            loader: "babel-loader"
        }, {
            test: /\.css$/,
            use: ExtractTextPlugin.extract({
                fallback: "style-loader",
                use: "css-loader?modules!postcss-loader"
            })
        }]
    },
    plugins: [
        new webpack.BannerPlugin("Copyright Flying Unicorns inc."), //在这个数组中new一个实例就能够了
        new HtmlWebpackPlugin({
            template: __dirname + "/app/index.tmpl.html" //new一个插件的实例,并传入相关的参数
        }),
        new webpack.HotModuleReplacementPlugin(), //热加载插件
        new webpack.optimize.OccurrenceOrderPlugin(),
        new webpack.optimize.UglifyJsPlugin(),
        new ExtractTextPlugin("style.css")
    ]
}

在终端中执行 npm start 命令,输出信息以下图:

此时项目结构已经发生改变,build 文件夹下多出了抽离出来的 style.css 文件还有对应的 style.css.map 文件,项目结构以下图所示:

                                                                   

 

若是你打开 build 文件夹下的 bundle.js 文件,就能够看到 bundle.js 文件内容已经被压缩处理了.

说明这三个插件已经配置成功了.

缓存

为了加快加载速度,合理的利用缓存是必不可少的.使用缓存的最好方法是保证文件名和文件内容是匹配的.内容改变,名称也相应改变.

Webpack 能够把一个哈希值添加到打包文件的文件名中,添加特殊的字符串混合体([name], [id] and [hash])到输出文件名前,便于修改 BUG 之后,对应更新用户本地的缓存文件.

编辑 webpack.config.js 文件修改 output / plugins 选项.编辑后的文件以下:

// webpack.config.js

var webpack = require("webpack");
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
    devtool: "source-map", //配置生成 Source Maps 的选项
    entry: __dirname + "/app/main.js", //入口文件路径
    output: {
        path: __dirname + "/build/", //存放打包后文件的地方路径
        filename: "[name]-[hash].js" //打包后的文件名
    },
    devServer: {
        port: "9000",
        inline: true,
        historyApiFallback: true,
        hot: true
    },
    module: {
        loaders: [{
            test: /\.json$/,
            loader: "json-loader"
        }, {
            test: /\.js$/,
            exclude: /node_modules/, //编译打包时须要排除 node_modules 文件夹
            loader: "babel-loader"
        }, {
            test: /\.css$/,
            use: ExtractTextPlugin.extract({
                fallback: "style-loader",
                use: "css-loader?modules!postcss-loader"
            })
        }]
    },
    plugins: [
        new webpack.BannerPlugin("Copyright Flying Unicorns inc."), //在这个数组中new一个实例就能够了
        new HtmlWebpackPlugin({
            template: __dirname + "/app/index.tmpl.html" //new一个插件的实例,并传入相关的参数
        }),
        new webpack.HotModuleReplacementPlugin(), //热加载插件
        new webpack.optimize.OccurrenceOrderPlugin(),
        new webpack.optimize.UglifyJsPlugin(),
        new ExtractTextPlugin("[name]-[hash].css")
    ]
}

 

在终端中执行 npm start 命令,输出信息以下图:

此时项目 build 文件夹下的 main.css 和 main.js 文件都对应的加上了哈希值.项目结构以下图所示:

                                             

项目结构

若是你打开 build 文件夹下的 index.html 文件,就能够看到引用的 css、js 文件名也对应发生了改变,这样修改 BUG 之后,也能对应更新用户本地的缓存文件.

进阶,永不止步

其实到这里个人这篇 Webpack 2.x 的入门实战已经完结了!但这也只是个入门而已!在实际项目中运用仍是不够的,还有不少细节我并没深刻讲,因此你们还想进阶的话建议好好去看看 webpack-china 的文档.

另外实战项目 webpack-demo 的源码,我已经放到 Github 上去了,欢迎你们提意见.

还有一点我以为很重要,要学会看控制台输出信息,可以看控制台输出信息解决的问题,就不要上 Google 搜了!

鸣谢

这篇 Webpack 2.x 的入门实战是基于 zhangwang<<入门Webpack,看这篇就够了>> 写出来的,是我学习 Webpack 的实战记录.特别感谢 zhangwang 付出,若是你以为这篇文章对你有帮助,请转到 zhangwang 为他点个赞.


转载地址: https://www.jianshu.com/p/b83a251d53db
相关文章
相关标签/搜索