diff --git a/README.md b/README.md index 007191d..2c0ee66 100644 --- a/README.md +++ b/README.md @@ -11,16 +11,20 @@ npm install --save-dev webpack-config-plugin ```js // webpack.config.js -var path = require("path") -var ConfigPlugin = require("webpack-config-plugin") +var path = require('path'); +var ConfigPlugin = require('webpack-config-plugin'); module.exports = { // [...] plugins: [ // [...] new ConfigPlugin({ - // Configuration directory - dir: path.join(__dirname, "config") + + // Configuration directory (required) + dir: path.join(__dirname, 'config'), + + // Filter expression(s) (optional) + filter: [ '-secret.property' ] }) ] } @@ -31,3 +35,6 @@ module.exports = { When the plugin has been configured it enables a faux-module `config` which is a merge between a default configuration, an environment-specific configuration, and a local configuration. + +Please see [json-property-filter](https://www.npmjs.com/package/json-property-filter) +for documentation of filter expressions. diff --git a/lib/config-loader.js b/lib/config-loader.js index 4050df9..a819e15 100644 --- a/lib/config-loader.js +++ b/lib/config-loader.js @@ -1,4 +1,14 @@ -module.exports = function() { - var config = JSON.parse(this.query.slice(1)) - return "module.exports = " + JSON.stringify(config) -} +const { JsonPropertyFilter } = require('json-property-filter'); + +module.exports = function () { + const { config, filter = [] } = JSON.parse(this.query.slice(1)); + + if (Array.isArray(filter) && filter.length > 0) { + const propertyFilter = new JsonPropertyFilter(filter); + const filteredOutput = propertyFilter.apply(config); + + return `module.exports = ${JSON.stringify(filteredOutput)}`; + } + + return `module.exports = ${JSON.stringify(config)}`; +}; diff --git a/lib/config-plugin.js b/lib/config-plugin.js index 08f2d71..24b2c58 100644 --- a/lib/config-plugin.js +++ b/lib/config-plugin.js @@ -1,76 +1,103 @@ -var _ = require("lodash") -var path = require("path") - -// Load configuration file -function loadFile(dir, filename) { - if (filename == null) return {} - filename = path.join(dir, filename) - try { - return require(filename) - } catch(e) { - return {} +const assert = require('assert'); +const path = require('path'); +const merge = require('lodash/merge'); + +class Config { + + // Load configuration file. + // Fails gracefully by returning an empty object. + static loadConfigFile(dir, filename) { + if (!filename) { + return {}; + } + + try { + const pathname = path.resolve(dir, filename); + + return require(pathname); + } catch (error) { + return {}; + } } -} -module.exports = Config -function Config(options) { - this.options = options - this._config = null + constructor(options = {}) { + assert(typeof options.dir === 'string', 'WebpackConfigPlugin: "options.dir" must be provided'); + assert(!options.filter || Array.isArray(options.filter), 'WebpackConfigPlugin: "options.filter" must be an array. See "json-property-filter" package for more details'); + + this.options = options; + this.config = null; - if (this.options.environment == null) { - this.options.environment = process.env.NODE_ENV || "development" + if (!this.options.environment) { + this.options.environment = process.env.NODE_ENV || 'development'; + } } -} -Config.prototype.getConfig = function () { - if (!this._config) { - this._config = _.merge({}, - loadFile(this.options.dir, "default"), - loadFile(this.options.dir, this.options.environment), - loadFile(this.options.dir, "local") - ) + getConfig() { + if (!this.config) { + const { dir, environment } = this.options; + + this.config = merge( + {}, + Config.loadConfigFile(dir, 'default'), + Config.loadConfigFile(dir, environment), + Config.loadConfigFile(dir, 'local') + ); + } + + return this.config; } - return this._config -} -Config.prototype.apply = function(compiler) { - // Build the configuration object - var config = this.getConfig() - - compiler.plugin('compilation', function(compilation) { - // Setup a resolver to faux-resolve a request for "config" - compilation.resolvers.normal.plugin("module", function(request, next) { - if (request.request !== "config") { - // This plugin only resolves for the explicit module "config" - return next() - } - - return next(null, { - // This path is not actually used but must be set to a real file - path: "package.json", - resolved: true - }) - }) - }) - - // Setup a module-factory to direct the flow to the loader ( - // which outputs the configuration JSON) - compiler.plugin("normal-module-factory", function(nmf) { - nmf.plugin("after-resolve", function(data, next) { - if (data.rawRequest !== "config") { - // This plugin only resolves for the explicit module "config" - return next(null, data) - } - - // console.log(data) - // NOTE: Parameters are passed via query string to the loader - // at `this.query` - data.loaders = [ - path.join(__dirname, "./config-loader.js") + "?" + - JSON.stringify(config) - ] - - return next(null, data) - }) - }) + apply(compiler) { + + // Build the configuration object + const config = this.getConfig(); + + compiler.plugin('compilation', compilation => { + + // Setup a resolver to faux-resolve a request for "config" + compilation.resolvers.normal.plugin('module', (request, next) => { + if (request.request !== 'config') { + + // This plugin only resolves for the explicit module "config" + return next(); + } + + return next(null, { + + // This path is not actually used but must be set to a real file + path: 'package.json', + resolved: true + }); + }); + }); + + // Setup a module-factory to direct the flow to the loader ( + // which outputs the configuration JSON) + compiler.plugin('normal-module-factory', factory => { + factory.plugin('after-resolve', (data, next) => { + if (data.rawRequest !== 'config') { + + // This plugin only resolves for the explicit module "config" + return next(null, data); + } + + const { filter } = this.options; + const loaderPathname = path.resolve(__dirname, 'config-loader.js'); + const loaderQuery = { + config, + filter + }; + + // NOTE: Parameters are passed via query string to the loader + // at `this.query` + data.loaders = [ + `${loaderPathname}?${JSON.stringify(loaderQuery)}` + ]; + + return next(null, data); + }); + }); + } } + +module.exports = Config; \ No newline at end of file diff --git a/package.json b/package.json index be55602..e2e7fe8 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,10 @@ { "name": "webpack-config-plugin", - "version": "1.0.0", + "version": "1.1.0", "description": "Configuration plugin (in the style of node-config) for webpack.", "main": "lib/config-plugin.js", - "peerDependencies": { - "webpack": ">=1.4.0" + "engines": { + "node": ">=6" }, "repository": { "type": "git", @@ -20,12 +20,22 @@ "email": "leckey.ryan@gmail.com", "url": "https://github.com/mehcode" }, + "contributors": [ + { + "name": "J. Snaras", + "email": "j@snaras.com" + } + ], "license": "MIT", "bugs": { "url": "https://github.com/mehcode/webpack-config-plugin/issues" }, "homepage": "https://github.com/mehcode/webpack-config-plugin", "dependencies": { - "lodash": "^3.10.1" + "json-property-filter": "^1.3.1", + "lodash": "^4.17.4" + }, + "peerDependencies": { + "webpack": ">=1.4.0" } }