手牵手带你掌握webpack5.x的安装与使用

概述

点关注,不迷路!先点赞,后观看,养成阅读好习惯!你长得这么好看,点个赞不过分吧~
在这里插入图片描述
在这里插入图片描述

首先,webpack是个啥呢?我们来看一下官方的定义:

Webpack is a static module bundler for modern JavaScript applications.

翻译过来就是“Webpack是一个用于现代JavaScript应用程序的静态模块打包器。

我们进行一下拆解:

  1. 打包bundler:webapck可以帮助我们打包,所以它是一个打包工具。
  2. 静态的static:这样表述的原因是因为我们最终可以将代码打包成静态资源(部署到静态服务器)
  3. 模块化module:webpack默认支持各种模块化开发,ES Module、CommonJS、AMD等
  4. 现代的modern:正式因为现代前端开发面临各式各样的问题,才催生了webpack的出现和发展。

我们知道前端开发最常使用的三大框架就是React、Vue和Angular,事实上,这三大框架的创建过程都是借助于脚手架CLI的。而Vue-Cli、create-react-app、Angular-Cli都是基于webpack来帮助我们支持模块化、less、TypeScript、打包优化等。

那webpack与其他常见的打包工具gulp、rollup有什么区别呢?这点改天我们单独开一篇文章好好唠唠。
简单来说就是gulp更加强调前端流程的自动化模块化不是它的核心webpack更加强调模块化开发管理,而文件压缩合并、预处理等功能,是他附带的功能;而rollup和定义和定位和webpack都非常相似,但是配置相对于webpack来说更加的简洁,使用场景有所不同。通常在实际项目开发过程中,我们都会使用webpack(比如vue、react、angular项目都是基于webpack的);
在对库文件进行打包时,我们通常会使用rollup(比如vue、react、dayjs源码本身都是基于rollup的);

使用步骤

好了,接下来就让我们进入正题吧!

安装node环境

Webpack的运行是依赖 Node 环境 的,所以我们电脑上必须有 Node 环境。
这里给出官方的地址: node官方网址。需要注意的是我们本篇文章都是基于最新版的webpack5.x进行讲述的,所以你下载的node最好是最新的LTS版的。

新建一个my-webpack文件夹

用来存放我们接下来的项目

初始化项目:npm init

npm init   // 可以添加一些自己对项目的说明,例如作者姓名、项目描述、使用的协议等
或
npm init -y	// 生成一个默认的package.json文件

package.json 文件是对项目或者模块包的描述,里面包含许多元信息。比如项目名称,项目版本,项目执行入口文件,项目贡献者等等。npm install 命令会根据这个文件下载所有依赖模块。

安装webpack、webpack-cli

npm install webpack webpack-cli -g // 全局安装
npm install webpack webpack-cli -D // 局部安装

这里我们采用局部安装,执行命令后会默认生成package-lock.json文件,锁定项目依赖的文件。
我们要同时安装这两个包。那这两个包有什么区别呢?

  • 执行webpack 命令,会执行 node_modules 下的 .bin 目录下的 webpack
  • webpack在执行时是依赖 webpack-cli 的,如果没有安装就会报错;
  • 而webpack-cli 中代码执行时,才是真正利用 webpack 进行编译和打包的过程;
  • 所以在安装webpack 时,我们需要同时安装 webpack-cli (第三方的脚手架事实上是没有使用 webpack-cli的,而是类似于自己的 vue-service-cli 的东西)

再总结一下就是:

  • webpack:编译和打包都是他来做。
  • webpack-cli:帮你形成文件的映射,知道用什么东西打包什么文件,然后交给webpack指令打包。

举个栗子就是。你执行npm run build指令webpack就会对文件进行打包,但webpack指令是不知道用什么打包工具打包各类文件的,webpack-cli做的就是这部分工作,找到正确的工具然后交给webpack指令编译和打包。

准备工作:根目录新建index.html、dist文件夹和src文件夹

dist文件夹可建和不建,还要在src中新建一个main.js文件,文件的说明在下方
在这里插入图片描述

配置入口、出口文件:根目录新建webpack.config.js(可改名)

将main.js配置为项目的入口文件,webpack打包会从入口文件开始查找,把入口文件引用的所有文件都进行打包。按照下图所示进行配置
在这里插入图片描述

