Skip to content

Add possibility to extend a base config #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 1, 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 37 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ While `next-compose-plugins` tries to eliminate this case by providing an altern

- [Installation](#installation)
- [Usage](#usage)
- [`withPlugins`](#usage)
- [Optional plugins](#optional-plugins)
- [Extend another config file](#extend-another-config-file)
- [Plugin developers](#plugin-developers)
- [Examples](#examples)
- [See also](#see-also)
Expand Down Expand Up @@ -145,6 +148,40 @@ module.exports = withPlugins([
]);
```

### Extend another config file

It sometimes makes sense to split a `next.config.js` file into multiple files, for example when you have more than just one next.js project in one repository.
You can then define the base config in one file and add project specific plugins/settings in the config file or the project.

To easily archive this, you can use the `extend` helper in the `next.config.js` file of your project.

```javascript
// next.config.js
const { withPlugins, extend } = require('next-compose-plugins');
const baseConfig = require('./base.next.config.js');

const nextConfig = { /* ... */ };

module.exports = extend(baseConfig).withPlugins([
[sass, {
cssModules: true,
}],
], nextConfig);
```

```javascript
// base.next.config.js
const withPlugins = require('next-compose-plugins');

module.exports = withPlugins([
[typescript, {
typescriptLoaderOptions: {
transpileOnly: false,
},
}],
]);
```

## Plugin developers

This plugin has a few extra functionality which you can use as a plugin developer.
Expand Down Expand Up @@ -227,7 +264,6 @@ module.exports = withPlugins([
[sass, {
cssModules: true,
cssLoaderOptions: {
importLoaders: 1,
localIdentName: '[local]___[hash:base64:5]',
},
}],
Expand Down Expand Up @@ -273,12 +309,10 @@ module.exports = withPlugins([
[sass, {
cssModules: true,
cssLoaderOptions: {
importLoaders: 1,
localIdentName: '[local]___[hash:base64:5]',
},
[PHASE_PRODUCTION_BUILD + PHASE_EXPORT]: {
cssLoaderOptions: {
importLoaders: 1,
localIdentName: '[hash:base64:8]',
},
},
Expand Down
101 changes: 99 additions & 2 deletions src/__tests__/index.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,104 @@
import 'jest';
import { withPlugins, extend } from '../index';

const PHASE_DEVELOPMENT_SERVER = 'phase-development-server';
const PHASE_PRODUCTION_SERVER = 'phase-production-server';

describe('next-compose-plugins', () => {
it('runs tests', () => {
expect(1).toEqual(1);
it('extends a base config', () => {
const plugin1 = jest.fn(nextConfig => ({ ...nextConfig, plugin1: true }));
const plugin2 = jest.fn(nextConfig => ({ ...nextConfig, plugin2: true }));
const plugin3 = jest.fn(nextConfig => ({ ...nextConfig, plugin3: true }));

const baseConfig = withPlugins([plugin1, plugin2], {
baseConfig: 'hello',
foo: 'bar',
});

const extendedConfig = extend(baseConfig).withPlugins([plugin3], { foo: 'baz', extendedConfig: 'world' });

expect(extendedConfig(PHASE_DEVELOPMENT_SERVER, { defaultConfig: { nextConfig: 'abc' } })).toEqual({
plugin1: true,
plugin2: true,
plugin3: true,
baseConfig: 'hello',
extendedConfig: 'world',
foo: 'baz',
nextConfig: 'abc',
});

expect(plugin1).toHaveBeenCalledTimes(1);
expect(plugin2).toHaveBeenCalledTimes(1);
expect(plugin3).toHaveBeenCalledTimes(1);
});

it('passes the current phase to the extended config', () => {
const plugin1 = jest.fn(nextConfig => ({ ...nextConfig, plugin1: true }));
const plugin2 = jest.fn(nextConfig => ({ ...nextConfig, plugin2: true }));
const plugin3 = jest.fn(nextConfig => ({ ...nextConfig, plugin3: true }));
const plugin4 = jest.fn(nextConfig => ({ ...nextConfig, plugin4: true }));

const baseConfig = withPlugins([
[plugin1, [PHASE_DEVELOPMENT_SERVER]],
[plugin2, [PHASE_PRODUCTION_SERVER]],
], {
baseConfig: 'hello',
foo: 'bar',
});

const extendedConfig = extend(baseConfig).withPlugins([
[plugin3, [PHASE_DEVELOPMENT_SERVER]],
[plugin4, [PHASE_PRODUCTION_SERVER]],
], { foo: 'baz', extendedConfig: 'world' });

expect(extendedConfig(PHASE_PRODUCTION_SERVER, { defaultConfig: { nextConfig: 'abc' } })).toEqual({
plugin2: true,
plugin4: true,
baseConfig: 'hello',
extendedConfig: 'world',
foo: 'baz',
nextConfig: 'abc',
});

expect(plugin1).toHaveBeenCalledTimes(0);
expect(plugin2).toHaveBeenCalledTimes(1);
expect(plugin3).toHaveBeenCalledTimes(0);
expect(plugin4).toHaveBeenCalledTimes(1);
});

it('extends the webpack config', () => {
const plugin1 = jest.fn(nextConfig => ({
...nextConfig,
webpack: () => {
if (nextConfig.webpack) {
return `changed from base ${nextConfig.webpack()}`;
}

return null;
},
}));

const plugin2 = jest.fn(nextConfig => ({
...nextConfig,
webpack: () => {
if (nextConfig.webpack) {
return `changed from current ${nextConfig.webpack()}`;
}

return null;
},
}));

const baseConfig = withPlugins([plugin1]);
const extendedConfig = extend(baseConfig).withPlugins([plugin2]);
const result = extendedConfig(PHASE_DEVELOPMENT_SERVER, {
defaultConfig: {
webpack: () => 'webpack config',
},
});

expect(result.webpack()).toEqual('changed from current changed from base webpack config');
expect(plugin1).toHaveBeenCalledTimes(1);
expect(plugin2).toHaveBeenCalledTimes(1);
});
});
17 changes: 17 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,26 @@ const withPlugins = ([...plugins], nextConfig = {}) => (phase, { defaultConfig }
return composePlugins(phase, plugins, config);
};

/**
* Extends a base next config.
*
* @param {function} baseConfig - basic configuration
*/
const extend = baseConfig => ({
withPlugins: (...params) => (phase, nextOptions) => {
const processedBaseConfig = baseConfig(phase, nextOptions);

return withPlugins(...params)(phase, {
...nextOptions,
defaultConfig: processedBaseConfig,
});
},
});

// define exports
const exports = withPlugins;
exports.withPlugins = withPlugins;
exports.optional = markOptional;
exports.extend = extend;

module.exports = exports;