Skip to content

Commit 16e4759

Browse files
ZachJW34BBB
andauthored
feat: support webpack-dev-server v4 (#17918)
* feat: migrate to new webpack-dev-server public api * fix: extract version check, and disallow minor releases matching `/3\./` with a starts with req. * feat: support webpack-dev-server v4 * fix webpack warning causing overlay and types * pin test dependency * fix tests that were using incorrect wewbpack configuration Co-authored-by: Ollie Relph <ollie@relph.me>
1 parent 175ae3e commit 16e4759

File tree

15 files changed

+576
-252
lines changed

15 files changed

+576
-252
lines changed

npm/angular/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262
"tslib": "^2.2.0",
6363
"tslint": "5.20.1",
6464
"typescript": "4.2.4",
65-
"webpack-dev-server": "3.11.2",
65+
"webpack-dev-server": "4.0.0",
6666
"zone.js": "0.11.4"
6767
},
6868
"peerDependencies": {

npm/webpack-dev-server/package.json

+4-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
"scripts": {
77
"build": "tsc",
88
"build-prod": "tsc",
9-
"test": "tsc && mocha -r @packages/ts/register test/**/*.spec.ts test/*.spec.ts --exit",
9+
"test": "node ./test-wds-3.js",
10+
"test-all": "tsc && mocha -r @packages/ts/register test/**/*.spec.ts test/*.spec.ts --exit",
1011
"watch": "tsc -w"
1112
},
1213
"dependencies": {
@@ -16,15 +17,15 @@
1617
},
1718
"devDependencies": {
1819
"@types/webpack": ">=4",
19-
"@types/webpack-dev-server": "^3.11.1",
20+
"@types/webpack-dev-server": "^4.0.0",
2021
"chai": "^4.2.0",
2122
"html-webpack-plugin": "4.x",
2223
"mocha": "^8.1.3",
2324
"snap-shot-it": "7.9.3",
2425
"speed-measure-webpack-plugin": "1.4.2",
2526
"typescript": "^4.2.3",
2627
"webpack": "^4.44.2",
27-
"webpack-dev-server": "^3.11.0"
28+
"webpack-dev-server": "^4.0.0"
2829
},
2930
"peerDependencies": {
3031
"html-webpack-plugin": ">=4",

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

+26-10
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { debug as debugFn } from 'debug'
22
import { AddressInfo } from 'net'
33
import { Server } from 'http'
44
import { start as createDevServer, StartDevServer } from './startServer'
5+
import { webpackDevServerFacts } from './webpackDevServerFacts'
56

67
const debug = debugFn('cypress:webpack-dev-server:webpack')
78

@@ -17,26 +18,41 @@ export { StartDevServer }
1718
export async function startDevServer (startDevServerArgs: StartDevServer, exitProcess = process.exit) {
1819
const webpackDevServer = await createDevServer(startDevServerArgs, exitProcess)
1920

20-
return new Promise<ResolvedDevServerConfig>((resolve) => {
21-
const httpSvr = webpackDevServer.listen(0, '127.0.0.1', () => {
22-
// webpack-dev-server v3 returns `http.Server`.
23-
// v4 returns a Promise that resolves `http.Server`.
24-
// use Promise.resolve to make sure we get the `http.Server`,
25-
// regardless of webpack-dev-server version.
26-
Promise.resolve(httpSvr).then((server: Server) => {
21+
return new Promise<ResolvedDevServerConfig>(async (resolve, reject) => {
22+
if (webpackDevServerFacts.isV3()) {
23+
const server: Server = webpackDevServer.listen(0, '127.0.0.1', () => {
2724
// FIXME: handle address returning a string
2825
const port = (server.address() as AddressInfo).port
2926

3027
debug('Component testing webpack server started on port', port)
3128

32-
return resolve({
29+
resolve({
3330
port,
3431
close: (done?: DoneCallback) => {
35-
httpSvr.close()
32+
server.close()
3633
done?.()
3734
},
3835
})
3936
})
40-
})
37+
38+
return
39+
}
40+
41+
if (webpackDevServerFacts.isV4()) {
42+
await webpackDevServer.start()
43+
44+
resolve({
45+
// @ts-expect-error @types do not yet support v4
46+
port: webpackDevServer.options.port,
47+
close: (done?: DoneCallback) => {
48+
webpackDevServer.stop()
49+
done?.()
50+
},
51+
})
52+
53+
return
54+
}
55+
56+
reject(webpackDevServerFacts.unsupported())
4157
})
4258
}

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

+17-7
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import Debug from 'debug'
22
import webpack from 'webpack'
33
import WebpackDevServer from 'webpack-dev-server'
4-
import webpackDevServerPkg from 'webpack-dev-server/package.json'
54
import { makeWebpackConfig, UserWebpackDevServerOptions } from './makeWebpackConfig'
5+
import { webpackDevServerFacts } from './webpackDevServerFacts'
66

77
export interface StartDevServer extends UserWebpackDevServerOptions {
88
/* this is the Cypress options object */
@@ -53,25 +53,35 @@ export async function start ({ webpackConfig: userWebpackConfig, template, optio
5353
hot: false,
5454
}
5555

56-
if (webpackDevServerPkg.version.match(/3\./)) {
56+
if (webpackDevServerFacts.isV3()) {
57+
debug('using webpack-dev-server v3')
5758
webpackDevServerConfig = {
5859
...webpackDevServerConfig,
60+
// @ts-expect-error ignore webpack-dev-server v3 type errors
5961
inline: false,
6062
publicPath: devServerPublicPathRoute,
6163
noInfo: false,
6264
}
63-
} else if (webpackDevServerPkg.version.match(/4\./)) {
65+
66+
// @ts-expect-error ignore webpack-dev-server v3 type errors
67+
return new WebpackDevServer(compiler, webpackDevServerConfig)
68+
}
69+
70+
if (webpackDevServerFacts.isV4()) {
71+
debug('using webpack-dev-server v4')
6472
webpackDevServerConfig = {
73+
host: 'localhost',
74+
port: 'auto',
6575
...userWebpackConfig?.devServer,
6676
devMiddleware: {
6777
publicPath: devServerPublicPathRoute,
6878
},
6979
hot: false,
7080
}
71-
} else {
72-
throw Error(`@cypress/webpack-dev-server only supports webpack-dev-server v3 and v4. Found: ${webpackDevServerPkg.version}.`)
81+
82+
// @ts-expect-error Webpack types are clashing between Webpack and WebpackDevServer
83+
return new WebpackDevServer(webpackDevServerConfig, compiler)
7384
}
7485

75-
// @ts-ignore types for webpack v5 are incorrect?
76-
return new WebpackDevServer(compiler, webpackDevServerConfig)
86+
throw webpackDevServerFacts.unsupported()
7787
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import webpackDevServerPkg from 'webpack-dev-server/package.json'
2+
3+
export const webpackDevServerFacts = {
4+
version: webpackDevServerPkg.version,
5+
isV3 (version = webpackDevServerPkg.version) {
6+
return /^3\./.test(version)
7+
},
8+
isV4 (version = webpackDevServerPkg.version) {
9+
return /^4\./.test(version)
10+
},
11+
unsupported () {
12+
return Error(`@cypress/webpack-dev-server only supports webpack-dev-server v3 and v4. Found: ${webpackDevServerFacts.version}.`)
13+
},
14+
}

npm/webpack-dev-server/test-wds-3.js

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
const execa = require('execa')
2+
const pkg = require('./package.json')
3+
const fs = require('fs')
4+
5+
/**
6+
* This file installs WebpackDevServer 3 and runs the tests for the dev-server.
7+
* We read package.json, update the webpack version, then re-run yarn install.
8+
* After it finishes, pass or fail,
9+
* we revert the package.json back to the original state.
10+
*
11+
* The tests for the example projects (inside of examples) run with WebpackDevServer 3.
12+
* This ensures we have some coverage for both versions.
13+
*/
14+
const main = async () => {
15+
const originalPkg = JSON.stringify(pkg, null, 2)
16+
17+
const resetPkg = async () => {
18+
fs.writeFileSync('package.json', originalPkg, 'utf8')
19+
await execa('yarn', ['install'], { stdio: 'inherit' })
20+
}
21+
22+
const checkExit = async ({ exitCode }) => {
23+
if (typeof exitCode !== 'number') {
24+
// eslint-disable-next-line no-console
25+
console.error(`Finished with missing exit code from execa (received ${exitCode})`)
26+
}
27+
28+
await resetPkg()
29+
process.exit(exitCode)
30+
}
31+
32+
pkg.devDependencies['webpack-dev-server'] = '3.11.0'
33+
// eslint-disable-next-line no-console
34+
console.log('[@cypress/webpack-dev-server]: updating package.json...')
35+
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2))
36+
37+
// eslint-disable-next-line no-console
38+
console.log('[@cypress/webpack-dev-server]: install dependencies...')
39+
await execa('yarn', ['install'], { stdio: 'inherit' })
40+
41+
const { exitCode } = await execa('yarn', ['test-all'], { stdio: 'inherit' })
42+
43+
await checkExit({ exitCode })
44+
}
45+
46+
// execute main function if called from command line
47+
if (require.main === module) {
48+
main()
49+
}

npm/webpack-dev-server/test/e2e.spec.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import webpack from 'webpack'
21
import path from 'path'
32
import sinon from 'sinon'
43
import { expect } from 'chai'
54
import { EventEmitter } from 'events'
65
import http from 'http'
76
import fs from 'fs'
7+
import { webpackDevServerFacts } from '../src/webpackDevServerFacts'
88

99
import { startDevServer } from '../'
1010

@@ -34,11 +34,11 @@ const requestSpecFile = (port: number) => {
3434

3535
const root = path.join(__dirname, '..')
3636

37-
const webpackConfig: webpack.Configuration = {
38-
output: {
39-
path: root,
40-
publicPath: root,
41-
},
37+
const webpackConfig = {
38+
devServer: webpackDevServerFacts.isV3()
39+
? { contentBase: root }
40+
: { static: { directory: root } },
41+
4242
}
4343

4444
const specs: Cypress.Cypress['spec'][] = [
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { expect } from 'chai'
2+
import { webpackDevServerFacts } from '../../src/webpackDevServerFacts'
3+
4+
describe('webpackDevServerFacts', () => {
5+
it('should detect v3', () => {
6+
expect(webpackDevServerFacts.isV3('3.0.0')).equals(true)
7+
expect(webpackDevServerFacts.isV3('3.1.4')).equals(true)
8+
expect(webpackDevServerFacts.isV3('4.0.0')).equals(false)
9+
expect(webpackDevServerFacts.isV3('4.3.0')).equals(false)
10+
})
11+
12+
it('should detect v4', () => {
13+
expect(webpackDevServerFacts.isV4('3.0.0')).equals(false)
14+
expect(webpackDevServerFacts.isV4('3.1.4')).equals(false)
15+
expect(webpackDevServerFacts.isV4('3.4.4')).equals(false)
16+
expect(webpackDevServerFacts.isV4('4.0.0')).equals(true)
17+
expect(webpackDevServerFacts.isV4('4.3.0')).equals(true)
18+
})
19+
})

packages/runner-ct/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"@fortawesome/free-regular-svg-icons": "5.15.2",
2424
"@fortawesome/react-fontawesome": "^0.1.14",
2525
"@packages/driver": "0.0.0-development",
26+
"@types/http-proxy": "1.17.4",
2627
"@types/node": "14.14.31",
2728
"@types/sockjs-client": "1.1.0",
2829
"ansi-to-html": "0.6.14",

packages/server-ct/example/webpack.config.js

-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,4 @@ module.exports = {
22
output: {
33
publicPath: '/',
44
},
5-
devServer: {
6-
publicPath: '/',
7-
},
85
}

packages/server-ct/test/fixtures/projects/inline-config-only/cypress/plugins/index.js

-3
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@ module.exports = (on, config) => {
77
output: {
88
publicPath: '/',
99
},
10-
devServer: {
11-
publicPath: '/',
12-
},
1310
},
1411
options,
1512
})

packages/server/test/support/fixtures/projects/component-tests/cypress/plugins/index.js

-3
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@ const webpackConfig = {
55
output: {
66
publicPath: '/',
77
},
8-
devServer: {
9-
publicPath: '/',
10-
},
118
}
129

1310
/**

packages/server/test/support/fixtures/projects/e2e/cypress/plugins/index.js

-3
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,6 @@ const webpackConfig = {
1212
output: {
1313
publicPath: '/',
1414
},
15-
devServer: {
16-
publicPath: '/',
17-
},
1815
}
1916

2017
/**

packages/ui-components/src/file-opener/file-opener.scss

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ $font-sans: "Helvetica Neue", Helvetica, Arial, sans-serif !default;
55

66
.editor-picker {
77
label {
8-
align-items: start;
8+
align-items: flex-start;
99
display: flex;
1010
flex-wrap: wrap;
1111
}

0 commit comments

Comments
 (0)