配置打包命令

在package.json里的scripts对象中配置打包命令,按照下图所示进行配置,在这里就可以修改配置文件webpack.config.js的名字了。
在这里插入图片描述
接下来在终端输入输入npm run build,就发现打包成功了
在这里插入图片描述

处理样式相关文件 – css、sass、less、stylus等

这里以css和less的处理举例,其他都类似。安装相关loader。

npm install css-loader less less-loader style-loader -D

在src文件夹下新建css文件夹,然后新建新建1个css文件和一个less文件div_style.css,title_style.less。
div_style.css

.content {
  font-size: 20px;
  color: red;
  user-select: none;
  background-color: #66666666;
}

title_style.less

@fontSize: 50px;
@fontColor: blue;

.title {
  font-size: @fontSize;
  color: @fontColor;
  user-select: none;
}

然后在

然后在wk.config.js(因为上面改名了)文件中进行如下配置

const path = require("path")

module.exports = {
  mode: 'development',
  entry: "./src/main.js",
  output: {
    path: path.resolve(__dirname, './build'),
    filename: "bundle.js"
  },
  // 所有loader的配置规则都在这里进行配置(也可单独抽取出去,下面会讲到)
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [ "style-loader", "css-loader"]
      },
      {
        test: /\.less$/,
        use: [ "style-loader", "css-loader", "less-loader"]
      }
  },
}

这里针对上述的配置做如下说明:

  1. 关于style-loader文件:css-loader只是负责将css文件进行解析,并不会将解析后的css插入到页面之中,这部分工作就是交给style-loader来做的。
  2. 关于loader的书写顺序:必须按照样例的书写顺序进行书写,因为loader的读取顺序是从右向左的。

在src下面新建component文件下,然后在其下面新建cpns.js文件。创建元素并使用刚才的css、less样式文件。
cpns.js

import "../css/div_style.css"
import "../css/title_style.less" 

// 创建div元素
const divEl = document.createElement("div")
divEl.textContent = "Hello Webpack"
divEl.classList.add("content")
document.body.append(divEl)

// 创建h2元素
const titleEl = document.createElement("h2")
titleEl.textContent = "哈哈哈哈"
titleEl.classList.add("title")
document.body.append(titleEl)

在index.html文件中导入打包后的文件。
index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Learn Webpack</title>
</head>
<body>
  <script src="./build/bundle.js"></script> 
</body>
</html>

执行npm run build并打开index.html文件。如图,说明我们的配置起效果了。
在这里插入图片描述

处理图片相关文件 – jpg、jpeg、png、svg、gif、webp等

这里有两点需要说明:

  1. 在webpack5之前,加载这些资源我们需要使用一些loader,比如raw-loader 、url-loader、file-loader。
  2. 从webpack5开始,我们可以直接使用资源模块类型( asset module type),来替代上面的这些loader。

资源模块类型 (asset module type) ,通过添加 4 种新的模块类型,来替换所有这些 loader:

  1. asset/resource发送一个单独的文件并导出 URL 。

之前通过使用 file-loader 实现;

  1. asset/inline导出一个资源的 data URI。

之前通过使用 url -loader实现;

  1. asset/source导出资源的源代码

之前通过使用raw-loader实现;

  1. asset 在导出一个 data URI和发送一个单独的文件之间自动选择

之前通过使用 url-loader,并且配置资源体积限制实现。

在src下面新建文件夹img,然后在其中放入两张图片,一张小于100kb,一张大于100kb。在css文件夹下新建bg_style.css ,内容如下

bg_style.css

.img-bg {
  width: 500px;
  height: 500px;
  background: url(../img/LessThan100.jpg);
}

在cpns.js文件中新增内容,如下:

cpns.js

import "../css/div_style.css"
import "../css/title_style.less"
import "../css/bg_style.css"

// 引入图片模块
import MoreThan100 from "../img/MoreThan100.png"

// 创建div元素
const divEl = document.createElement("div")
divEl.textContent = "Hello Webpack"
divEl.classList.add("content")
document.body.append(divEl)

// 创建h2元素
const titleEl = document.createElement("h2")
titleEl.textContent = "哈哈哈哈"
titleEl.classList.add("title")
document.body.append(titleEl)

// 创建img元素
const imgEl = document.createElement("img")
imgEl.src = MoreThan100
document.body.append(imgEl)

