Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Improve webpack-dev-server performance #15158

Merged
merged 9 commits into from
Feb 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ packages/server/test/support/fixtures/server/libs
# from npm/react
/npm/react/bin/*
/npm/react/cypress/videos
/npm/react/.babel-cache

# from runner-ct
/packages/runner-ct/cypress/screenshots
Expand Down
8 changes: 8 additions & 0 deletions circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1086,13 +1086,21 @@ jobs:
- attach_workspace:
at: ~/
- check-conditional-ci
- restore_cache:
name: Restore yarn cache
key: v{{ .Environment.CACHE_VERSION }}-{{ arch }}-npm-react-babel-cache
- run:
name: Build
command: yarn workspace @cypress/react build
- run:
name: Run tests
command: yarn workspace @cypress/react test
- store-npm-logs
- save_cache:
name: Save Cache
key: v{{ .Environment.CACHE_VERSION }}-{{ arch }}-npm-react-babel-cache
paths:
- cypress/npm/react/.babel-cache
- persist_to_workspace:
root: ~/
paths: cypress/npm/react
Expand Down
6 changes: 1 addition & 5 deletions cli/types/cypress.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5134,11 +5134,7 @@ declare namespace Cypress {

interface DevServerOptions {
specs: Spec[]
config: {
supportFile?: string
projectRoot: string
webpackDevServerPublicPathRoute: string
},
config: ResolvedConfigOptions & RuntimeConfigOptions,
devServerEvents: NodeJS.EventEmitter,
}

Expand Down
6 changes: 4 additions & 2 deletions npm/react/cypress/plugins/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// @ts-check
const { startDevServer } = require('@cypress/webpack-dev-server')
const path = require('path')
const babelConfig = require('../../babel.config.js')

/** @type import("webpack").Configuration */
Expand All @@ -17,7 +19,7 @@ const webpackConfig = {
{
test: /\.(js|jsx|mjs|ts|tsx)$/,
loader: 'babel-loader',
options: babelConfig,
options: { ...babelConfig, cacheDirectory: path.resolve(__dirname, '..', '..', '.babel-cache') },
Copy link
Contributor

@lmiller1990 lmiller1990 Feb 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this? Is this just to speed up CI?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And show users how to optimize theirs.

},
{
test: /\.modules\.css$/i,
Expand Down Expand Up @@ -59,7 +61,7 @@ const webpackConfig = {
* @type Cypress.PluginConfig
*/
module.exports = (on, config) => {
on('dev-server:start', (options) => startDevServer({ options, webpackConfig }))
on('dev-server:start', (options) => startDevServer({ options, webpackConfig, disableLazyCompilation: false }))

return config
}
1 change: 1 addition & 0 deletions npm/webpack-dev-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
},
"dependencies": {
"debug": "4.3.2",
"lazy-compile-webpack-plugin": "0.1.11",
"semver": "^7.3.4",
"webpack-merge": "^5.4.0"
},
Expand Down
17 changes: 4 additions & 13 deletions npm/webpack-dev-server/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,9 @@
import { EventEmitter } from 'events'
import { debug as debugFn } from 'debug'
import { AddressInfo } from 'net'
import { start as createDevServer } from './startServer'
const debug = debugFn('cypress:webpack-dev-server:webpack')
import { UserWebpackDevServerOptions } from './makeWebpackConfig'

export interface DevServerOptions {
specs: Cypress.Cypress['spec'][]
config: {
supportFile: string
projectRoot: string
webpackDevServerPublicPathRoute: string
}
devServerEvents: EventEmitter
}
const debug = debugFn('cypress:webpack-dev-server:webpack')

type DoneCallback = () => unknown

Expand All @@ -21,9 +12,9 @@ export interface ResolvedDevServerConfig {
close: (done?: DoneCallback) => void
}

export interface StartDevServer {
export interface StartDevServer extends UserWebpackDevServerOptions {
/* this is the Cypress options object */
options: DevServerOptions
options: Cypress.DevServerOptions
/* support passing a path to the user's webpack config */
webpackConfig?: Record<string, any>
}
Expand Down
46 changes: 37 additions & 9 deletions npm/webpack-dev-server/src/makeWebpackConfig.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,51 @@
import { debug as debugFn } from 'debug'
import * as path from 'path'
import { Configuration } from 'webpack'
import * as webpack from 'webpack'
import { merge } from 'webpack-merge'
import defaultWebpackConfig from './webpack.config'
import LazyCompilePlugin from 'lazy-compile-webpack-plugin'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the one: https://github.com/liximomo/lazy-compile-webpack-plugin ?

I'm surprised more people are not using this 🤔 seems not well known

import CypressCTOptionsPlugin, { CypressCTOptionsPluginOptions } from './plugin'

const debug = debugFn('cypress:webpack-dev-server:makeWebpackConfig')
const WEBPACK_MAJOR_VERSION = Number(webpack.version.split('.')[0])

export interface UserWebpackDevServerOptions {
/**
* if `true` will compile all the specs together when the first one is request and can slow up initial build time.
* @default false
*/
disableLazyCompilation?: boolean
}

interface MakeWebpackConfigOptions extends CypressCTOptionsPluginOptions, UserWebpackDevServerOptions {
webpackDevServerPublicPathRoute: string
isOpenMode: boolean
}

const mergePublicPath = (baseValue, userValue = '/') => {
return path.join(baseValue, userValue, '/')
}

interface MakeWebpackConfigOptions extends CypressCTOptionsPluginOptions {
webpackDevServerPublicPathRoute: string
function getLazyCompilationWebpackConfig (options: MakeWebpackConfigOptions): webpack.Configuration {
if (options.disableLazyCompilation || !options.isOpenMode) {
return {}
}

switch (WEBPACK_MAJOR_VERSION) {
case 4:
return { plugins: [new LazyCompilePlugin()] }
case 5:
return { experiments: { lazyCompilation: true } } as webpack.Configuration
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right - so webpack 5 has lazy built in, but webpack 4 you need the plugin?

Copy link
Contributor Author

@dmtrKovalenko dmtrKovalenko Feb 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be clear from the code <3

Happy that my code is readable :D

default:
return { }
}
}

export async function makeWebpackConfig (userWebpackConfig: Configuration, options: MakeWebpackConfigOptions): Promise<Configuration> {
export async function makeWebpackConfig (userWebpackConfig: webpack.Configuration, options: MakeWebpackConfigOptions): Promise<webpack.Configuration> {
const { projectRoot, webpackDevServerPublicPathRoute, files, supportFile, devServerEvents } = options

debug(`User passed in webpack config with values %o`, userWebpackConfig)

const defaultWebpackConfig = require('./webpack.config')

debug(`Merging Evergreen's webpack config with users'`)

debug(`New webpack entries %o`, files)
debug(`Project root`, projectRoot)
debug(`Support file`, supportFile)
Expand All @@ -45,7 +68,12 @@ export async function makeWebpackConfig (userWebpackConfig: Configuration, optio
],
}

const mergedConfig = merge<Configuration>(userWebpackConfig, defaultWebpackConfig, dynamicWebpackConfig)
const mergedConfig = merge<webpack.Configuration>(
userWebpackConfig,
defaultWebpackConfig,
dynamicWebpackConfig,
getLazyCompilationWebpackConfig(options),
)

mergedConfig.entry = entry

Expand Down
9 changes: 6 additions & 3 deletions npm/webpack-dev-server/src/startServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,22 @@ import { makeWebpackConfig } from './makeWebpackConfig'

const debug = Debug('cypress:webpack-dev-server:start')

export async function start ({ webpackConfig: userWebpackConfig, options }: StartDevServer): Promise<WebpackDevServer> {
export async function start ({ webpackConfig: userWebpackConfig, options, ...userOptions }: StartDevServer): Promise<WebpackDevServer> {
if (!userWebpackConfig) {
debug('User did not pass in any webpack configuration')
}

const { projectRoot, webpackDevServerPublicPathRoute } = options.config
// @ts-expect-error ?? webpackDevServerPublicPathRoute is not a valid option of Cypress.Config
const { projectRoot, webpackDevServerPublicPathRoute, isTextTerminal } = options.config

const webpackConfig = await makeWebpackConfig(userWebpackConfig || {}, {
files: options.specs,
projectRoot,
webpackDevServerPublicPathRoute,
devServerEvents: options.devServerEvents,
supportFile: options.config.supportFile,
supportFile: options.config.supportFile as string,
isOpenMode: !isTextTerminal,
...userOptions,
})

debug('compiling webpack')
Expand Down
1 change: 1 addition & 0 deletions npm/webpack-dev-server/src/webpack.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

/** @type {import('webpack').Configuration} */
module.exports = {
mode: 'development',
optimization: {
Expand Down
3 changes: 2 additions & 1 deletion npm/webpack-dev-server/test/e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ const specs: Cypress.Cypress['spec'][] = [
const config = {
projectRoot: root,
supportFile: '',
isTextTerminal: true,
webpackDevServerPublicPathRoute: root,
}
} as any as Cypress.ResolvedConfigOptions & Cypress.RuntimeConfigOptions

describe('#startDevServer', () => {
it('serves specs via a webpack dev server', async () => {
Expand Down
10 changes: 9 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -13421,7 +13421,7 @@ detect-node@^2.0.4:
resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c"
integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==

[email protected]:
[email protected], detect-port-alt@^1.1.6:
version "1.1.6"
resolved "https://registry.yarnpkg.com/detect-port-alt/-/detect-port-alt-1.1.6.tgz#24707deabe932d4a3cf621302027c2b266568275"
integrity sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==
Expand Down Expand Up @@ -21463,6 +21463,14 @@ lazy-cache@^1.0.3:
resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e"
integrity sha1-odePw6UEdMuAhF07O24dpJpEbo4=

[email protected]:
version "0.1.11"
resolved "https://registry.yarnpkg.com/lazy-compile-webpack-plugin/-/lazy-compile-webpack-plugin-0.1.11.tgz#be3b9487ccc731a606dc55bcfcd80000c72e4237"
integrity sha512-d2D72x0XqFSj83SRmgx1dvgRvmyIoXpC2lMj+XVS+xzt0FxXDPzF/2FbxOVmW9gzp6d8U29Ne4RGF4x+MTYwow==
dependencies:
detect-port-alt "^1.1.6"
loader-utils "^1.2.3"

lazy-property@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/lazy-property/-/lazy-property-1.0.0.tgz#84ddc4b370679ba8bd4cdcfa4c06b43d57111147"
Expand Down