Skip to content

Commit a07a2a1

Browse files
fix(webpack-dev-server): add custom project config to handler
1 parent 9ba3ed3 commit a07a2a1

File tree

12 files changed

+7096
-714
lines changed

12 files changed

+7096
-714
lines changed

cli/types/cypress.d.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3047,16 +3047,29 @@ declare namespace Cypress {
30473047

30483048
type PickConfigOpt<T> = T extends keyof DefineDevServerConfig ? DefineDevServerConfig[T] : any
30493049

3050+
type ProjectConfig = {
3051+
root: string,
3052+
sourceRoot: string,
3053+
buildOptions: Record<string, any>
3054+
}
3055+
30503056
type DevServerFn<ComponentDevServerOpts = any> = (cypressDevServerConfig: DevServerConfig, devServerConfig: ComponentDevServerOpts) => ResolvedDevServerConfig | Promise<ResolvedDevServerConfig>
30513057

30523058
type DevServerConfigOptions = {
30533059
bundler: 'webpack'
3054-
framework: 'react' | 'vue' | 'vue-cli' | 'nuxt' | 'create-react-app' | 'next' | 'angular'
3060+
framework: 'react' | 'vue' | 'vue-cli' | 'nuxt' | 'create-react-app' | 'next'
30553061
webpackConfig?: PickConfigOpt<'webpackConfig'>
30563062
} | {
30573063
bundler: 'vite'
30583064
framework: 'react' | 'vue'
30593065
viteConfig?: Omit<Exclude<PickConfigOpt<'viteConfig'>, undefined>, 'base' | 'root'>
3066+
} | {
3067+
bundler: 'webpack',
3068+
framework: 'angular',
3069+
webpackConfig?: PickConfigOpt<'webpackConfig'>,
3070+
options?: {
3071+
projectConfig: ProjectConfig
3072+
}
30603073
}
30613074

30623075
interface ComponentConfigOptions<ComponentDevServerOpts = any> extends Omit<CoreConfigOptions, 'baseUrl' | 'experimentalSessionAndOrigin'> {

npm/webpack-dev-server/src/devServer.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ export type WebpackDevServerConfig = {
2424
} & {
2525
framework?: typeof ALL_FRAMEWORKS[number] // Add frameworks here as we implement
2626
webpackConfig?: unknown // Derived from the user's webpack
27+
options?: {
28+
projectConfig?: Cypress.ProjectConfig
29+
}
2730
}
2831

2932
export const ALL_FRAMEWORKS = ['create-react-app', 'nuxt', 'react', 'vue-cli', 'next', 'vue', 'angular'] as const

npm/webpack-dev-server/src/helpers/angularHandler.ts

Lines changed: 64 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,22 @@ import { pathToFileURL } from 'url'
55
import type { PresetHandlerResult, WebpackDevServerConfig } from '../devServer'
66
import { sourceDefaultWebpackDependencies } from './sourceRelativeWebpackModules'
77

8+
type BuildOptions = Record<string, any>
9+
10+
type Configurations = {
11+
configurations?: {
12+
[configuration: string]: BuildOptions
13+
}
14+
}
15+
16+
export type MyType = Extract<Cypress.DevServerConfigOptions, { framework: 'angular'}>
17+
818
export type AngularJsonProjectConfig = {
919
projectType: string
1020
root: string
1121
sourceRoot: string
1222
architect: {
13-
build: {
14-
options: { [key: string]: any } & { polyfills?: string }
15-
configurations?: {
16-
[configuration: string]: {
17-
[key: string]: any
18-
}
19-
}
20-
}
23+
build: { options: BuildOptions } & Configurations
2124
}
2225
}
2326

@@ -30,21 +33,7 @@ type AngularJson = {
3033

3134
const dynamicImport = new Function('specifier', 'return import(specifier)')
3235

33-
export async function angularHandler (devServerConfig: WebpackDevServerConfig): Promise<PresetHandlerResult> {
34-
const webpackConfig = await getAngularCliWebpackConfig(devServerConfig)
35-
36-
return { frameworkConfig: webpackConfig, sourceWebpackModulesResult: sourceDefaultWebpackDependencies(devServerConfig) }
37-
}
38-
39-
async function getAngularCliWebpackConfig (devServerConfig: WebpackDevServerConfig) {
40-
const { projectRoot } = devServerConfig.cypressConfig
41-
42-
const {
43-
generateBrowserWebpackConfigFromContext,
44-
getCommonConfig,
45-
getStylesConfig,
46-
} = await getAngularCliModules(projectRoot)
47-
36+
async function getProjectConfig (projectRoot: string): Promise<Cypress.ProjectConfig> {
4837
const angularJson = await getAngularJson(projectRoot)
4938

5039
let { defaultProject } = angularJson
@@ -59,24 +48,20 @@ async function getAngularCliWebpackConfig (devServerConfig: WebpackDevServerConf
5948

6049
const defaultProjectConfig = angularJson.projects[defaultProject]
6150

62-
const tsConfig = await generateTsConfig(devServerConfig, defaultProjectConfig)
63-
64-
const buildOptions = getAngularBuildOptions(defaultProjectConfig, tsConfig)
65-
66-
const context = createFakeContext(projectRoot, defaultProject, defaultProjectConfig)
67-
68-
const { config } = await generateBrowserWebpackConfigFromContext(
69-
buildOptions,
70-
context,
71-
(wco: any) => [getCommonConfig(wco), getStylesConfig(wco)],
72-
)
73-
74-
delete config.entry.main
51+
const { architect, root, sourceRoot } = defaultProjectConfig
52+
const { build } = architect
7553

76-
return config
54+
return {
55+
root,
56+
sourceRoot,
57+
buildOptions: {
58+
...build.options,
59+
...build.configurations?.development || {},
60+
},
61+
}
7762
}
7863

79-
export function getAngularBuildOptions (projectConfig: AngularJsonProjectConfig, tsConfig: string) {
64+
export function getAngularBuildOptions (buildOptions: BuildOptions, tsConfig: string) {
8065
// Default options are derived from the @angular-devkit/build-angular browser builder, with some options from
8166
// the serve builder thrown in for development.
8267
// see: https://github.com/angular/angular-cli/blob/main/packages/angular_devkit/build_angular/src/builders/browser/schema.json
@@ -115,16 +100,15 @@ export function getAngularBuildOptions (projectConfig: AngularJsonProjectConfig,
115100
extractLicenses: false,
116101
sourceMap: true,
117102
namedChunks: true,
118-
...projectConfig.architect.build.options,
119-
...projectConfig.architect.build.configurations?.development || {},
103+
...buildOptions,
120104
tsConfig,
121105
aot: false,
122106
outputHashing: 'none',
123107
budgets: undefined,
124108
}
125109
}
126110

127-
export async function generateTsConfig (devServerConfig: WebpackDevServerConfig, projectConfig: AngularJsonProjectConfig): Promise<string> {
111+
export async function generateTsConfig (devServerConfig: WebpackDevServerConfig, buildOptions: BuildOptions): Promise<string> {
128112
const { cypressConfig } = devServerConfig
129113
const { projectRoot } = cypressConfig
130114

@@ -138,8 +122,8 @@ export async function generateTsConfig (devServerConfig: WebpackDevServerConfig,
138122
includePaths.push(toPosix(cypressConfig.supportFile))
139123
}
140124

141-
if (projectConfig.architect.build.options.polyfills) {
142-
const polyfills = getProjectFilePath(projectConfig.architect.build.options.polyfills)
125+
if (buildOptions?.polyfills) {
126+
const polyfills = getProjectFilePath(buildOptions?.polyfills)
143127

144128
includePaths.push(polyfills)
145129
}
@@ -215,14 +199,14 @@ export async function getAngularJson (projectRoot: string): Promise<AngularJson>
215199
return JSON.parse(angularJson)
216200
}
217201

218-
function createFakeContext (projectRoot: string, defaultProject: string, defaultProjectConfig: any) {
202+
function createFakeContext (projectRoot: string, defaultProjectConfig: Cypress.ProjectConfig) {
219203
const logger = {
220204
createChild: () => ({}),
221205
}
222206

223207
const context = {
224208
target: {
225-
project: defaultProject,
209+
project: 'angular',
226210
},
227211
workspaceRoot: projectRoot,
228212
getProjectMetadata: () => {
@@ -239,3 +223,38 @@ function createFakeContext (projectRoot: string, defaultProject: string, default
239223
}
240224

241225
export const toPosix = (filePath: string) => filePath.split(path.sep).join(path.posix.sep)
226+
227+
async function getAngularCliWebpackConfig (devServerConfig: WebpackDevServerConfig) {
228+
const { projectRoot } = devServerConfig.cypressConfig
229+
230+
const {
231+
generateBrowserWebpackConfigFromContext,
232+
getCommonConfig,
233+
getStylesConfig,
234+
} = await getAngularCliModules(projectRoot)
235+
236+
// normalize
237+
const projectConfig = devServerConfig.options?.projectConfig || await getProjectConfig(projectRoot)
238+
239+
const tsConfig = await generateTsConfig(devServerConfig, projectConfig.buildOptions)
240+
241+
const buildOptions = getAngularBuildOptions(projectConfig.buildOptions, tsConfig)
242+
243+
const context = createFakeContext(projectRoot, projectConfig)
244+
245+
const { config } = await generateBrowserWebpackConfigFromContext(
246+
buildOptions,
247+
context,
248+
(wco: any) => [getCommonConfig(wco), getStylesConfig(wco)],
249+
)
250+
251+
delete config.entry.main
252+
253+
return config
254+
}
255+
256+
export async function angularHandler (devServerConfig: WebpackDevServerConfig): Promise<PresetHandlerResult> {
257+
const webpackConfig = await getAngularCliWebpackConfig(devServerConfig)
258+
259+
return { frameworkConfig: webpackConfig, sourceWebpackModulesResult: sourceDefaultWebpackDependencies(devServerConfig) }
260+
}

0 commit comments

Comments
 (0)