// 创建div元素, 设置背景
const divBgEl = document.createElement("div")
divBgEl.classList.add("img-bg")
document.body.append(divBgEl)

在wk.config.js中增加如下配置

const path = require("path") 

module.exports = {
  mode: 'development',
  entry: "./src/main.js",
  output: {
    path: path.resolve(__dirname, './build'),
    filename: "bundle.js"
  }, 
  module: {
    rules: [
      // 刚刚已经做过的配置
      // ...
      {
        test: /\.(png|jpe?g|svg|gif|webp)$/,
        // 1.打包两张图片, 并且这两张图片有自己的地址, 将地址设置到img/bgi中
        // 缺点: 多图片加载的两次网络请求
        // type: "asset/resource",

        // 2.将图片进行base64的编码, 并且直接编码后的源码放到打包的js文件中
        // 缺点: 造成js文件非常大, 下载js文件本身消耗时间非常长
        // 造成js代码的下载和解析/执行时间过长
        // type: "asset/inline"

        // 3.合理的规范:
        // 3.1.对于小一点的图片, 可以进行base64编码
        // 3.2.对于大一点的图片, 单独的图片打包, 形成url地址, 单独的请求这个url图片
        type: "asset",
        parser: {
          dataUrlCondition: {
            maxSize: 100 * 1024	 // 超过100kb(自定义)的就单独打包,否则转base64编码
          }
        },
        generator: {
          // 占位符
          // name: 指向原来的图片名称
          // ext: 扩展名
          // hash: webpack生成的hash
          filename: "img/[name]_[hash:8][ext]"
        }
      },
    ]
  },
}

删除build文件夹,重新运行npm run build,结果如下。可以看到大于100kb的图片被打包成了一个单独的图片文件,而小于100kb的图片则被转为了base64编码。
在这里插入图片描述
在这里插入图片描述

配置babel

babel是什么?Babel 是一个工具链 ,主要用于旧浏览器或者环境中将ECMAScript 2015+代码转换为向后兼容版本的JavaScript ;
包括:语法转换、源代码等。
需要安装的包:babel-loader,@babel/preset-env。

对@babel/preset-env的说明:
常见的预设有三个:

  • env
  • react
  • TypeScript
npm install babel-loader @babel/preset-env -D

配置wk.config.js,如下

const path = require("path") 

module.exports = {
  mode: 'development',
  entry: "./src/main.js",
  output: {
    path: path.resolve(__dirname, './build'),
    filename: "bundle.js"
  }, 
  module: {
    rules: [
      // 刚刚已经做过的配置
      // ...
     {
        test: /\.m?js$/,
        use: [
          { 
            loader: "babel-loader", 
            options: {
              presets: ["@babel/preset-env"]
            } 
          }
        ]
      },
    ]
  },
}

重新执行打包命令,可以看到bundle.js中找不到const定义的内容了
在这里插入图片描述

将babel-loader的配置单独抽取出去

如果觉得wk.config.js中的内容过多的话,也可以将babel-loader的配置内容抽取到一个单独的文件中去,其他配置文件的抽取类似
在根目录下新建一个**babel.config.js(在你没有能力更改时,名字是固定的,不要瞎编!!!)**文件,内容如下
babel.config.js

module.exports = {
  presets: [
    "@babel/preset-env"
  ]
}

然后wk.config.js中babel的配置只要这样写就行了

{
   test: /\.m?js$/,
   use: ["babel-loader"]
},

重新打包后可以看到打包后的效果和上面是一致的,bundle.js中找不到“const”之类的内容。

打包.vue文件

需要安装的包:vue-loader、@vue/compiler-sfc(安装vue时就已经安装好了)

npm install vue-loader vue -D

配置wk.config.js,如下

const path = require("path") 
const { VueLoaderPlugin } = require("vue-loader/dist/index")

module.exports = {
  mode: 'development',
  entry: "./src/main.js",
  output: {
    path: path.resolve(__dirname, './build'),
    filename: "bundle.js"
  }, 
  plugins: [new VueLoaderPlugin()],
  module: {
    rules: [
      // 刚刚已经做过的配置
      // ...
       {
        test: /\.vue$/,
        loader: "vue-loader"
      }
    ]
  },
}

