GitChat前端进击之路

Webpack 基本介绍

2019-06-24  本文已影响3人  进击的波拿拿

注:文章转载自 《透视前端工程化》

这个系列是我自己购买的课程内容,把比较干货的试读章节放在我的简书上,作为个人Mark。但其他篇目因为版权问题不好直接放,所以感兴趣的小伙伴们自取吧。


1 Webpack 的特点

图片来源于网络

Webpack 是一款强大的打包工具。在 Webpack 中一切皆模块。Webpack 官网的 banner 图完美地诠释了这一理念。Webpack 从一个入口文件开始递归地分析模块的依赖关系,根据依赖关系将这些模块打包成一个或多个文件。

目前几乎所有的前端构建和开发都是采用 Webpack 。因为 Webpack 有强大的社区生态,每月 Webpack 的下载量超过百万。通过 loader、plugin 支持 Webpack 与主流的前端框架和语言进行集成,比如 Vue、React、TypeScript。

2 Webpack 构建流程

Webpack 的构建流程是一种事件流机制。整个构建流程可以看成是一个流水线,每个环节负责单一的任务,处理完将进入下一个环节。Webpack 会在每个环节上发布事件,供内置的和自定义的插件有机会干预 Webpack 的构建过程,控制 Webpack 的构建结果。Webpack 的基本的构建流程图如下:

graph LR
A(初始化)-->B(开始编译)
B(开始编译)-->C(编译模块)
C(编译模块)-->D(编译完成)
D(资源输出)-->E(完成)

3 核心概念

入口

入口是 Webpack 进行构建的起点,Webpack 在构建过程中从入口文件开始,递归地编译模块,并分析模块间的依赖关系,最终得出依赖图。Webpack 依据该依赖图对模块进行组装,输出到最终的 bundle 文件中。

我们可以在Webpack 的配置文件中配置 entry 属性,来指定入口文件,入口文件可以是一个也可以指定多个。

我们来看一个例子:

// Webpack .config.js
module.exports = {
  entry: './src/app.js'
};

配置多个入口的场景常见于多页应用中。如果配置多个入口可以这样:

// Webpack .config.js
module.exports = {
  entry: {
    pageOne: './src/pageOne/app.js',
    pageTwo: './src/pageTwo/app.js'
  }
};
输出

配置 output 选项可以指示 Webpack 如何去输出、在哪里输出我们的静态资源文件。

我们通过一个例子来看一下 output 如何使用:

// Webpack .config.js
module.exports = {
  output: {
    filename: 'bundle.js',
    path: './dist'
  }
};

上例中,我们指示 Webpack 最终的输出文件名为 bundle.js ,输出的目录为 ./dist

loader

loader 的使用

Webpack 本身是不能处理非 js 资源的,但我们却可以在 Webpack 中引入 css、图片、字体等非 js 文件。例如:

// app.js
import Styles from './styles.css';

那么 Webpack 是如何实现的呢?

Webpack 中使用 loader 对非 js 文件进行转换。loader 可以在我们 import 或者加载模块时,对文件进行预处理,将非 js 的文件内容,最终转换成 js 代码。

loader 有三种使用方式:

在实际的应用中,绝大数都是采用配置的方式来使用,一方面在配置文件中,可以非常直观地看到某种类型的文件使用了什么 loader,另一方面,在项目复杂的情况下,便于进行维护。

我们通过一个简单的例子来看一下 loader 的使用:

// Webpack .config.js
module.exports = {
 module: {
    rules: [
      { test: /\.css$/, use: 'css-loader' }
    ]
  }
};

我们需要告诉 Webpack 当遇到 css 文件的时候,使用 css-loader 进行预处理。这里由于 css-loader 是单独的 npm 模块,使用前我们需要先进行安装:

npm install --save-dev css-loader

常用的 loader

Webpack 可以处理任何非 js 语言,得益于社区提供的丰富的 loader,日常开发中所使用到的 loader,都可以在社区找到。这里对一些常用的 loader 进行简要的说明。

plugin

插件的使用

插件是 Webpack 的非常重要的功能,Webpack 本身也是建立在插件系统之上的。插件机制极大增强了 Webpack 的功能,为 Webpack 增加了足够的灵活性。通过插件,我们可以在 Webpack 的构建过程中,引入自己的操作,干预构建结果。

我们通过一个示例来看一下插件的使用:

// Webpack .config.js
const HtmlWebpack Plugin = require('html-Webpack -plugin'); 
const Webpack  = require('Webpack '); 

