【webpack快速入门】webpack有哪些强大的插件机制?

前言

大家好,我是东东吖,一名前端工程师。前面我们学习了webpack五大概念的loader加载器,今天我们将来学习webpack五大核心概念的插件机制

Webpack插件机制介绍

  • loader 专注实现资源模块加载
  • Plugin 解决其他自动化工作

e.g.

  • 清除dist目录,清除上一次的打包结果
  • 拷贝静态文件至输出目录
  • 压缩输出代码

Webpack自动清除输出目录插件

webpack打包会覆盖上一次的打包结果,但是只能覆盖同名文件,对于其他已经移除的文件,就会积累在里面,非常不合理。

那么我们应该怎么做呢?接下来我们将来介绍webpack的一款插件clean-webpack-plugin,该插件可以自动清除输出目录。

//安装clean-webpack-plugin  插件

yarn  add clean-webpack-plugin --dev
复制代码

在webpack中配置插件:

image.png

//webpack.config.js

const path = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");

module.exports = {
  mode: "development", //使用开发模式打包
  entry: "./src/main.js", //打包前入口
  // publicPath:'dist/'  ,        //注意dist后面的/不能省略
  output: {
    //打包后出口
    filename: "bundle.js", //打包后文件名
    path: path.join(__dirname, "dist"), //打包后路径
  },

  module: {
    // 匹配不同的资源loader加载器
    rules: [
      {
        test: /.js$/,
        use: {
          loader: "babel-loader",
          options: {
            presets: ["@babel/preset-env"],
          },
        },
      },
      {
        test: /.css$/,
        use: [
          "style-loader",
          "css-loader", //使用多个loader,是从后往前执行,所有要先写样式,再把样式通过标签渲染到页面
        ],
      },
      {
        test: /.(png|jpg)$/,
        use: {
          loader: "url-loader",
          options: {
            limit: 30 * 1024, //30KB,因为这里的单位是字节,所有需要*1024
          },
        },
      },
      {
        test: /.html$/,
        use: {
          loader: "html-loader",
        },
      },
      {
        test: /.md$/,
        use: "./markdown-loader",
      },
    ],
  },
  plugins:[
      new CleanWebpackPlugin()
  ]
};

复制代码

执行打包命令,就可以发现dist目录被清空了,执行的是本次的打包结果。

Webpack在dist下自动生成index.html

除了自动清除输出目录,还有一个常见的需求就是自动生成使用bundle.js的HTML

现状:写死路径,手动硬编码,配置改变,得手动改变引入路径。

image.png

安装html-webpack-plugin 插件
 yarn  add html-webpack-plugin --dev
复制代码

执行打包命令,确实在dist目录生成了html文件,但是也报错了。 image.png

原因在于:html-webpack-plugin有一个.ejs文件,需要更换babel-loader的正则方法,/.js/ 换成 /\.js/即可解决。

image.png

查看打包结果:

image.png

我们删除src同级目录的index.html,在生产环境直接访问dist下面的index.html

在webpack配置index.html标题

image.png

查看打包结果

image.png

打开浏览器直接访问dist目录下的index.html。

image.png

当然,我们还可以在src下面使用模板文件,然后在配置文件中指定模板文件路径。

image.png

在再次打包,访问dist下面的index,就会访问src下面的index.html的模板文件

image.png

Webpack生成多个页面文件

image.png

//webpack.config.js  关键代码

const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const htmlWebpackPlugin = require('html-webpack-plugin')


 plugins:[
    // 用于清空dist目录
      new CleanWebpackPlugin(),
      // 用于生成index.html
      new htmlWebpackPlugin({
        title:"东东吖",
        meta:{
          viewport:"width=device-width"

        },
        template:'./src/index.html'
      }),
      // 用于生成about.html
      new htmlWebpackPlugin({
        filename:'about.html'
      })

  ]
复制代码

copy不参与构建的静态文件

在我们的项目中,还有一些不需要参与构建的静态文件,他们最终需要发布到线上, 例如网站的favicon.icn。我们该怎么去copy不参与构建的静态文件呢?至于静态文件资源大家可以去阿里巴巴矢量图 网站自行下载自己喜欢的图标。

我下载的是一个小老虎,把他放在src/public下面

image.png

我们需要把此类文件直接copy,不参与打包。

安装copy-webpack-plugin

 yarn add copy-webpack-plugin --dev
复制代码

配置插件,执行打包命令

image.png

//webpack.config.js  关键代码

const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const htmlWebpackPlugin = require('html-webpack-plugin')
const copyWebpackPlugin = require('copy-webpack-plugin')

plugins:[
    // 用于清空dist目录
      new CleanWebpackPlugin(),
      // 用于生成index.html
      new htmlWebpackPlugin({
        title:"东东吖",
        meta:{
          viewport:"width=device-width"

        },
        template:'./src/index.html'
      }),
      // 用于生成about.html
      new htmlWebpackPlugin({
        filename:'about.html'
      }),

      new copyWebpackPlugin({
        patterns :[
         { from:'src/public',to:'public'}
        ]
      })

  ]
复制代码

自己开发一个插件

相比于loader,Plugin拥有更宽泛的能力范围,Plugin是通过软件开发中的钩子机制实现。

接下来,我们自己开发一个插件,需求就是:用于清除在none模式下打包后js多余的注释。如下图所示:

image.png

通过webpack的api

image.png

我们来定义一个MyPlugin,并且把它应用起来。

image.png

image.png

//webpack.config.js

const path = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const htmlWebpackPlugin = require('html-webpack-plugin')
const copyWebpackPlugin = require('copy-webpack-plugin');


