fix(nextjs): remove the need to install @nx/next for production builds (#16469)
This commit is contained in:
parent
a10b6b1290
commit
564ffaeebd
@ -6,4 +6,4 @@ export { componentGenerator } from './src/generators/component/component';
|
|||||||
export { libraryGenerator } from './src/generators/library/library';
|
export { libraryGenerator } from './src/generators/library/library';
|
||||||
export { pageGenerator } from './src/generators/page/page';
|
export { pageGenerator } from './src/generators/page/page';
|
||||||
export { withNx } from './plugins/with-nx';
|
export { withNx } from './plugins/with-nx';
|
||||||
export { composePlugins } from './src/utils/config';
|
export { composePlugins } from './src/utils/compose-plugins';
|
||||||
|
|||||||
@ -1,23 +1,14 @@
|
|||||||
import {
|
/**
|
||||||
createProjectGraphAsync,
|
* WARNING: Do not add development dependencies to top-level imports.
|
||||||
joinPathFragments,
|
* Instead, `require` them inline during the build phase.
|
||||||
offsetFromRoot,
|
*/
|
||||||
parseTargetString,
|
import * as path from 'path';
|
||||||
ProjectGraph,
|
|
||||||
ProjectGraphProjectNode,
|
|
||||||
Target,
|
|
||||||
workspaceRoot,
|
|
||||||
} from '@nx/devkit';
|
|
||||||
import {
|
|
||||||
calculateProjectDependencies,
|
|
||||||
DependentBuildableProjectNode,
|
|
||||||
} from '@nx/js/src/utils/buildable-libs-utils';
|
|
||||||
import type { NextConfig } from 'next';
|
import type { NextConfig } from 'next';
|
||||||
import { PHASE_PRODUCTION_SERVER } from 'next/constants';
|
import { PHASE_PRODUCTION_SERVER } from 'next/constants';
|
||||||
|
import type { NextConfigFn } from '../src/utils/config';
|
||||||
import * as path from 'path';
|
import type { NextBuildBuilderOptions } from '../src/utils/types';
|
||||||
import { createWebpackConfig, NextConfigFn } from '../src/utils/config';
|
import type { DependentBuildableProjectNode } from '@nx/js/src/utils/buildable-libs-utils';
|
||||||
import { NextBuildBuilderOptions } from '../src/utils/types';
|
import type { ProjectGraph, ProjectGraphProjectNode, Target } from '@nx/devkit';
|
||||||
|
|
||||||
export interface WithNxOptions extends NextConfig {
|
export interface WithNxOptions extends NextConfig {
|
||||||
nx?: {
|
nx?: {
|
||||||
@ -78,6 +69,7 @@ function getNxContext(
|
|||||||
targetName: string;
|
targetName: string;
|
||||||
configurationName?: string;
|
configurationName?: string;
|
||||||
} {
|
} {
|
||||||
|
const { parseTargetString } = require('@nx/devkit');
|
||||||
const targetConfig = getTargetConfig(graph, target);
|
const targetConfig = getTargetConfig(graph, target);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -119,7 +111,6 @@ function getNxContext(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to read output dir from project, and default to '.next' if executing outside of Nx (e.g. dist is added to a docker image).
|
* Try to read output dir from project, and default to '.next' if executing outside of Nx (e.g. dist is added to a docker image).
|
||||||
*/
|
*/
|
||||||
@ -130,22 +121,36 @@ async function determineDistDirForProdServer(
|
|||||||
const target = process.env.NX_TASK_TARGET_TARGET;
|
const target = process.env.NX_TASK_TARGET_TARGET;
|
||||||
const configuration = process.env.NX_TASK_TARGET_CONFIGURATION;
|
const configuration = process.env.NX_TASK_TARGET_CONFIGURATION;
|
||||||
|
|
||||||
if (project && target) {
|
try {
|
||||||
const originalTarget = { project, target, configuration };
|
if (project && target) {
|
||||||
const graph = await createProjectGraphAsync();
|
// If NX env vars are set, then devkit must be available.
|
||||||
|
const {
|
||||||
|
createProjectGraphAsync,
|
||||||
|
joinPathFragments,
|
||||||
|
offsetFromRoot,
|
||||||
|
} = require('@nx/devkit');
|
||||||
|
const originalTarget = { project, target, configuration };
|
||||||
|
const graph = await createProjectGraphAsync();
|
||||||
|
|
||||||
const { options, node: projectNode } = getNxContext(graph, originalTarget);
|
const { options, node: projectNode } = getNxContext(
|
||||||
const outputDir = `${offsetFromRoot(projectNode.data.root)}${
|
graph,
|
||||||
options.outputPath
|
originalTarget
|
||||||
}`;
|
);
|
||||||
return nextConfig.distDir && nextConfig.distDir !== '.next'
|
const outputDir = `${offsetFromRoot(projectNode.data.root)}${
|
||||||
? joinPathFragments(outputDir, nextConfig.distDir)
|
options.outputPath
|
||||||
: joinPathFragments(outputDir, '.next');
|
}`;
|
||||||
} else {
|
return nextConfig.distDir && nextConfig.distDir !== '.next'
|
||||||
return '.next';
|
? joinPathFragments(outputDir, nextConfig.distDir)
|
||||||
|
: joinPathFragments(outputDir, '.next');
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// ignored -- fallback to Next.js default of '.next'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nextConfig.distDir || '.next';
|
||||||
}
|
}
|
||||||
export function withNx(
|
|
||||||
|
function withNx(
|
||||||
_nextConfig = {} as WithNxOptions,
|
_nextConfig = {} as WithNxOptions,
|
||||||
context: WithNxContext = getWithNxContext()
|
context: WithNxContext = getWithNxContext()
|
||||||
): NextConfigFn {
|
): NextConfigFn {
|
||||||
@ -155,9 +160,16 @@ export function withNx(
|
|||||||
const { nx, ...validNextConfig } = _nextConfig;
|
const { nx, ...validNextConfig } = _nextConfig;
|
||||||
return {
|
return {
|
||||||
...validNextConfig,
|
...validNextConfig,
|
||||||
distDir: await determineDistDirForProdServer(validNextConfig),
|
distDir: await determineDistDirForProdServer(_nextConfig),
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
const {
|
||||||
|
createProjectGraphAsync,
|
||||||
|
joinPathFragments,
|
||||||
|
offsetFromRoot,
|
||||||
|
workspaceRoot,
|
||||||
|
} = require('@nx/devkit');
|
||||||
|
|
||||||
// Otherwise, add in webpack and eslint configuration for build or test.
|
// Otherwise, add in webpack and eslint configuration for build or test.
|
||||||
let dependencies: DependentBuildableProjectNode[] = [];
|
let dependencies: DependentBuildableProjectNode[] = [];
|
||||||
|
|
||||||
@ -179,6 +191,9 @@ export function withNx(
|
|||||||
const projectDirectory = projectNode.data.root;
|
const projectDirectory = projectNode.data.root;
|
||||||
|
|
||||||
if (options.buildLibsFromSource === false && targetName) {
|
if (options.buildLibsFromSource === false && targetName) {
|
||||||
|
const {
|
||||||
|
calculateProjectDependencies,
|
||||||
|
} = require('@nx/js/src/utils/buildable-libs-utils');
|
||||||
const result = calculateProjectDependencies(
|
const result = calculateProjectDependencies(
|
||||||
graph,
|
graph,
|
||||||
workspaceRoot,
|
workspaceRoot,
|
||||||
@ -202,6 +217,7 @@ export function withNx(
|
|||||||
|
|
||||||
const userWebpackConfig = nextConfig.webpack;
|
const userWebpackConfig = nextConfig.webpack;
|
||||||
|
|
||||||
|
const { createWebpackConfig } = require('../src/utils/config');
|
||||||
nextConfig.webpack = (a, b) =>
|
nextConfig.webpack = (a, b) =>
|
||||||
createWebpackConfig(
|
createWebpackConfig(
|
||||||
workspaceRoot,
|
workspaceRoot,
|
||||||
@ -407,3 +423,5 @@ module.exports = withNx;
|
|||||||
// Support for newer generated code: `const { withNx } = require(...);`
|
// Support for newer generated code: `const { withNx } = require(...);`
|
||||||
module.exports.withNx = withNx;
|
module.exports.withNx = withNx;
|
||||||
module.exports.getNextConfig = getNextConfig;
|
module.exports.getNextConfig = getNextConfig;
|
||||||
|
|
||||||
|
export { withNx };
|
||||||
|
|||||||
@ -0,0 +1,59 @@
|
|||||||
|
import { getWithNxContent } from './create-next-config-file';
|
||||||
|
import { stripIndents } from '@nx/devkit';
|
||||||
|
|
||||||
|
describe('Next.js config: getWithNxContent', () => {
|
||||||
|
it('should swap distDir and getWithNxContext with static values', () => {
|
||||||
|
const result = getWithNxContent({
|
||||||
|
withNxFile: `with-nx.js`,
|
||||||
|
withNxContent: stripIndents`
|
||||||
|
// SHOULD BE LEFT INTACT
|
||||||
|
const constants = require("next/constants");
|
||||||
|
|
||||||
|
// TO BE SWAPPED
|
||||||
|
function getWithNxContext() {
|
||||||
|
const { workspaceRoot, workspaceLayout } = require('@nx/devkit');
|
||||||
|
return {
|
||||||
|
workspaceRoot,
|
||||||
|
libsDir: workspaceLayout().libsDir,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// SHOULD BE LEFT INTACT
|
||||||
|
function withNx(nextConfig = {}, context = getWithNxContext()) {
|
||||||
|
return (phase) => {
|
||||||
|
if (phase === constants.PHASE_PRODUCTION_SERVER) {
|
||||||
|
//...
|
||||||
|
} else {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// SHOULD BE LEFT INTACT
|
||||||
|
module.exports.withNx = withNx;
|
||||||
|
`,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result).toContain(`const constants = require("next/constants")`);
|
||||||
|
expect(result).toContain(stripIndents`
|
||||||
|
// SHOULD BE LEFT INTACT
|
||||||
|
function withNx(nextConfig = {}, context = getWithNxContext()) {
|
||||||
|
return (phase) => {
|
||||||
|
if (phase === constants.PHASE_PRODUCTION_SERVER) {
|
||||||
|
//...
|
||||||
|
} else {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// SHOULD BE LEFT INTACT
|
||||||
|
module.exports.withNx = withNx;
|
||||||
|
`);
|
||||||
|
expect(result).not.toContain(
|
||||||
|
`const { workspaceRoot, workspaceLayout } = require('@nx/devkit');`
|
||||||
|
);
|
||||||
|
expect(result).toContain(`libsDir: ''`);
|
||||||
|
expect(result).not.toContain(`libsDir: workspaceLayout.libsDir()`);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -1,9 +1,23 @@
|
|||||||
import { ExecutorContext } from '@nx/devkit';
|
import type { ExecutorContext } from '@nx/devkit';
|
||||||
|
import {
|
||||||
import { copyFileSync, existsSync } from 'fs';
|
applyChangesToString,
|
||||||
|
ChangeType,
|
||||||
|
stripIndents,
|
||||||
|
workspaceLayout,
|
||||||
|
workspaceRoot,
|
||||||
|
} from '@nx/devkit';
|
||||||
|
import * as ts from 'typescript';
|
||||||
|
import {
|
||||||
|
copyFileSync,
|
||||||
|
existsSync,
|
||||||
|
mkdirSync,
|
||||||
|
readFileSync,
|
||||||
|
writeFileSync,
|
||||||
|
} from 'fs';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
|
|
||||||
import type { NextBuildBuilderOptions } from '../../../utils/types';
|
import type { NextBuildBuilderOptions } from '../../../utils/types';
|
||||||
|
import { findNodes } from 'nx/src/utils/typescript';
|
||||||
|
|
||||||
export function createNextConfigFile(
|
export function createNextConfigFile(
|
||||||
options: NextBuildBuilderOptions,
|
options: NextBuildBuilderOptions,
|
||||||
@ -13,7 +27,77 @@ export function createNextConfigFile(
|
|||||||
? join(context.root, options.nextConfig)
|
? join(context.root, options.nextConfig)
|
||||||
: join(context.root, options.root, 'next.config.js');
|
: join(context.root, options.root, 'next.config.js');
|
||||||
|
|
||||||
|
// Copy config file and our `.nx-helpers` folder to remove dependency on @nrwl/next for production build.
|
||||||
if (existsSync(nextConfigPath)) {
|
if (existsSync(nextConfigPath)) {
|
||||||
copyFileSync(nextConfigPath, join(options.outputPath, 'next.config.js'));
|
const helpersPath = join(options.outputPath, '.nx-helpers');
|
||||||
|
mkdirSync(helpersPath, { recursive: true });
|
||||||
|
copyFileSync(
|
||||||
|
join(__dirname, '../../../utils/compose-plugins.js'),
|
||||||
|
join(helpersPath, 'compose-plugins.js')
|
||||||
|
);
|
||||||
|
writeFileSync(join(helpersPath, 'with-nx.js'), getWithNxContent());
|
||||||
|
writeFileSync(
|
||||||
|
join(helpersPath, 'compiled.js'),
|
||||||
|
`
|
||||||
|
const withNx = require('./with-nx');
|
||||||
|
module.exports = withNx;
|
||||||
|
module.exports.withNx = withNx;
|
||||||
|
module.exports.composePlugins = require('./compose-plugins').composePlugins;
|
||||||
|
`
|
||||||
|
);
|
||||||
|
writeFileSync(
|
||||||
|
join(options.outputPath, 'next.config.js'),
|
||||||
|
readFileSync(nextConfigPath)
|
||||||
|
.toString()
|
||||||
|
.replace(/["']@nx\/next["']/, `'./.nx-helpers/compiled.js'`)
|
||||||
|
// TODO(v17): Remove this once users have all migrated to new @nx scope and import from '@nx/next' not the deep import paths.
|
||||||
|
.replace('@nx/next/plugins/with-nx', './.nx-helpers/compiled.js')
|
||||||
|
.replace('@nrwl/next/plugins/with-nx', './.nx-helpers/compiled.js')
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function readSource() {
|
||||||
|
const withNxFile = join(__dirname, '../../../../plugins/with-nx.js');
|
||||||
|
const withNxContent = readFileSync(withNxFile).toString();
|
||||||
|
return {
|
||||||
|
withNxFile,
|
||||||
|
withNxContent,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exported for testing
|
||||||
|
export function getWithNxContent({ withNxFile, withNxContent } = readSource()) {
|
||||||
|
const withNxSource = ts.createSourceFile(
|
||||||
|
withNxFile,
|
||||||
|
withNxContent,
|
||||||
|
ts.ScriptTarget.Latest,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
const getWithNxContextDeclaration = findNodes(
|
||||||
|
withNxSource,
|
||||||
|
ts.SyntaxKind.FunctionDeclaration
|
||||||
|
)?.find(
|
||||||
|
(node: ts.FunctionDeclaration) => node.name?.text === 'getWithNxContext'
|
||||||
|
);
|
||||||
|
if (getWithNxContextDeclaration) {
|
||||||
|
withNxContent = applyChangesToString(withNxContent, [
|
||||||
|
{
|
||||||
|
type: ChangeType.Delete,
|
||||||
|
start: getWithNxContextDeclaration.getStart(withNxSource),
|
||||||
|
length: getWithNxContextDeclaration.getWidth(withNxSource),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: ChangeType.Insert,
|
||||||
|
index: getWithNxContextDeclaration.getStart(withNxSource),
|
||||||
|
text: stripIndents`function getWithNxContext() {
|
||||||
|
return {
|
||||||
|
workspaceRoot: '${workspaceRoot}',
|
||||||
|
libsDir: '${workspaceLayout().libsDir}'
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return withNxContent;
|
||||||
|
}
|
||||||
|
|||||||
@ -30,7 +30,7 @@ const plugins = [
|
|||||||
withNx,
|
withNx,
|
||||||
];
|
];
|
||||||
|
|
||||||
module.exports = composePlugins(...plugins)(nextConfig));
|
module.exports = composePlugins(...plugins)(nextConfig);
|
||||||
<% } else if (style === 'styl') { %>
|
<% } else if (style === 'styl') { %>
|
||||||
const { withStylus } = require('@nx/next/plugins/with-stylus');
|
const { withStylus } = require('@nx/next/plugins/with-stylus');
|
||||||
|
|
||||||
|
|||||||
59
packages/next/src/utils/compose-plugins.spec.ts
Normal file
59
packages/next/src/utils/compose-plugins.spec.ts
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import { NextConfig } from 'next';
|
||||||
|
import { composePlugins } from './compose-plugins';
|
||||||
|
import { NextConfigFn } from './config';
|
||||||
|
|
||||||
|
describe('composePlugins', () => {
|
||||||
|
it('should combine multiple plugins', async () => {
|
||||||
|
const nextConfig: NextConfig = {
|
||||||
|
env: {
|
||||||
|
original: 'original',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const a = (config: NextConfig): NextConfig => {
|
||||||
|
config.env['a'] = 'a';
|
||||||
|
return config;
|
||||||
|
};
|
||||||
|
const b = (config: NextConfig): NextConfig => {
|
||||||
|
config.env['b'] = 'b';
|
||||||
|
return config;
|
||||||
|
};
|
||||||
|
const fn = await composePlugins(a, b);
|
||||||
|
const output = await fn(nextConfig)('test', {});
|
||||||
|
|
||||||
|
expect(output).toEqual({
|
||||||
|
env: {
|
||||||
|
original: 'original',
|
||||||
|
a: 'a',
|
||||||
|
b: 'b',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should compose plugins that return an async function', async () => {
|
||||||
|
const nextConfig: NextConfig = {
|
||||||
|
env: {
|
||||||
|
original: 'original',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const a = (config: NextConfig): NextConfig => {
|
||||||
|
config.env['a'] = 'a';
|
||||||
|
return config;
|
||||||
|
};
|
||||||
|
const b = (config: NextConfig): NextConfigFn => {
|
||||||
|
return (phase: string) => {
|
||||||
|
config.env['b'] = phase;
|
||||||
|
return config;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
const fn = await composePlugins(a, b);
|
||||||
|
const output = await fn(nextConfig)('test', {});
|
||||||
|
|
||||||
|
expect(output).toEqual({
|
||||||
|
env: {
|
||||||
|
original: 'original',
|
||||||
|
a: 'a',
|
||||||
|
b: 'test',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
30
packages/next/src/utils/compose-plugins.ts
Normal file
30
packages/next/src/utils/compose-plugins.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import type { NextConfig } from 'next';
|
||||||
|
import type {
|
||||||
|
NextConfigFn,
|
||||||
|
NextPlugin,
|
||||||
|
NextPluginThatReturnsConfigFn,
|
||||||
|
} from './config';
|
||||||
|
|
||||||
|
export function composePlugins(
|
||||||
|
...plugins: (NextPlugin | NextPluginThatReturnsConfigFn)[]
|
||||||
|
): (baseConfig: NextConfig) => NextConfigFn {
|
||||||
|
return function (baseConfig: NextConfig) {
|
||||||
|
return async function combined(
|
||||||
|
phase: string,
|
||||||
|
context: any
|
||||||
|
): Promise<NextConfig> {
|
||||||
|
let config = baseConfig;
|
||||||
|
for (const plugin of plugins) {
|
||||||
|
const fn = await plugin;
|
||||||
|
const configOrFn = fn(config);
|
||||||
|
if (typeof configOrFn === 'function') {
|
||||||
|
config = await configOrFn(phase, context);
|
||||||
|
} else {
|
||||||
|
config = configOrFn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return config;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -1,7 +1,6 @@
|
|||||||
import type { NextConfig } from 'next';
|
|
||||||
import 'nx/src/utils/testing/mock-fs';
|
import 'nx/src/utils/testing/mock-fs';
|
||||||
import { composePlugins, createWebpackConfig, NextConfigFn } from './config';
|
|
||||||
import { TsconfigPathsPlugin } from 'tsconfig-paths-webpack-plugin';
|
import { TsconfigPathsPlugin } from 'tsconfig-paths-webpack-plugin';
|
||||||
|
import { createWebpackConfig } from './config';
|
||||||
|
|
||||||
jest.mock('@nx/webpack', () => ({}));
|
jest.mock('@nx/webpack', () => ({}));
|
||||||
jest.mock('tsconfig-paths-webpack-plugin');
|
jest.mock('tsconfig-paths-webpack-plugin');
|
||||||
@ -76,60 +75,4 @@ describe('Next.js webpack config builder', () => {
|
|||||||
expect(config.module.rules.length).toBe(2);
|
expect(config.module.rules.length).toBe(2);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('composePlugins', () => {
|
|
||||||
it('should combine multiple plugins', async () => {
|
|
||||||
const nextConfig: NextConfig = {
|
|
||||||
env: {
|
|
||||||
original: 'original',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const a = (config: NextConfig): NextConfig => {
|
|
||||||
config.env['a'] = 'a';
|
|
||||||
return config;
|
|
||||||
};
|
|
||||||
const b = (config: NextConfig): NextConfig => {
|
|
||||||
config.env['b'] = 'b';
|
|
||||||
return config;
|
|
||||||
};
|
|
||||||
const fn = await composePlugins(a, b);
|
|
||||||
const output = await fn(nextConfig)('test', {});
|
|
||||||
|
|
||||||
expect(output).toEqual({
|
|
||||||
env: {
|
|
||||||
original: 'original',
|
|
||||||
a: 'a',
|
|
||||||
b: 'b',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should compose plugins that return an async function', async () => {
|
|
||||||
const nextConfig: NextConfig = {
|
|
||||||
env: {
|
|
||||||
original: 'original',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const a = (config: NextConfig): NextConfig => {
|
|
||||||
config.env['a'] = 'a';
|
|
||||||
return config;
|
|
||||||
};
|
|
||||||
const b = (config: NextConfig): NextConfigFn => {
|
|
||||||
return (phase: string) => {
|
|
||||||
config.env['b'] = phase;
|
|
||||||
return config;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
const fn = await composePlugins(a, b);
|
|
||||||
const output = await fn(nextConfig)('test', {});
|
|
||||||
|
|
||||||
expect(output).toEqual({
|
|
||||||
env: {
|
|
||||||
original: 'original',
|
|
||||||
a: 'a',
|
|
||||||
b: 'test',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@ -8,7 +8,18 @@ import {
|
|||||||
createTmpTsConfig,
|
createTmpTsConfig,
|
||||||
DependentBuildableProjectNode,
|
DependentBuildableProjectNode,
|
||||||
} from '@nx/js/src/utils/buildable-libs-utils';
|
} from '@nx/js/src/utils/buildable-libs-utils';
|
||||||
import { NxWebpackExecutionContext } from '@nx/webpack';
|
|
||||||
|
export interface NextConfigFn {
|
||||||
|
(phase: string, context?: any): Promise<NextConfig> | NextConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NextPlugin {
|
||||||
|
(config: NextConfig): NextConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NextPluginThatReturnsConfigFn {
|
||||||
|
(config: NextConfig): NextConfigFn;
|
||||||
|
}
|
||||||
|
|
||||||
export function createWebpackConfig(
|
export function createWebpackConfig(
|
||||||
workspaceRoot: string,
|
workspaceRoot: string,
|
||||||
@ -96,39 +107,3 @@ function isTsRule(r: RuleSetRule): boolean {
|
|||||||
|
|
||||||
return r.test.test('a.ts');
|
return r.test.test('a.ts');
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NextConfigFn {
|
|
||||||
(phase: string, context?: any): Promise<NextConfig> | NextConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface NextPlugin {
|
|
||||||
(config: NextConfig): NextConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface NextPluginThatReturnsConfigFn {
|
|
||||||
(config: NextConfig): NextConfigFn;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function composePlugins(
|
|
||||||
...plugins: (NextPlugin | NextPluginThatReturnsConfigFn)[]
|
|
||||||
): (baseConfig: NextConfig) => NextConfigFn {
|
|
||||||
return function (baseConfig: NextConfig) {
|
|
||||||
return async function combined(
|
|
||||||
phase: string,
|
|
||||||
context: any
|
|
||||||
): Promise<NextConfig> {
|
|
||||||
let config = baseConfig;
|
|
||||||
for (const plugin of plugins) {
|
|
||||||
const fn = await plugin;
|
|
||||||
const configOrFn = fn(config);
|
|
||||||
if (typeof configOrFn === 'function') {
|
|
||||||
config = await configOrFn(phase, context);
|
|
||||||
} else {
|
|
||||||
config = configOrFn;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return config;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user