139 lines
4.7 KiB
TypeScript
139 lines
4.7 KiB
TypeScript
import type { BuilderContext } from '@angular-devkit/architect';
|
|
import type { ServerBuilderOutput } from '@angular-devkit/build-angular';
|
|
import {
|
|
joinPathFragments,
|
|
normalizePath,
|
|
targetToTargetString,
|
|
} from '@nx/devkit';
|
|
import { existsSync } from 'fs';
|
|
import { relative } from 'path';
|
|
import { Observable, from } from 'rxjs';
|
|
import { switchMap } from 'rxjs/operators';
|
|
import { assertBuilderPackageIsInstalled } from '../../executors/utilities/builder-package';
|
|
import { createTmpTsConfigForBuildableLibs } from '../utilities/buildable-libs';
|
|
import { mergeCustomWebpackConfig } from '../utilities/webpack';
|
|
import { Schema } from './schema';
|
|
// This is required to ensure that the webpack version used by the Module Federation is the same as the one used by the builders.
|
|
const Module = require('module');
|
|
|
|
const originalResolveFilename = Module._resolveFilename;
|
|
const patchedWebpackPath = require.resolve('webpack', {
|
|
paths: [require.resolve('@angular-devkit/build-angular')],
|
|
});
|
|
|
|
// Override the resolve function
|
|
Module._resolveFilename = function (request, parent, isMain, options) {
|
|
// Intercept webpack specifically
|
|
if (request === 'webpack') {
|
|
// Force webpack to resolve from your specific path
|
|
return patchedWebpackPath;
|
|
}
|
|
|
|
// For all other modules, use the original resolver
|
|
return originalResolveFilename.call(this, request, parent, isMain, options);
|
|
};
|
|
|
|
function buildServerApp(
|
|
options: Schema,
|
|
context: BuilderContext
|
|
): Observable<ServerBuilderOutput> {
|
|
assertBuilderPackageIsInstalled('@angular-devkit/build-angular');
|
|
|
|
const { buildLibsFromSource, customWebpackConfig, ...delegateOptions } =
|
|
options;
|
|
// If there is a path to custom webpack config
|
|
// Invoke our own support for custom webpack config
|
|
if (customWebpackConfig && customWebpackConfig.path) {
|
|
const pathToWebpackConfig = joinPathFragments(
|
|
context.workspaceRoot,
|
|
customWebpackConfig.path
|
|
);
|
|
|
|
if (existsSync(pathToWebpackConfig)) {
|
|
return buildServerAppWithCustomWebpackConfiguration(
|
|
delegateOptions,
|
|
context,
|
|
pathToWebpackConfig
|
|
);
|
|
} else {
|
|
throw new Error(
|
|
`Custom Webpack Config File Not Found!\nTo use a custom webpack config, please ensure the path to the custom webpack file is correct: \n${pathToWebpackConfig}`
|
|
);
|
|
}
|
|
}
|
|
|
|
return from(import('@angular-devkit/build-angular')).pipe(
|
|
switchMap(({ executeServerBuilder }) =>
|
|
executeServerBuilder(delegateOptions, context)
|
|
)
|
|
);
|
|
}
|
|
|
|
function buildServerAppWithCustomWebpackConfiguration(
|
|
options: Schema,
|
|
context: BuilderContext,
|
|
pathToWebpackConfig: string
|
|
) {
|
|
return from(import('@angular-devkit/build-angular')).pipe(
|
|
switchMap(({ executeServerBuilder }) =>
|
|
executeServerBuilder(options, context as any, {
|
|
webpackConfiguration: async (baseWebpackConfig) => {
|
|
// Angular auto includes code from @angular/platform-server
|
|
// This includes the code outside the shared scope created by ModuleFederation
|
|
// This code will be included in the generated code from our generators,
|
|
// maintaining it within the shared scope.
|
|
// Therefore, if the build is an MF Server build, remove the auto-includes from
|
|
// the base webpack config from Angular
|
|
let mergedConfig = await mergeCustomWebpackConfig(
|
|
baseWebpackConfig,
|
|
pathToWebpackConfig,
|
|
options,
|
|
context.target
|
|
);
|
|
|
|
if (mergedConfig.target === 'async-node') {
|
|
mergedConfig.entry.main = mergedConfig.entry.main.filter(
|
|
(m) => !m.startsWith('@angular/platform-server/init')
|
|
);
|
|
mergedConfig.module.rules = mergedConfig.module.rules.filter((m) =>
|
|
!m.loader
|
|
? true
|
|
: !m.loader.endsWith(
|
|
'@angular-devkit/build-angular/src/builders/server/platform-server-exports-loader.js'
|
|
)
|
|
);
|
|
}
|
|
|
|
return mergedConfig;
|
|
},
|
|
})
|
|
)
|
|
);
|
|
}
|
|
|
|
export function executeWebpackServerBuilder(
|
|
options: Schema,
|
|
context: BuilderContext
|
|
): Observable<ServerBuilderOutput> {
|
|
options.buildLibsFromSource ??= true;
|
|
|
|
process.env.NX_BUILD_LIBS_FROM_SOURCE = `${options.buildLibsFromSource}`;
|
|
process.env.NX_BUILD_TARGET = targetToTargetString({ ...context.target });
|
|
|
|
if (!options.buildLibsFromSource) {
|
|
const { tsConfigPath } = createTmpTsConfigForBuildableLibs(
|
|
options.tsConfig,
|
|
context
|
|
);
|
|
options.tsConfig = normalizePath(
|
|
relative(context.workspaceRoot, tsConfigPath)
|
|
);
|
|
}
|
|
|
|
return buildServerApp(options, context);
|
|
}
|
|
|
|
export default require('@angular-devkit/architect').createBuilder(
|
|
executeWebpackServerBuilder
|
|
) as any;
|