class MyPlugin{
  apply(compiler){
    console.log("MyPlugin 启动");
    compiler.hooks.emit.tap("MyPlugin",compilation=>{
      // compilation => 可以理解为此次打包的上下文
    for(const name in   compilation.assets){
      console.log("每个文件的名称:",name);

    }

    })
  }

}

module.exports = {
  mode: "none", //打包的模式
  entry: "./src/main.js", //打包前入口
  // publicPath:'dist/'  ,        //注意dist后面的/不能省略
  output: {
    //打包后出口
    filename: "bundle.js", //打包后文件名
    path: path.join(__dirname, "dist"), //打包后路径
  },

  module: {
    // 匹配不同的资源loader加载器
    rules: [
      {
        test: /\.js$/,
        use: {
          loader: "babel-loader",
          options: {
            presets: ["@babel/preset-env"],
          },
        },
      },
      {
        test: /\.css$/,
        use: [
          "style-loader",
          "css-loader", //使用多个loader,是从后往前执行,所有要先写样式,再把样式通过标签渲染到页面
        ],
      },
      {
        test: /\.(png|jpg)$/,
        use: {
          loader: "url-loader",
          options: {
            limit: 30 * 1024, //30KB,因为这里的单位是字节,所有需要*1024
          },
        },
      },
      {
        test: /\.html$/,
        use: {
          loader: "html-loader",
        },
      },
      {
        test: /\.md$/,
        use: "./markdown-loader",
      },
    ],
  },
  plugins:[
    // 用于清空dist目录
      new CleanWebpackPlugin(),
      // 用于生成index.html
      new htmlWebpackPlugin({
        title:"东东吖",
        meta:{
          viewport:"width=device-width"

        },
        template:'./src/index.html'
      }),
      // 用于生成about.html
      new htmlWebpackPlugin({
        filename:'about.html'
      }),

      new copyWebpackPlugin({
        patterns :[
         { from:'src/public',to:'public'}
        ]
      }),
      new MyPlugin()

  ]
};

复制代码

执行打包命令,我们通过循环compilation.assets这个对象,他里面的key就是每个文件的名称。

image.png

接下来,我们需要判断文件是否是js,然后获取里面的内容,通过正则把里面多余的注释替换,最后把内容和内容的大小返回。

image.png

通过控制台打印,我们能清楚看见没一步的内容

image.png

image.png

最后我们来看打包后的结果,发现js里面多余的注释已经被清除了。

image.png

//webpack.config.js

const path = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const htmlWebpackPlugin = require('html-webpack-plugin')
const copyWebpackPlugin = require('copy-webpack-plugin');


class MyPlugin{
  apply(compiler){
    console.log("MyPlugin 启动");
    compiler.hooks.emit.tap("MyPlugin",compilation=>{
      // compilation => 可以理解为此次打包的上下文
    for(const name in   compilation.assets){
      // console.log("每个文件的名称:",name);
      // console.log("具体文件的内容:",compilation.assets[name].source);
      if (name.endsWith('.js')) {   //判断是否js文件
        const contents =compilation.assets[name].source()   //js文件的内容
        const widthoutComments =contents.replace(/\/\*\*+\*\//g,'')  //利用正则替换内容丽多余的注释
         //把结果通过source返回,size表示返回内容的大小
        compilation.assets[name] ={
          source:()=>widthoutComments,
          size:()=>widthoutComments.length
        }

        // 打印相关信息理解
        console.log("js文件的内容:",contents);
        console.log("利用正则替换内容丽多余的注释",widthoutComments);
        
        
      }

    }

    })
  }

}

module.exports = {
  mode: "none", //打包的模式
  entry: "./src/main.js", //打包前入口
  // publicPath:'dist/'  ,        //注意dist后面的/不能省略
  output: {
    //打包后出口
    filename: "bundle.js", //打包后文件名
    path: path.join(__dirname, "dist"), //打包后路径
  },

  module: {
    // 匹配不同的资源loader加载器
    rules: [
      {
        test: /\.js$/,
        use: {
          loader: "babel-loader",
          options: {
            presets: ["@babel/preset-env"],
          },
        },
      },
      {
        test: /\.css$/,
        use: [
          "style-loader",
          "css-loader", //使用多个loader,是从后往前执行,所有要先写样式,再把样式通过标签渲染到页面
        ],
      },
      {
        test: /\.(png|jpg)$/,
        use: {
          loader: "url-loader",
          options: {
            limit: 30 * 1024, //30KB,因为这里的单位是字节,所有需要*1024
          },
        },
      },
      {
        test: /\.html$/,
        use: {
          loader: "html-loader",
        },
      },
      {
        test: /\.md$/,
        use: "./markdown-loader",
      },
    ],
  },
  plugins:[
    // 用于清空dist目录
      new CleanWebpackPlugin(),
      // 用于生成index.html
      new htmlWebpackPlugin({
        title:"东东吖",
        meta:{
          viewport:"width=device-width"

        },
        template:'./src/index.html'
      }),
      // 用于生成about.html
      new htmlWebpackPlugin({
        filename:'about.html'
      }),

      new copyWebpackPlugin({
        patterns :[
         { from:'src/public',to:'public'}
        ]
      }),
      new MyPlugin()

  ]
};

复制代码

以上就是我们利用webpack插件移除js多余注释的过程,插件是在生命周期的钩子中挂载函数实现扩展。

结束

相信通过本文,你已经对webpack强大的插件机制有所了解,webpack还有许多强大的插件,来满足我们日常的需求 对于本文章,你有任何疑问,可在评论区留言。如果想进前端交流群(目前群里有40余人前端工程师,气氛活跃,欢迎大家加入),可以加我微信fangdongdong_25,请备注掘金哦。

猜你喜欢

转载自juejin.im/post/7129682621256171534