const config = {
  plugins: [
    new Webpack .optimize.UglifyJsPlugin(),
    new HtmlWebpack Plugin({template: './src/index.html'})
  ]
};

module.exports = config;

示例中,我们用到了两个插件,一个是内置的 UglifyJsPlugin 插件,该插件对 js 进行压缩,减小文件的体积。一个是外部插件 HtmlWebpack Plugin,用来自动生成入口文件,并将最新的资源注入到 HTML 中。

常用的插件

4 如何使用 Webpack

下面我们通过一个简单的例子来看一下 Webpack 的使用。这里假定你已经安装了最新版本的 nodejs 和 npm,因为使用旧版本可能会遇到各种问题。

4.1 安装

创建 Webpack -demo 目录,初始化 npm,并且在 Webpack -demo 目录中安装 Webpack 和 Webpack -cli:

mkdir Webpack -demo && cd Webpack -demo
npm init -y
npm install Webpack  Webpack -cli --save-dev

Webpack -cli 用来在命令行中运行 Webpack 。这里建议本地安装 Webpack 和 Webpack -cli,因为全局安装的话,Webpack 的升级会影响到所有的项目。

接下来我们先在项目中新增一些目录和文件:

Webpack -demo
├── package.json
├── dist
├── index.html
└── src
    └── index.js

index.html 内容如下:

<!doctype html>
<html>
  <head>
    <title>Webpack -demo</title>
  </head>
  <body>
    <script src="./src/index.js"></script>
  </body>
</html>

src/index.js 内容如下:

function createEl() {
  var element = document.createElement('div')
  element.innerHTML = 'hello world'

  return element;
}

document.body.appendChild(createEl());

4.2 第一次构建

在命令行运行:

./node_modules/.bin/Webpack 

Hash: 2353b0d3d427eaa8a18a
Version: Webpack  4.29.6
Time: 175ms
Built at: 2019-04-03 22:08:36
  Asset   Size  Chunks             Chunk Names
main.js  1 KiB       0  [emitted]  main
Entrypoint main = main.js
[0] ./src/index.js 175 bytes {0} [built]

大家可以发现,我们并没有在配置文件中指定打包的入口和输出的出口,也没有在命令行中指定配置参数,但可以看到在 ./dist 目录下新增了一个 main.js。这是因为 Webpack 配置中 entry 的默认值为 ./src,出口的默认目录是 ./dist。

Webpack -demo
├── package.json
├── dist
|    └── main.js
├── index.html
└── src
     └── index.js

构建后的项目目录中新增了 main.js。

<!doctype html>
<html>
  <head>
    <title>Webpack -demo</title>
  </head>
  <body>
    <script src="./dist/main.js"></script>
  </body>
</html>

我们现在将 index.html 中的脚本引用修改为构建后的文件 ./dist/main.js,在浏览器预览,如果一切正常应该可以看到页面上会输出文本 hello world

4.3 使用配置文件

对于简单的构建,Webpack 基本可以做到零配置。但对于复杂的单页应用而言,则需要使用 Webpack 的配置文件来提供个性化的功能。

首先我们在项目根目录下新增 Webpack .config.js 文件:

// Webpack .config.js
const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
};

在配置文件中,通过 entry 指定了入口文件为 ./src/index.js,通过 output 指定了输出的目录为 ./dist,输出的文件名为 bundle.js。目录结构更新如下:

Webpack -demo
├── package.json
├── Webpack .config.js
├── index.html
├── dist
|    └── bundle.js
└── src
     └── index.js

同时为了调用简单,我们在 package.json 文件中设置快捷命令来调用 ./node_modules/.bin/Webpack

// package.json
{
  "scripts": {
    "build": "Webpack "
  }
}


再次执行构建命令:

npm run build
> Webpack -demo@1.0.0 build C:\work\tech\Webpack -demo
> Webpack 

Hash: d0fa6b1e011af414e622
Version: Webpack  4.29.6
Time: 157ms
Built at: 2019-04-03 22:42:50
 Asset   Size  Chunks             Chunk Names
bundle.js  1 KiB       0  [emitted]  main
Entrypoint main = bundle.js
[0] ./src/index.js 175 bytes {0} [built]

index.html 中的 script 引用链接修改为 ./dist/bundle.js,在浏览器中预览页面,不出意外的话会输出文本 hello world

4.4 使用插件

