Skip to content

Commit

Permalink
pull support for JIT from vite since it doesn't have an affect for en…
Browse files Browse the repository at this point in the history
…d users or performance (webpack only) [run ci]

rebase this
  • Loading branch information
AtofStryker committed Nov 19, 2024
1 parent 37ea320 commit 35bf933
Show file tree
Hide file tree
Showing 17 changed files with 45 additions and 80 deletions.
2 changes: 1 addition & 1 deletion cli/types/cypress.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3117,7 +3117,7 @@ declare namespace Cypress {
* Allows for just-in-time compiling of a component test, which will only compile assets related to the component.
* This results in a smaller bundle under test, reducing resource constraints on a given machine. This option is recommended
* for users with large component testing projects and those who are running into webpack 'chunk load error' issues.
* Supported for vite and webpack. For component testing only.
* Supported for webpack-dev-server only. For component testing only.
* @see https://on.cypress.io/experiments#Configuration
*/
experimentalJustInTimeCompile: boolean
Expand Down
7 changes: 6 additions & 1 deletion npm/vite-dev-server/src/plugins/cypress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,12 @@ export const Cypress = (
// eslint-disable-next-line no-restricted-syntax
let loader = fs.readFileSync(INIT_FILEPATH, 'utf8')

devServerEvents.on('dev-server:specs:changed', (specs: Spec[]) => {
devServerEvents.on('dev-server:specs:changed', ({ specs, options }: { specs: Spec[], options?: { neededForJustInTimeCompile: boolean }}) => {
if (options?.neededForJustInTimeCompile) {
// if an option is needed for just in time compile, no-op as this isn't supported in vite
return
}

debug(`dev-server:secs:changed: ${specs.map((spec) => spec.relative)}`)
specsPathsSet = getSpecsPathsSet(specs)
})
Expand Down
4 changes: 1 addition & 3 deletions npm/vite-dev-server/src/resolveConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ export const createViteDevServerConfig = async (config: ViteDevServerConfig, vit
function makeCypressViteConfig (config: ViteDevServerConfig, vite: Vite): InlineConfig | InlineConfig {
const {
cypressConfig: {
experimentalJustInTimeCompile,
port,
projectRoot,
devServerPublicPathRoute,
Expand Down Expand Up @@ -129,8 +128,7 @@ function makeCypressViteConfig (config: ViteDevServerConfig, vite: Vite): Inline
port: vitePort,
host: '127.0.0.1',
// Disable file watching and HMR when executing tests in `run` mode
// if experimentalJustInTimeCompile is configured, we need to watch for file changes as the spec entries are going to be updated per test in run mode
...(isTextTerminal && !experimentalJustInTimeCompile
...(isTextTerminal
? { watch: { ignored: '**/*' }, hmr: false }
: {}),
},
Expand Down
35 changes: 0 additions & 35 deletions npm/vite-dev-server/test/resolveConfig.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,40 +109,5 @@ describe('resolveConfig', function () {
expect(viteConfig.server?.hmr).to.be.undefined
})
})

describe('experimentalJustInTimeCompile', () => {
let viteDevServerConfig: ViteDevServerConfig

beforeEach(async () => {
const projectRoot = await scaffoldSystemTestProject(`vite${version}-inspect`)

viteDevServerConfig = getViteDevServerConfig(projectRoot)
viteDevServerConfig.cypressConfig.experimentalJustInTimeCompile = true
})

describe('open mode', () => {
beforeEach(() => {
viteDevServerConfig.cypressConfig.isTextTerminal = false
})

it('enables hmr and watching', async () => {
const viteConfig = await createViteDevServerConfig(viteDevServerConfig, discoveredVite)

expect(viteConfig.server.watch).to.be.undefined
})
})

describe('run mode', () => {
beforeEach(() => {
viteDevServerConfig.cypressConfig.isTextTerminal = true
})

it('enables hmr and watching', async () => {
const viteConfig = await createViteDevServerConfig(viteDevServerConfig, discoveredVite)

expect(viteConfig.server.watch).to.be.undefined
})
})
})
})
})
2 changes: 1 addition & 1 deletion npm/webpack-dev-server/src/CypressCTWebpackPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ export class CypressCTWebpackPlugin {
*
* See https://github.com/cypress-io/cypress/issues/24398
*/
private onSpecsChange = async (specs: Cypress.Cypress['spec'][]) => {
private onSpecsChange = async ({ specs, options }: { specs: Cypress.Cypress['spec'][], options?: { neededForJustInTimeCompile: boolean}}) => {
if (!this.compilation || _.isEqual(specs, this.files)) {
return
}
Expand Down
7 changes: 5 additions & 2 deletions npm/webpack-dev-server/src/makeWebpackConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,18 @@ export async function makeWebpackConfig (
) {
let userWebpackConfig = config.devServerConfig.webpackConfig
const frameworkWebpackConfig = config.frameworkConfig as Partial<Configuration>

const {
cypressConfig: {
projectRoot,
supportFile,
experimentalJustInTimeCompile,
},
specs: files,
framework,
} = config.devServerConfig

config.devServerConfig.specs = experimentalJustInTimeCompile ? [] : config.devServerConfig.specs

if (!userWebpackConfig && !frameworkWebpackConfig) {
debug('Not user or framework webpack config received. Trying to automatically source it')

Expand Down Expand Up @@ -121,7 +124,7 @@ export async function makeWebpackConfig (
)

debug(`User passed in user and framework webpack config with values %o`, userAndFrameworkWebpackConfig)
debug(`New webpack entries %o`, files)
debug(`New webpack entries %o`, config.devServerConfig.specs)
debug(`Project root`, projectRoot)
debug(`Support file`, supportFile)

Expand Down
4 changes: 3 additions & 1 deletion npm/webpack-dev-server/test/devServer-e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,9 @@ describe('#devServer', () => {
const oldmtime = fs.statSync(cypressConfig.indexHtmlFile).mtimeMs

await once(devServerEvents, 'dev-server:compile:success')
devServerEvents.emit('dev-server:specs:changed', [newSpec])
devServerEvents.emit('dev-server:specs:changed', {
specs: [newSpec],
})

await once(devServerEvents, 'dev-server:compile:success')
const updatedmtime = fs.statSync(cypressConfig.indexHtmlFile).mtimeMs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ type ProjectDirs = typeof fixtureDirs
const EXPERIMENTAL_JIT_DIR: ProjectDirs[number] = 'experimental-JIT'

const PROJECTS: {bundler: 'vite' | 'webpack'}[] = [
// when running for vite, experimentalJustInTimeCompile=true is set but is a no-op for vite since JIT compiling is not supported in vite
{ bundler: 'vite' },
{ bundler: 'webpack' },
]
Expand Down
16 changes: 8 additions & 8 deletions packages/data-context/src/data/ProjectLifecycleManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,14 +239,14 @@ export class ProjectLifecycleManager {
const span = telemetry.startSpan({ name: 'dataContext:ct:startDevServer' })

/**
* We need to start the dev server in the ProjectLifecycleManager when:
* 1. GA component testing is running so we can compile the dev server will all specs matching the specPattern
* 2. experimentalJustInTimeCompile is enabled. In this case, we start a dev server
* with an empty specs list to initially compile the support file and related dependencies in order to hopefully
* leverage the dev server cache for recompiling for when we actually have a spec to add to the dev server entry.
*/
const specsToStartDevServer = finalConfig.experimentalJustInTimeCompile ? [] : this.ctx.project.specs
const devServerOptions = await this.ctx._apis.projectApi.getDevServer().start({ specs: specsToStartDevServer, config: finalConfig })
* We need to start the dev server in the ProjectLifecycleManager when:
* 1. GA component testing is running so we can compile the dev server will all specs matching the specPattern
* 2. experimentalJustInTimeCompile is enabled (for webpack-dev-server). In this case, we start a dev server
* with an empty specs list to initially compile the support file and related dependencies in order to hopefully
* leverage the dev server cache for recompiling for when we actually have a spec to add to the dev server entry.
* The empty specs are handled within the @cypress/webpack-dev-server package as this has no impact on vite.
*/
const devServerOptions = await this.ctx._apis.projectApi.getDevServer().start({ specs: this.ctx.project.specs, config: finalConfig })

// If we received a cypressConfig.port we want to null it out
// because we propagated it into the devServer.port and it is
Expand Down
19 changes: 3 additions & 16 deletions packages/data-context/src/sources/ProjectDataSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -382,22 +382,9 @@ export class ProjectDataSource {
additionalIgnorePattern,
})

try {
const config = await this.ctx.project.getConfig()

// If running the experimentalJustInTimeCompile for CT,
// ignore this watcher since we only handle one spec at a time and do not need to recompile any time the file system changes.
if (config.experimentalJustInTimeCompile && testingType === 'component') {
this.ctx.actions.project.refreshSpecs(specs)

// If no differences are found, we do not need to emit events
return
}
} catch (e) {
// for cy-in-cy tests the config is the second instance of cypress isn't considered initialized yet.
// in this case since we only need it for experimental JIT in open mode, swallow the error
}

// with JIT, since we are unable to deterministically determine the dev-server in use, the test will recompile
// any time the spec directory has contents added/removed. This means a recompile when it is not needed, but this should
// only be applicable in open mode and seldomly experienced.
if (_.isEqual(this.specs, specs)) {
this.ctx.actions.project.refreshSpecs(specs)

Expand Down
6 changes: 4 additions & 2 deletions packages/server/lib/modes/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -826,8 +826,10 @@ async function runSpecs (options: { config: Cfg, browser: Browser, sys: any, hea

// If in run mode, we need to update the dev server with our spec.
// in open mode, this happens in the browser through the web socket, but we do it here in run mode
// to try and have it happen as early as possible to make the test run as fast as possible
await ctx._apis.projectApi.getDevServer().updateSpecs([spec])
// to try and have it happen as early as possible to make the test run as fast as possible.
// NOTE: this is a no-op for @cypress/vite-dev-server and only applies to @cypress/webpack-dev-server
// since just-in-time compile does not apply to vite.
await ctx._apis.projectApi.getDevServer().updateSpecs([spec], { neededForJustInTimeCompile: true })
}
}

Expand Down
4 changes: 2 additions & 2 deletions packages/server/lib/plugins/child/dev-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ const wrap = (ipc, invoke, ids, args) => {
const [options] = args
const devServerEvents = new EE()

ipc.on('dev-server:specs:changed', (specs) => {
devServerEvents.emit('dev-server:specs:changed', specs)
ipc.on('dev-server:specs:changed', (specsAndOptions) => {
devServerEvents.emit('dev-server:specs:changed', specsAndOptions)
})

devServerEvents.on('dev-server:compile:success', ({ specFile } = {}) => {
Expand Down
8 changes: 4 additions & 4 deletions packages/server/lib/plugins/dev-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ const errors = require('../errors')
const baseEmitter = new EE()

plugins.registerHandler((ipc) => {
baseEmitter.on('dev-server:specs:changed', (specs) => {
ipc.send('dev-server:specs:changed', specs)
baseEmitter.on('dev-server:specs:changed', (specsAndOptions) => {
ipc.send('dev-server:specs:changed', specsAndOptions)
})

ipc.on('dev-server:compile:success', ({ specFile } = {}) => {
Expand All @@ -29,8 +29,8 @@ const API = {
return plugins.execute('dev-server:start', { specs, config })
},

updateSpecs (specs) {
baseEmitter.emit('dev-server:specs:changed', specs)
updateSpecs (specs, options) {
baseEmitter.emit('dev-server:specs:changed', { specs, options })
},

close () {
Expand Down
2 changes: 1 addition & 1 deletion packages/server/lib/socket-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ export class SocketBase {
// update the dev server with the spec running
debug(`updating CT dev-server with spec: ${spec.relative}`)
// @ts-expect-error
await devServer.updateSpecs([spec])
await devServer.updateSpecs([spec], { neededForJustInTimeCompile: true })

return socket.emit('dev-server:on-spec-updated')
})
Expand Down
2 changes: 1 addition & 1 deletion system-tests/projects/experimental-JIT/webpack/README.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
yarn cypress:run --project=/Users/bill/Repositories/ct-webpack-test --component
yarn cypress:run --project=./cypress/system-tests/projects/experimental-JIT --component
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module.exports = ({ mode } = { mode: 'production' }) => {
mode,
// so we don't get variable module output when comparing snapshots in system-tests
stats: 'errors-only',
// stats: 'normal', // if debugging JIT
resolve: {
extensions: ['.js', '.ts', '.jsx', '.tsx'],
alias: {
Expand Down
5 changes: 3 additions & 2 deletions system-tests/test/experimental_jit.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const getAllMatches = (source, regex) => {
describe('component testing: experimentalJustInTimeCompile', function () {
systemTests.setup()

// makes sure experimentalJustInTimeCompile=true has no affect on how vite compiles files.
systemTests.it('vite@5', {
project: 'experimental-JIT/vite',
testingType: 'component',
Expand All @@ -41,8 +42,8 @@ describe('component testing: experimentalJustInTimeCompile', function () {

// expect 1 server to be created
expect(totalServersSamePort).to.equal(1)
// expect each component compiled individually
expect(totalComponentsCompiledSeparately).to.equal(3)
// expect each component to be compiled all together (no JIT support for vite)
expect(totalComponentsCompiledSeparately).to.equal(0)
},
})

Expand Down

0 comments on commit 35bf933

Please sign in to comment.