Loader 和 Plugin

Loader

Loader 是一个打包方案,本身是一个函数,接受源文件作为参数,返回转换的结果。

loaders 需要安装:npm install [loader名称] -D

Loader 的使用方式

  • 配置方式(Configuration)
    Loader 是有执行顺序的,从下到上,从右到左,因为 Webpack 使用的是 compose 函数式编程方式,这种表达式的执行是从右到左。

    module.exports = {
      module: {
        rules: [
          {
            test: /\.css$/,
            use: ["style-loader", "css-loader", "postcss-loader"],
          },
        ]
      }
    }
    
  • 内联方式(Inline)
    可以在 import 语句或任何与 import 方法同等的引用方式中指定 loader。
    使用 ! 将资源中的 loader 分开。

    import Styles from 'style-loader!css-loader?modules!./styles.css';
    

常用的 Loader

babel-loader

转换 ES6+ 新语法为 ES5。

module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        use: ['babel-loader'],
        include: srcPath,
        exclude: /node_modules/
      }
    ]
  }
}

style-loader

把 CSS 插入到 DOM 中。
推荐将 style-loadercss-loader 一起使用。

css-loader

@importurl() 进行处理,分析 CSS 模块之间的关系,并合并成一个 CSS。

module.exports = {
  module: {
    rules: [
      {
        test: /.css$/i,
        use: ['style-loader', 'css-loader'],
      },
    ],
  },
};

postcss-loader

  • CSS 预处理器:可以使用像 Sass、Less 或 Stylus 这样的预处理器编写 CSS 代码,然后通过 postcss-loader 将其转换为标准的 CSS。
  • 自动添加前缀:通过 Autoprefixer 等插件,postcss-loader 可以自动为 CSS 属性添加浏览器前缀,以确保在不同浏览器中具有一致的表现。
module.exports = {
  module: {
    rules: [
      {
        test: /.css$/i,
        use: ['style-loader', 'css-loader', 'postcss-loader'],
      },
    ],
  },
};

手写一个 loader

  • loader 是一个函数,不能使用箭头函数,因为要用到上下文中的 this
  • 接收一个源文件参数
  • 返回处理后的文件结果
// customLoader.js
// 转化文件大小写
module.exports = function (source) {
  const transform = source.replace(/[A-Z]/g, function (match) {
    return match.toLowerCase();
  });

  return transform;
};

使用:

module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.js$/, // 匹配需要使用 loader 的文件
        use: path.resolve(__dirname, "./customBabel.js"),
      },
    ],
  },
};

测试文件:

// index.js
const a = "A";
const B = "B";
console.log("a", a);
console.log("B", B);

打包后结果:

// dist/bundle.js
console.log("a","a"),console.log("b","b");

Plugin

插件的目的是为了解决 Loader 无法实现的其他事。

Webpack 插件是一个具有 apply 方法的 js 对象。

用法:new xxxPlugin(参数)

常用的 plugin

CommonsChunkPlugin

提取 chunk 之间的公共模块用来共享,是一个 Webpack 的内置插件,不需要安装。

new webpack.optimize.CommonsChunkPlugin({
  name: 'commons',
  filename: 'commons.js',
});

CleanWebpackPlugin

删除/清理构建目录。

$ yarn add clean-webpack-plugin -D
const CleanWebpackPlugin = require('clean-webpack-plugin');

module.exports = {
  plugins: [
    // 打包之前清除 dist 文件
    new CleanWebpackPlugin(['dist'], { root: process.cwd(), verbose: true })
  ]
}

HtmlWebpackPlugin

在打包结束后,自动生成一个 html 文件,并把打包生成的 js 模块引入到该 html 中。

$ npm install --save-dev html-webpack-plugin
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
  plugins: [
     new HtmlWebpackPlugin({
      template: path.join(__dirname, "../../src/template.html.ejs"),
      filename: "index.html",
      chunks: ["vendor", "runtime"],
      inject: "body",
    }),
  ]
};
<!-- src/template.html.ejs -->
<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <title>
    <%= htmlWebpackPlugin.options.title || '标题' %>
  </title>
</head>
<body></body>
</html>

