• 【前端】webpack5常用loader和plugin


    一、前言

    在我的前一篇博客中,已经介绍了webpack的基本配置和使用:【前端】webpack5的配置及基本使用

    但是如果想要webpack用于实际项目开发,我们还要配置许多loader和plugin。

    Loader:模块代码转换器,让webpack能够去处理除了JS、JSON之外的其他类型的文件,并将它们转换为有效 模块,以供应用程序使用,以及被添加到依赖图中。

    Plugin:扩展插件。在webpack运行的生命周期中会广播出许多事件,plugin可以监听这些事件,在合适的时机通过webpack提供的api改变输出结果。常见的有:打包优化,资源管理,注入环境变量。

    二、loader

    在Webpack中,一切皆模块,我们常见的Javascript、CSS、Less、Typescript、Jsx、图片等文件都是模块,不同模块的加载是通过模块加载器来统一管理的,当我们需要使用不同的 Loader 来解析不同类型的文件时,我们可以在module.rules字段下配置相关规则。

    loader本质: output=loader(input)
    
    • 1

    2.1 babel-loader

    Babel是一个Javscript编译器,可以将高级语法(主要是ECMAScript 2015+ )编译成浏览器支持的低版本语法,它可以帮助你用最新版本的Javascript写代码,提高开发效率。

    webpack通过babel-loader来使用babel,用于解析JavaScript文件。babel有丰富的预设和插件,babel的配置可以直接写到options里或者单独写道配置文件里。

    npm install -D babel-loader @babel/core @babel/preset-env webpack
    
    • 1
    // webpack.config.js
    module: {
      rules: [
        {
          test: /\.m?js$/,
          exclude: /node_modules/,
          use: {
            loader: 'babel-loader',
            options: {
              presets: [
                ['@babel/preset-env', { targets: "defaults" }]
              ],
              plugins: ['@babel/plugin-proposal-class-properties'],
              // 缓存 loader 的执行结果到指定目录,默认为node_modules/.cache/babel-loader,之后的 webpack 构建,将会尝试读取缓存
              cacheDirectory: true,
            }
          }
        }
      ]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    详情配置:babel配置文档

    2.2 ts-loader

    webpack提供的 TypeScript loader,打包编译Typescript。

    npm install ts-loader --save-dev
    npm install typescript --dev
    
    • 1
    • 2
    
    // webpack.config.json
    module.exports = {
      //...
      resolve: {
        // Add `.ts` and `.tsx` as a resolvable extension.
        extensions: [".ts", ".tsx", ".js"]
      },
      module: {
        rules: [
          // all files with a `.ts` or `.tsx` extension will be handled by `ts-loader`
          { test: /\.tsx?$/, loader: "ts-loader" }
        ]
      }
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    2.3 raw-loader

    将文件以字符串的形式引入。

    // webpack.config.js
    module.exports = {
      module: {
        rules: [
          {
            test: /\.txt$/,
            use: 'raw-loader'
          }
        ]
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2.4 file-loader

    用于处理文件类型资源,如jpg,png等图片。返回值为publicPath为准。

    // file.js
    import img from './webpack.png';
    console.log(img); // 编译后:https://www.tencent.com/webpack_605dc7bf.png
    // webpack.config.js
    module.exports = {
      module: {
        rules: [
          {
            test: /\.(png|jpe?g|gif)$/i,
            loader: 'file-loader',
            options: {	
              name: '[name]_[hash:8].[ext]',
              publicPath: "https://www.tencent.com",
            },
          },
        ],
      },
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    2.5 url-loader

    它与file-loader作用相似,也是处理图片的,只不过url-loader可以设置一个根据图片大小进行不同的操作,如果该图片大小大于指定的大小,则将图片进行打包资源,否则将图片转换为base64字符串合并到js文件里。

    2.6 style-loader

    通过注入

    2.7 css-loader

    仅处理css的各种加载语法(@import和url()函数等),就像 js 解import/require() 一样。

    2.8 less-loader

    解析less,转换为css。

    2.9 vue-loader

    解析和转换.vue文件,提取出其中的逻辑代码script,样式代码style以及HTML模板template,再分别将它们交给对应的loader去处理。

    vue-cli中默认配置了vue-loader,所以我们可以直接引入vue文件。

    三、plugin

    Webpack 就像一条生产线,要经过一系列处理流程后才能将源文件转换成输出结果。 这条生产线上的每个处理流程的职责都是单一的,多个流程之间有存在依赖关系,只有完成当前处理后才能交给下一个流程去处理。 插件就像是一个插入到生产线中的一个功能,在特定的时机对生产线上的资源做处理。

    3.1 copy-webpack-plugin

    将已经存在的单个文件或者目录复制到打包构建的目录。

    const CopyPlugin = require("copy-webpack-plugin");
    
    module.exports = {
      plugins: [
        new CopyPlugin({
          patterns: [
            { 
              from: './template/page.html', 
              to: `${__dirname}/dist/page.html` 
            },
          ],
        }),
      ],
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    上述配置在进行打包时会将template/page.html复制到/dist/page.html

    3.2 html-webpack-plugin

    生成html文件,单页应用可以生成一个html入口,多页应用可以配置多个html-webpack-plugin实例来生成多个页面入口。

    并且可以会为html中引入外部资源如script、link。

    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    module.exports = {
      entry: {
        news: [path.resolve(__dirname, '../src/news/index.js')],
        video: path.resolve(__dirname, '../src/video/index.js'),
      },
      plugins: [
        new HtmlWebpackPlugin({
          title: 'news page',
          // 生成的文件名称 相对于webpackConfig.output.path路径而言
          filename: 'pages/news.html',
          // 生成filename的文件模板
          template: path.resolve(__dirname, '../template/news/index.html'),
          chunks: ['news']
    
        }),
        new HtmlWebpackPlugin({
          title: 'video page',
          // 生成的文件名称
          filename: 'pages/video.html',
          // 生成filename的文件模板
          template: path.resolve(__dirname, '../template/video/index.html'),
          chunks: ['video']
        }),
      ]
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    3.3 clean-webpack-plugin

    默认情况下,这个插件会删除webpack的output.path中的所有文件,以及每次成功重新构建后所有未使用的资源。
    这个插件在生产环境用的频率非常高,因为生产环境经常会通过 hash 生成很多 bundle 文件,如果不进行清理的话每次都会生成新的,导致文件夹非常庞大。

    const { CleanWebpackPlugin } = require('clean-webpack-plugin');
    module.exports = {
        plugins: [
            new CleanWebpackPlugin(),
        ]
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    3.4 mini-css-extract-plugin

    会将 CSS 提取到单独的文件中,为每个包含 CSS 的 JS 文件创建一个 CSS 文件。

    // 建议 mini-css-extract-plugin 与 css-loader 一起使用
    // 将 loader 与 plugin 添加到 webpack 配置文件中
    const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    
    module.exports = {
      plugins: [new MiniCssExtractPlugin()],
      module: {
        rules: [
          {
            test: /\.css$/i,
            use: [MiniCssExtractPlugin.loader, 'css-loader'],
          }
        ],
      },
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    3.5 webpack.DefinePlugin

    创建一个在编译时可以配置的全局常量。这会对开发模式和生产模式的构建允许不同的行为非常有用。

    因为这个插件直接执行文本替换,给定的值必须包含字符串本身内的实际引号。

    通常,有两种方式来达到这个效果,使用’“production”', 或者使用 JSON.stringify(‘production’)。

    // webpack.config.js
    const isProd = process.env.NODE_ENV === 'production';
    module.exports = {
      plugins: [
        new webpack.DefinePlugin({
          PAGE_URL: JSON.stringify(isProd
            ? 'https://www.tencent.com/page'
            : 'http://testsite.tencent.com/page'
          )
        }),
      ]
    }
    
    // 代码里面直接使用
    console.log(PAGE_URL);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    3.6 webpack-bundle-analyzer

    可以看到项目各模块的大小,可以按需优化。

    一个webpack的bundle文件分析工具,将bundle文件以可交互缩放的treemap的形式展示。

    const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
    
    module.exports = {
      plugins: [
        new BundleAnalyzerPlugin()
      ]
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3.7 SplitChunksPlugin

    用于代码分割。

    
    const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
    
    module.exports = {
      optimization: {
        splitChunks: {
          // 分隔符
          // automaticNameDelimiter: '~',
          // all, async, and initial
          chunks: 'all',
          // 它可以继承/覆盖上面 splitChunks 中所有的参数值,除此之外还额外提供了三个配置,分别为:test, priority 和 reuseExistingChunk
          cacheGroups: {
            vendors: {
              // 表示要过滤 modules,默认为所有的 modules,可匹配模块路径或 chunk 名字,当匹配的是 chunk 名字的时候,其里面的所有 modules 都会选中
              test: /[\\/]node_modules\/antd\//,
              // priority:表示抽取权重,数字越大表示优先级越高。因为一个 module 可能会满足多个 cacheGroups 的条件,那么抽取到哪个就由权重最高的说了算;
              // priority: 3,
              // reuseExistingChunk:表示是否使用已有的 chunk,如果为 true 则表示如果当前的 chunk 包含的模块已经被抽取出去了,那么将不会重新生成新的。
              reuseExistingChunk: true,
              name: 'antd'
            }
          }
        }
      },
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    四、写在最后

    可以看到,loader和plugin非常多,并且配置起来也并不容易,所以我们每次都是直接使用别人封装好的脚手架,然后进行项目开发,例如vue-cli或者create-react-app等常用脚手架。

    但是了解了基本的loader和plugin作用,对于我们排除错误或者对项目的理解都有很大的帮助。

    参考文章:
    腾讯TNTWeb前端团队 - 吐血整理的webpack入门知识及常用loader和plugin

  • 相关阅读:
    腾讯云国际版云服务器欠费说明
    Xilinx FPGA模式配置
    244:vue+openlayers 显示滚动效果的线段Line
    js高级程序设计-代理与反射
    9.4语言是一种实践2
    JavaScript开发工具WebStorm入门教程:用户界面概况
    【大数问题】字符串相减(大数相减)<模拟>
    2023职教高考报名开启,报考人数继续增加
    浅析 Vue3 响应式原理
    基于Web停车场管理系统的设计与实现
  • 原文地址:https://blog.csdn.net/ZHANGYANG_1109/article/details/126690088