-
Notifications
You must be signed in to change notification settings - Fork 3.3k
/
Copy pathdevServer.ts
150 lines (122 loc) · 4.62 KB
/
devServer.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
/// <reference types="cypress" />
import type WebpackDevServer5 from 'webpack-dev-server'
import type WebpackDevServer4 from 'webpack-dev-server-4'
import type { Compiler, Configuration } from 'webpack'
import { createWebpackDevServer } from './createWebpackDevServer'
import debugLib from 'debug'
import { nextHandler } from './helpers/nextHandler'
import { sourceDefaultWebpackDependencies, SourceRelativeWebpackResult } from './helpers/sourceRelativeWebpackModules'
import { angularHandler } from './helpers/angularHandler'
const debug = debugLib('cypress:webpack-dev-server:devServer')
export type Frameworks = Extract<Cypress.DevServerConfigOptions, { bundler: 'webpack' }>['framework']
type FrameworkConfig = {
framework?: Exclude<Frameworks, 'angular'>
} | {
framework: 'angular'
options?: {
projectConfig: Cypress.AngularDevServerProjectConfig
}
}
export type ConfigHandler =
Partial<Configuration>
| (() => Partial<Configuration> | Promise<Partial<Configuration>>)
export type WebpackDevServerConfig = {
specs: Cypress.Spec[]
cypressConfig: Cypress.PluginConfigOptions
devServerEvents: NodeJS.EventEmitter
onConfigNotFound?: (devServer: 'webpack', cwd: string, lookedIn: string[]) => void
webpackConfig?: ConfigHandler // Derived from the user's webpack config
} & FrameworkConfig
/**
* @internal
*/
type DevServerCreateResult = {
version: 4
server: WebpackDevServer4
compiler: Compiler
} | {
version: 5
server: WebpackDevServer5
compiler: Compiler
}
/**
* import { devServer } from '@cypress/webpack-dev-server'
*
* Creates & returns a WebpackDevServer for serving files related
* to Cypress Component Testing
*
* @param config
*/
export function devServer (devServerConfig: WebpackDevServerConfig): Promise<Cypress.ResolvedDevServerConfig> {
return new Promise(async (resolve, reject) => {
const result = await devServer.create(devServerConfig) as DevServerCreateResult
result.server.start().then(() => {
if (!result.server.options.port) {
return reject(new Error(`Expected port ${result.server.options.port} to be a number`))
}
debug(`Component testing webpack server ${result.version} started on port %s`, result.server.options.port)
resolve({
port: result.server.options.port as number,
// Close is for unit testing only. We kill this child process which will handle the closing of the server
close: async (done) => {
debug('closing dev server')
result.server.stop().then(() => done?.()).catch(done).finally(() => {
debug('closed dev server')
})
},
})
}).catch(reject)
})
}
export type PresetHandlerResult = { frameworkConfig: Configuration, sourceWebpackModulesResult: SourceRelativeWebpackResult }
type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>
const thirdPartyDefinitionPrefixes = {
// matches @org/cypress-ct-*
namespacedPrefixRe: /^@.+?\/cypress-ct-.+/,
globalPrefix: 'cypress-ct-',
}
export function isThirdPartyDefinition (framework: string) {
return framework.startsWith(thirdPartyDefinitionPrefixes.globalPrefix) ||
thirdPartyDefinitionPrefixes.namespacedPrefixRe.test(framework)
}
async function getPreset (devServerConfig: WebpackDevServerConfig): Promise<Optional<PresetHandlerResult, 'frameworkConfig'>> {
const defaultWebpackModules = () => ({ sourceWebpackModulesResult: sourceDefaultWebpackDependencies(devServerConfig) })
// Third party library (eg solid-js, lit, etc)
if (devServerConfig.framework && isThirdPartyDefinition(devServerConfig.framework)) {
return defaultWebpackModules()
}
switch (devServerConfig.framework) {
case 'next':
return await nextHandler(devServerConfig)
case 'angular':
return await angularHandler(devServerConfig)
case 'react':
case 'vue':
case 'svelte':
case undefined:
return defaultWebpackModules()
default:
throw new Error(`Unexpected framework ${(devServerConfig as any).framework}, please visit https://on.cypress.io/frameworks to see a list of supported frameworks`)
}
}
/**
* Synchronously create the webpack server instance, without starting.
* Useful for testing
*
* @internal
*/
devServer.create = async function (devServerConfig: WebpackDevServerConfig) {
const { frameworkConfig, sourceWebpackModulesResult } = await getPreset(devServerConfig)
const { server, compiler } = await createWebpackDevServer({
devServerConfig,
frameworkConfig,
sourceWebpackModulesResult,
})
const result = {
server,
compiler,
version: sourceWebpackModulesResult.webpackDevServer.majorVersion,
}
return result
}
export default devServer