在src文件下新建Hello.vue文件,内容如下:

<template>
  <div>
    <!-- html -->
    <h2 class="title_vue">{{title}}</h2>
    <p class="content_vue">
      我是内容, 哈哈哈哈哈哈哈哈
    </p>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        title: "我是Vue的标题"
      }
    }
  }
</script>

<style>
  .title_vue {
    color: green;
    font-size: 100px;
  }

  .content_vue {
    color: yellow;
    font-size: 30px;
  }
</style>

index.html中增加一个Hello.vue的预挂载元素:div#app
index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>learn webpack</title>
  </head>
  <body>
    <div id="app"></div>

    <script src="./build/bundle.js"></script>
  </body>
</html>

然后在main.js中引入Hello.vue,并将其挂载到div#app上去
main.js

import { createApp } from "vue"
import Hello from "./vue_demo/Hello"

// 刚刚的代码
// ...

// Vue代码
createApp(Hello).mount("#app")

重新执行打包命令,可以看到.vue文件被成功解析了。
在这里插入图片描述

文件路径的解析和配置:配置别名&自动添加扩展名

我们知道,在项目中,我们经常需要从其他文件中引入文件,有时候呢,我们需要引入的文件比较多,并且这些文件的层级可能还比较深,而且还有不同的扩展名需要书写。这个时候,有些同学可能会说,不是有代码提示吗,也不用我去费力写啊!但是,你想想,如果你引入了许多文件,每个文件都是这样:“…/…/…/…/xxx/xx/xx.xx”写的话真的好吗?所以,这部分工作就交给webpack来做吧。

  • extensions: 解析到文件时自动添加扩展名,默认值是[‘.wasm’, '.mjs ', ‘.js’, ‘.json’],可以自己添加其他的。
  • alias:为文件路径配置别名。

在wk.config.js中添加如下配置。

const path = require("path") 

module.exports = {
  mode: 'development',
  entry: "./src/main.js",
  output: {
    path: path.resolve(__dirname, './build'),
    filename: "bundle.js"
  }, 
   // 刚刚已经做过的配置
  // ...
  resolve: {
    //  这样我们后期引入如下后缀名的文件就不用写后缀名了
    extensions: [".js", ".json", ".vue", ".jsx", ".ts", ".tsx"],
    // 这样我们下次再引入src下面utils下面的文件时,就不用写成src/utils/了
    // 直接写成utils/就行了
    alias: {
      utils: path.resolve(__dirname, "./src/utils"),
      test: "utils/abc/cba/nba/why"
    }
  },
}

如下图,在utils文件下新建两个文件math.js和test.js,将test.js放到很深的地方去
在这里插入图片描述
math.js

export function sum(num1, num2) {
  return num1 + num2
}

test.js

import { sum } from "utils/math.js"

console.log(sum(20, 30))

在main.js中引入并使用。
main.js

// 只写这一行代码
// 单独看一下我们的配置的别名和省略扩展名的写法有没有生效
// 前面一个test表示配置的深层文件夹的别名
// 后面一个表示的是深层文件夹下的test.js这个文件
import "test/test"

重新执行打包命令,如图,解析成功
在这里插入图片描述

loader与plugin的区别

loader:用于 特定的模块类型 转换。
plugin:用于执行更加广泛的任务,比如打包优化、资源管理、环境变量注入等。

Webpack默认只能处理js文件,处理其他文件需要安装相应的loader。

webpack插件之clean

前面演示时,每次修改配置重新打包时,都要手动删除build文件夹,有些太麻烦,这件事情我们可以交给一个插件CleanWebpackPlugin来做

npm install clean-webpack-plugin -D

重新执行打包命令后就能看到,打包文件夹build里的内容先被自动删除,然后又重新构建了。

当然,webpack5现在还有一种更简便的方法:直接在output中配置clean属性即可
wk.config.js

const path = require("path") 

module.exports = {
  mode: 'development',
  entry: "./src/main.js",
  output: {
    path: path.resolve(__dirname, './build'),
    filename: "bundle.js",
    clean: true
  }, 
  // 之前的代码
  // ...
}

webpack插件之打包html

我们看到,我们最终打包的代码中是没有index.html这个文件的,但是进行对应的部署时,是必须要有对应的入口文件index.html的,所以我们也需要对index.html文件进行打包。

