构建webpack5.x 知识体系:3、基础之图片、html、js、其他配置

1,314 阅读14分钟

这是一个系列文的分享记录,本篇主要是webpack的基础之其他配置,如图片、html、其他资源的配置、devserver配置、环境配置。在此文还会简述一下webpack的工作模式,构建流程,Loader和Plugin的不同?等知识;遇到的坑、问题分享;

正式开始:

预备技能

基本nodejs知识和npm指令

注意:版本问题导致不同,本系列实战中用到的webpack版本是:"webpack": "^5.68.0",

"webpack-cli": "^4.9.2",

前置知识

在上一篇遗留一个问题就是我们想,自动产出html,要不然每次都删除的build文件夹,我们自己还要手动在创建index.html文件,太麻烦~~ 这个时候我们需要引出另一个核心概念的 plugin

Plugin

在上一篇基础概念中有简单介绍了一下Plugin的概念。

插件(Plugin):扩展插件,在 Webpack 构建流程中的特定时机注入扩展逻辑来改变构建结果或做你想要的事情。可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量等。

plugins配置:
  • 1、下载模块
  • 2、引入
  • 3、使用

总结:想要使用一个插件,先安装下载这个插件,在需要 require() 它,然后把它添加到 plugins 数组中。多数插件可以通过选项(option)自定义。你也可以在一个配置文件中因为不同目的而多次使用同一个插件,这时需要通过使用 new 操作符来创建一个插件实例。

打包html资源--自动产出html

我们希望自动能产出HTML文件,并在里面引入产出后的资源

1、下载模块

npm i html-webpack-plugin -D

2、引入

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

3、使用

 plugins: [
 // 功能:默认会创建一个空的HTML 自动会引入打包输出的所有资源(js/css)
        // 需要有结构的html文件
        new HtmlWebpackPlugin({
            // 复制 './index.html' 文件并自动会引入打包输出的所有资源(js/css)
            template: './index.html' // //指定模板文件
        }),
  ]      

'html-webpack-plugin'中的属性参数有:

  • minify 是对html文件进行压缩,removeAttrubuteQuotes是去掉属性的双引号
  • hash 引入产出资源的时候加上查询参数,值为哈希避免缓存
  • template 模版路径
  • filename 产出后的文件名
  • chunksSortMode:'manual'//对引入代码块进行排序的模式
  • inject 打包的资源引入到HTML的哪个区域,我们可以看到默认是 加载到了

4、在根目录创建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>Document</title>
</head><body>
    <div id="title">webpack5知识</div>
</body></html>

5、运行 webpack

image.png

查看build文件夹中的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>Document</title>
<script defer src="built.js"></script></head><body>
    <div id="title">webpack5知识</div>
</body></html>

我们可以看到自动添加了

<script defer src="built.js"></script>

查看浏览器,也是正常的。

图片资源配置

1、在src下创建assets/images文件夹,这个文件夹下准备存放一些图片资源

image.png

2、然后修改index.html,添加三个div盒子,盒子大小为100px,200px, 300px,背景用图片填充

<!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>Document</title>
</head><body>
    <div id="title">webpack5知识</div>
    <hr>
    <div class="box box1"></div>
    <hr>
    <div class="box box2"></div>
    <hr>
    <div class="box box3"></div>
    <hr>
</body></html>

3、背景图引入:修改index.less

#title{
    color: chocolate;
}
.box{
    border: 1px saddlebrown solid;
    background-size: 100%;
    background-repeat: no-repeat;
​
    &.box1{
        width: 100px;
        height: 100px;
        background-image: url('./assets/images/vite.png');
    }
​
    &.box2{
        width: 200px;
        height: 200px;
        background-image: url('./assets/images/webpack.jpg');
    }
​
    &.box3{
        width: 300px;
        height: 300px;
        background-image: url('./assets/images/zx.png');
    }
}

运行webpack

编译通过

查看浏览器:

image.png

