1. 开发准备
在进入webpack世界之前,先用原生的方法构建一个web应用。
新建一个JavaScript文件,编写一段通用的函数helloworld:
function helloWolrd() {
console.log('Hello World');
}
新建index.js文件,在文件里面直接调用helloWorld函数:
helloWolrd();
最后再创建一个html文件去引用这两个js文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="./src/index.js"></script>
<script src="./src/helloworld.js"></script>
</body>
</html>
运行html文件之后会发现报如下错误:

说明helloWorld函数没有生效。将index.js与helloworld文件调用顺序换一下,再次运行。得到了我们想要的结果:

这里会有个问题,这里只有两个js,如果js非常多,我们需要手工的进行js顺序的调整,那么开发的负担会非常重。那如何去解决这个问题呢?
2. 安装webpack
1)前提条件
在开始之前,请确保安装了nodejs的最新版本。使用nodejs最新的长期支持版本(LTS - long term support)是理想的起步。使用旧版本你可能会遇到各种问题。因为它们可能缺少webpack功能,或者缺少相关package。
检查nodejs是否安装成功:

webpack安装有两种情况,一种是在全局安装webpack,另一种是在本地工作目录下安装webpack。另外,安装webpack需要安装两个包,一个是webpack主包,一个是webpack-cli。webpack-cli表示我们可以在命令行里面执行webpack命令。
2)本地安装
首先安装一个npm包管理的配置文件:
$ npm init -y
执行完毕后,会在项目根目录下生成一个package.json文件,这个配置文件默认有一些配置:
{
"name": "felixcourses",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
安装webpack,webpack-cli:
$ npm install webpack webapck-cli --save-dev
安装完成之后会发现根目录下多了一个node_modules文件夹,里面有webpack和其他的一些依赖包。同时还生成一个package-lock.json的文件,这个文件表示当前这两个包的一些依赖。
3)全局安装
global 全局环境安装。这样做的好处是可以让我们在任何目录下面去执行webpack。
$ npm install webpack webapck-cli --global

但是不推荐全局去安装webpack,因为这样会使你项目的webpck锁定到某个版本里。并且在使用不同的webpack版本的项目里面可能会导致构建失败。还有,如果是一个团队协作的项目,你的伙伴不知道在全局里安装了webpack,也会有问题。
3. 运行webpack
调整一下helloWorld.js和index.js:
function helloWorld() {
console.log("Hello World");
}
export default helloWorld;
import helloWorld from "./hello-world";
helloWorld();
在项目目录下面直接执行 webpack:

执行命令之后,发现项目目录下多了一个dist文件夹,文件夹下有一个main.js文件。由此可见,执行webpack,默认会帮我们完成一些打包,main.js就是默认打包出来的。那么这个文件是通过读取哪些文件来打的包呢?
执行命令:
$ webpack --stats detailed
得到一些详细的打包信息:

从上述信息可以看出main.js是从src里面得到的。src里面正好有一个index.js,那么这个index.js就是他默认的打包的入口文件了。
这里有个问题,上面的webpack命令是使用的当前项目下的webpack吗?其实不是,其实是使用的全局的webpack。
我们卸载全局的webpack:
$ npm uninstall webpack webpack-cli --global
之后执行webpack,会发现报错:

这样我们只能使用本地webpack了。我们需要一个新的工具叫npx。npx依托于npm,npm安装好之后,npx就可以直接使用了。npx表示我们可以观察当前文件夹里面有没有你想要去运行的这个命令。
执行命令:
$ npx webpack

webpack打包正常执行。再看main.js这个文件,它直接,默认打包了我们的index.js的模块,那么我们能不能自己去修改入库文件的路径和文件名呢?
4. 自定义webpack配置
实际上,webpack-cli给我们提供了非常丰富的终端命令行指令,可以通过 webpack --help 查看

1)命令行工具配置入口文件
删除dist文件夹,执行命令:
$ npx webpack --entry 入口文件 --mode 环境

dist目录生成成功,main.js也没问题。那dist文件和main.js我们能不能自己定义呢?当然可以,只是需要执行相应的命令。当然你可能会发现,命令行的方式用起来真的不是太方便,也不直观,而且也不能帮我们保存一些配置。因此webpack还给我们提供了通过一个配置文件来去自定义配置参数这样的能力。
2)通过配置文件配置自定义参数
在当前项目下新建 webpack-config.js,文件名称不能随便修改,因为这是webpack自动去读取的。由于这个文件是在nodejs里面去运行的,因此我们定义模块的时候得使用nodejs的CommonJS模块。
module.exports = {
entry: './src/index.js', //入口文件配置
// 出口文件配置
output: {
filename: 'bundle.js', // 指定输出文件的文件名
path: './dist', //指定文件输入路径
}
}
执行 npx webpack 命令:

结果path不是一个绝对路径的错误,言外之意是path必须设置成绝对路径,那么绝对路径怎么配置呢?
需要引入一个nodejs的模块:
const path = require('path'); //引入nodejs的path模块
module.exports = {
entry: "./src/index.js", //入口文件配置
// 出口文件配置
output: {
filename: "bundle.js", // 指定输出文件的文件名
// path: './dist', //报错:必须为绝对路径
// 调用path模块的resolve方法
path: path.resolve(__dirname, "./dist"), //指定文件输入路径
// __dirname 表示获取到当前的webpack.config.js这个文件所在的物理路径
// "./dist" 表示基于前面的第一个路径去找到 dist文件夹
},
};
再次执行 npx webpack:

执行成功。但是有mode未配置提示,配置mode:
const path = require('path'); //引入nodejs的path模块
module.exports = {
entry: "./src/index.js", //入口文件配置
// 出口文件配置
output: {
filename: "bundle.js", // 指定输出文件的文件名
// path: './dist', //报错:必须为绝对路径
// 调用path模块的resolve方法
path: path.resolve(__dirname, "./dist"), //指定文件输入路径
// __dirname 表示获取到当前的webpack.config.js这个文件所在的物理路径
// "./dist" 表示基于前面的第一个路径去找到 dist文件夹
},
mode: 'none'
};
再执行npx webpack命令,提示消失。
在html文件中引入打包后的dist下的boundle.js并运行:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- <script src="./src/helloworld.js"></script>
<script src="./src/index.js"></script> -->
<script src="./dist/bundle.js"></script>
</body>
</html>
结果如下:

说明我们的webpack打包成功了。
那么问题来了,我们每次要手工的去修改script标签里面的src的路径和文件名吗?很显然,这个不方便。
5. 自动引入资源
目前为止,我们都是在index.html文件中手动引入所有资源的,但是,随着应用程序的增长,我们继续手动管理index.html就会变得越来越困难。webpack能帮我们自动引入所有资源吗?使用webpack插件就能实现。
什么是插件?webpack就想一条生产线,它要你经过一系列的处理流程以后才能将源文件即入口文件转换成输出结果。入口js还可以依赖其他的两个js模块,其中被依赖的js模块可能还依赖其他的js模块,并且这个js模块可能引用css文件,css文件的引入需要使用 webpack loaders 即加载器。webpack会把这个依赖的关系都记录下来,然后交给webpack编译器,webpack编译器经过加工以后会生成目标文件,比如css和js文件。webpack的编译过程需要一些工具来帮忙,这些工具可以帮助webpack执行一些特定的任务,比如打包优化,资源管理等。这些工具就是所谓的 plugins 插件。

1)使用htmlWebpackPlugin
安装html-webpack-plugin插件,该插件将为你生成一个 HTML5 文件:
$ npm install html-webpack-plugin -D
添加配置:
const path = require('path'); //引入nodejs的path模块
const HtmlWebpackPlugin = require('html-webpack-plugin'); //引入html-webpack-plugin插件
module.exports = {
entry: "./src/index.js", //入口文件配置
// 出口文件配置
output: {
filename: "bundle.js", // 指定输出文件的文件名
// path: './dist', //报错:必须为绝对路径
// 调用path模块的resolve方法
path: path.resolve(__dirname, "./dist"), //指定文件输入路径
// __dirname 表示获取到当前的webpack.config.js这个文件所在的物理路径
// "./dist" 表示基于前面的第一个路径去找到 dist文件夹
},
mode: "none",
plugins: [
//插件配置
new HtmlWebpackPlugin(), //实例化插件
],
};
执行npx webpack命令:

执行命令成功后,生成新的dist文件目录,目录下除了bundle.js之外还有一个index.html文件:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Webpack App</title>
<meta name="viewport" content="width=device-width, initial-scale=1"><script defer src="bundle.js"></script></head>
<body>
</body>
</html>
head标签里面的bundle.js的script标签是webpack帮助我们自动生成的。运行html文件之后,程序正常运行,说明webpack帮我们添加的那个script标签是有效的。
那么如何基于外部的index.html生成打包后的index.html?
修改配置,配置插件的options选项:
const path = require('path'); //引入nodejs的path模块
const HtmlWebpackPlugin = require('html-webpack-plugin'); //引入html-webpack-plugin插件
module.exports = {
... ...
... ...
//插件配置
plugins: [
//实例化插件
new HtmlWebpackPlugin({
template: "./index.html", // 使用模板
filename: "app.html", // 生成文件名称
inject: "body", //生成script标签位置
}),
],
};
再执行npx webpack命令:

app.html生成成功,并且script标签在body标签里面,app.html也是基于外部index.html生成的。运行app.html,程序正常执行。
但是,打开dist文件夹,会发现上次打包的index.html文件还在,那么能不能在生成新的打包文件的时候,把上次遗留的文件清理掉呢?
2)清理dist
修改webpack配置:clean: true
const path = require('path'); //引入nodejs的path模块
const HtmlWebpackPlugin = require('html-webpack-plugin'); //引入html-webpack-plugin插件
module.exports = {
entry: "./src/index.js", //入口文件配置
// 出口文件配置
output: {
filename: "bundle.js", // 指定输出文件的文件名
// path: './dist', //报错:必须为绝对路径
// 调用path模块的resolve方法
path: path.resolve(__dirname, "./dist"), //指定文件输入路径
// __dirname 表示获取到当前的webpack.config.js这个文件所在的物理路径
// "./dist" 表示基于前面的第一个路径去找到 dist文件夹
clean: true, //生成新文件之前,清空之前的文件
},
mode: "none",
//插件配置
plugins: [
//实例化插件
new HtmlWebpackPlugin({
template: "./index.html", // 使用模板
filename: "app.html", // 生成文件名称
inject: "body", //生成script标签位置
}),
],
};
再次执行命令,dist下的index.html就不存在了:

这里会发现一个问题,每次浏览网页的时候都需要右键在浏览器打开网页,那么能不能不用我们自己去手动打开浏览器预览网页呢?