webpack5打包原理及应用(插件篇)

webpack5打包原理及应用(插件篇)

概念:

  1. loader:通常用来完成非JavaScript模块的转化成webpack能处理的模块;
  2. plugin:能够完成更多定制化操作的插件

🚀 如果想要插件起作用,需要在webpack.config.js中的 plugins 数组中进行实例的传递

// webpack.config.js基础配置
const path = require('path')

module.exports = {
    entry: './src/main.js',
    output: {
        filename: 'build.js',
        path: path.resolve(__dirname, 'dist'),
        assetModuleFilename: 'img/[name]-[hash:6][ext]'
    },
    stats: 'errors-only', // 只显示错误信息
    // 此处并未列出完整的module, 请参考以前的文章
    module: {}
}

1. clean-webpack-plugin 的使用

🎪 插件说明:该插件可以将原本产出的dist目录进行自动删除

// 在webpack.config.js进行如下配置
// -- 以解构的方式进行导入
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

// -- 在暴露的对象中加入插件
plugins: [
    new CleanWebpackPlugin()
]

// -- 效果 => 每次执行build自动删除上次的dist目录

备注:首先执行 npm install clean-webpack-plugin -D 安装成开发依赖

2. html-webpack-plugin 的使用

🎪 插件说明:该插件主要用于入口 index.html 动态生成,默认情况我们不需要提供index.html,会自动生成到产出目录

// 在webpack.config.js进行如下配置
// -- 导入HtmlWebpackPlugin, 不需要解构的原因是考虑插件的自身导出规则
const HtmlWebpackPlugin = require('clean-webpack-plugin')

// -- 插件列表如下:
plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin()
]

🎪 自动生成的 index.html 如下

<!doctype html>
<html>

<head>
    <meta charset="utf-8">
    <title>Webpack App</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <script defer="defer" src="build.js"></script>
</head>

<body></body>

</html>

🎪 可以对index.html进行参数的设置(原因是由插件的默认ejs来控制)

// -- 对应插件实例化时,进行参数的传递
plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
        title: 'html-webpack-plugin-learn'
    })
]
// -- 效果 => 在生成index.html中,对应的head中title替换成了 html-webpack-plugin-learn

🎪 可以对index.html进行自定义模板提供

<!-- 提供如下index.html模板到public模块中 -->
<!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>
        <%= htmlWebpackPlugin.options.title %>
    </title>
</head>
<body>
    <div id="app">
        测试 html-webpack-plugin 
    </div>
</body>
</html>

<!-- -- -- -- -- -- -- -- -- -- --  

// 需要提供对应的 template 路径
plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
        title: 'html-webpack-plugin-learn',
        template: './public/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">
    <title>html-webpack-plugin-learn</title>
    <script defer="defer" src="build.js"></script>
</head>

<body>
    <div id="app">测试 html-webpack-plugin</div>
</body>

</html>

🎪 如果使用如下的vue的默认index.html模板

<!-- 默认的vue模板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>

备注:首先执行 npm i html-webpack-plugin -D 安装成开发依赖

3. define-plugin 的使用

🎄 提供了上述的index.html模板页面进行处理时,会产生ERROR in Template execution failed: ReferenceError: BASE_URL is not defined错误
🍺 解决方案是配置 webpack 的 BASE_URL

// 使用webpack内置的插件 DefinePlugin
const { DefinePlugin } = require('webpack')

// 对应插件列表如下:
plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
        title: 'html-webpack-plugin-learn',
        template: './public/index.html'
    }),
    new DefinePlugin({
        BASE_URL: '"./"' // 此处会将我们设置的值原封不动的进行去除,所以需要加上引号
    })
]
// -- 效果 => 打包成功,注意需要自己提供一个favicon.ico文件

4. babel 的使用

🎪 为什么需要babel?JSX、TS、ES6+语法 需要转化成浏览器平台可以使用的js

// 提供main.js如下:
const title = '前端'
const foo = () => {
    console.log(title)
}

foo()
// 在webpack.config.js中设置mode为development npm run build后可以观察到eval函数中并没有对es6+语法进行处理

4.1 进行babel的安装

PS > npm i @babel/core -D

# 如果要在命令进行操作,则需要安装如下包
PS > npm i @babel/cli -D
# ---------------------- 使用npx babel .\src\main.js ----------------------
PS > npx babel .\src\main.js
const title = '前端';

const foo = () => {
  console.log(title);
};

foo();
# ------- 上述操作可以发现并未作任何处理 这是因为 babel/core 只是一个微内核 -------