在index.css尝试上述步骤也是可以的。

4、页面直接引入:使用img标签

<!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>Document</title>
</head><body>
    <div id="title">webpack5知识</div>
    <hr>
    <div class="box box1"></div>
    <hr>
    <div class="box box2"></div>
    <hr>
    <div class="box box3"></div>
    <hr>
    <img src="./src/assets/images/vite.png" class="img" />
</body></html>

在编译webpack

编译通过。

再查看浏览器:

image.png

图片没有找到。

5、在js中引入图片

./src/index.js

const logo = require('./assets/images/vite.png');
​
const img = new Image();
img.src = logo;
document.body.appendChild(img);

在运行编译webpack

image.png

其实在webpack4.x的版本的时候 使用背景图方式引入,编译也是会报错的。

如果我们看过其他的webapck知识可能要告诉我们说要安装loader了,来吧,我们看看~

解决问题:

因为使用url-loader需要依赖file-loader,所以要安装两个

npm i url-loader file-loader -D

修改配置webpack.config.js

 {
     // 处理图片 
     test: /.(jpe?g|png|gif|svg)$/,
     loader: 'url-loader',
  }

运行webpack

我们可以看到 编译通过。

查看浏览器

image.png

咦,图片都不显示。

这是怎么回事呢?好坑🕳

因为:在webpack5中我们使用assets-module,因为在v5中url-loader已经被废弃:可以直接使用资源模块类型(asset module type),来替代 比如raw-loader 、url-loader、file-loader;

解决问题:

我们再次修改配置文件webpack.config.js改为:

 {
     // 处理图片 
     test: /.(jpe?g|png|gif|svg)$/,
     type: "asset/resource",
  }

运行webpack

我们可以看到 编译通过。

查看浏览器

image.png

我们可以看到,处理在页面html中引入的图片,其他的js中,css背景图片都能正常显示成功了。

页面html中引入的图片,这个图片不显示,我们怎么处理呢?

解决问题:

这个时候需要再次,增加一个loader配置。处理html。

修改配置webpack.config.js

​
            {
                // 处理图片 
                // 问题:默认处理不了html中img图片
                test: /.(jpg|png|gif|svg)$/,
                // loader: 'url-loader',
                type: "asset/resource"
            },
            {
                // 处理html
                // 问题:处理不了html中img图片
                test: /.html$/,
                // 使用一个loader 就是要loader属性值为字符串,多个使用use 值为数组
                // 需要html中的img图片 (负责引入img 在url-loader在处理)
                loader: 'html-loader'
​
            }

运行webpack

我们可以看到 编译通过。

查看浏览器

image.png

这个时候所有图片都可以正常加载了!!!

坑注意:解决问题:

可能有的低版本的webpack5,这个时候还是不可以,这是因为:html-loader默认是以esModule的方式进行编译,而url-loader处理图片的方式是commonjs,所以需要修改一下html-loader的options配置,将esModule改为false。

{
                test: /.html$/,
                loader: 'html-loader',
                options: {
                    esModule: false
                }
            }

而我的这个webpack版本已经不需要了。

————————————————

好了,我们在来看一下build文件夹下的图片,

image.png

图片文件的名字都已经变了,并且带上了 hash 值。

需求:如何更改打包后图片hash的名字呢?

解决问题:

修改配置webpack.config.js

 {
                // 处理图片 
                // 问题:默认处理不了html中img图片
                test: /.(jpe?g|png|gif|svg)$/,
                // loader: 'url-loader',
                type: "asset/resource",
                generator: {
                    //与output.assetModuleFilename是相同的,这个写法引入的时候也会添加好这个路径
                    filename: '[name][ext]'
                },
            },

[ext]  表示扩展名 

[name]: 表示文件的名字

运行webpack

我们可以看到 编译通过。

查看浏览器,没有问题。

我们看build文件中图片的名字。已经跟之前的名字一样了。

image.png

