webpack 学习总结

源码链接: 点我点我

为什要使用WebPack

现今的很多网页其实可以看做是功能丰富的应用,它们拥有着复杂的JavaScript代码和一大堆依赖包。为了简化开发的复杂度,前端社区涌现出了很多好的实践方法,比如说 模块化,Scss 和 less等CSS预处理器。

这些改进大大提高了我们的开发效率,但是利用它们开发的文件往往需要进行额外的处理才能让浏览器识别,而手动处理又是非常繁琐而且麻烦,这就为WebPack类的工具的出现提供了需求。

什么是Webpack

WebPack可以看做是模块打包机:它做的事情是,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其转换和打包为合适的格式供浏览器使用。

开始使用Webpack

千言万语不如实际操作一番,你会发现 webpack 不过如此。

安装

新建一个空的练习文件夹,在终端中转到该文件夹后执行下述指令就可以完成安装.

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

正式使用Webpack前的准备

  1. 在终端中执行一下命令,会创建一个 package.json 文件,这是一个标准的npm说明文件,里面蕴含了丰富的信息,包括当前项目的依赖模块,自定义的脚本任务等等。
1
npm init

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

  1. 接着安装 Webpack 作为依赖包

    1
    2
    // 安装Webpack
    npm install --save-dev webpack
  2. 回到之前的空文件夹,并在里面创建两个文件夹,app 文件夹和public文件夹,app文件夹用来存放原始数据和我们将写的JavaScript模块,public文件夹用来存放之后供浏览器读取的文件(包括使用webpack打包生成的js文件以及一个index.html文件)。接下来我们再创建三个文件:

  3. 1
    2
    3
    index.html --放在public文件夹中;
    Greeter.js-- 放在app文件夹中;
    main.js-- 放在app文件夹中;

此时项目结构如下图所示
image

index.html 文件中写入最基础的html代码,它在这里目的在于引入打包后的js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- index.html -->
<!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>

Greeter.js中定义一个返回包含问候信息的html元素的函数,并依据CommonJS规范导出这个函数为一个模块:

1
2
3
4
5
6
// Greeter.js
module.exports = function() {
var greet = document.createElement('div');
greet.textContent = "Hi there and greetings!";
return greet;
};

main.js文件中我们写入下述代码,用以把 Greeter 模块返回的节点插入页面。

1
2
3
//main.js
const greeter = require('./Greeter.js');
document.querySelector("#root").appendChild(greeter());

正式使用Webpack

经过前面的准备工作,我们现在就开始使用 Webpack,在终端中输出:

1
2
3
4
5
# webpack 全局安装
webpack
# webpack 非全局安装的情况
node_modules/.bin/webpack app/main.js public/bundle.js

结果如下:

image

可以看出webpack同时编译了main.jsGreeter,js,现在打开 index.html,可以看到如下结果:

image

说明我们已经成功用 webpack 打包了一个文件!但是我们一个项目中不仅仅打包一个文件这么简单,因此我们需要配置文件来处理复杂的开发需求。

通过配置文件来使用Webpack

当前练习文件夹的根目录下新建一个名为 webpack.config.js 的文件,我们在其中写入如下所示的简单配置代码

1
2
3
4
5
6
7
8
const path = require('path');
module.exports = {
entry: "./app/main.js", //唯一入口文件
output: {
path: path.resolve(__dirname, 'public'), //打包后的文件存放的地方
filename: 'bundle.js' //打包后输出文件的文件名
}
}

有了这个配置之后,再打包文件,只需在终端里运行webpack命令就可以了,这条命令会自动引用 webpack.config.js 文件中的配置选项。

NPM 脚本(NPM Scripts)

考虑到用 CLI 这种方式来运行本地的 webpack 不是特别方便,我们可以设置一个快捷方式。在 package.json 添加一个 npm 脚本(npm script):

package.json

1
2
3
4
5
6
7
{
...
"scripts": {
"build": "webpack"
},
...
}

以后我们可以执行 npm run build 来打包项目。

webpack 基础功能就是如此,但是 webpack 这时候还是一个残缺品,因为它只能处理 js 文件,还不能处理 css、less 或者图片等,Webpack 是通过一个叫 loader 的东西来解决这个问题。

Loaders

默认情况下 webpack 只认识js文件,如果你在 js 中 require 进一个 css 模块是无法打包成功的,这时候 loaders 出现了,它的作用就是将 css/scss/jpg 等文件转换成 module 并添加到依赖图中。

使用 loaders

Loaders 需要单独安装并且需要在 webpack.config.js 中的 modules 关键字下进行配置,下面以 style-loader 为例。

  1. 安装 style-loader

    1
    npm install style-loader --save-dev
  2. webpack.config.js

