前言
Webpack是一个前端资源加载/打包工具。它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源。
Webpack的概念如下:
本质上,webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具。当 webpack 处理应用程序时,它会在内部从一个或多个入口点构建一个 依赖图(dependency graph),然后将你项目中所需的每一个模块组合成一个或多个 bundles,它们均为静态资源,用于展示你的内容。
为什么需要Webpack?
首先我们要清楚Webpack有三大作用:
- 编译
前端工程其实存在很多规范,但是这些规范并非是我们所说的官方认定的统一标准,只不过是众多开发者的共同约定从而促成了一个个看似标准的“规范”。所以呢我们就用到了Webpack,它可以把浏览器不认识的各种资源,语法,规则转换成浏览器认识的。那么这个过程我们就可以理解为编译。
- 集成
Webpack作为一种自动构建工具,它能集成很多种别的构建工具,形成一套完整的构建部署体系,或者叫工具链。Webpack处于各种工具的中心位置,自然成为连接别的工具的纽带。
- 压缩、优化
所谓压缩(compress)、优化(optimization)、最小化(minimizer)、精简化(terser),都是差不多的意思,就是减小JS代码的体积。最典型的做法是把所有变量名都精简为一个字母,所有的换行符和缩进都去掉。或者更简单地说,就是把所有的代码都变成乱码。当然了这样做的目的也是为了加载速度更快,使得代码内容更加安全。
总而言之,在这些功能在接下来我们进行的前端项目构建过程中起到了至关重要的作用,并且像React,Vue这样的主流前端框架都是使用Webpack构建和部署,足可见其地位之重要。接下来我们就一探究竟。
开始!
本章练习用到相关依赖及其版本
1.首先,我们使用如下命令创建一个空项目工程。
npm init
我们创建一个空目录,然后在该目录内执行上述命令。
2.接下来我们在node项目中添加webpack工具。
npm install webpack webpack-cli -D
通过上述命令,我们添加Node接口webpack,该接口仅负责编译的部分。webpack-cli负责在命令中运行webpack。
3.接下来我们修改package.json完成脚本内容添加。
{
"scripts":{
"dev":"webpack"
}
}
在真正开始webpack学习之前,我们可以先在package.json文件内做一些系统配置层面的修改。
语法标准
webpack模块能以各种方式表达它们之间的依赖关系。
- ES2015
import
语句 - CommonJS
require()
语句 - AMD
define
和require
语句 - css/sass/less文件中的
@import
语句 - stylesheet
url()
或者HTML<img src="...">
文件中的图片链接
注意:为了尽可能让我们的编程风格统一,我们可以将默认node支持的CommonJS语法更换为ESM语法。
{ "type":"module" //默认值:commonjs }
4.现在,我们来创建完善以下目录结构、文件和内容:
myproject
|-package.json
|-package-lock.json
|-index.html
|-/src
|- index.js
5.创建webpack配置文件。
很多时候我们的项目都会需要跟复杂的配置,所以我们可以在项目中添加一个webpack配置文件 webpack.config.js
。由于刚才我们已经将node语法环境更换为ESM,所以接下来的所有配置语法均需要参考ESM方式。
import * as path from 'path'
import {fileURLToPath} from 'url'
//由于默认规范和当前规范的不同,所以导致commonjs中的 __dirname不能获取,语法规则不同,正确配置如下:
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
export default {
//表示当前编程采用的模式,有如下三种默认值
// "production" | "development" | "none"
mode : "development",
//代表程序的入口
entry : './src/index.js',
output : {
//设置每个输出bundle(捆)的名称,
filename : 'main.js',
//默认编译结果文件生成目录
path : path.resolve(__dirname, 'dist')
}
}
6.接下来我们通过一个简单示例来印证配置的正确性。
在项目中我们安装 jquery
和bootstrap@4
依赖。
npm install jquery bootstrap@4
在index.html中添加列表组:
<script src="./dist/main.js"></script>
<ul class="list-group">
<li class="list-group-item">An item</li>
<li class="list-group-item">A second item</li>
<li class="list-group-item">A third item</li>
<li class="list-group-item">A fourth item</li>
<li class="list-group-item">And a fifth one</li>
</ul>
在index.js中完成如下编码,实现元素的隔行变色功能。
import $ from 'jquery'
$(function(){
$('li:even').css('background-color','blue')
})
这个时候我们就可以使用 npm run dev
命令编译项目了。打开页面之后我们可以得到以下页面效果。
7.那么我们想要使用bootstrap样式又应该如何引入呢?
我们无法默认像使用javascript模块那样方便的引入并使用样式,这个时候要想解决问题我们就要使用 loader
。loader可以在我们使用import加载模块时进行预处理文件,从而通过判断文件的格式来选择合适的解析方式。所以在javascript中使用import引入CSS也就变得轻而易举了。
我们需要通过安装 css-loader
和 style-loader
来实现CSS样式的解析。
npm install css-loader style-loader -D
然后再webpack.config.js文件中通过rules配置来指示对每一个.css文件的解析。
{
{
module:{
rules:[
{
test:/\.css$/,
//此处必须保证顺序,否则会报错
use:['style-loader','css-loader']
}
]
}
}
}
模块 loader 可以链式调用。链中的每个 loader 都将对资源进行转换。链会逆序执行。第一个 loader 将其结果(被转换后的资源)传递给下一个 loader,依此类推。最后,webpack 期望链中的最后的 loader 返回 JavaScript。
对于像文字,图片相关的静态资源加载也同样需要配置相应的loader。在webpack5中,可以使用内置的Asset Module,此时我们可以轻松的将这些资源混入到系统中:
-- webpack.config.js
{
{
module:{
rules:[
{
test:/\.css$/,
use:['style-loader','css-loader']
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
}
]
}
}
}
8.如何使用webpack插件(plugin)
Webpack有一个丰富的插件界面。webpack 本身中的大多数功能都使用此插件接口。这使得 webpack 变得灵活。
此处我们以HtmlWebpackPlugin
插件为例。HtmlWebpackPlugin简化了HTML文件的创建,以便为我们的webpack包提供服务。简单说使用该插件,可以为我们自动生成一个HTML5文件。
npm install html-webpack-plugin -D
下载Mockjs官方文档
npm install mockjs
//webpack.config.js
import HtmlWebpackPlugin from 'html-webpack-plugin'
export default {
//... 省略其他属性配置
plugins:[
new HtmlWebpackPlugin()
]
}
- 默认创建的HTML文件位于
/dist/index.html
- 生成的HTML中使用<script>引入脚本文件
- 使用的相关CSS文件会使用<style>引入
// src/index.js
// 使用下面的代码可以替换上面示例中手动创建index.html的操作
import $ from 'jquery'
//使用Mock需要 npm install mockjs
import Mock from 'mockjs'
import 'bootstrap/dist/css/bootstrap.css'
$(function(){
var div = document.createElement("div");
div.setAttribute("id","app");
var ul = document.createElement("ul");
ul.setAttribute("class","list-group")
for (let i = 1; i <= 5; i++) {
var li = document.createElement("li");
li.setAttribute("class","list-group-item")
li.innerText = Mock.mock({"string":"@sentence"}).string;
ul.appendChild(li);
}
div.appendChild(ul);
document.body.appendChild(div);
// $('li:even').css('background-color','blue')
})
9.如果想要启动一个本地服务应该如何配置?
webpack-dev-server
是一个可以用来快速搭建本地服务的工具。
npm install webpack-dev-server -D
//webpack.config.js
export default {
//... 省略其他配置
devServer:{
hot: true, //开启热更新
port: '8080', //服务端口号
host: 'localhost',
proxy:{
//当请求url中存在 api 的时候代理到后端服务
'/api': 'http://localhost:8088'
}
}
}
// package.json
"dev": "webpack-dev-server --hot --open --config webpack.config.js --mode development",
- –hot 开启热启动
- –open 启动后自动打开默认浏览器
- –mode 设置模式
在工程中使用Vue
- 添加依赖
npm install vue@2.7.14
npm install vue-loader@15 -D
-
此处我们使用Vue2,所以vue-loader版本不能高于15
-
Vue Loader是webpack的一个loader,它允许程序员可以以一种名为
单文件组件
的格式撰写Vue组件// xxx.vue <template> <div>{{ msg }}</div> </template> <script> export default { data () { return { msg: 'Hello world!' } } } </script> <style> .example { color: red; } </style>
-
允许为 Vue 组件的每个部分使用其它的 webpack loader
-
允许在一个
.vue
文件中使用自定义块,并对其运用自定义的 loader 链 -
使用 webpack loader 将 <style> 和 <template> 中引用的资源当作模块依赖来处理
-
为每个组件模拟出 scoped CSS
-
在开发过程中使用热重载来保持状态
//webpack.config.js
import {VueLoaderPlugin} from "vue-loader";
export default {
//... 省略其他属性
resolve:{
//所有通过‘@’引入的路径结尾无需指定文件后缀,自动根据下面的规则依次查找
extensions:['.js','.json','.vue'],
alias:{
//以后就可以使用 @ 表示src路径
'@':path.join(__dirname,'src')
}
},
plugins:[
new VueLoaderPlugin()
],
module:{
rules:[
{
test: /\.vue$/,
use:'vue-loader'
}
]
}
}
在工程中如果需要使用jsx,则需要完成如下步骤:
# 安装babel-loader
npm install --save-dev babel-loader@8.1.0
# 安装babel
npm install --save-dev @babel/core@7.11.0 @babel/preset-env@7.11.0
创建Babel配置文件,.babelrc
。
{
"presets": [
[
"@babel/preset-env",
{
"targets": "> 0.25%, not dead"
}
]
]
}
webpack配置文件中添加loader配置
{
module:{
rules: [
{
test: /\.js$/,
exclude: /(node_modules)/, // 排除文件
loader: 'babel-loader'
}
]
}
}
babel-loader 与 babel有版本配对要求一般是 babel-loader8 + babel7 或 babel-loader7 + babel6 或 babel-loader6 + babel5
# 安装Vue+JSX
npm install @vue/babel-preset-jsx @vue/babel-helper-vue-jsx-merge-props
Babel配置文件添加配置
{
"presets":
[
"@vue/babel-preset-jsx",
["@babel/preset-env",
{
"targets": "> 0.25%, not dead"
}
]
]
}