需求:如果就想使用url-loader等旧的loader可以吗?

解决问题:

当然可以,需要添加 type: 'javascript/auto',

修改配置:

{
                // 处理图片 
                // 问题:默认处理不了html中img图片
                test: /.(jpe?g|png|gif|svg)$/,
                // loader: 'url-loader',
                use: [{
                    loader: 'url-loader',
                    options: {
                        // 解析时会出现问题:[Object Module] 因为url-loader默认使用es6模块化解析, 而html-loader引入图片的commonjs解析
                        // 解决:url-loader 的es6模块化,使用commonjs解析
                        esModule: false,
                        // 图片进行重命名 
                        // [hash:10] 取图片的hash的前10位
                        // [ext] 图片的原来的扩展名
                        name: '[hash:10].[ext]'
                    }
                }],
                // !!!!!! 注意这个坑,webpack5的问题,旧assets loader(比如raw-loader 、url-loader、file-loader) 已经弃用,需要添加这个配置
                type: 'javascript/auto',
                // type: "asset/resource",
                // generator: {
                //     //与output.assetModuleFilename是相同的,这个写法引入的时候也会添加好这个路径
                //     filename: '[name][ext]'
                // },
            },

注意:esModule: false,不能少不然会报错。默认为true,即使用es6模块化;设为false,即使用commonJs模块语法

总结:

Webpack 无法识别图片文件,需要在打包的时候处理一下。

备注备注2
webpack4url-loader注意url-loader中依赖file-loader,所以我们要同时安装url-loader和file-loader,----
webpack5assets-moduleasset/inline 导出一个资源的 data URI。之前通过使用 url-loader 实现;asset/source 导出资源的源代码。之前通过使用 raw-loader 实现; asset 在导出一个 data URI 和发送一个单独的文件之间自动选择。之前通过使用 url-loader,并且配置资源体积限制实现;如果想使用url-loader,需要添加 type: 'javascript/auto',

图片处理时,通过需要的loader,如下:

  • file-loader:解决图片引入路径问题,并将图片 copy 到指定目录,默认为 dist
  • url-loader:解依赖 file-loader,当图片小于 limit 值的时候,会将图片转为 base64 编码,大于 limit 值的时候依然是使用 file-loader 进行拷贝
  • img-loader:压缩图片

其他处理图片可能用到的loader

url-loader参考: www.webpackjs.com/loaders/url… www.npmjs.com/package/url…

file-loader参考: www.webpackjs.com/loaders/fil… www.npmjs.com/package/fil…

img-loader参考: www.npmjs.com/package/img…

imagemin-mozjpeg配置项参考: www.npmjs.com/package/ima…

imagemin-gifsicle配置项参考: www.npmjs.com/package/ima…

imagemin-pngquant配置项参考: www.npmjs.com/package/ima…

ps:当然wepack5中已经不需要raw-loader 、url-loader、file-loader了

其他资源配置

  • 资源模块是一种模块类型,它允许使用资源文件(字体,图标等)而无需配置额外 loader
  • raw-loader => asset/source 导出资源的源代码
  • file-loader => asset/resource 发送一个单独的文件并导出 URL
  • url-loader => asset/inline 导出一个资源的 data URI
  • asset 在导出一个 data URI 和发送一个单独的文件之间自动选择。之前通过使用 url-loader,并且配置资源体积限制实现

1、比如字体资源的配置

我们在前端开发的时候,不可避免的会使用到,字体资源,也的时候是ui自己设计,有的时候是我们从一些ui库中下载的,这个时候配置呢,怎么办呢?一起来看看实战吧~~~

我们可以先下载一些图标,如可以使用iconfont官网

image.png

我这是自己找的字体资源下载的;

  • 修改index.js,将src/icons/iconfont.css引入。
