资讯专栏INFORMATION COLUMN

[译]如何写一个webpack插件

wupengyu / 1916人阅读

摘要:原文译者插件能够将引擎的全部潜力暴露给第三方的开发者。当将一个插件应用到环境中,这个插件将会获得一个对于这个的引用。表示有关模块资源,已编译资源,已更改文件和监视依赖关系的当前状态的信息。

原文:how to write a plugin

译者:neal1991

welcome to star my articles-translator , providing you advanced articles translation. Any suggestion, please issue or contact me

LICENSE: MIT

插件能够将webpack引擎的全部潜力暴露给第三方的开发者。通过使用阶段构建回调,开发者能够将他们自己的行为引入到webpack的构建过程中。构建插件比构建loader更高级,因为你需要理解一些webpack低层次的内部钩子。准备好阅读一些源代码吧!

Compiler以及Compilation

在开发插件的时候最重要的两个资源就是compilercompilation对象。理解它们的角色是拓展webpack引擎重要的第一步。

compiler对象代表了完整的配置的webpack环境。一旦开启webpack之后,这个对象就被构建了,并且这个对象会使用所有操作设置,包括options, loaders, 以及plugins来进行配置。当将一个插件应用到webpack环境中,这个插件将会获得一个对于这个compiler的引用。使用这个compiler可以访问主要的webpack环境。

一个compilation对象代表版本资源的一次构建。当运行webpack开发中间件的时候,每次检测到文件变化的时候都会产生一个新的compilation,因此会生成一系列编译后的资源。Compilation表示有关模块资源,已编译资源,已更改文件和监视依赖关系的当前状态的信息。该compilation还提供了许多回调点,插件可以选择执行自定义操作。

这两个组件是任何webpack插件(特别是compilation)的内部一部分,因此开发者熟悉这些源代码文件之后将会受益非凡:

Compiler Source

Compilation Source

基本的插件架构

插件是实例对象,并且在它们的prototype上,会有一个apply方法。当安装这个插件的时候,这个apply方法就会被webpack compiler调用。这个apply会给出一个对于潜在的webpack compiler的引用,保证了对于compiler回调的访问。一个简单的插件结构如下:

function HelloWorldPlugin(options) {
  // Setup the plugin instance with options...
}

HelloWorldPlugin.prototype.apply = function(compiler) {
  compiler.plugin("done", function() {
    console.log("Hello World!"); 
  });
};

module.exports = HelloWorldPlugin;

接着是安装这个插件,只要在你的webpack 配置plugins数组里面添加一个实例:

var HelloWorldPlugin = require("hello-world");

var webpackConfig = {
  // ... config settings here ...
  plugins: [
    new HelloWorldPlugin({options: true})
  ]
};
访问compilation

使用compiler对象,你可能绑定提供那个对于每一个新的compilation引用的回调。这些compilation提供对于在构建过程中对于很多步骤钩子的回调。

function HelloCompilationPlugin(options) {}

HelloCompilationPlugin.prototype.apply = function(compiler) {

  // Setup callback for accessing a compilation:
  compiler.plugin("compilation", function(compilation) {
    
    // Now setup callbacks for accessing compilation steps:
    compilation.plugin("optimize", function() {
      console.log("Assets are being optimized.");
    });
  });
};

module.exports = HelloCompilationPlugin;

对于更多关于compiler以及compilation上的回调以及其他重要的对象,请参考 [[plugins API|plugins]] 文档。

异步compilation plugins

有一些compilation插件步骤是异步的,并且当你的插件完成运行的时候,传递一个必须被调用的回调函数。

function HelloAsyncPlugin(options) {}

HelloAsyncPlugin.prototype.apply = function(compiler) {
  compiler.plugin("emit", function(compilation, callback) {

    // Do something async...
    setTimeout(function() {
      console.log("Done with async work...");
      callback();
    }, 1000);

  });
};