EJS 是一套简单的模版语法,帮你利用普通的 JavaScript 代码生成 HTML 文件。

MiniCssExtractPlugin

提取 CSS 到一个单独的文件中。

$ npm install --save-dev mini-css-extract-plugin
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
 ...,
  module: {
   rules: [
    {
       test: /\.s[ac]ss$/,
       use: [
         {
           loader: MiniCssExtractPlugin.loader
         },
         'css-loader',
         'sass-loader'
        ]
     }
   ]
 },
  plugins: [
    ...,
    new MiniCssExtractPlugin({
     filename: '[name].css'
    }),
    ...
  ]
}

DefinePlugin

允许在编译时创建配置的全局对象,是一个 webpack 内置的插件,不需要安装。

module.exports = {
  plugins: [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': '"production"',
      PRODUCTION: true
    })
  ]
}

CopyWebpackPlugin

复制文件或目录到执行区域。

$ yarn add copy-webpack-plugin -D
const pathUtil = require('path');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const appRoot = pathUtil.join(__dirname, '../..');
module.exports = {
  plugins: [
    new CopyWebpackPlugin([
      {
        from: './static',  // 设置从哪一个源开始复制
        to: pathUtil.join(appRoot, 'priv/static'),  // 复制到的位置,可以省略,默认复制到打包的目录中
        globOptions: {}  // 设置一些额外的选项,其中可以编写需要忽略的文件
      }
    ])
  ]
}

__dirname:返回当前模块文件解析后,所在的文件夹(目录)的绝对路径。
__filename:返回当前模块文件被解析后的绝对路径。

手写一个 Plugin

  • plugin 是一个构造函数,能够通过 new 来实例化对象;
  • PluginName 可以写成普通函数,apply 方法必须挂载到原型对象(PluginName.prototype)上;
  • 有一个 apply 方法,作为插件的入口点,Webpack 会调用此方法并传入 compiler对象参数。
// customPlugin.js
// 该定义插件会在打包完成后会输出每个模块的打包时间
class CustomPlugin {
  // 构造函数接收一个 options 参数,用来配置插件的行为
  constructor(options) {}
  // apply 方法是插件的入口点,webpack 会调用此方法并传入 compiler 对象
  apply(compiler) {
    // 注册一个钩子函数,监听 webpack 打包完成的事件
    compiler.hooks.compilation.tap("CustomPlugin", (compilation) => {
      compilation.hooks.buildModule.tap("CustomPlugin", (module) => {
        module.startTime = Date.now();
      });
    });
    compiler.hooks.thisCompilation.tap("CustomPlugin", (compilation) => {
      compilation.hooks.finishModules.tap("CustomPlugin", (modules) => {
        modules.forEach((module) => {
          if (module.resource) {
            const buildTime = module.startTime ? Date.now() - module.startTime : "N/A";
            console.log(`${module.resource} - Build Time: ${buildTime}ms`);
          }
        });
      });
    });
  }
}

module.exports = CustomPlugin;

执行结果:

Loader 和 Plugin

loader 🆚 plugin

功能不同

  • Loader:加载器,Webpack 将一切文件视为模块,但 Webpack 原生只能解析 JS 文件,所以 Loader 的作用是让 Webpack 拥有了加载和解析非 JS 文件的能力。
  • Plugin:插件,Plugin 是用于拓展 Webpack 的功能,在 Webpack 构建过程中执行一些额外的任务,如优化资源、打包输出结果、注入环境变量等。

用法不同

  • Loader:在 module.rules 中配置,类型是数组,每一项都是 Object,里面描述了对于什么类型的文件(test),使用什么加载(use),使用的参数(options)等。
  • Plugin:在 plugins 中单独配置,类型是数组,每一项为一个 pluin 的实例,参数通过构造函数传入。

运行时机不同

  • Loader:打包之前。
  • Plugin:整个构建过程都起作用。

参考:官方文档 Loaders
参考:官方文档 Plugins

欢迎纠错~

Loader 和 Plugin

原文链接:https://juejin.cn/post/7356130355693305875 作者:南殇

(0)
上一篇 2024年4月11日 下午4:48
下一篇 2024年4月11日 下午4:59

相关推荐

发表回复

登录后才能评论