// ./src/index/js
import dataJson from './data.json';
import './index.css';
import './index.less';
import './index.scss';
​
import './assets/icons/iconfont.css';
// 引入样式文件
function add(x, y) {
  return x + y;
}
console.log(add(1, 2));
console.log(dataJson, 'dataJson');
​
// js中引入图片
const logo = require('./assets/images/vite.png');
​
const img = new Image();
img.src = logo;
document.body.appendChild(img);
​
  • 使用样式

./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>Document</title>
</head><body>
    <div id="title">webpack5知识</div>
    <hr>
    <div class="box box1"></div>
    <hr>
    <div class="box box2"></div>
    <hr>
    <div class="box box3"></div>
    <hr>
    <img src="./src/assets/images/vite.png" class="img" />
    <hr>
    <i class="iconfont icon-shouji"></i>
    <hr>
</body></html>

运行webpack,编译

浏览器查看

image.png

但是如果是加载这个资源,配置好 loader 并将字体文件放在合适的位置后,你可以通过一个 @font-face 声明将其混合。本地的 url(...) 指令会被 webpack 获取处理,就像它处理图片一样:

在样式中添加:

@font-face {
font-family: 'MyFont';
src: url('./src/assets/icons/iconfont.ttf') format('ttf'),
font-weight: 600;
font-style: normal;
}
​
.hello {
  color: red;
font-family: 'MyFont';
}

运行webpack就会报错了,这个时候webpack.config.js中最好添加:

{
                    test: /.(woff|woff2|eot|ttf|otf)$/i,
                    type: 'asset/resource',
                },

2、CSV、TSV 和 XML这文件

要导入 CSV、TSV 和 XML,你可以使用 csv-loaderxml-loader。让我们处理加载这三类文件:

安装依赖

npm install --save-dev csv-loader xml-loader

./src/data.xml

<?xml version="1.0" encoding="UTF-8"?>
<note>
  <to>Mary</to>
  <from>John</from>
  <heading>Reminder</heading>
  <body>Call Cindy on Tuesday</body>
</note>

./src/data.csv

to,from,heading,body
Mary,John,Reminder,Call Cindy on Tuesday
Zoe,Bill,Reminder,Buy orange juice
Autumn,Lindsey,Letter,I miss you

./src/index.js

import Data from './data.xml';
import Notes from './data.csv';
console.log(Data);
console.log(Notes);

配置文件webpack.config.js中修改

{
        test: /.(csv|tsv)$/i,
        use: ['csv-loader'],
      },
      {
        test: /.xml$/i,
        use: ['xml-loader'],
      },

运行wepack编译,查看!

工作模式配置

mode

模式(Mode):指示 webpack 使用相应模式的配置。

选项描述特点
development会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 development。启用 NamedChunksPlugin 和 NamedModulesPlugin。能让代码本地调试运行的环境
production会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 production。启用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin 和 TerserPlugin。能让代码优化上线运行的环境
none不使用任何默认优化选项webpack 在 4 以后就支持 0 配置打包,

工作模式配置

mode

模式(Mode):指示 webpack 使用相应模式的配置。

选项描述特点
development会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 development。启用 NamedChunksPlugin 和 NamedModulesPlugin。能让代码本地调试运行的环境
production会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 production。启用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin 和 TerserPlugin。能让代码优化上线运行的环境
none不使用任何默认优化选项webpack 在 4 以后就支持 0 配置打包,

工作模式配置

  1. 只需在配置对象中提供 mode 选项:webpack.config.js

    module.exports = {
    mode: 'development',// 开发环境模式
    // mode: 'production', //生产模式
    };
    

区分环境

在真正的实战中,我们是需要区分不同的环境,本地开发和部署上线,不同的环境对整个项目想要的要求也不同;具体可以分为一下情况:

开发环境

  • 注重打包构建速度

  • 注重代码调试

生产环境

  • 注重打包构建速度

  • 注重代码运行的性能:

  • 需要压缩图片体积

  • 需要更小的包体积

