前面的话
现在团队开发基本会采用“模块化 + 新语言 + 新框架”的模式进行开发,webpack成为构建工具的首选。
什么是webpack?
webpack 是一个打包模块化JavaScript的工具,在webpack里面一切皆为模块,例如一个js文件、css文件,图片、模板等。webpack将这些相互有依赖的模块,打包成一个供浏览器能使用的静态资源(一个js文件)。
webpack5大特点
-
代码拆分
webpack 有两种组织模块依赖的方式,同步和异步。异步依赖作为分割点,形成一个新的块。在优化了依赖树后,每一个异步区块都作为一个文件被打包。 -
Loader
Webpack 本身只能处理原生的 JavaScript 模块,但是 loader 转换器可以将各种类型的资源转换成 JavaScript 模块。这样,任何资源都可以成为 Webpack 可以处理的模块。 -
智能解析
Webpack 有一个智能解析器,几乎可以处理任何第三方库,无论它们的模块形式是 CommonJS、 AMD 还是普通的 JS 文件。甚至在加载依赖的时候,允许使用动态表达式 require("./templates/" + name + “.jade”)。 -
插件系统
Webpack 还有一个功能丰富的插件系统。大多数内容功能都是基于这个插件系统运行的,还可以开发和使用开源的 Webpack 插件,来满足各式各样的需求。 -
快速运行
Webpack 使用异步 I/O 和多级缓存提高运行效率,这使得 Webpack 能够以令人难以置信的速度快速增量编译
体验webpack打包过程
初始化一个web项目
在根目录下使用一下命令初始化一个最简单的采用模块化开发的项目,完成之后,根目录下生产一个package.json文件。
$ npm init -y
安装webpack
想要使用webpack先保证安装了Node.js.
一定要全局安装webpack,否则会出现无法使用webpack命令的情况。在安装了全局的webpack后,在其他项目中可只安装本地的webpack。
$ npm install -g webpack // 全局的安装
$ npm install -D webpack // 本地安装
建立入口文件
- 建立页面入口文件:index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app"></div>
<!-- 导入webpack输出的JavaScript文件 -->
<script src="./dist/bundle.js"></script>
</body>
</html>
- 建立一个含操作函数的show.js文件,并导出该函数
// 操作DOM
function show(content) {
window.document.getElementById('app').innerText = 'hello,' + content;
}
// 使用CommonJS规范导出show函数
module.exports = show;
- 建立执行入口的main.js文件
// 通过CommonJS规范导入show函数
const show = require('./show.js');
// 执行show函数
show('webpack');
配置默认的webpack.config.js文件
webpack在执行时,需要读取一些配置才能进行打包。我们将这些配置写在根目录下的默认文件webpack.comfig.js中。新建它:
const path = require('path');
module.exports = {
//Js执行入口文件
entry: './main.js',
output: {
// 将所有的依赖的模块合并输出到一个bundle.js文件
filename: 'bundle.js',
// 将输出的文件都放在dist目录下
path: path.resolve(__dirname, './dist')
}
}
将上面的main.js文件作为入口文件,将webpack打包的最终输出文件
放在dist目录下。
运行
执行以下命令,我门会发现目录下多出一个dist目录,里面有一个bundle.js文件,这就是一个可执行的js文件,它包含了页面所依赖的两个模块main.js和show.js,以及webpackBootstrap启动函数。
$ webpack
如果无法使用webpack命令,安装webpack-cli即可。
$ npm install -g webpack-cli
此时在用浏览器打开index.html网页,就可以看到hello,webpack
最后看一看整个项目的结构:
到此,一个简单的项目就完成了。现在应该可以领会到webpack是什么,以及它的工作原理了吧。webpack会从配置文件中的entry中找到入口文件(这里是main.js),然后识别文件中的导入语句,找出入口文件中的所有依赖(这里只有show.js),最后将入口文件以及其他依赖打包到一个单独的文件中(这里是bundle.js),供浏览器使用。
使用Loader
webpack本身只能处理JavaScript模块,如果想处理其他文件(例如css模块),就需要使用Loader转换器,它可以将任意类型资源转换为js模块。(关于Loader之后再详讲)。
我们接着上面的例子,我们在建立一个main.css文件,对id为’app’的div进行样式处理:
#app {
color: red;
text-align: center;
}
并且修改入口文件main.js,导入main.css模块:
// 引入css模块
require('./main.css');
// 通过CommonJS规范导入show函数
const show = require('./show.js');
// 执行show函数
show('webpack');
前面说过,webpack只能处理js模块,那么我们想要它处理css模块,就要使用它的Loader机制。修改默认的配置文件webpack.config.js文件:
const path = require('path');
module.exports = {
//Js执行入口文件
entry: './main.js',
output: {
// 将所有的依赖的模块合并输出到一个bundle.js文件
filename: 'bundle.js',
// 将输出的文件都放在dist目录下
path: path.resolve(__dirname, './dist')
},
module: {
rules: [
{
// 用正则表达式去匹配要用到Loader转换的css文件
test: /\.css$/,
use: ['style-loader', 'css-loader?importLoaders']
}
]
}
}
这里的module.rules数组,告诉webpack在遇到哪些文件时需要使用Loader去加载和转换。上面的配置告诉webpack,在遇到以.css结尾的文件时,先试用css-loader读取css文件,再由style-loader 将css内容注入到JavaScript里。注意:
-
use属性的值是一个由loader名称组成的数组 ,各Loader的执行顺序是由后往前的。
-
每个Loader都可以通过URL querystring的方式传入参数。上例中‘css-loader?importLoaders’的‘importLoaders’表示css-loader前可以有多少个loader。
-
除了使用URL querystring的方式传入参数,还可以使用Object实现(具体其他的options配置可以参考官网)。可以将上面的use属性改为下面内容:
use:[ 'style-loader', { loader: 'css-loader', options: { importLoaders: 1 } } ]
不管使用哪一种方式都可以。
修改完配置文件后,还不够,我们需要引入这两个Loader,使用以下命令即可引入新的loader:
npm install -D style-loader css-loader
安装完后,使用webpack命令重新构建:
$ webpack
刷新index.html页面,就是我们想要的样式了:
从这个例子我们就可以看到webpack中Loader机制所发挥的作用。这个小例子中其实就是css-loader与style-loader的功劳,前者先读取css文件,后者将css的内容用JavaScript里的字符串存储起来,网页执行JavaScript时通过DOM动态的向HTML < head>< /head>标签中插入style标签。
使用Plugin
Plugin(插件)是用来扩展webpack功能的,它可以完成loader不能完成的功能。Plugin的使用是在配置文件的plugins选项中指定的。webpack本身内置一些插件,同样也需要通过npm安装第三方插件。(有关Plugin的详细内容,后面再说)。
接着上面的例子来说,我们使用loader转换器将css文件转换为可执行的js文件,并且将其注入到最后输出的js文件中,这样会导致js文件变大并且加载网页时间变长。为了解决这个问题,我们就可以使用插件让webpack输出单独的css文件。
修改上面的配置文件:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
//Js执行入口文件
entry: './main.js',
output: {
// 将所有的依赖的模块合并输出到一个bundle.js文件
filename: 'bundle.js',
// 将输出的文件都放在dist目录下
path: path.resolve(__dirname, './dist')
},
module: {
rules: [
{
// 用正则表达式去匹配要用到Loader转换的css文件
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader']
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './index.html',
filename: 'index.html',
minify: {
collapseWhitespace: true,
},
hash: true,
}),
new MiniCssExtractPlugin({
// 定义从js文件中提取的css文件名称,[name]是css文件的名称
// [contenthash:8]是根据css文件内容算出的hash值
filename: '[name]_[contenthash:8].css'
})
]
}
上面的mini-css-extract-plugin插件的作用就是提取JavaScript代码的css到一个单独的文件。
[注意]:(webpack4只有就是用mini-css-extract-plugin插件分离css文件了,extract-text-webpack-plugin插件被废弃了)
当然少不了安装新的插件:mini-css-extract-plugin
$ npm install -D mini-css-extract-plugin
除了使用mini-css-extract-plugin插件分离css文件外,还需要配合使用html-webpack-plugin插件,它可以将分离出来的css文件通过下面的方式注入到js文件中,并且生成一个新的html文件。
<link href="main_aad60e05.css?6c2761aee4b5c4379d88" rel="stylesheet">
接下来执行webpack命令:
$ webpack
可以看到dist目录下有一个新的css文件和一个新的html文件:
点开新生成的index.html文件我们也可以看到刚刚生成的main_aad60e05.css文件被通过< link>的方式注入到index.html文件了。启动新的index.html文件可以看到跟上面只使用Loader机制一样的效果。
使用DevServer
通过前面的内容,我们可以使用webpack在本地预览文件,但实际开发中我们可能会需要:
- 提供HTTP服务,而不是本地预览
- 监听文件的变化,修改文件后保存,就能自动刷新页面,不需要再输入命令
这时候DevServer就是最好的选择,接着上面的例子我们来体验一下DevServer的功能:
首先还是要安装DevServer:
$ npm install -g webpack-dev-server
可以看到控制台的日志:
这样我们成功使用DevServer启动了一个HTTP服务器监听在8080端口,并且会以监听模式自动运行 webpack,我们可以在浏览器打开 http://localhost:8080。
注意这里我们还需要修改index.html文件中的bundle.js的位置,不在需要dist目录了,原因是:DevServer会将webpack构建输出的bundle.js文件保存在内存中,在要访问输出文件时,必须通过HTTP服务访问。所以DevServer不会理会webpack配置文件中的output中的path属性的内容,要获取bundle.js文件正确的URL是http://localhost:8080/bundle.js
接着上面的步骤,要体验一下DevServer实时预览的效果,我们修改一下main.css文件中的内容,并保存。
#app {
color: blue;
text-align: center;
height: 200px;
width:200px;
border: 1px solid #000;
}
可以看到浏览器自动刷新了页面。
一次最基础的webpack体验就到此为止啦,下一篇在具体讲讲webpack常用的功能。