This repository has been archived on 2026-03-31. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
react-iconpack/lib/WebpackPlugin.js

103 lines
4.1 KiB
JavaScript

/**
* WebpackPlugin.js
*
* The Webpack plugin for react-iconpack. Manages intercepting the
* build/loader/etc processes and injecting the SVG icon set as a module.
*
* @author Ryan McGrath <ryan@rymc.io>
*/
var path = require('path'),
ReactSVGComponentFilePath = require.resolve('../components/svg.js'),
IconStubComponentPath = require.resolve('../components/react-iconpack-icons.js');
/**
* WebpackPlugin
*
* Accepts a packer, and options for configuring the packer instance itself.
* @Note: You likely don't want this, but the API in index.js.
*
* @param {Object} packer An instance of IconPacker (see lib/IconPacker.js).
* @param {Object} opts Options for configuring IconPacker (for certain use cases it's ideal to update here).
* @returns {Object} WebpackPlugin A new Webpack plugin.
*/
var WebpackPlugin = function(packer, opts) {
this.packer = packer;
this.packer.update(opts);
return this;
};
/**
* WebpackPlugin.loader()
*
* This is Webpack-specific functionality, which is why it's here - not looking
* to overly pollute index.js. This should be .call()'d with the loader context from
* index.js, along with the options.
*
* @param {Object} engine The engine object from index.js, which is just the source code.
* @param {Object} packer The packer object from index.js, shared amongst everything.
* @returns {void}
*/
WebpackPlugin.loader = function(engine, packer) {
var callback = this.async();
packer.compileForWebpack(function(source) {
callback(null, engine.replace('module.exports = {react_iconpack_icons: {}};', source));
});
};
/**
* This prototype.apply chain satisfies the Webpack plugin API. To be quite honest, the
* documentation surrounding Webpack plugin development is (almost, but not quite) as bad
* as Browserify. Really annoying to decipher.
*
* What we essentially do here is the following:
*
* - With each attempt to resolve a module, we check to see if it's one of our
* react-icon-* modules. With both of them, we redirect the request to a file in
* the component directory. This stops Webpack from blowing up and lets us provide
* a nicer API.
*
* - After module resolution is done, we check to see if the one being passed is
* the icons file. We specifically want to apply a loader (our index.js file) to
* replace the module source code with our true icons source code.
*
* This takes advantage of how Webpack consumes loaders. I originally wanted to make use
* of the compilation.addModule call but I could not figure out that undocumented... thing for
* the life of me (creating a RawModule and adding it did nothing).
*/
WebpackPlugin.prototype.apply = function(compiler) {
var packer = this.packer;
compiler.plugin('normal-module-factory', function(nmf) {
nmf.plugin('before-resolve', function(result, callback) {
if(!result)
return callback();
// We'll patch them in later... (see index.js)
if(/react-iconpack-icons$/.test(result.request))
result.request = IconStubComponentPath;
// Inject react-iconpack Component
// To do this we actually want to redirect the require statement directive
// to the proper file~
if(/react-iconpack$/.test(result.request))
result.request = ReactSVGComponentFilePath;
callback(null, result);
});
// This callback function parameter isn't even in the damn docs, just guessed at it...
// At any rate, if the icons module is detected we push our loader to the front of it
// What's nice is that we can do it ourselves and not require the user to do more configuration
// Note: this is called for every module, so the check is important.
nmf.plugin('after-resolve', function(data, callback) {
if(/react-iconpack-icons\.js/.test(data.request))
data.loaders.unshift(path.join(__dirname, '../index.js'));
callback(null, data);
});
});
};
module.exports = WebpackPlugin;