区分环境

  • --mode用来设置模块内的process.env.NODE_ENV
  • --env用来设置webpack配置文件的函数参数
  • cross-env用来设置node环境的process.env.NODE_ENV
  • DefinePlugin用来设置模块内的全局变量
命令行配置--mode
  • webpack的mode默认为production
  • webpack serve的mode默认为development
  • 可以在模块内通过process.env.NODE_ENV获取当前的环境变量,无法在webpack配置文件中获取此变量
 "scripts": {
    "build": "webpack",
    "start": "webpack serve"
  },

index.js

console.log(process.env.NODE_ENV);// development | production

webpack.config.js

console.log('NODE_ENV',process.env.NODE_ENV);// undefined

ps: index.js中的process.env.NODE_ENV 中与 webpack.config.js中的process.env.NODE_ENV 是不一样的。

package.json

"build": "webpack --mode=production",  "start": "webpack --mode=development serve"

index.js

 console.log(process.env.NODE_ENV);//  development | production

webpack.config.js

console.log('NODE_ENV',process.env.NODE_ENV);// undefined
命令行配置--env

package.json

"scripts": {   "dev": "webpack serve --env=development",   "build": "webpack --env=production",}

index.js

 console.log(process.env.NODE_ENV);// undefined

webpack.config.js

console.log('NODE_ENV',process.env.NODE_ENV);// undefined

webpack.config.js

对于我们的 webpack 配置,有一个必须要修改之处。通常,module.exports 指向配置对象。要使用 env 变量,你必须将 module.exports 转换成一个函数:

module.exports = (env,argv) => {  console.log('env',env);// development | production};
定义环境变量DefinePlugin

使用 webpack 内置插件 DefinePlugin 用来设置模块内的全局变量.

注意:

  • 设置全局变量(不是window),所有模块都能读取到该变量的值
  • 可以在任意模块内通过 process.env.NODE_ENV 获取当前的环境变量
  • 但无法在node环境(webpack 配置文件中)下获取当前的环境变量

DefinePlugin 中的每个键,是一个标识符.

  • 如果 value 是一个字符串,会被当做 code 片段
  • 如果 value 不是一个字符串,会被stringify
  • 如果 value 是一个对象,正常对象定义即可
  • 如果 key 中有 typeof,它只针对 typeof 调用定义
//webpack.config.js
const webpack = require('webpack');
module.exports = {
    plugins: [
        new webpack.DefinePlugin({
        // 定义的只有在编译阶段使用 会把key用值替换了,真正打包后已经是值了,没有 key:'process.env.NODE_ENV'只有真正的 'development'或者其他设置的JSON.stringify(process.env.NODE_ENV)值
            'process.env.NODE_ENV':JSON.stringify(process.env.NODE_ENV),
            DEV: JSON.stringify('dev'), //字符串
            FLAG: 'true' //FLAG 是个布尔类型
        })
    ]
}

index.js

console.log(process.env.NODE_ENV);//  production

webpack.config.js

console.log('process.env.NODE_ENV',process.env.NODE_ENV);// undefined
console.log('NODE_ENV',NODE_ENV);// error !!!
使用cross-env****

针对不同的需求,首先要做的就是做好环境的区分

  • 只能设置node环境下的变量NODE_ENV 1、安装 cross-env
npm install cross-env -D

2、配置启动命令

更改package.json

"scripts": {
  "dev": "cross-env NODE_ENV=dev webpack serve --mode development",
  "test": "cross-env NODE_ENV=test webpack --mode production",
  "build": "cross-env NODE_ENV=prod webpack --mode production"
}

3、修改配置文件

const { resolve } = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
​
const config = (mode) => {
  return {
      // webpack 配置
      // 入口起点
      entry: './src/index.js',
      // 输出
      output: {
          // 输出路径 __dirname nodejs变量 代表当前文件的目录绝对路径
          path: resolve(__dirname, 'build'),
          // 输出ming
          filename: 'built.js'
      },
      // loader 配置
      module: {
          rules: [
​
              {
                  //匹配以css结尾的文件
                  test: /.css$/,
                  //采用css-loader进行处理,让webpack能够识别
                  //单个loader使用loader属性
                  //loader: 'css-loader'
​
                  //多个loader处理一个文件,需要使用use
                  //use属性的执行顺序为逆序,也就是数组尾->数组首的顺序
                  use: ['style-loader', 'css-loader']
​
​
              },
              {
                  //匹配以.less结尾的文件
                  test: /.less$/,
                  // less-loader 讲less文件变成成css文件 (需要下载两个依赖 less和less-loder)
                  // css-loader 将css文件变成commonjs模块加载到js中 里边内容是样式字符串
                  // style-loader 创建style标签,将js中的样式资源插入进行,添加到head中生效
                  // use数组执行顺序是倒叙,就是先执行'style-loader',在执行'css-loader'在执行'style-loader'
                  use: ['style-loader', 'css-loader', 'less-loader']
              },
              {
                  //匹配以.scss结尾的文件
                  test: /.scss$/,
                  use: ['style-loader', 'css-loader', 'sass-loader']
              },
              {
                  // 处理图片
                  // 问题:默认处理不了html中img图片
                  test: /.(jpe?g|png|gif|svg)$/,
                  // loader: 'url-loader',
                  use: [{
                      loader: 'url-loader',
                      options: {
                          // publicPath: './img', //相对打包后index.html的图片位置
                          //输出到build中的目录img下
                          // outputPath: 'img/',
                          // 图片大小小于8kb,就会被处理base64 (一般8-12 kb比较合适在项目中)
                          // 优点:减少请求数量(减轻服务器压力)
                          // 缺点:图片体积会更大 (文件请求速度更慢)
                          // limit: 11 * 1024,
                          // 解析时会出现问题:[Object Module] 因为url-loader默认使用es6模块化解析, 而html-loader引入图片的commonjs解析
                          // 解决:url-loader 的es6模块化,使用commonjs解析
                          esModule: false,
                          // 图片进行重命名
                          // [hash:10] 取图片的hash的前10位
                          // [ext] 图片的原来的扩展名
                          name: '[hash:10].[ext]'
                      }
                  }],
                  // !!!!!! 注意这个坑,webpack5的问题,旧assets loader(比如raw-loader 、url-loader、file-loader) 已经弃用,需要添加这个配置
                  type: 'javascript/auto',
                  // type: "asset/resource",
                  // generator: {
                  //     //与output.assetModuleFilename是相同的,这个写法引入的时候也会添加好这个路径
                  //     filename: '[name][ext]'
                  // },
              },
              {
                  // 处理html
                  // 问题:默认处理不了html中img图片
                  test: /.html$/,
                  // 使用一个loader 就是要loader属性值为字符串,多个使用use 值为数组
                  // 需要html中的img图片 (负责引入img 在url-loader在处理)
                  loader: 'html-loader',
                  // html-loader打包图片无法显示的问题 关闭es6模块的解析, 使用commonjs模块解析
                  // options: {
                  //     esModule: false
                  // }
​
              }
          ]
      },
      // plugins 的配置
      plugins: [
​
​
          // 功能:默认会创建一个空的HTML 自动会引入打包输出的所有资源(js/css)
          // 需要有结构的html文件
          new HtmlWebpackPlugin({
              // 复制 './index.html' 文件并自动会引入打包输出的所有资源(js/css)
              template: './index.html'
          }),
​
          // 清除build文件夹
          new CleanWebpackPlugin()
      ],
​
​
      mode, //开发模式
      // mode: 'production', //生产模式
​
      // 开发服务器 devserver 用来自动化(自动编译 自动打开浏览器 自动刷新浏览器。。。)
      // 特点 指挥在内存中编译打包 不会有任何输出
      // 启动devServer 指令 为npx webpack-dev-server
      // 1、下载依赖 2、使用 启动devServer 指令 为npx webpack-dev-server
      devServer: {
          // npx webpack-dev-server 报错 把 contentBase改为 static 或者注释掉 /webpack5中不用配置contentBase了,注释掉后正常打包
          static: resolve(__dirname, 'build'),
          // 启动gzip压缩
          compress: true,
          // 端口号
          port: 8888,
          // 自动打开浏览器
          open: true,
          // 开启HMR功能
          hot: true,
          // 域名
          host: 'localhost',
          // 服务器代理 -->解决开发环境跨域问题
          proxy: {
              '/api': {
                  target: 'http://localhost:5000',
                  pathRewrite: {
                      '^/api': ''
                  }
              }
          }
      },
​
​
  }
}
module.exports = (env, argv) => {
  console.log('argv.mode=', argv.mode, "env:", env)
      // 这里可以通过不同的模式修改 config 配置
  return config(argv.mode);
}

4、运行命令

  • 执行 npm run build
  • 执行 npm run dev

devServer配置

开发服务器 devserver 用来自动化(自动编译 自动打开浏览器 自动刷新浏览器。。。)

特点: 指挥在内存中编译打包 不会有任何输出

1、下载依赖 2、使用 启动devServer 指令 为npx webpack-dev-server 1、下载依赖

npm install -D webpack-dev-server

2、使用,修改webpack.config.js文件

const { resolve } = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
    // webpack 配置
    // 入口起点
    entry: './src/index.js',
    // 输出
    output: {
        //  输出路径 __dirname nodejs变量 代表当前文件的目录绝对路径
        path: resolve(__dirname, 'build'),
        // 输出ming
        filename: 'built.js',
        clean: true
    },
    // loader 配置
    module: {
        rules: [
​
            {
                //匹配以css结尾的文件
                test: /.css$/,
                //采用css-loader进行处理,让webpack能够识别 
                //单个loader使用loader属性
                //loader: 'css-loader'
​
                //多个loader处理一个文件,需要使用use
                //use属性的执行顺序为逆序,也就是数组尾->数组首的顺序
                use: ['style-loader', 'css-loader']
​
​
            },
            {
                //匹配以.less结尾的文件
                test: /.less$/,
                //  less-loader 讲less文件变成成css文件 (需要下载两个依赖 less和less-loder)
                // css-loader 将css文件变成commonjs模块加载到js中 里边内容是样式字符串
                // style-loader 创建style标签,将js中的样式资源插入进行,添加到head中生效
                // use数组执行顺序是倒叙,就是先执行'style-loader',在执行'css-loader'在执行'style-loader'
                use: ['style-loader', 'css-loader', 'less-loader']
            },
            {
                //匹配以.scss结尾的文件
                test: /.scss$/,
                use: ['style-loader', 'css-loader', 'sass-loader']
            },
                {
                    // 处理图片 
                    // 问题:默认处理不了html中img图片
                    test: /.(jpe?g|png|gif|svg)$/,
                    type: "asset",
                    generator: {
                        //与output.assetModuleFilename是相同的,这个写法引入的时候也会添加好这个路径
                        filename: 'imgs/[name].[hash:6][ext]',
                        //打包后对资源的引入,文件命名已经有/img了
                        // publicPath: './'
                    },
                },
                {
                    test: /.(woff|woff2|eot|ttf|otf)$/i,
                    type: 'asset/resource'
                },
            {
                // 处理html
                // 问题:默认处理不了html中img图片
                test: /.html$/,
                // 使用一个loader 就是要loader属性值为字符串,多个使用use 值为数组
                // 需要html中的img图片 (负责引入img 在url-loader在处理)
                loader: 'html-loader',
                // html-loader打包图片无法显示的问题 关闭es6模块的解析, 使用commonjs模块解析
                // options: {
                //     esModule: false
                // }
​
            }
        ]
    },
    // plugins 的配置 
    plugins: [
​
​
        // 功能:默认会创建一个空的HTML 自动会引入打包输出的所有资源(js/css)
        // 需要有结构的html文件
        new HtmlWebpackPlugin({
            // 复制 './index.html' 文件并自动会引入打包输出的所有资源(js/css)
            template: './index.html'
        })
    ],
​
​
    mode: 'development', //开发模式
    // mode: 'production', //生产模式
​
    // 开发服务器 devserver 用来自动化(自动编译 自动打开浏览器 自动刷新浏览器。。。)
    // 特点 指挥在内存中编译打包 不会有任何输出
    // 启动devServer 指令 为npx webpack-dev-server
    // 1、下载依赖 2、使用 启动devServer 指令 为npx webpack-dev-server
    devServer: {
        // npx webpack-dev-server 报错 把 contentBase改为 static 或者注释掉 /webpack-dev-server 版本大于 4.0.0中不用配置contentBase了,注释掉后正常打包
        static: resolve(__dirname, 'build'),
        // 启动gzip压缩
        compress: true,
        // 端口号
        port: 8888,
        // 自动打开浏览器
        open: true,
        // 开启HMR功能
        hot: true,
        // 域名
        host: 'localhost',
        // 服务器代理 -->解决开发环境跨域问题
        proxy: {
            '/api': {
                target: 'http://localhost:5000',
                pathRewrite: {
                    '^/api': ''
                }
            }
        }
    },
}

