Webpack 5 超详细解读(二)

news2024/10/7 3:19:15

11.importLoaders 属性

问题:
test.css的内容如下:

.title {
    transition: all .5s;
    user-select: none;
}

login.css的内容如下:

/* 导入test.css */

@import './test.css';
.title {
    color: #12345678;
}

再次npm run build发现运行之后的test.css里面的代码并没有做兼容性处理。

问题分析:

  • login.css @import 语句导入了test.css
  • login.css可以被匹配,当它被匹配到之后就是postcss-loader进行工作
  • 基于当前的代码,postcss-loader拿到了login.css当中的代码之后分析基于我们的筛选条件并不需要做额外的处理
  • 最终就将代码交给了css-loader
  • 此时css-loader是可以处理@import media、 url … ,这个时候它又拿到了test.css文件,但是loader不会回头找
  • 最终将处理好的css代码交给style-loader进行展示

解决问题:修改Webpack.config.js给css-loader设置一些属性。

const path = require('path')
module.exports = {
    entry: './src/index.js',
    output: {
        filename: 'build.js',
        //output必须设置绝对路径,所以这里导入path模块
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
           
            {
                //简写方式
                test: /\.css$/,
                //先执行style-loader再执行css-loader
                //顺序规则,从右往左,从下往上,因为兼容性处理要在css调用之前,所以需要将postcss-loader的配置放在css-loader右边
                use: ['style-loader', {
                    loader: 'css-loader',
                    options: {
                        // css-loader工作时,遇到css文件时,再往前找一个loader,即追回到postcss-loader
                        importLoaders: 1
                    }
                }, 'postcss-loader']
            },
            {
                //简写方式
                test: /\.less$/,
                //先执行style-loader再执行css-loader
                //顺序规则,从右往左,从下往上
                use: ['style-loader', 'css-loader', 'postcss-loader', 'less-loader']
            }
        ]
    }
}

再次运行成功。运行结果如下,test.css的内容也被修改成功。

12.file-loader 处理图片

12.1 JS导入图片并写入HTML

在js文件中引入img图片并输出到页面上

要处理jpg、png等格式的图片,我们也需要有对应的loader: file-loader。file-loader的作用就是帮助我们处理import/require()等方式引入的一个文件资源,并且会将它放到我们输出的文件夹中;当然也可以修改它的名字和所在文件夹

安装file-loader

npm install file-loader -D

目录结构:

Image.js中导入图片并显示在页面上:

import oImgSrc from '../img/01.wb.png'


function packImg() {
  // 01 创建一个容器元素
  const oEle = document.createElement('div')

  // 02 创建 img 标签,设置 src 属性
  const oImg = document.createElement('img')
  oImg.width = 600
  // 写法1:使用require...default取值
  // require导入默认一个对象,有一个default的键,代表的导入的内容
  // oImg.src = require('../img/01.wb.png').default


  // 写法2:lg.Webpack.js配置文件搭配使用,不需要写default取值
  // esModule: false // 不转为 esModule
  // oImg.src = require('../img/01.wb.png')


  // 写法3:使用import导入,不需要写default或者config配置esModule
  oImg.src = oImgSrc
  oEle.appendChild(oImg)

  return oEle
}

document.body.appendChild(packImg())

lg.Webpack.js

const path = require('path')

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
              esModule: false
            }
          },
          'postcss-loader'
        ]
      },
      {
        test: /\.less$/,
        use: [
          'style-loader',
          'css-loader',
          'postcss-loader',
          'less-loader'
        ]
      },
      {
        test: /\.(png|svg|gif|jpe?g)$/,
        // use: [
        //   {
        //     loader: 'file-loader',
        //     options: {
        //       esModule: false // 不转为 esModule,在js导入时无需写default取值
        //     }
        //   }
        // ]
        use: ['file-loader']
      }
    ]
  }
}

最终效果:

12.2 JS导入图片并设置到css样式

css-loader处理时,会默认将background-image: url('../img/02.react.png')处理为require的形式,而require会返回一个ESModule,所以需要在Webpack配置中添加css-loader的属性值->esModule: false

{
  test: /\.css$/,
    use: [
      'style-loader',
      {
        loader: 'css-loader',
        options: {
          importLoaders: 1,
          esModule: false
        }
      },
      'postcss-loader'
    ]
},

img.css

.bgBox {
  width: 240px;
  height: 310px;
  border: 1px solid #000;
  background-image: url('../img/02.react.png');
}

Image.js

import oImgSrc from '../img/01.wb.png'
import '../css/img.css'


function packImg() {
  // 01 创建一个容器元素
  const oEle = document.createElement('div')

  // 02 创建 img 标签,设置 src 属性
  const oImg = document.createElement('img')
  oImg.width = 600
  // 写法1:使用require...default取值
  // require导入默认一个对象,有一个default的键,代表的导入的内容
  // oImg.src = require('../img/01.wb.png').default


  // 写法2:lg.Webpack.js配置文件搭配使用,不需要写default取值
  // esModule: false // 不转为 esModule
  // oImg.src = require('../img/01.wb.png')


  // 写法3:使用import导入,不需要写default或者config配置esModule
  oImg.src = oImgSrc
  oEle.appendChild(oImg)

  // 03 设置背景图片
  const oBgImg = document.createElement('div')
  oBgImg.className = 'bgBox'
  oEle.appendChild(oBgImg)

  return oEle
}

document.body.appendChild(packImg())

lg.Webpack.js

const path = require('path')

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
              esModule: false
            }
          },
          'postcss-loader'
        ]
      },
      {
        test: /\.less$/,
        use: [
          'style-loader',
          'css-loader',
          'postcss-loader',
          'less-loader'
        ]
      },
      {
        test: /\.(png|svg|gif|jpe?g)$/,
        // use: [
        //   {
        //     loader: 'file-loader',
        //     options: {
        //       esModule: false // 不转为 esModule
        //     }
        //   }
        // ]
        use: ['file-loader']
      }
    ]
  }
}

