1、webpack是什么?
webpack是一种前端资源构建(打包)工具(npm run build),一个静态模块打包器。在webpack看来,前端的所有资源文件(js/json/css/image/less/sass...)都会作为模块处理。它将根据模块的依赖关系进行静态分析,打包生成对应的静态资源。webpack可以解决当前web开发中所面临的困境,webpack提供了:
-
友好的模块化支持
-
代码压缩混淆
-
处理js兼容问题
-
性能优化
目前绝大多数企业中的前端项目,都是基于webpack进行打包构建的。
示例:使用==模块化开发思想(能拆就拆原则)==创建一个隔行换色的效果
先初始化一个空项目npm init -y
<body>
<ul>
<li>这是第1个li标签</li>
<li>这是第2个li标签</li>
<li>这是第3个li标签</li>
<li>这是第4个li标签</li>
<li>这是第5个li标签</li>
<li>这是第6个li标签</li>
<li>这是第7个li标签</li>
</ul>
</body>
<script src="./index.js"></script>
// 先需要安装jQuery,npm i -S jquery
import $ from "jquery";
$(function () {
$("li:odd").css("backgroundColor", "blue");
$("li:even").css("backgroundColor", "green");
});
在浏览器中执行的时候会报错,需要注意,代码是没有问题的,问题是浏览器不兼容(浏览器不认识模块化的语法,需要使用特定的工具进行转化)。
2、webpack简单使用
webpack是运行在node环境中的,需要Node>= 8.10和npm>=5.6的版本支持。在项目中安装webpack的方式如下:
npm i -D webpack webpack-cli # 不要将其安装为全局包
安装好后可以通过先前提及过的npx
命令来检查webpack的版本以确定是否安装成功:
npx webpack --version # npx可以帮助我们快速执行一些模块内部的命令
确认能够通过上述命令输出webpack
的版本信息后,再在package.json文件中的scripts
节点配置webpack运行脚本命令(==指令名称自行决定==):
此时,我们可以在终端中运行自定义命令npm run build
来对项目使用webpack打包,例如打包之前写的隔行换色
代码:
npm run build
打包完毕后会在当前项目目录下产生dist
目录,里面会包含一个main.js
文件,修改src/index.html
文件,将原先的JavaScript文件引入修改为打包好的文件:
<!-- <script src="../src/index.js"></script> -->
<script src="../dist/main.js"></script>
最终效果如下:
此时虽说我们已经让原本原本浏览器不认识的模块化代码得以运行,但我们的开发调试环境与之前学习vue、react时相比,还有很多不足的地方,例如:
-
需要手动在public/index.html中引入打包好的文件
-
如果修改了js代码,我们希望看到最新的结果,还需要重新打包
-
不支持css、less等文件的打包
-
....
如果需要解决上述的问题,我们还需要更多的webpack知识来支撑。
3、webpack的核心概念
核心概念即webpack的五个核心配置项。
-
entry入口
本项目应该使用哪个模块来作为构建其内部依赖图的开始(指定打包入口文件)。打包入口文件默认为src/index.js
。【vue的入口是main.js,react的入口是index.js】
-
output输出
在哪里输出它所创建的 bundles,以及如何命名这些文件,打包输出文件默认值为dist/main.js
。【vue打包目录是dist,react的打包目录是build】
-
loader加载器
loader让webpack能够去处理那些非js文件(webpack自身只理解js)
-
plugins插件
插件则可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量。插件接口功能极其强大,可以用来处理各种各样的任务。
-
mode 模式
通过选择 development 或 production(默认值) 之中的一个,来设置 mode 参数,你可以启用相应模式下的 webpack 内置的优化
4、webpack配置文件
4.1、配置文件基础
我们在上一节的概述中提及了webpack的五个核心概念,这五个核心概念都属于webpack的配置。因此,如果需要更好的运用webpack,我们需要掌握其配置文件的相关知识点。
我们可以在项目的根目录下创建名为webpack.config.js
的文件,将配置代码写在其中,在没有指定具体其它文件的情况下该文件中的配置会在执行打包命令的时候被webpack自动读取,配置文件采用CommonJS规范,参考的基础配置如:
const path = require('path')
module.exports = {
// 打包模式 development | production
mode: 'development',
// 项目入口
entry: './src/index.js',
// 项目出口
output: {
// 出口路径
path: path.resolve(__dirname, 'dist'),
// [name]默认的名称为main
filename: 'js/[name].js',
// 资源的保存路径
assetModuleFilename: 'images/[hash][ext][query]',
// 静态资源的访问路径
publicPath: '/',
},
}
配置好其配置文件后,我们可以尝试再次对案例进行打包,发现之前首次打包时命令行中针对mode
的警告已经没了,说明此时配置生效。
但,webpack的配置项十分的多,如果我们希望在构建测试/准生产代码时使用A版本配置项,而在构建生产代码时使用B版本配置项,我们将面临着来回修改配置项的痛楚。所以在实际使用webpack的时候,我们往往会依据构建版本的可能性,为webpack提供多套配置文件。例如:
-
创建development版本配置文件:config/development.js
-
创建production版本配置文件:config/production.js
随后,我们在package.json文件中,为两套配置文件分别指定npm命令如图:
注意:由于在config下面的配置文件中指定了输出的路径,此时路径也需要做一下修改,否则打包的dist目录就会在"config/dist"这个位置。只需要给“dist”加上“../”即可:==该路径一定要求是绝对路径==
path: path.resolve(__dirname, "../dist"),
这样配置完成后,我们就可以通过npm命令npm run build:dev
来构建开发版本的代码,通过npm run build:pro
来构建生产版本的代码。
4.2、自动复制访问入口
在打包好的代码中并没有index.html,还需要手动在src目录中将html代码复制到dist目录中才会具有vue或react下的打包效果。是否有什么好的办法让这个手动操作自动化呢?
我们需要借助webpack强大的插件机制来解决上述问题。我们需要安装一个插件模块,安装命令如下:
npm i -D html-webpack-plugin
随后修改webpack的配置文件(根据需要决定修改哪些webpack配置文件),增加以下配置项:
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
// ....
plugins: [
new HtmlWebpackPlugin({
template: "./public/index.html",
}),
],
}
使用该款插件后,会自动在视图中去帮我们引入打包好的文件main.js
,因此我们需要剔除之前手动引入的代码。
4.3、配置开发服务器
通过上一节,我们已经可以使用打包工具去将写好的代码进行打包了,但是在操作的过程中大家可能会发现有一个比较麻烦的地方:修改一次代码就得重新打包一次,这种感觉有点类似于之前的node xxx.js
一样,那么在webpack这里是否有类似于nodemon
那么好用的自动化工具能帮助我们自动检测文件的变化并自动执行呢?
答案是有的,它就是webpack-dev-server
自动化打包工具。
webpack-dev-server
的安装指令如下:
npm i -D webpack-dev-server
自动打包服务支持一系列配置选项,可以根据以下代码取所需的配置:
module.exports = {
devServer: {
// 端口号
port: 8080,
// 域名
host: 'localhost',
// 自动打开浏览器
open: true,
// 服务器代理 --> 解决开发环境跨域问题
proxy: {
// 一旦devServer服务器接受到 /api开头的请求,就会把请求转发到另一个服务器
'/api': {
target: 'http://localhost:3000',
// 发送请求时,请求路径重写: 将/api 去除
pathRewrite: {
'^/api': '',
},
},
},
},
};
开发服务器因是开发调试时需要用到,因此我们建议将devServer
段落放在开发版本的webpack配置文件中,但需要留意,该配置需要与4.2
节中的配置并存。
安装、配置好后同样也需要在package.json
中配置自定义执行的指令:
5、加载器
在实际开发中,webpack只能打包处理以.js
为后缀的模块(并且是其中一部分比较简单的JavaScript代码),其他非.js
后缀的模块webpack默认处理不了,而需要调用loader加载器才能正常打包,否则会报错!
loader加载器可以协助webpack打包处理特定的文件模块了,例如:
-
less-loader可以打包处理
.less
相关的文件 -
sass-loader可以打包处理
.scss
相关的文件 -
...
5.1、样式处理
5.1.1、处理css
正如前面所说,webpack默认不能打包css文件,如果在没有安装css加载器的时候打包包含css文件的项目则会报错:
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See Concepts | webpack
根据报错提示,我们需要安装一个合适的加载器才能继续。
所以要想打包css文件,则需要安装css加载器,该加载器的安装命令为:
npm i -D style-loader css-loader
安装好需要的加载器后需要对webpack进行配置,告诉webpack当遇到css后缀的文件应该交由哪个加载器去处理。在webpack打包命令对应的module
的rules
数组中添加css-loader规则:
module: { rules: [{ test: /\.css$/, use: ["style-loader", "css-loader"] }], },
在写加载器use
的时候,需要注意:
-
use数组中指定的加载器顺序是固定的,==顺序不能随意调换==
在配置好对应的css加载器后,webpack才能打包对应的css文件(提醒:配置好之后需要重新启动自动打包服务让配置文件生效)。
5.1.2、处理less
要想通过webpack打包less文件,同样需要安装对应的加载器:
npm i -D less-loader less
安装好后也需要在对应的webpack配置文件中配置针对less文件打包的规则:
module: { rules: [ {test: /\.less$/,use: ["style-loader","css-loader","less-loader"]} ] }
5.1.3、抽取css
通过前面的学习,细心的同学会发现,打包好的html文件在浏览器运行时,“审查元素”时 能够看到所有的样式代码都以“style”标签写入了html,这些样式都是由JavaScript动态生成的,每次都这样动态生成:
-
消耗性能
-
在html中本身是没有style代码的,而是通过js后续生成的,再塞入到html中
-
-
无法做静态资源加速(CDN)
因此,此处可以对该部分进行改善操作。我们可以让webpack在打包时直接将这些样式抽成一个样式文件。步骤如下:
-
安装插件
-
npm i -D mini-css-extract-plugin
-
-
导入插件
-
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
-
-
配置插件
-
new MiniCssExtractPlugin({ filename: 'css/[name]_[hash:6].css', }),
-
-
使用插件
-
MiniCssExtractPlugin.loader(使用它去替换之前的“style-loader”)
-
6、其它细节
6.1、路径别名与默认后缀
在先前学习Vue及React框架过程中,我们经常会在写代码的时候用到这俩个特性:
-
在写路径的时候会用
@
表示./src
-
遇到
.js
、.vue
、.jsx
后缀可以省略不写
但这两特性在webpack中默认是不允许的,或者说存在很大的限制。默认情况下,只允许省略.js
后缀。
先前脚手架已经帮我们配置好了,那么在webpack里该如何手动配置这个很便利的操作呢?
配置方式如下:修改webpack的配置文件,在配置选项中添加resolve
选项,增加别名配置:
resolve: {
// 配置解析模块路径别名:优点简写路径,缺点路径没有提示
alias: {
// 定义一个@,可在import引入时使用
'@': path.join(__dirname, '../src'),
},
// 设置可以忽略不写的后缀
extensions: ['.js'],
},
这时,再写模块导入路径的时候即可简化路径写法。
6.2、忽略打包
在开发项目时,有些外部模块通过CDN链接
使用script
标签引入到页面中可能要比通过打包使用更加方便。例如layui库,我们在组件化开发中顶多也就使用其弹窗功能,那么我们采用script标签引入layer会更合适。此时就可以使用externals
忽略打包的方式去指定哪些库不需要webpack进行打包。
externals
选项指定实现的方式比较简单,只需要在webpack配置文件中添加externals选项指定需要忽略的包信息即可。
以jQuery为例,需要忽略对jQuery的打包,则可以写成:
externals: { jquery: 'jquery', // ..... }