module.exports = HelloAsyncPlugin;
一个简单的例子

一旦我们可以锁定到webpack compiler以及每一个独立的compilation,我们可以利用引擎本身就能发挥无穷的潜力。我们能够重新格式化存在的文件,创建衍生文件,或者制造全新的资源。

让我们写一个简单的能够生成一个新的打包文件filelist.md的插件例子;这个文件的内容会列出所有存在我们build之内的资源文件。这个插件可能看起来是这个样子的:

function FileListPlugin(options) {}

FileListPlugin.prototype.apply = function(compiler) {
  compiler.plugin("emit", function(compilation, callback) {
    // Create a header string for the generated file:
    var filelist = "In this build:

";

    // Loop through all compiled assets,
    // adding a new line item for each filename.
    for (var filename in compilation.assets) {
      filelist += ("- "+ filename +"
");
    }
    
    // Insert this list into the Webpack build as a new file asset:
    compilation.assets["filelist.md"] = {
      source: function() {
        return filelist;
      },
      size: function() {
        return filelist.length;
      }
    };

    callback();
  });
};

module.exports = FileListPlugin;
有用的插件模式

插件允许在webpack构建系统内发挥无尽可能的定制化。这允许你创建自定义的资源类型,执行特殊的构建调整,或者设置在使用中间件的时候进一步提升webpack运行时间。下面的webpack的一些特性在开发插件的时候变得很有用。

探索assets, chunks, modules, 以及dependencies

在compilation完成之后,compilation中的所有的结构都可能被遍历。

function MyPlugin() {}

MyPlugin.prototype.apply = function(compiler) {
  compiler.plugin("emit", function(compilation, callback) {
    
    // Explore each chunk (build output):
    compilation.chunks.forEach(function(chunk) {
      // Explore each module within the chunk (built inputs):
      chunk.modules.forEach(function(module) {
        // Explore each source file path that was included into the module:
        module.fileDependencies.forEach(function(filepath) {
          // we"ve learned a lot about the source structure now...
        });
      });

      // Explore each asset filename generated by the chunk:
      chunk.files.forEach(function(filename) {
        // Get the asset source for each file generated by the chunk:
        var source = compilation.assets[filename].source();
      });
    });

    callback();
  });
};

module.exports = MyPlugin;

compilation.modules: 在compilation中由模块(构建输入)组成的数组。每个模块管理来自于源代码库中的源文件的构建。

module.fileDependencies: 包含在模块中的源文件路径数组。 这包括源JavaScript文件本身(例如:index.js)以及所需的所有依赖项资源文件(样式表,图像等)。 查看依赖关系对于查看哪些源文件属于模块很有用。

compilation.chunks: Compilation中由chunks组成的数组(构建输出)。 每个chunk管理最终渲染资源的组合。

chunk.modules: 包含在一个chunk中的模块数组。 通过扩展,您可以查看每个模块的依赖关系,以查看传递到chunk中的原始源文件

chunk.files: 由chunk生成的输出文件名的数组。 您可以从compilation.assets表访问这些资源。

检测观察图

在运行webpack中间件时,每个compilation都包含一个fileDependencies数组(正在监视的文件)和一个将观察文件路径映射到时间戳的fileTimestamps哈希。 这些对于检测compilation中哪些文件已更改非常有用:

function MyPlugin() {
  this.startTime = Date.now();
  this.prevTimestamps = {};
}

MyPlugin.prototype.apply = function(compiler) {
  compiler.plugin("emit", function(compilation, callback) {
    
    var changedFiles = Object.keys(compilation.fileTimestamps).filter(function(watchfile) {
      return (this.prevTimestamps[watchfile] || this.startTime) < (compilation.fileTimestamps[watchfile] || Infinity);
    }.bind(this));
    
    this.prevTimestamps = compilation.fileTimestamps;
    callback();
  }.bind(this));
};

module.exports = MyPlugin;

您还可以将新的文件路径传入观察图,以便在这些文件更改时接收compilation触发器。 只需将有效的文件路径推送到compilation.fileDependencies数组中即可将其添加到观察列表中。 注意:在每个compilation中重建fileDependencies数组,因此您的插件必须将自己观察的依赖项推送到每个编译中,以使它们保持监视。

改变的chunks

与观察图类似,通过跟踪它们的哈希值,可以在compilation中监视更改的块(或模块)。

function MyPlugin() {
  this.chunkVersions = {};
}

MyPlugin.prototype.apply = function(compiler) {
  compiler.plugin("emit", function(compilation, callback) {
    
    var changedChunks = compilation.chunks.filter(function(chunk) {
      var oldVersion = this.chunkVersions[chunk.name];
      this.chunkVersions[chunk.name] = chunk.hash;
      return chunk.hash !== oldVersion;
    }.bind(this));
    
    callback();
  }.bind(this));
};

module.exports = MyPlugin;

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/82989.html

相关文章

  • Webpack 4.0 发布:有哪些新特性?(

    摘要:有哪些新特性有哪些改进学着使用这个新版本,来构建更快的应用吧。继版本之后,花了将近八个月的时间来发布。的创始人之一,,建议用户使用,以便使用最优的性能,是因为源代码使用了新特性。全新的插件系统配备了全新整改的插件系统。 本文原文地址:https://auth0.com/blog/webpac...第一次翻译,不当之处,欢迎指正 官方已经发布了Webpack 4.0。有哪些新特性?有哪些...

    HitenDev 评论0 收藏0
  • [] 用 ES6 构建新一代可复用 JS 模块

    摘要:我们已经运用了的一些闪亮的新特性,那么如何才能转化为的代码呢首先,我们需要通过来安装在全局安装会提供我们一个命令行工具。 你是不是也在为可以使用ES6的新特性而兴奋,却不太确定应该从哪开始,或者如何开始?不止你一个人这样!我已经花了一年半的时间去解决这个幸福的难题。在这段时间里 JavaScript 工具链中有几个令人兴奋的突破。 这些突破让我们可以用ES6书写完全的JS模块,而不会为...

    phpmatt 评论0 收藏0
  • []Webpack的奇妙世界

    摘要:相反,解释背后的原理是什么使他比一个构造器更加强大。仍然是构造器类似这样的工具存在的主要原因之一就是解决依赖问题。是一个模块构造器,就是前文所说的。 Webpack是一个JavaScript模块构造器。 这是适合它功能的名称。 但是,我想在本文中展现Webpack的真正功能。 本文将不讲解如何使用Webpack。 相反,解释背后的原理:是什么使他比一个构造器更加强大。 Webpack仍...

    enali 评论0 收藏0
  • [] Webpack 前端构建集成方案

    摘要:现在,让我们创建项目的入口,并使用然后创建我们的配置,文件名为,的配置文件是一个,并且需要成一个对象在这里,告诉那些文件是你应用的入口。代码分割便是用来解决之前所说的单集成模块不可维护的引用的问题。 构建工具逐渐成为前端工程必备的工具,Grunt、Gulp、Fis、Webpack等等,译者有幸使用过Fis、Gulp。前者是百度的集成化方案,提供了一整套前端构建方案,优点是基本帮你搞定了...

    lewif 评论0 收藏0
  • 一个小时搭建一个全栈Web应用框架(下)——美化与功能

    摘要:点击直达前文译一个小时搭建一个全栈应用框架上如果没有,但还是要继续学习本教程,可以到我的页面下载代码。从服务器返回随机语言的每当我们与服务器上的端点进行通话时,为了能够请求一个随机的欧洲语言,必须更改文件中的功能。 翻译:疯狂的技术宅原文标题:Creating a full-stack web application with Python, NPM, Webpack and Reac...

    Luosunce 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<