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

Commit

Permalink
Feature: allow specifying .before or .after to order plugins and uses
Browse files Browse the repository at this point in the history
  • Loading branch information
eliperelman committed Oct 6, 2017
1 parent fb6ea2f commit a9f8f37
Show file tree
Hide file tree
Showing 6 changed files with 247 additions and 16 deletions.
88 changes: 86 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ config
.entry('index')
.add('src/index.js')
.end()

// Modify output settings
.output
.path('dist')
Expand Down Expand Up @@ -194,6 +193,8 @@ values()
// where the key is the object property, and the value
// corresponding to the key. Will return `undefined` if the backing
// Map is empty.
// This will order properties by their name if the value is also
// a ChainedMap that used .before() or .after().
// returns: Object, undefined if empty
entries()
````
Expand Down Expand Up @@ -356,7 +357,7 @@ config
config
.entry(name)
.clear()
.clear()
// Using low-level config.entryPoints:
Expand Down Expand Up @@ -611,6 +612,48 @@ config
config.plugins.delete(name)
```

#### Config plugins: ordering before

Specify that the current `plugin` context should operate before another named `plugin`.
You cannot use both `.before()` and `.after()` on the same plugin.

```js
config
.plugin(name)
.before(otherName)
// Example
config
.plugin('html-template')
.use(HtmlWebpackTemplate)
.end()
.plugin('script-ext')
.use(ScriptExtWebpackPlugin)
.before('html-template');
```

#### Config plugins: ordering after

Specify that the current `plugin` context should operate after another named `plugin`.
You cannot use both `.before()` and `.after()` on the same plugin.

```js
config
.plugin(name)
.after(otherName)
// Example
config
.plugin('html-template')
.after('script-ext')
.use(HtmlWebpackTemplate)
.end()
.plugin('script-ext')
.use(ScriptExtWebpackPlugin);
```

#### Config resolve plugins

```js
Expand Down Expand Up @@ -650,6 +693,47 @@ config.resolve
config.resolve.plugins.delete(name)
```

#### Config resolve plugins: ordering before

Specify that the current `plugin` context should operate before another named `plugin`.
You cannot use both `.before()` and `.after()` on the same resolve plugin.

```js
config.resolve
.plugin(name)
.before(otherName)
// Example
config.resolve.plugin('beta')
.use(BetaWebpackPlugin)
.end()
.plugin('alpha')
.use(AlphaWebpackPlugin)
.before('beta');
```

#### Config resolve plugins: ordering after

Specify that the current `plugin` context should operate after another named `plugin`.
You cannot use `.before()` and `.after()` on the same resolve plugin.

```js
config.resolve
.plugin(name)
.after(otherName)
// Example
config.resolve
.plugin('beta')
.after('alpha')
.use(BetaWebpackTemplate)
.end()
.plugin('alpha')
.use(AlphaWebpackPlugin);
```

#### Config node

```js
Expand Down
39 changes: 30 additions & 9 deletions src/ChainedMap.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ module.exports = class extends Chainable {
methods.map(method => {
this[method] = value => this.set(method, value);
});
return this;
}