13.设置图片名称与输出

修改file-loader的options用于设置图片名称和输出。

常见占位符:

[ext]: 扩展名 
[name]: 文件名称 
[hash]: 文件内容+MD4生成128为占位置,作为文件名 
[contentHash]: 文件内容+MD4生成128为占位置,作为文件名 
[hash:<length>]: hash截取,作为文件名
[path]: 文件路径

lg.Webpack.js

{
  test: /\.(png|svg|gif|jpe?g)$/,
  use: [
    {
      loader: 'file-loader',
      options: {
        name: 'img/[name].[hash:6].[ext]',
        // outputPath: 'img'
      }
    }
  ]
}

其中,目录有两种写法,一种为添加outputPath: 'img',另一种为直接在name处写入img/重新打包后,目录如下:

14.url-loader 处理图片

14.1 什么是 url-loader

url-loader 会将引入的文件进行编码,生成 DataURL,相当于把文件翻译成了一串字符串,再把这个字符串打包到 JavaScript

14.2 什么时候使用

一般来说,我们会发请求来获取图片或者字体文件。如果图片文件较多时(比如一些 icon),会频繁发送请求来回请求多次,这是没有必要的。此时,我们可以考虑将这些较小的图片放在本地,然后使用 url-loader 将这些图片通过 base64 的方式引入代码中。这样就节省了请求次数,从而提高页面性能。

14.3 什么时候使用

一般来说,我们会发请求来获取图片或者字体文件。如果图片文件较多时(比如一些 icon),会频繁发送请求来回请求多次,这是没有必要的。此时,我们可以考虑将这些较小的图片放在本地,然后使用 url-loader 将这些图片通过 base64 的方式引入代码中。这样就节省了请求次数,从而提高页面性能。

14.4 如何使用

  1. 安装 url-loader
npm install url-loader --save-dev
  1. 配置 webapck