# 如果需要处理箭头函数和块级作用域则需要导入别的包
PS > npm i @babel/plugin-transform-arrow-functions @babel/plugin-transform-block-scoping -D   
# ---------------- 此时再次使用babel进行处理 ----------------
PS > npx babel .\src\main.js --plugins=@babel/plugin-transform-arrow-functions,@babel/plugin-transform-block-scoping 
var title = '前端';

var foo = function () {
  console.log(title);
};

foo();
# ---------------- 可以发现此时已经进行了转化 ----------------

# 可以通过安装babel提供的预设方案(包括了常见的转化依赖)
PS > npm i @babel/preset-env -D
# ---------------- 在命令行中再次执行处理操作 ----------------
PS > npx babel .\src\main.js --presets=@babel/preset-env                                                           
"use strict";

var title = '前端';

var foo = function foo() {
  console.log(title);
};

foo();
# ----------------- 此时的输出结果是预期内的 -----------------

4.2 babel-loader 的使用

// 在 webpack.config.js 中的module的rules新增一条规则
{
    test: /\.js$/,
    // use: ['babel-loader'] // 此种方式无法进行插件处理
    use: {
        loader: 'babel-loader',
        options: {
            plugins: [
                '@babel/plugin-transform-arrow-functions',
                '@babel/plugin-transform-block-scoping'
            ]
        }
    }
}
// -- 效果 => 此时的dist目录中 build.js 则是经过处理后的js

// 下面采用预设的方式进行处理
{
    test: /\.js$/,
    // use: ['babel-loader'] // 此种方式无法进行插件处理
    use: {
        loader: 'babel-loader',
        options: {
            presets: ['@babel/preset-env']
        }
    }
}
// -- 效果 => 此时的dist目录中 build.js 与前面效果相同

🎄 注意:babel需要 browerslist 的配合,会根据需要兼容的浏览器来确定babel转化的结果!
.browserslistrc中内容更改成 chrome 91,babel处理后的结果不会进行转化,因为该浏览器支持。
注意: babel-loader 会默认读取.browserslistrc文件~

// 如果进行了如下的配置,为preset指定默认的targets,则会以该targets优先
 {
    test: /\.js$/,
    // use: ['babel-loader'] // 此种情况 该方式暂无法进行插件处理
    use: {
        loader: 'babel-loader',
        options: {
            presets: [
                [
                    '@babel/preset-env', {
                        targets: 'chrome 91'
                    }
                ]
            ]
        }
    }
}

🎪 babel-loader 相关的配置文件(可以有如下几种表现形式)

  1. babel.config.js(json cjs mjs)
  2. babelrc.json(js)
  3. .babelrc
// webpack.config.js rules如下:
{
    test: /\.js$/,
    use: ['babel-loader']  // 由于单独配置babel-loader的配置文件
}
// babel.config.js 如下:
module.exports = {
    presets: ['@babel/preset-env']
}

备注:首先执行 npm i babel-loader -D 安装成开发依赖

4.3 polyfill 的使用

ployfill 可以理解为打补丁(官方解释是:用来为旧浏览器提供它没有原生支持的较新的功能。)
比如promise浏览器无法实现,需要以其他方式进行替代实现
备注:首先执行 npm i core-js regenerator-runtime 安装成生产依赖

// 在babel.config.js中配置
module.exports = {
    presets: [
        [
            '@babel/preset-env',
            {
                // false: 不对当前js作polyfill填充
                // usage: 会根据需要进行polyfill,记得要指定corejs为3版本(因为安装的3版本,会出现报错)
                // entry: 首先需要在main.js导入,会将所有的都进行polyfill了
                useBuiltIns: 'entry',
                corejs: 3
            }
        ]
    ]
}

5. copy-webpack-plugin 的使用

🎪 该插件可以用来完成一些文件的复制操作

// webpack.config.js 相应配置如下:
const CopyWebpackPlugin = require('copy-webpack-plugin')

plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
        title: 'html-webpack-plugin-learn',
        template: './public/index.html'
    }),
    new DefinePlugin({
        BASE_URL: '"./"' // 此处会将我们设置的值原封不动的进行去除,所以需要加上引号
    }),
    new CopyWebpackPlugin({
        patterns: [
            {
                from: 'public' // 从public复制到dist目录
            }
        ]
    })
]

🎄 注意事项:使用如上方式进行配置会出现ERROR in Conflict: Multiple assets emit different content to the same filename index.html 错误,原因是前面html-webpack-plugin已经对 index.html 进行过了复制操作
🍺 解决方案:使用globOptions中的ignore进行文件忽略, 具体信息如下:

new CopyWebpackPlugin({
    patterns: [
        {
            from: 'public', // 从public复制到dist目录
            globOptions: {
                ignore: ['**/index.html'] // 需要加上 **
            }
        }
    ]
})

备注:首先执行 npm i copy-webpack-plugin -D 安装成开发依赖

  • 8
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值