clear() {
Expand All @@ -24,21 +25,41 @@ module.exports = class extends Chainable {
return this;
}

entries() {
const entries = [...this.store];

if (!entries.length) {
return;
}

return entries.reduce((acc, [key, value]) => {
order() {
const entries = [...this.store].reduce((acc, [key, value]) => {
acc[key] = value;
return acc;
}, {});
const names = Object.keys(entries);
const order = [...names];

names.forEach(name => {
const { __before, __after } = entries[name];

if (__before && order.includes(__before)) {
order.splice(order.indexOf(name), 1);
order.splice(order.indexOf(__before), 0, name);
} else if (__after && order.includes(__after)) {
order.splice(order.indexOf(name), 1);
order.splice(order.indexOf(__after) + 1, 0, name);
}
});

return { entries, order };
}

entries() {
const { entries, order } = this.order();

if (order.length) {
return entries;
}
}

values() {
return [...this.store.values()];
const { entries, order } = this.order();

return order.map(name => entries[name]);
}

get(key) {
Expand Down
31 changes: 31 additions & 0 deletions src/Orderable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
module.exports = (Class) => class extends Class {
before(name) {
if (this.__after) {
throw new Error(`Unable to set .before(${JSON.stringify(name)}) with existing value for after`);
}

this.__before = name;
return this;
}

after(name) {
if (this.__before) {
throw new Error(`Unable to set .after(${JSON.stringify(name)}) with existing value for before`);
}

this.__after = name;
return this;
}

merge(obj, omit = []) {
if (obj.before) {
this.before(obj.before);
}

if (obj.after) {
this.after(obj.after);
}

return super.merge(obj, [...omit, 'before', 'after']);
}
};
7 changes: 4 additions & 3 deletions src/Plugin.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const ChainedMap = require('./ChainedMap');
const Orderable = require('./Orderable');

module.exports = class extends ChainedMap {
module.exports = Orderable(class extends ChainedMap {
constructor(parent) {
super(parent);
this.extend(['init']);
Expand Down Expand Up @@ -28,12 +29,12 @@ module.exports = class extends ChainedMap {
this.set('args', obj.args);
}

return super.merge(obj, [...omit, 'args', 'plugin'])
return super.merge(obj, [...omit, 'args', 'plugin']);
}

toConfig() {
const init = this.get('init');

return init(this.get('plugin'), this.get('args'));
}
};
});
5 changes: 3 additions & 2 deletions src/Use.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
const ChainedMap = require('./ChainedMap');
const Orderable = require('./Orderable');
const merge = require('deepmerge');

module.exports = class extends ChainedMap {
module.exports = Orderable(class extends ChainedMap {
constructor(parent) {
super(parent);
this.extend(['loader', 'options']);
Expand All @@ -27,4 +28,4 @@ module.exports = class extends ChainedMap {
toConfig() {
return this.clean(this.entries() || {});
}
};
});
93 changes: 93 additions & 0 deletions test/Orderable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import test from 'ava';
import Orderable from '../src/Orderable';
import ChainedMap from '../src/ChainedMap';

const Ordered = Orderable(class Test extends ChainedMap {});

test('before', t => {
const ordered = new Ordered();
const instance = ordered
.set('gamma')
.before('beta');

t.is(instance, ordered);
t.is(ordered.__before, 'beta');
});

test('after', t => {
const ordered = new Ordered();
const instance = ordered
.set('gamma')
.after('alpha');

t.is(instance, ordered);
t.is(ordered.__after, 'alpha');
});

test('before throws with after', t => {
const ordered = new Ordered();

t.throws(() => ordered.after('alpha').before('beta'));
});

test('after throws with before', t => {
const ordered = new Ordered();

t.throws(() => ordered.before('beta').after('alpha'));
});

test('ordering before', t => {
const map = new ChainedMap();

map.set('beta', new Ordered().set('beta', 'beta'));
map.set('alpha', new Ordered().set('alpha', 'alpha').before('beta'));

t.deepEqual(map.values().map(o => o.values()), [['alpha'], ['beta']]);
});

test('ordering after', t => {
const map = new ChainedMap();

map.set('beta', new Ordered().set('beta', 'beta').after('alpha'));
map.set('alpha', new Ordered().set('alpha', 'alpha'));

t.deepEqual(map.values().map(o => o.values()), [['alpha'], ['beta']]);
});

test('ordering before and after', t => {
const map = new ChainedMap();

map.set('beta', new Ordered().set('beta', 'beta'));
map.set('gamma', new Ordered().set('gamma', 'gamma').after('beta'));
map.set('alpha', new Ordered().set('alpha', 'alpha').before('beta'));

t.deepEqual(map.values().map(o => o.values()), [['alpha'], ['beta'], ['gamma']]);
});

test('merge with before', t => {
const ordered = new Ordered();
const instance = ordered
.set('gamma')
.merge({
before: 'beta'
});

t.is(instance, ordered);
t.is(ordered.__before, 'beta');
});

test('merge with after', t => {
const ordered = new Ordered();
const instance = ordered
.set('gamma')
.merge({
after: 'alpha'
});

t.is(instance, ordered);
t.is(ordered.__after, 'alpha');
});

test('merging throws using before with after', t => {
t.throws(() => new Ordered().merge({ before: 'beta', after: 'alpha' }));
});

0 comments on commit a9f8f37

Please sign in to comment.