1
2
3
4
5
6
7
8
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
}
  1. 在 app 目录下新建一个 css 文件夹,并且新建一个 common.css 文件,在 main.js require 进来。

common.css:

1
2
3
#root{
color: red;
}

main.js:

1
2
3
4
const commonCss = require('./css/common.css');
const greeter = require('./Greeter.js');
document.querySelector("#root").appendChild(greeter());

运行 npm start 后再打开 index.html ,发现字体颜色已经变成红色。

读者可以尝试将 style-loader 去掉看看报错信息。

还有图片loader、font loader 等等都可以在官网的教程中提到:
Webpack-guide

Webpack 不仅仅有 loader,还有另一个强大的功能——plugin

plugin

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

与loader 的比较

Loaders和Plugins常常被弄混,但是他们其实是完全不同的东西,可以这么来说,loaders是在打包构建过程中用来处理源文件的(Scss,Less..),一次处理一个,插件并不直接操作单个文件,它直接对整个构建过程其作用。

插件使用

比如说 webpack-dev-server 插件,该插件提供了一个简易的 web Server 和热更新功能。

  1. 安装
1
npm install --save-dev webpack-dev-server
  1. webpack.config.js
1
2
3
4
5
devServer: {
contentBase: "./public",//本地服务器所加载的页面所在的目录
hot: true //开启热更新功能
}
  1. package.json
1
2
3
4
5
{
"scripts": {
"start": "webpack-dev-server --open"
},
}

我们在命令行中输入 npm start 后,会看到浏览器自动加载我们的页面。如果改变了源代码,web server 会在编译后自动重载页面,也就是热更新功能。

PS:webpack-dev-middleware 内置于 webpack-dev-server 中,但它是一个独立的插件,用处是将 webpack 处理过的文件发送给服务器。我们抛弃 webpack-dev-server 插件,运用 webpack-dev-middleware 插件能够获得更多自定义的设置。比如说跟 express 服务器结合。其中 vue-cli 的脚手架就是这么做的。其中的好处待研究,官网有教程。


以上内容解释了什么是 loader 和 plugin,但是日常项目中我们会遇到多页面的情况,解决这个问题我们就需要了解 Entry 这个概念。


Entry

Webpack 创建了一个包含所有依赖的图,这个图的起点就是 entry point。entry point 告诉 webpack 在依赖图中的打包起始点和打包内容。你可以将 entry 看做是 webpack 打包的起始点。

一个最简单的例子就是:

1
2
3
4
module.exports = {
entry: "./app/main.js"
}

多页面

现在来解决我们多页面开发的问题

准备工作

在 app 目录下新增一个 hello.js 文件,在 public 文件下新增一个 temple.html 文件。

hello.js

1
document.querySelector("#root").style.color = 'red';;

temple.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Sample 2</title>
<style>
</style>
</head>
<body>
<div id='root'>
hello world
</div>
</body>
</html>

开始配置

  1. 多入口 Entry 配置信息
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    module.exports = {
    entry: {
    app:'./app/main.js',
    hello: './app/hello.js'
    },
    output: {
    path: path.resolve(__dirname, 'public'), //打包后的文件存放的地方
    filename: '[name].bundle.js'
    }
    }

通过 npm run build 命令可以发现生成了 app.bundle.js 和 hello.bunlde.js 文件,我们打开 public 文件夹下面的生成的 html 文件就可以看到分别打包后效果。

  1. HtmlWebpackPlugin

为了避免每次都要在 html 文件中修改 js 名称和路径,有一个 HtmlWebpackPlugin 帮助我们自动化了这个过程。

2.1 安装

1
npm install --save-dev html-webpack-plugin

2.2 webpack.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const HtmlWebpackPlugin = require('html-webpack-plugin');
plugins: [
// OccurenceOrderPlugin is needed for webpack 1.x only
new HtmlWebpackPlugin({
template: 'temple.html', //模板文件
chunks: ['app'] //设置未入口的配置的字段
}),
new HtmlWebpackPlugin({
template: 'temple.html',
chunks: ['hello'],
filename: 'index-2.html'
})
],

注意:根据官网的解释,我们想要生成 html 页面的数量要等于 HtmlWebpackPlugin 的数量
执行 npm run start,可以看出在 public 文件夹下生成了两个文件:index.html 和 index-2.html。

总结

至此,我们简单的过了一遍 Webpack 的使用场景、如何使用的问题,以及重要概念如 loader,plugin 和 entry,并且做到每个概念都有一个应用场景来解释其意义所在。

写到后面才发现其实 webpack 官网的教程已经很详细了,并且有相应的中文文档,帮助初学者快速上手,也省去了去网上找一些良莠不齐教程的时间。

参考资料。