打包html需要用到html-webpack-plugin这个插件

npm install html-webpack-plugin -D

然后在wk.config.js文件中增加如下配置:
wk.config.js

const path = require("path") 
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  mode: 'development',
  entry: "./src/main.js",
  output: {
    path: path.resolve(__dirname, './build'),
    filename: "bundle.js",
    clean: true
  }, 
  plugins: [  
    new HtmlWebpackPlugin({
      title: "Learn Webpack",
      // 将当前文件下的index.html作为模板
      template: "./index.html"
    }),
  ],
  // 之前的代码
  // ...
}

配置后,我们要将原先的index.html引入bundle.js的部分删除掉,否则一会会发现bundle.js文件被引入了两次。
重新打包后我们发现在build文件夹中生成了一个index.html文件,并且自动引入了打包的bundle.js文件。

那这个文件是如何生成的呢?

  • 默认情况下是根据ejs的一个模板来生成的。(注 EJS:Embedded JavaScript templating 是一个JavaScript模板库,用来从JSON数据中生成HTML字符串)
  • 在html-webpack-plugin的源码中,有一个default_index.ejs模块是负责这部分工作的。

自定义HTML模板

有时,我们想要在自己的模块中加入一些特别的内容,比如:

  1. 添加一个noscript标签,在用户的JS被关闭时,给予一些提示。
  2. 在开发vue/react项目中,我们需要添加一个可以挂载后续组件的根标签<div id="app"></div>

这个时候我们就需要一个属于自己的index.html模板
自定义的index.html

<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

上面的 代码中,会有一些类似这样语法 <% 变量 %> ,这个是EJS模块填充数据的方式
在配置 HtmlWebpackPlugin时,我们可以添加如下配置:

  • template:指定我们要使用的模块所在路径;
  • title:在进行 htmlWebpackPlugin.options.title读取时,就会读到该信息

我们上面的配置也是按照这种方式配置的。
如果我们用自定义的index.html文件替换掉原先的index.html文件,直接打包的话是会出现问题的,因为有个变量BASE_URL我们并没有进行定义。这个时候就要用到插件DefinePlugin了,它是webpack内置的插件,不需要单独安装。在wk.config.js增加如下配置:
wk.config.js

const path = require("path") 
const { DefinePlugin } = require("webpack")

module.exports = {
  mode: 'development',
  entry: "./src/main.js",
  output: {
    path: path.resolve(__dirname, './build'),
    filename: "bundle.js",
    clean: true
  }, 
  plugins: [  
  	// 在DefinePlugin定义的变量会变成全局变量
     new DefinePlugin({
     // 这里写的东西会被当做JS代码去执行,相当于进行了eval操作
     // 因此要写成"'./'",这样经过eval("'./'") = './'才是我们想要的结果(字符串)
      BASE_URL: "'./'",
      name: "'Lee'",
      counter: "123"
    })
  ],
  // 之前的代码
  // ...
}

重新打包后就会看到如下结果了,说明配置成功了:
在这里插入图片描述

webpack开启本地服务器

从上面的操作中我们可以看出,每改一次代码就得重新打包一次,非常繁琐,有没有可以改代码自动重新打包的呢?这就要用到
webpack-dev-server了

npm i webpack-dev-server -D

到wk.config.js中配置devServer

devServer: {
	hot: true,  // 热模块更新,默认为true
	// host: "0.0.0.0",
	// port: 8888,	// 设置监听的端口,默认8080
	// open: true	// 是否打开浏览器
	// compress: true  // 是否为静态文件开gzip compression,默认false
},

然后到package.json中配置一下启动命令

"scripts": {
  "build": "webpack --config wk.config.js",
  "serve": "webpack serve --config wk.config.js"
},

此时我们运行npm run serve就可以启动项目啦!

总结

本篇文章我们详细讲述了webapck5.x的安装,以及常见的loader和plugin的使用,但是针对一些细节性的问题没有进行描述,比如HMR,Proxy,@babel/preset 的预设等等,如果再写的话,这篇文章就太长了。常见的内容讲的差不多了,如果遇到个别不常见的配置内容,大家就去查阅官方的文档和网上的资料吧。

我们现在只是会用了,但针对webpack的优化又该如何下手呢?不要急,好饭不怕晚,在肝了,在肝了~

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值