Skip to content
This repository has been archived by the owner on Feb 18, 2024. It is now read-only.

Support specifying plugins by path #102

Merged
merged 1 commit into from
Sep 12, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
28 changes: 27 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -609,13 +609,16 @@ config
.use(WebpackPlugin, args)

// Examples

config
.plugin('hot')
.use(webpack.HotModuleReplacementPlugin);

// Plugins can also be specified by their path, allowing the expensive require()s to be
// skipped in cases where the plugin or webpack configuration won't end up being used.
config
.plugin('env')
.use(webpack.EnvironmentPlugin, ['NODE_ENV']);
.use(require.resolve('webpack/lib/EnvironmentPlugin'), [{ 'VAR': false }]);
```

#### Config plugins: modify arguments
Expand Down Expand Up @@ -1217,6 +1220,29 @@ config.toString();
*/
```

Plugins specified via their path will have their `require()` statement generated
automatically:

``` js
config
.plugin('env')
.use(require.resolve('webpack/lib/ProvidePlugin'), [{ jQuery: 'jquery' }])

config.toString();

/*
{
plugins: [
new (require('/foo/bar/src/node_modules/webpack/lib/EnvironmentPlugin.js'))(
{
jQuery: 'jquery'
}
)
]
}
*/
```

You can also call `toString` as a static method on `Config` in order to
modify the configuration object prior to stringifying.

Expand Down
10 changes: 7 additions & 3 deletions src/Config.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,17 @@ module.exports = class extends ChainedMap {
const prefix = `/* ${configPrefix}.plugin('${
value.__pluginName
}') */\n`;
const constructorName = value.__pluginConstructorName;
const constructorExpression = value.__pluginPath
? // The path is stringified to ensure special characters are escaped
// (such as the backslashes in Windows-style paths).
`(require(${stringify(value.__pluginPath)}))`
: value.__pluginConstructorName;

if (constructorName) {
if (constructorExpression) {
// get correct indentation for args by stringifying the args array and
// discarding the square brackets.
const args = stringify(value.__pluginArgs).slice(1, -1);
return `${prefix}new ${constructorName}(${args})`;
return `${prefix}new ${constructorExpression}(${args})`;
}
return (
prefix +
Expand Down
19 changes: 16 additions & 3 deletions src/Plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,30 @@ module.exports = Orderable(

toConfig() {
const init = this.get('init');
const plugin = this.get('plugin');
let plugin = this.get('plugin');
const args = this.get('args');
let pluginPath = null;

// Support using the path to a plugin rather than the plugin itself,
// allowing expensive require()s to be skipped in cases where the plugin
// or webpack configuration won't end up being used.
if (typeof plugin === 'string') {
pluginPath = plugin;
// eslint-disable-next-line global-require, import/no-dynamic-require
plugin = require(pluginPath);
}

const constructorName = plugin.__expression
? `(${plugin.__expression})`
: plugin.name;

const config = init(this.get('plugin'), this.get('args'));
const config = init(plugin, args);

Object.defineProperties(config, {
__pluginName: { value: this.name },
__pluginArgs: { value: this.get('args') },
__pluginArgs: { value: args },
__pluginConstructorName: { value: constructorName },
__pluginPath: { value: pluginPath },
});

return config;
Expand Down
22 changes: 21 additions & 1 deletion test/Config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import test from 'ava';
import { validate } from 'webpack';
import EnvironmentPlugin from 'webpack/lib/EnvironmentPlugin';
import stringify from 'javascript-stringify';
import Config from '../src/Config';

class StringifyPlugin {
Expand Down Expand Up @@ -100,6 +102,9 @@ test('toConfig with values', t => {
.plugin('stringify')
.use(StringifyPlugin)
.end()
.plugin('env')
.use(require.resolve('webpack/lib/EnvironmentPlugin'))
.end()
.module.defaultRule('inline')
.use('banner')
.loader('banner-loader')
Expand Down Expand Up @@ -132,7 +137,7 @@ test('toConfig with values', t => {
path: 'build',
},
target: 'node',
plugins: [new StringifyPlugin()],
plugins: [new StringifyPlugin(), new EnvironmentPlugin()],
module: {
defaultRules: [
{
Expand Down Expand Up @@ -199,6 +204,9 @@ test('validate with values', t => {
.plugin('stringify')
.use(StringifyPlugin)
.end()
.plugin('env')
.use(require.resolve('webpack/lib/EnvironmentPlugin'), [{ VAR: false }])
.end()
.module.rule('compile')
.include.add('alpha')
.add('beta')
Expand Down Expand Up @@ -228,10 +236,16 @@ test('toString', t => {
.use('babel')
.loader('babel-loader');

const envPluginPath = require.resolve('webpack/lib/EnvironmentPlugin');
const stringifiedEnvPluginPath = stringify(envPluginPath);

class FooPlugin {}
FooPlugin.__expression = `require('foo-plugin')`;

config
.plugin('env')
.use(envPluginPath, [{ VAR: false }])
.end()
.plugin('gamma')
.use(FooPlugin)
.end()
Expand Down Expand Up @@ -264,6 +278,12 @@ test('toString', t => {
]
},
plugins: [
/* config.plugin('env') */
new (require(${stringifiedEnvPluginPath}))(
{
VAR: false
}
),
/* config.plugin('gamma') */
new (require('foo-plugin'))(),
/* config.plugin('delta') */
Expand Down
14 changes: 14 additions & 0 deletions test/Plugin.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import test from 'ava';
import EnvironmentPlugin from 'webpack/lib/EnvironmentPlugin';
import Plugin from '../src/Plugin';

class StringifyPlugin {
Expand Down Expand Up @@ -97,3 +98,16 @@ test('toConfig with object literal plugin', t => {

t.is(initialized, TestPlugin);
});

test('toConfig with plugin as path', t => {
const plugin = new Plugin(null, 'gamma');
const envPluginPath = require.resolve('webpack/lib/EnvironmentPlugin');

plugin.use(envPluginPath);

const initialized = plugin.toConfig();

t.true(initialized instanceof EnvironmentPlugin);
t.is(initialized.__pluginConstructorName, 'EnvironmentPlugin');
t.is(initialized.__pluginPath, envPluginPath);
});