From d040763a738fc522c68d888a277268da12a3d0b7 Mon Sep 17 00:00:00 2001 From: Ben Heidemann Date: Sun, 4 Apr 2021 01:22:28 +0100 Subject: [PATCH] feat: add filer webpack plugin --- src/webpack-plugin/plugin.js | 88 ++++++++++++++++++++++++++++++++ src/webpack-plugin/processors.js | 33 ++++++++++++ src/webpack-plugin/schema.js | 26 ++++++++++ src/webpack-plugin/utils.js | 26 ++++++++++ 4 files changed, 173 insertions(+) create mode 100644 src/webpack-plugin/plugin.js create mode 100644 src/webpack-plugin/processors.js create mode 100644 src/webpack-plugin/schema.js create mode 100644 src/webpack-plugin/utils.js diff --git a/src/webpack-plugin/plugin.js b/src/webpack-plugin/plugin.js new file mode 100644 index 0000000..b1cb334 --- /dev/null +++ b/src/webpack-plugin/plugin.js @@ -0,0 +1,88 @@ +var path = require('path'); +var utils = require('./utils'); + +const PLUGIN_NAME = 'filer-webpack-plugin'; + +const OPTIONS_SCHEMA = require('./schema'); +const OPTIONS_PROCESSORS = require('./processors'); + +module.exports = class FilerWebpackPlugin { + + constructor(options = {}) { + utils.validateOptions(options, OPTIONS_SCHEMA); + this.options = utils.processOptions(options, OPTIONS_PROCESSORS); + } + + apply(compiler) { + compiler.hooks.normalModuleFactory.tap( + PLUGIN_NAME, + (factory) => { + factory.hooks.resolve.tap( + PLUGIN_NAME, + (resolveData) => { + // Resolve fsProvider if required + if ( + resolveData.request === 'fsProvider' + && resolveData.context === this.options.shimsDir + ) { + return this.resolveFsProvider(resolveData); + } + + // Ignore filer files (these should resolve modules normally) + if (resolveData.context.startsWith(this.options.filerDir)) return; + + // Apply fs, path and buffer shims if required + switch (resolveData.request) { + case 'fs': + if (!this.options.shimFs) return; + return this.applyFsShim(resolveData); + case 'path': + if (!this.options.shimPath) return; + return this.applyPathShim(resolveData); + case 'buffer': + if (!this.options.shimBuffer) return; + return this.applyBufferShim(resolveData); + default: + return; + } + } + ); + }, + ) + } + + resolveFsProvider(resolveData) { + switch (this.options.fsProvider) { + case 'default': + resolveData.request = path.join(this.options.fsProviderDir, 'default.js'); + break; + case 'indexeddb': + resolveData.request = path.join(this.options.fsProviderDir, 'indexeddb.js'); + break; + case 'memory': + resolveData.request = path.join(this.options.fsProviderDir, 'memory.js'); + break; + case 'custom': + resolveData.request = path.join(this.options.fsProviderDir, 'custom.js'); + break; + default: + throw new Error([ + `Invalid option for fsProvider.`, + `fsProvider must be one of 'default', 'indexeddb', 'memory' or 'custom'.`, + `If using a custom fsProvider, you must also provide the fsProviderDir option.` + ].join(' ')); + } + } + + applyFsShim(resolveData) { + resolveData.request = path.join(this.options.shimsDir, 'fs.js'); + } + + applyPathShim(resolveData) { + resolveData.request = path.join(this.options.shimsDir, 'path.js'); + } + + applyBufferShim(resolveData) { + resolveData.request = path.join(this.options.shimsDir, 'buffer.js'); + } +} diff --git a/src/webpack-plugin/processors.js b/src/webpack-plugin/processors.js new file mode 100644 index 0000000..71f2a0e --- /dev/null +++ b/src/webpack-plugin/processors.js @@ -0,0 +1,33 @@ +const ROOT_DIR_TAG = ''; +const CWD = process.cwd(); + +module.exports = { + filerDir: { + process: function(value) { + if (!value) { + return path.join(CWD, 'node_modules', 'filer'); + } + return value.replace(ROOT_DIR_TAG, CWD); + }, + }, + shimsDir: { + process: function(value) { + if (!value) { + return path.join(CWD, 'node_modules', 'filer', 'shims'); + } + return value.replace(ROOT_DIR_TAG, CWD); + } + }, + shimFs: { default: true }, + shimPath: { default: true}, + shimBuffer: { default: true}, + fsProvider: { default: 'default'}, + fsProviderDir: { + process: function(value) { + if (!value) { + return path.join(CWD, 'node_modules', 'filer', 'shims', 'providers'); + } + return value.replace(ROOT_DIR_TAG, CWD);validateOptions + }, + }, +}; diff --git a/src/webpack-plugin/schema.js b/src/webpack-plugin/schema.js new file mode 100644 index 0000000..40e57ac --- /dev/null +++ b/src/webpack-plugin/schema.js @@ -0,0 +1,26 @@ +module.exports = { + type: 'object', + properties: { + filerDir: { + type: 'string', + }, + shimsDir: { + type: 'string', + }, + shimFs: { + type: 'boolean', + }, + shimPath: { + type: 'boolean', + }, + shimBuffer: { + type: 'boolean', + }, + fsProvider: { + type: 'string', + }, + fsProviderDir: { + type: 'string', + }, + } +}; diff --git a/src/webpack-plugin/utils.js b/src/webpack-plugin/utils.js new file mode 100644 index 0000000..79954cb --- /dev/null +++ b/src/webpack-plugin/utils.js @@ -0,0 +1,26 @@ +var { validate } = require('schema-utils'); + +function validateOptions(options, schema) { + validate(schema, options); +} + +function processOptions(options, processors) { + const processedOptions = {}; + + for (const [property, processor] of Object.entries(processors)) { + processedOptions[property] = options[property]; + if (processedOptions[property] === undefined) { + processedOptions[property] = processor.default; + } + if (processor.process) { + processedOptions[property] = processor.process(processedOptions[property]); + } + } + + return processedOptions; +} + +module.exports = { + validateOptions, + processOptions, +};