-
Notifications
You must be signed in to change notification settings - Fork 2.4k
/
webpack-browser.impl.ts
160 lines (146 loc) · 5.52 KB
/
webpack-browser.impl.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
import {
joinPathFragments,
normalizePath,
ProjectGraph,
readCachedProjectGraph,
targetToTargetString,
} from '@nx/devkit';
import type { DependentBuildableProjectNode } from '@nx/js/src/utils/buildable-libs-utils';
import { WebpackNxBuildCoordinationPlugin } from '@nx/webpack/src/plugins/webpack-nx-build-coordination-plugin';
import { existsSync } from 'fs';
import { isNpmProject } from 'nx/src/project-graph/operators';
import { getDependencyConfigs } from 'nx/src/tasks-runner/utils';
import { relative } from 'path';
import { from, Observable } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import { createTmpTsConfigForBuildableLibs } from '../utilities/buildable-libs';
import {
mergeCustomWebpackConfig,
resolveIndexHtmlTransformer,
} from '../utilities/webpack';
import type { BrowserBuilderSchema } from './schema';
function shouldSkipInitialTargetRun(
projectGraph: ProjectGraph,
project: string,
target: string
): boolean {
const allTargetNames = new Set<string>();
for (const projectName in projectGraph.nodes) {
const project = projectGraph.nodes[projectName];
for (const targetName in project.data.targets ?? {}) {
allTargetNames.add(targetName);
}
}
const projectDependencyConfigs = getDependencyConfigs(
{ project, target },
{},
projectGraph,
Array.from(allTargetNames)
);
// if the task runner already ran the target, skip the initial run
return projectDependencyConfigs.some(
(d) => d.target === target && d.projects === 'dependencies'
);
}
export function executeWebpackBrowserBuilder(
options: BrowserBuilderSchema,
context: import('@angular-devkit/architect').BuilderContext
): Observable<import('@angular-devkit/architect').BuilderOutput> {
options.buildLibsFromSource ??= true;
const {
buildLibsFromSource,
customWebpackConfig,
indexHtmlTransformer,
indexFileTransformer,
...delegateBuilderOptions
} = options;
process.env.NX_BUILD_LIBS_FROM_SOURCE = `${buildLibsFromSource}`;
process.env.NX_BUILD_TARGET = targetToTargetString({ ...context.target });
const pathToWebpackConfig =
customWebpackConfig?.path &&
joinPathFragments(context.workspaceRoot, customWebpackConfig.path);
if (pathToWebpackConfig && !existsSync(pathToWebpackConfig)) {
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}`
);
}
const normalizedIndexHtmlTransformer =
indexHtmlTransformer ?? indexFileTransformer;
const pathToIndexFileTransformer =
normalizedIndexHtmlTransformer &&
joinPathFragments(context.workspaceRoot, normalizedIndexHtmlTransformer);
if (pathToIndexFileTransformer && !existsSync(pathToIndexFileTransformer)) {
throw new Error(
`File containing Index File Transformer function Not Found!\n Please ensure the path to the file containing the function is correct: \n${pathToIndexFileTransformer}`
);
}
let dependencies: DependentBuildableProjectNode[];
let projectGraph: ProjectGraph;
if (!buildLibsFromSource) {
projectGraph = readCachedProjectGraph();
const { tsConfigPath, dependencies: foundDependencies } =
createTmpTsConfigForBuildableLibs(
delegateBuilderOptions.tsConfig,
context,
{ projectGraph }
);
dependencies = foundDependencies;
delegateBuilderOptions.tsConfig = normalizePath(
relative(context.workspaceRoot, tsConfigPath)
);
}
return from(import('@angular-devkit/build-angular')).pipe(
switchMap(({ executeBrowserBuilder }) =>
executeBrowserBuilder(delegateBuilderOptions, context as any, {
webpackConfiguration: (baseWebpackConfig) => {
if (!buildLibsFromSource && delegateBuilderOptions.watch) {
const workspaceDependencies = dependencies
.filter((dep) => !isNpmProject(dep.node))
.map((dep) => dep.node.name);
// default for `nx run-many` is --all projects
// by passing an empty string for --projects, run-many will default to
// run the target for all projects.
// This will occur when workspaceDependencies = []
if (workspaceDependencies.length > 0) {
const skipInitialRun = shouldSkipInitialTargetRun(
projectGraph,
context.target.project,
context.target.target
);
baseWebpackConfig.plugins.push(
// @ts-expect-error - difference between angular and webpack plugin definitions bc of webpack versions
new WebpackNxBuildCoordinationPlugin(
`nx run-many --target=${
context.target.target
} --projects=${workspaceDependencies.join(',')}`,
skipInitialRun
)
);
}
}
if (!pathToWebpackConfig) {
return baseWebpackConfig;
}
return mergeCustomWebpackConfig(
baseWebpackConfig,
pathToWebpackConfig,
delegateBuilderOptions,
context.target
);
},
...(pathToIndexFileTransformer
? {
indexHtml: resolveIndexHtmlTransformer(
pathToIndexFileTransformer,
delegateBuilderOptions.tsConfig,
context.target
),
}
: {}),
})
)
);
}
export default require('@angular-devkit/architect').createBuilder(
executeWebpackBrowserBuilder
) as any;