module.exports = {
  module: {
    rules: [
      {
        test: /\.(png|jpg|gif)$/,
        use: [
          {
            loader: 'url-loader',
            options: {},
          },
        ],
      },
    ],
  },
};
  1. 引入一个文件,可以是 import(或 require
import logo from '../assets/image/logo.png';
console.log('logo的值: ', logo); // 打印一下看看 logo 是什么

简单三步就搞定了。

  1. 见证奇迹的时刻
Webpack

执行 Webpack 之后,dist 目录只生成了一个 bundle.js。和 file-loader 不同的是,没有生成我们引入的那个图片。上文说过,url-loader 是将图片转换成一个 DataURL,然后打包到 JavaScript 代码中。

那我们就看看 bundle.js 是否有我们需要的 DataURL

// bundle.js
(function(module, exports) {
module.exports = "data:image/jpeg;base64.........."; // 省略无数行
})

我们可以看到这个模块导出的是一个标准的 DataURL

一个标准的DataURL: data:[<mediatype>][;base64],<data>

通过这个 DataURL,我们就可以从本地加载这张图片了,也就不用将图片文件打包到 dist 目录下。

使用 base64 来加载图片也是有两面性的:

  • 优点:节省请求,提高页面性能
  • 缺点:增大本地文件大小,降低加载性能

所以我们得有取舍,只对部分小 size 的图片进行 base64 编码,其它的大图片还是发请求吧。

url-loader 自然是已经做了这个事情,我们只要通过简单配置即可实现上述需求。

14.5 options

  • limit: 文件阈值,当文件大小大于 limit 的时候使用 fallbackloader 来处理文件
  • fallback: 指定一个 loader 来处理大于 limit 的文件,默认值是 file-loader

我们来试试设一个 limit

{
  test: /\.(png|jpg|gif)$/,
  use: [
    {
      loader: 'url-loader',
      options: {
        name: 'img/[name].[hash:6].[ext]',
        limit: 25 * 1024  // 25kb
      }
    }
  ]
},
/**
 * 01 url-loader base64 uri 文件当中,减少请求次数
 * 02 file-loader 将资源拷贝至指定的目录,分开请求
 * 03 url-loader 内部其实也可以调用 file-loader
 * 04 limit
 */

重新执行 Webpack,由于我们引入的 logo.png 大于 1000,所以使用的是 file-loader 来处理这个文件。图片被打包到 dist 目录下,并且返回的值是它的地址:

(function(module, exports, __Webpack_require__) {
module.exports = __Webpack_require__.p + "dab1fd6b179f2dd87254d6e0f9f8efab.png";
}),

14.6 源码解析

file-loader 的代码也不多,就直接复制过来通过注释讲解了:

import { getOptions } from 'loader-utils'; // loader 工具包
import validateOptions from 'schema-utils'; // schema 工具包
import mime from 'mime';

import normalizeFallback from './utils/normalizeFallback'; // fallback loader
import schema from './options.json'; // options schema

// 定义一个是否转换的函数
/*
 *@method shouldTransform
 *@param {Number|Boolean|String} limit 文件大小阈值
 *@param {Number} size 文件实际大小
 *@return {Boolean} 是否需要转换
*/
function shouldTransform(limit, size) {
  if (typeof limit === 'boolean') {
    return limit;
  }

  if (typeof limit === 'number' || typeof limit === 'string') {
    return size <= parseInt(limit, 10);
  }

  return true;
}

export default function loader(src) {
  // 获取 Webpack 配置里的 options
  const options = getOptions(this) || {};

  // 校验 options
  validateOptions(schema, options, {
    name: 'URL Loader',
    baseDataPath: 'options',
  });

  // 判断是否要转换,如果要就进入,不要就往下走
  // src 是一个 Buffer,所以可以通过 src.length 获取大小
  if (shouldTransform(options.limit, src.length)) {
    const file = this.resourcePath;
    // 获取文件MIME类型,默认值是从文件取,比如 "image/jpeg"
    const mimetype = options.mimetype || mime.getType(file);

    // 如果 src 不是 Buffer,就变成 Buffer
    if (typeof src === 'string') {
      src = Buffer.from(src);
    }

    // 构造 DataURL 并导出
    return `module.exports = ${JSON.stringify(
      `data:${mimetype || ''};base64,${src.toString('base64')}`
    )}`;
  }

  // 判断结果是不需要通过 url-loader 转换成 DataURL,则使用 fallback 的 loader
  const {
    loader: fallbackLoader,
    options: fallbackOptions,
  } = normalizeFallback(options.fallback, options);

  // 引入 fallback loader
  const fallback = require(fallbackLoader);

  // fallback loader 执行环境
  const fallbackLoaderContext = Object.assign({}, this, {
    query: fallbackOptions,
  });

  // 执行 fallback loader 来处理 src
  return fallback.call(fallbackLoaderContext, src);
}

// 默认情况下 Webpack 对文件进行 UTF8 编码,当 loader 需要处理二进制数据的时候,需要设置 raw 为 true
export const raw = true;

15.asset 处理图片

Webpack 出现之前,前端开发人员会使用 gruntgulp 等工具来处理资源,并
将它们从 /src 文件夹移动到 /dist/build 目录中。Webpack 最出色的功能之一就是,除了引入 JavaScript,还可以内置的资源模块 Asset Modules 引入任何其他类型的文件。

Webpack4的时候以及之前,我们通常是使用file-loaderurl-loader来帮助我们加载其他资源类型。

15.1 Asset Modules Type的四种类型

而Webpack5可以使用资源模块来帮助我们,称之为Asset Modules,它允许我们打包其他资源类型,比如字体文件、图表文件、图片文件等。

其中,资源模块类型我们称之为Asset Modules Type,总共有四种,来代替loader,分别是:

  1. asset/resource:发送一个单独的文件并导出URL,替代file-loader
  2. asset/inline:导出一个资源的data URI,替代url-loader
  3. asset/source:导出资源的源代码,之前通过使用raw-loader实现
  4. asset:介于asset/resourceasset/inline之间,在导出一个资源data URI和发送一个单独的文件并导出URL之间做选择,之前通过url-loader+limit属性实现。

不过在介绍这四种资源模块类型之前,我们先说一下怎么自定义这些输出的资源模块的文件名

15.2 自定义资源模块名称

15.2.1 assetModuleFilename

第一种方式,就是在 Webpack 配置中设置 output.assetModuleFilename 来修改此模板字符串,其中assetModuleFilename默认会处理文件名后缀的点,所以无需手动添加点。此方式为公共的处理方法,当需要同时处理图片资源和字体资源时,通用方法会导致两种资源类型放在同一个目录下,此处不建议使用assetModuleFilename。

比如关于图片的输出文件名,我们可以让其都输出在images文件夹下面,[contenthash]表示文件名称,[ext]表示图片文件的后缀,比如.png、.jpg、.gif、jpeg等,[query]表可能存在的参数

output: {
   ···
   assetModuleFilename: 'images/[contenthash][ext][query]' 
   ···
},

15.2.2 geneator属性

第二种方式,就是在module.rules里面某种资源文件配置的时候,加上geneator属性,例如

rules: [
	{ 
		test: /\.png/, 
		type: 'asset/resource', 
		generator: { 
	      	filename: 'images/[contenthash][ext][query]' 
	 	} 
	}
]

【注意】
generator 的优先级高于 assetModuleFilename

15.3 四种类型的导入

首先我们先新建一个文件夹来测试,文件夹目录如下,我们在src下面新建一个assets文件夹,里面放上事先准备好的集中不同类型的图片

index.js

import hello from './hello'
import img1 from './assets/man.jpeg'
import img2 from './assets/store.svg'
import img3 from './assets/women.jpg'
import Txt from './assets/wenzi.txt'
import dynamic from './assets/dongtu.gif'
hello()

const IMG1 = document.createElement('img')
IMG1.src = img1
document.body.appendChild(IMG1)

const IMG2 = document.createElement('img')
IMG2.src = img2
IMG2.style.cssText = 'width:200px;height:200px'
document.body.appendChild(IMG2)

const IMG3 = document.createElement('img')
IMG3.src = img3
document.body.appendChild(IMG3)

const TXT = document.createElement('div')
TXT.textContent = Txt
TXT.style.cssText = 'width:200px;height:200px;backGround:aliceblue'
document.body.appendChild(TXT)

const DYNAMIC = document.createElement('img')
DYNAMIC.src = dynamic
document.body.appendChild(DYNAMIC)

hello.js

function hello(){
    console.log("hello-world!!!")
}

export default hello

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>你是,永远的神</title>
</head>
<body>
</body>
</html>

Webpack.config.js

const path = require('path')
const HtmlWebpackPlugin = require('html-Webpack-plugin')

module.exports = {
    entry : './src/index.js',

    output : {
        filename:'bundle.js',
        path:path.resolve(__dirname,'./dist'),
        clean:true,
        //如果不设置,打包完之后资源会直接打包在dist目录下
        assetModuleFilename:'images/[contenthash][ext][query]'
    },

    mode : 'development',

    devtool:'inline-source-map',

    plugins:[
        new HtmlWebpackPlugin({
            template:'./index.html',
            filename:'app.html',
            inject:"body"
        })
    ],

    devServer:{
        static:'./dist'
    },

    module:{
        rules:[{
            test:/\.jpeg$/,
            type:"asset/resource",
            generator:{
               filename:'images/[contenthash][ext][query]'
            }
        },{
            test:/\.svg$/,
            type:'asset/inline'
        },{
            test:/\.txt$/,
            type:'asset/source'
        },{
            test:/\.(gif|jpg)$/,
            type:'asset',
            parser:{
                dataUrlCondition:{
                    maxSize : 10 * 1024 * 1024
                }
            }
        }]
    }
    
}

15.3.1 resource 资源类型

asset/resource可以发送一个单独的文件并导出URL

我们将.jpeg后缀的图片设置typeasset/resource,我们在index.js里面导入该图片并插入在body中,即将其当成资源显示在页面上

npx Webpack打包之后,dist文件夹下的images文件中就出现该图片

npx Webpack-dev-server --open``自动打开浏览器,我们在控制台中查看该图片类型,发现``asset/resource``类型确实可以导出一个文件和其URL路径

15.3.2 inline资源类型

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

仿照上面的方式,我们将.svg后缀的图片设置type为asset/inline,我们在index.js里面导入该图片并插入在body中,即将其当成资源显示在页面上,同时我们简单设置一下样式

不过不同的是,npx Webpack打包之后,dist文件夹下面并没有打包过.svg类型的图片

npx Webpack-dev-server --open``自动打开浏览器,我们在控制台中查看该图片类型,发现asset/inline类型确实可以导出Data URI形式的路径`

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tdNft1xs-1669024454621)(http://5coder.cn/img/1667899086_6db380698c5f300aa8f603a96259c3ef.png)]

15.3.3 source资源类型

source资源,导出资源的源代码

仿照上面的方式,我们创建一个.txt后缀的文本文件,设置type为asset/source,我们在index.js里面导入该文本并插入在body中,即将其当成资源显示在页面上,同时我们简单设置一下样式

不过不同的是,npx Webpack打包之后,dist文件夹下面并没有打包过.txt类型的文本文件

npx Webpack-dev-server --open自动打开浏览器,我们在控制台中查看该文本类型,发现asset/source类型确实可以导出资源的源代码

15.3.4 asset通用资源类型

asset会介于asset/resourceasset/inline之间,在发送一个单独的文件并导出URL导出一个资源data URI之间做选择

默认情况下,Webpack5会以8k为界限来判断:

  • 当资源大于8k时,自动按asset/resource来判断
  • 当资源小于8k时,自动按asset/inline来判断

我们可以手动更改临界值,设置parser(解析),其是个对象,里面有个固定的属性,叫dataUrlCondition,顾名思义,data转成url的条件,也就是转成bas64的条件,maxSize是就相当于Limit了

module:{
        rules:[
        ···
        {
            test:/\.(gif|jpg)$/,
            type:'asset',
            parser:{
                dataUrlCondition:{
                    maxSize : 100 * 1024 
                }
            }
        }
        ···
        ]
    }

这里我们设置100 * 1024即100kb,来作为临界值
【1b * 1024 = 1kb,1kb * 1024 = 1M】

仿照上面的方式,我们将.gif.jpg后缀的图片设置type为asset资源类型,我们在index.js里面导入2张图片并插入在body中,即将其当成资源显示在页面上,其中.gif大小为128.11kb(超过了100kb的临界值),.jpg大小为12kb(未超过100kb的临界值)

npx Webpack打包之后,dist文件夹下面有打包过的.gif类型的图片,但是没有打包过.jpg类型的图片

npx Webpack-dev-server --open自动打开浏览器,我们在控制台中查看2种图片类型,发现.gif图片是单独一个文件的URL路径,而.jpg图片是Data URI格式的base64路径

16.asset处理图标字体

同上面所说,处理字体图标文件时,需要将其视为resource资源直接复制,所以需要使用asset/resource。此时准备好的字体文件及其目录如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qfOGeexu-1669024454626)(http://5coder.cn/img/1667912567_615bc7ed1f6fdaa5eb09f02bc8918739.png)]

font目录中,准备了iconfont.css及其字体文件,其中iconfont.css中对font-family进行赋值对应的字体。

单独常见font.js文件,并在文件中引入iconfont.css以及自定义的index.css文件,创建页面DOM元素并显示。

iconfont.css

@font-face {
  font-family: "iconfont"; /* Project id 2250626 */
  src: url('iconfont.woff2?t=1628066777598') format('woff2'),
       url('iconfont.woff?t=1628066777598') format('woff'),
       url('iconfont.ttf?t=1628066777598') format('truetype');
}

.iconfont {
  font-family: "iconfont" !important;
  font-size: 16px;
  font-style: normal;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.icon-linggan:before {
  content: "\e602";
}

.icon-publish:before {
  content: "\e635";
}

.icon-image:before {
  content: "\e629";
}


index.css

.lg-icon {
  color: red;
  font-size: 50px;
}

Font.js

import '../font/iconfont.css'
import '../css/index.css'

function packFont() {
  const oEle = document.createElement('div')

  const oSpan = document.createElement('span')
  oSpan.className = 'iconfont icon-linggan lg-icon'
  oEle.appendChild(oSpan)

  return oEle
}

document.body.appendChild(packFont())

当然,此时直接运行yarn build肯定会报错,因为此时Webpack不认识ttf/woff/woff2等资源,所以需要单独使用asset/resouce进行打包配置。

lg.Webpack.js

const path = require('path')

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
    // assetModuleFilename: "img/[name].[hash:4][ext]"
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
              esModule: false
            }
          },
          'postcss-loader'
        ]
      },
      {
        test: /\.less$/,
        use: [
          'style-loader',
          'css-loader',
          'postcss-loader',
          'less-loader'
        ]
      },
      {
        test: /\.(png|svg|gif|jpe?g)$/,
        type: 'asset',
        generator: {
          filename: "img/[name].[hash:4][ext]"
        },
        parser: {
          dataUrlCondition: {
            maxSize: 30 * 1024
          }
        }
      },
      {
        test: /\.(ttf|woff2?)$/,
        type: 'asset/resource',  // 使用资源复制
        generator: {
          filename: 'font/[name].[hash:3][ext]'  // 指定字体文件输出路径
        }
      }
    ]
  }
}

此时执行yarn build,我们发现在dist目录下新增了font目录,font目录中的字体文件为Webpack拷贝而来。打开页面可以看到iconfont.css以及自定义的index.css文件样式已经生效。

17.Webpack 插件使用

插件机制是Webpack当中另外一个核心特性‌‌,它目的是为了增强Webpack项目自动化方面的能力‌‌,loader就是负责实现各种各样的资源模块的加载‌‌,从而实现整体项目打包‌‌,plugin则是用来去解决项目中除了资源以外,其它的一些自动化工作‌,例如:

  • plugin可以帮我们去实现自动在打包之前去清除dist目录‌‌,也就是上一次打包的结果‌‌;
  • 又或是它可以用来去帮我们拷贝那些不需要参与打包的资源文件到输出目录‌‌;
  • 又或是它可以用来去帮我们压缩我们打包结果输出的代码‌‌。

总之‌‌,有了plugin的Webpack,几乎无所不能的实现了前端工程化当中绝大多数经常用到的部分‌‌,这也正是很多初学者会有Webpack就是前端工程化的这种理解的原因‌‌。

clean-Webpack-plugin:自动清空dist目录

之前的测试中,每次都需要用户手动的删除dist目录,我们希望Webpack每次打包时,先将之前的dist目录删除,再进行打包,这里使用clean-Webpack-plugin进行处理。

同样的,需要先进行安装clean-Webpack-plugin

yarn add clean-Webpack-plugin -D

之后按照其使用方法,在lg.Webpack.js中进行插件配置。首先使用require导入clean-Webpack-plugin,其中导出东西过多,需要进行解构:const { CleanWebpackPlugin } = require('clean-Webpack-plugin')。其次每个导出对象都是一个类,都有其自己的构造函数constructor,在plugins中使用时需要new CleanWebpackPlugin。代码如下:

const path = require('path')
const { CleanWebpackPlugin } = require('clean-Webpack-plugin')

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
    // assetModuleFilename: "img/[name].[hash:4][ext]"
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
              esModule: false
            }
          },
          'postcss-loader'
        ]
      },
      {
        test: /\.less$/,
        use: [
          'style-loader',
          'css-loader',
          'postcss-loader',
          'less-loader'
        ]
      },
      {
        test: /\.(png|svg|gif|jpe?g)$/,
        type: 'asset',
        generator: {
          filename: "img/[name].[hash:4][ext]"
        },
        parser: {
          dataUrlCondition: {
            maxSize: 30 * 1024
          }
        }
      },
      {
        test: /\.(ttf|woff2?)$/,
        type: 'asset/resource',
        generator: {
          filename: 'font/[name].[hash:3][ext]'
        }
      }
    ]
  },
  plugins: [
    new CleanWebpackPlugin()  // 每个插件就是一个类
  ]
}

先使用yarn build进行打包,生成dist目录,随后在dist目录中手动添加一个a.txt文件,如果再次执行yarn builda.txt被删除了,说明clean-Webpack-plugin已经正常工作了。

18.html-webapck-plugin 使用

除了清理dist的目录以外,‌‌还有一个非常常见的需求就是自动去生成使用打包结果的HTML,在这之前HTML‌‌都是通过硬编码的方式单独去存放在项目根目录下的。‌‌

index.html每次打包完成之后手动需要修改title,以及打包产生的文件由于分包过后文件类型或者数量比较多,需要用户手动的进行修改,这些行为都可以通过html-Webpack-plugin进行处理

默认情况下,不需要手动创建index.html文件Webpack在使用html-Webpack-plugin插件后会默认在打包结果dist目录自动创建index.html文件。

首先手动删除准备好的index.html,没有使用html-Webpack-plugin插件时,执行yarn build进行打包,通过观察发现dist目录中并没有生成index.html文件。

18.1 使用默认index.html模板

在配置文件中,首先导入html-Webpack-plugin。

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

在plugins字段中进行使用:

const HtmlWebpackPlugin = require('html-Webpack-plugin')
...
plugins: [
  new HtmlWebpackPlugin()
]
...

此时进行yarn build打包处理,可以发现dist目录中已经有了index.html文件。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mv51eLgK-1669024454630)(http://5coder.cn/img/1667915057_650596a463dae3f02e60811981b2bdb8.png)]

此时index.html内容是html-Webpack-plugin默认提供的,可以在node_modules中找到html-Webpack-plugin中的default_index.ejs查看。

18.2 使用自定义index.html模板

其中默认模板中的占位符在官方文档中有详细描述。

NameTypeDefaultDescription
title{String}Webpack AppThe title to use for the generated HTML document
filename`{StringFunction}`'index.html'
template{String}``Webpack relative or absolute path to the template. By default it will use src/index.ejs if it exists. Please see the docs for details
templateContent`{stringFunctionfalse}`
templateParameters`{BooleanObjectFunction}`
inject`{BooleanString}`true
publicPath`{String‘auto’}`'auto'
scriptLoading`{‘blocking’‘defer’‘module’}`
favicon{String}``Adds the given favicon path to the output HTML
meta{Object}{}Allows to inject meta-tags. E.g. meta: {viewport: 'width=device-width, initial-scale=1, shrink-to-fit=no'}
base`{ObjectStringfalse}`
minify`{BooleanObject}`true if mode is 'production', otherwise false
hash{Boolean}falseIf true then append a unique Webpack compilation hash to all included scripts and CSS files. This is useful for cache busting
cache{Boolean}trueEmit the file only if it was changed
showErrors{Boolean}trueErrors details will be written into the HTML page
chunks{?}?Allows you to add only some chunks (e.g only the unit-test chunk)
chunksSortMode`{StringFunction}`auto
excludeChunks{Array.<string>}``Allows you to skip some chunks (e.g don’t add the unit-test chunk)
xhtml{Boolean}falseIf true render the link tags as self-closing (XHTML compliant)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6LxMqoHN-1669024454640)(http://5coder.cn/img/1667915415_704784ee69f5f9963d59803a0654d2a0.png)]

对于占位符,我们可以在plugin中进行传参,赋予其默认值。

new HtmlWebpackPlugin({
  title: 'html-Webpack-plugin',  // title占位符
})
const path = require('path')
const { DefinePlugin } = require('Webpack')
const { CleanWebpackPlugin } = require('clean-Webpack-plugin')
const HtmlWebpackPlugin = require('html-Webpack-plugin')

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
    // assetModuleFilename: "img/[name].[hash:4][ext]"
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
              esModule: false
            }
          },
          'postcss-loader'
        ]
      },
      {
        test: /\.less$/,
        use: [
          'style-loader',
          'css-loader',
          'postcss-loader',
          'less-loader'
        ]
      },
      {
        test: /\.(png|svg|gif|jpe?g)$/,
        type: 'asset',
        generator: {
          filename: "img/[name].[hash:4][ext]"
        },
        parser: {
          dataUrlCondition: {
            maxSize: 30 * 1024
          }
        }
      },
      {
        test: /\.(ttf|woff2?)$/,
        type: 'asset/resource',
        generator: {
          filename: 'font/[name].[hash:3][ext]'
        }
      }
    ]
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      title: 'html-Webpack-plugin',  // title占位符
    })
  ]
}

再次yarn build进行打包后,index.htmltitle已经更新了。

此时我们使用的是html-Webpack-plugin内置的html模板文件。但是在实际使用过程中,我们可能需要使用特殊的模板文件。此时使用template字段去定义自己的index.html模板。

new HtmlWebpackPlugin({
  title: 'html-Webpack-plugin',
  template: './public/index.html'
}),

此时使用yarn build打包后,就会使用自定义的index.html模板文件。

此时,网站图标的路径使用<link rel="icon" href="<%= BASE_URL %>favicon.ico">,再使用DefinePlugin(Webpack默认,无需安装)进行定义全局配置的常量。

new DefinePlugin({
	BASE_URL: '"./"'
})

此时,完整的配置文件如下:

const path = require('path')
const { DefinePlugin } = require('Webpack')
const { CleanWebpackPlugin } = require('clean-Webpack-plugin')
const HtmlWebpackPlugin = require('html-Webpack-plugin')

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
    // assetModuleFilename: "img/[name].[hash:4][ext]"
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
              esModule: false
            }
          },
          'postcss-loader'
        ]
      },
      {
        test: /\.less$/,
        use: [
          'style-loader',
          'css-loader',
          'postcss-loader',
          'less-loader'
        ]
      },
      {
        test: /\.(png|svg|gif|jpe?g)$/,
        type: 'asset',
        generator: {
          filename: "img/[name].[hash:4][ext]"
        },
        parser: {
          dataUrlCondition: {
            maxSize: 30 * 1024
          }
        }
      },
      {
        test: /\.(ttf|woff2?)$/,
        type: 'asset/resource',
        generator: {
          filename: 'font/[name].[hash:3][ext]'
        }
      }
    ]
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      title: 'html-Webpack-plugin',
      template: './public/index.html'
    }),
    new DefinePlugin({
      BASE_URL: '"./"'  // Webpack会将常量原封不动的拿走,所以需要使用引号包裹
    })
  ]
}

再次进行打包后,结果如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n0HRrQU2-1669024454644)(http://5coder.cn/img/1667916420_f344a9bd9dd0b61dbbede8ea828a5f33.png)]

除了自定义输出文件的内容,同时输出多个页面文件也是一个非常常见的需求。其实配置非常简单,配置文件中添加一个新的HtmlWebpackPlugin对象,配置如下:

  plugins: [
    new CleanWebpackPlugin(),
    // 用于生成 index.html
    new HtmlWebpackPlugin({
      title: 'Webpack Plugin Sample',
      meta: {
        viewport: 'width=device-width'
      },
      template: './src/index.html'
    }),
    // 用于生成 about.html
    new HtmlWebpackPlugin({
      filename: 'about.html',  // 用于指定生成的文件名称,默认值是index.html
      title: 'About html'
    })
  ]

19.copy-Webpack-plugin

在项目中,一般还有一些不需要参与构建的静态文件,‌‌它们最终也需要发布到线上,‌‌例如我们网站的favicon.icon,‌‌一般会把这一类的文件统一放在项目的public目录当中,‌‌希望Webpack在打包时,可以一并将它们复制到输出目录。

‌‌对于这种需求,可以借助于copy-Webpack-plugin,‌‌先安装一下这个插件‌‌,然后再去导入这个插件的类型,‌‌最后同样在这个plugin属性当中去添加一个这个类型的实例,‌‌这类型的构造函数它要求传入一个数组,‌‌用于去指定需要去拷贝的文件路径,它可以是一个通配符,也可以是一个目录或者是文件的相对路径,‌‌这里使用plugin,‌‌它表示在打包时会将所有的文件全部拷贝到输出目录,‌‌再次运行Webpack指令,‌‌打包完成过后,public目录下所有的文件就会同时拷贝到输出目录。

const path = require('path')
const { CleanWebpackPlugin } = require('clean-Webpack-plugin')
const HtmlWebpackPlugin = require('html-Webpack-plugin')
const CopyWebpackPlugin = require('copy-Webpack-plugin')

module.exports = {
  mode: 'none',
  entry: './src/main.js',
  output: {
    filename: 'bundle.js',
    path: path.join(__dirname, 'dist'),
    // publicPath: 'dist/'
  },
  module: {
    rules: [
      {
        test: /.css$/,
        use: [
          'style-loader',
          'css-loader'
        ]
      },
      {
        test: /.png$/,
        use: {
          loader: 'url-loader',
          options: {
            limit: 10 * 1024 // 10 KB
          }
        }
      }
    ]
  },
  plugins: [
    new CleanWebpackPlugin(),
    // 用于生成 index.html
    new HtmlWebpackPlugin({
      title: 'Webpack Plugin Sample',
      meta: {
        viewport: 'width=device-width'
      },
      template: './src/index.html'
    }),
    // 用于生成 about.html
    new HtmlWebpackPlugin({
      filename: 'about.html'
    }),
    new CopyWebpackPlugin({
      patterns: [
        {
          from: 'public',
          globOptions: {
            ignore: ['**/index.html']  // 必须写入**/, ** 两个星号的意思是在当前路径
          }
        }
      ]
    })
  ]
}

20.babel 使用

由于Webpack默认就能处理代码当中的importexport,‌‌所以很自然都会有人认为Webpack会自动编译的ES6代码。实则不然,‌‌那是Webpack的仅仅是对模块去完成打包工作,‌‌所以说它才会对代码当中的importexport做一些相应的转换,‌‌它并不能去转换我们代码当中其它的ES6特性。

如果需要将ES6的代码打包并编译为ES5的代码,需要一些其它的编译形加载器。这里安装一些额外的插件。

首先,Webpack是可以识别ES6+的语法的,这里来测试一下,在index.js中写入ES6+的语法,使用yarn build进行打包,观察打包过后的代码可以发现,Webpack原封不动的把index.js中的ES6+语法代码拿了过来,并没有进行任何处理。

所以针对ES6+语法,需要使用特殊工具进行处理,这里安装@babel/core以及命令行工具@babel/cli进行代码测试,看babel默认是否会帮助处理ES6+语法。

yarn add @babel/core @babel/cli
yarn babel 

使用后发现,babel仍然没有帮我们处理ES6+语法,这是为什么呢?原因是babel还需要使用特殊插件进行处理。

yarn babel 目标路径 --out-put 输出路径

yarn babel src --out-put build

因此,我们需要特殊的插件来对箭头函数或者const、let关键字进行处理。

  • @babel/plugin-transform-arrow-functions(处理箭头函数)
  • @babel/plugin-transform-block-scoping(处理块级作用域)
yarn add @babel/plugin-transform-arrow-functions @babel/plugin-transform-block-scoping
# 执行babel
yarn babel src --out-dir build --plugins=@babel/plugin-transform-arrow-functions,@babel/plugin-transform-block-scoping

重新执行后,发现箭头函数和let、const关键字作用域已经被处理成var关键字。

image-20221109082655277

但是我们发现,每次需要处理不同的特殊情况,都需要安装不同的babel插件,特别不方便。因此babel将绝大多数有关ES6+语法以及stage草案的插件组合成一个集合@babel/preset-env,以后只需要使用这一个集合就可以处理绝大多数的ES6+语法。

# 安装@babel/preset-env
yarn add @babel/preset-env
# 使用babel进行编译
yarn babel src --out-dir build --presets=@babel/preset-env

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/25382.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

外汇天眼:想通过外汇交易在几个月内成为亿万富翁吗?你必须知道的七大交易法则

WikiFX 策略 -这里有七个交易规则&#xff0c;将在不同程度上让您受益。 1.交易不是儿戏 这是一项业务&#xff0c;如果没有适当的计划、战略和有效的运营&#xff0c;就不可能取得长期的成功。 2.损失不可避免 由于市场始终存在风险&#xff0c;因此在您的交易中从多头转为…

C++:项目相互依赖调用解决方法两种方法

Bmodel依赖于Amodel&#xff0c;但是Amodel又需要BModel的信息。这样就会导致相互依赖。 方法一&#xff1a;采用静态变量static 链接&#xff1a;C开发中一个解决方案里&#xff0c;两个项目的相互引用&#xff0c;相互依赖的实现方法&#xff08;解决方法&#xff09;_Capri…

P物质肽[DArg1, DTrp5, 7, 9, Leu11]

这种物质P类似物是一种非常有效的小细胞肺癌(SCLC)细胞体外生长的广谱神经肽抑制剂(IC₅₀ 5M)。此外&#xff0c;它在体外有效地抑制信号转导通路&#xff0c;并在体内显著延缓SCLC异种移植物的生长。因此&#xff0c;它可能对SCLC有治疗价值。 编号: 139994中文名称: P物质肽…

数据结构学习笔记(Ⅰ):绪论

课程链接:【旧版】1.0_开篇_数据结构在学什么_哔哩哔哩_bilibili 目录 1 数据结构的基本概念 2 算法 2.1 算法的基本概念 1.算法概念 2.算法的特性 3.好算法特质 2.2 算法的时间复杂度 2.3 算法的空间复杂度 1 数据结构的基本概念 数据&#xff1a;能输入到计算机中并…

Android StudioJNI开发之NDK环境的搭建以及添加JNI支持(图文解释 简单易懂)

有问题可以评论区留言讨论~~~ 一、NDK环境搭建 Android系统的所谓原生开发是在App中调用C/C代码&#xff0c;鉴于这两个语言具有跨平台的特性&#xff0c;如果某项功能使用C/C实现&#xff0c;就很容易在不同平台之间移植。 完整的Android环境包括三个开发工具。分别是JDK SD…

如何缩减layout电路面积?减少晶体管的数量——以全加器为例【VLSI】

如何缩减layout电路面积&#xff1f;减少晶体管的数量——以全加器为例【VLSI】What is Full adder ?全加器的设计方法1. 32T 原始表达式不经过化简的电路图2. 28个晶体管 最基本的静态互补CMOS电路的全加器静态互补CMOS静态互补CMOS的优势与劣势28T 电路图28T的棒状图Stick D…

彻底搞明白概率论:随机事件,样本空间,必然事件,不可能事件

文章目录样本空间样本点随机事件&#xff0c;必然事件&#xff0c;不可能事件参考视频样本空间 随机试验E的一切可能基本结果&#xff08;或实验过程如取法或分配法&#xff09;组成的集合称为E的样本空间&#xff0c;记为S 注意&#xff0c;对于不同的实验&#xff0c;样本空间…

【构建ML驱动的应用程序】第 3 章 :构建您的第一个端到端管道

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

FastDFS安装

fastdfs架构图 准备安装包 libfastcommon-1.0.43.tar.gz fastdfs-6.06.tar.gz fastdfs-nginx-module-1.22.tar.gz 一 、FastDFS--tracker安装 FastDFS安装环境 FastDFS是C语言开发&#xff0c;建议在linux上运行&#xff0c;本教程使用Centos7.4作为安装环境。 安装gcc …

如何使用做一个弹幕效果

效果展示 前置准备 背景图 图片素材 具体步骤 添加一个图片背景 添加一个水平滚动容器 添加一个容器 制作弹幕字体 制作弹幕动画效果 步骤分解 添加一个图片背景 拖拽 图片组件 到 编辑区 选中 图片组件 点击 检查面板 中的 样式 调整 图片组件 的 样式 添加一个水平滚动容…

餐饮机器人AB面:有人离场、有人挺进

民以食为天&#xff0c;餐饮生意是一颗“常青树”。 餐饮行业“常青”不代表没有变化&#xff0c;近年来Z世代消费者对餐饮口味、餐饮效率和餐饮安全提出更高要求。与此同时&#xff0c;在新消费、新技术、新模式的推动下&#xff0c;餐饮行业衍生出多元化趋势&#xff0c;外卖…

详解环境变量

目录前言一、什么是环境变量&#xff1f;二、查看环境变量的方法三、查看环境变量的内容四、普通变量VS环境变量五、导出环境变量六、常见的环境变量七、set命令&#xff1a;查看普通变量或环境变量八、C/C语言中main函数中的参数1、main函数的第一个和第二个参数应用&#xff…

IDEA提交本地项目到Gitee远程仓库

上一篇【Git的安装、配置、使用02【Idea对GitHub支持使用】】https://liush.blog.csdn.net/article/details/123446538 1. 新建仓库 2. IDEA登录gitee账号 3. 选择当前的项目作为本地库&#xff08;相当于初始化&#xff09; 4. 将项目添加到暂存区中 5. 将暂存区项目文件提交…

【CSS】CSS文本样式【CSS基础知识详解】

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;花无缺 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 花无缺 原创 本文章收录于专栏 【CSS】 【CSS专栏】已发布文章 &#x1f4c1;【CSS基础认知】 &#x1f4c1;【CSS选择器全解指南】 &#x1f4c1…

十万部冷知识:“澳大利亚”为什么属于亚洲球队?

在2022年卡塔尔世界杯上&#xff0c;总共有6支球队入围&#xff0c;他们分别是日本队&#xff0c;韩国队&#xff0c;沙特队&#xff0c;伊朗队&#xff0c;澳大利亚队&#xff0c;还有就是东道主卡塔尔队。但是我们知道&#xff0c;澳大利亚&#xff0c;并不是亚洲的国家&…

Flutter 项目中管理你的 Assets Texts Widgets

Flutter 项目中管理你的 Assets Texts Widgets 原文 https://medium.com/mustafatahirhussein/managing-your-assets-texts-and-widgets-professionally-a-must-read-flutter-guide-ffb93b19eff0 前言 这篇文章是 Mustafa Tahir 写的关于 Flutter 项目管理的技巧&#xff0c;可…

音视频SDP协议详解(描述会话的协议)

前言 ①SDP协议是会话描述协议&#xff08;Session Description Protocol&#xff09;的缩写&#xff0c;是一种会话描述格式&#xff0c;一种描述流媒体初始化参数的格式&#xff0c;为描述多媒体数据而设计。 文末卡片领取音视频免费资料合集 &#xff08;流媒体是指在传输过…

csdn月入过万的作者是如何练成的?

很多年前&#xff0c;我有一个成为作家的梦想。 后来从事了技术&#xff0c;觉得与作家梦越来越远了。 虽然梦想远去&#xff0c;但写字的欲望没有停止。 这些年&#xff0c;一直在有道云笔记上记录自己的工作心得&#xff0c;偶尔会来csdn上写一写。 我在csdn真正发力的时候…

自己怎么搭建一个网站?【自己建立网站】

说到建立网站&#xff0c;有些动手能力比较强的小伙伴可能就在想自己怎么搭建一个网站。想自己搭建一个网站&#xff0c;至少也是需要看懂html和cssdiv这些编程代码的&#xff0c;如果不懂代码就只能另寻方法了。那么自己怎么搭建一个网站&#xff1f; 现在市面上有很多的建站…

数据分析基础入门_环境安装

前言 python版本为3.6.8 主要记录一下数据分析入门或者人工智能入门基础所用到的库文件的环境安装过程。 1.批量安装所需库文件 新建 requirements.txt 文件&#xff0c;将以下内容复制到文本文件中保存。 matplotlib2.2.2 numpy1.14.2 pandas0.20.3 tables3.5.2 jupyter1…