为了我们后面使用方便,修改package.json,添加启动命令

"scripts": {
        "test": "echo "Error: no test specified" && exit 1",
        "dev": "webpack serve",
        "build":"webpack"
    },

当然也可以直接命令行运行npx webpack-dev-server

image.png

这次不用我们自己手动打开浏览器,运行页面了,执行命令npx webpack-dev-server,会自动打开浏览器,端口号也被更改了~ 且会监听我们文件变化的功能~

image.png

坑来了需要注意:

⚠️注意:本文使用的 webpack-dev-server 版本是 ^4.7.4,当版本 version >= 4.0.0 时,需要使用 devServer.static 进行配置,版本比4.0.0小的是使用 devServer.contentBase 配置项。

在webpack5中package.json中写webpack serve

  • webpack-dev-server 在编译之后不会写入到任何输出文件。而是将 bundle 文件保留在内存中,然后将它们 serve 到 server 中,就好像它们是挂载在 server 根路径上的真实文件一样。如果你的页面希望在其他不同路径中找到 bundle 文件,则可以通过 dev server 配置中的 devMiddleware.publicPath 选项进行修改。
  • 将可以通过 http://[devServer.host]:[devServer.port]/[output.publicPath]/[output.filename] 进行访问
  • 报错 把 contentBase改为 static 或者注释掉 /webpack5中不用配置contentBase了,注释掉后正常打包
  • 从什么位置查找文件

Loader和Plugin的不同?

  • Loader直译为加载器。Webpack将一切文件视为模块,但是webpack原生是只能解析js文件,如果想将其他文件也打包的话,就会用到loader。 所以Loader的作用是让webpack拥有了加载和解析非JavaScript文件的能力
  • Plugin直译为插件。Plugin可以扩展webpack的功能,让webpack具有更多的灵活性。 在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果

webpack的构建流程是什么?

  • 初始化参数:从配置文件和Shell语句中读取与合并参数,得出最终的参数;

  • 开始编译:用上一步得到的参数初始化Compiler对象,加载所有配置的插件,执行对象的run方法开始执行编译; 确定入口:根据配置中的entry找出所有的入口文件

  • 编译模块:从入口文件出发,调用所有配置的Loader对模块进行编译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理;

  • 完成模块编译:在经过第 4 步使用Loader翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个Chunk转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会

  • 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统

    在以上过程中,Webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用 Webpack 提供的 API 改变 Webpack 的运行结果

感谢

到此,本篇介绍到此结束,之后将陆续整理 webpack 知识体系的内容分享,尽情期待,感谢您的阅读~~