我们发现在构建的过程中,如果构建后的资源名称发生了变化,index.html 中对资源的引用会被动地跟着修改,非常不方便,我们引入 HtmlWebpack Plugin 来帮助我们自动生成入口文件,自动将生成的资源文件注入 index.html 中。

安装:

npm install --save-dev html-Webpack -plugin

配置:

const path = require("path");
const HtmlWebpack Plugin = require("html-Webpack -plugin");
module.exports = {
  entry: "./src/index.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "dist")
  },
  plugins: [new HtmlWebpack Plugin()]
};


在配置文件中,我们引入插件,并在 plugins 选项中,将插件实例化后添加到数组中。该插件会自动生成 index.html,因此原目录中的 index.html 文件可以删除。

Webpack -demo
├── package.json
├── Webpack .config.js
├── dist
|    └── bundle.js
└── src
     └── index.js

再次执行构建命令:

$ npm run build

> Webpack -demo@1.0.0 build C:\work\tech\Webpack -demo
> Webpack 

Hash: 39dc7567ef99a69140e7
Version: Webpack  4.29.6
Time: 1241ms
Built at: 2019-04-03 22:53:44
     Asset       Size  Chunks             Chunk Names
 bundle.js      1 KiB       0  [emitted]  main
index.html  182 bytes          [emitted]
Entrypoint main = bundle.js
[0] ./src/index.js 175 bytes {0} [built]


命令执行后我们发现我们的 ./dist 下多了一个 index.html 文件,并且 index.html 中的资源引用被自动更新为了 <script type="text/javascript" src="bundle.js"></script>

4.5 使用 loader 处理 css 文件

为了使 Webpack 可以处理 import 进来的 css 文件,我们需要安装并配置 style-loadercss-loader

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

修改 Webpack 的配置如下:

const path = require("path");
const HtmlWebpack Plugin = require("html-Webpack -plugin");
module.exports = {
  entry: "./src/index.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "dist")
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"]
      }
    ]
  },
  plugins: [new HtmlWebpack Plugin()]
};


如此一来,当 Webpack 匹配到后缀为 .css 的文件都会使用 css-loader 和 style-loader 进行处理。

接下来我们在 ./src 目录下新增一个样式文件 main.css。在样式中,设置文本的字体颜色为红色。

// main.css
div{color: red}

紧接着我们在 ./src/index.js 中引用 main.css:

import "./main.css";

function createEl() {
  var element = document.createElement("div");
  element.innerHTML = "hello world";

  return element;
}

document.body.appendChild(createEl());

执行构建命令:

$ npm run build

> Webpack -demo@1.0.0 build C:\work\tech\Webpack -demo
> Webpack 

Hash: f9fcb8cfd689f4b96ce6
Version: Webpack  4.29.6
Time: 2672ms
Built at: 2019-04-03 23:24:40
     Asset       Size  Chunks             Chunk Names
 bundle.js   6.85 KiB       0  [emitted]  main
index.html  182 bytes          [emitted]
Entrypoint main = bundle.js
[0] ./src/index.js 199 bytes {0} [built]
[1] ./src/main.css 1.05 KiB {0} [built]
[2] ./node_modules/css-loader/dist/cjs.js!./src/main.css 170 bytes {0} [built]
    + 3 hidden modules

在浏览器预览,不出意外字体的颜色已经变成了红色,打开浏览器调试工具,可以看到在 <head> 标签里插入了一个 <style> 标签。

<style type="text/css">
  div {
    color: red;
  }
</style>

通过以上完整的示例,我们演示了 Webpack 的核心的几个配置的使用方式,我们对 Webpack 的使用应该有了一个基本的认识。

Webpack 中还有很多其他有用的配置项,篇幅原因不做详细的介绍。大家可以查阅 官方文档自行配置和练习。

总结

本节我们对 Webpack 进行了总体的介绍。借助 loader、Webpack 可以处理一切资源,JS 的、非 JS 的,都可以。

通过插件,我们可以在 Webpack 的构建过程中的每个事件节点加入自己的行为,来影响 Webpack 的构建。对 Webpack 的使用有了认识后,接下来我们要以之为基础搭建起项目的基本框架。

点击了解《透视前端工程化》


作者简介:

王超,现任快狗打车(原58速运)前端负责人。

先后任职于人人网、奇虎360,8 年知名互联网工作经验。

从 0 到 1 组建了快狗前端团队,负责团队技术体系的搭建,形成了以 Webpack 和 Vue 为基础、 Node.js 中间层为补充的,自动化、工程化、组件化的快狗前端技术体系。

上一篇下一篇

猜你喜欢

热点阅读