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

chore: vite-dev-server refactor to enable version bumps and testing vite core perf improvements #20532

Merged
merged 26 commits into from
Mar 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
eca9a83
wip
JessicaSachs Mar 1, 2022
36e4681
wip
JessicaSachs Mar 1, 2022
78d5bed
wip
JessicaSachs Mar 2, 2022
7c715d0
wip
JessicaSachs Mar 2, 2022
2bf55dc
wip
JessicaSachs Mar 4, 2022
99a6887
updated versions
JessicaSachs Mar 4, 2022
6960cc8
updated versions
JessicaSachs Mar 4, 2022
8bc9ad8
updated versions
JessicaSachs Mar 4, 2022
58fe6de
updated versions
JessicaSachs Mar 4, 2022
6c09616
updated versions
JessicaSachs Mar 4, 2022
d743256
Merge remote-tracking branch 'origin/10.0-release' into chore/vite-de…
JessicaSachs Mar 4, 2022
f19186b
cleaning up the vite-dev-server
JessicaSachs Mar 5, 2022
2403855
cleaning up the vite-dev-server. removing virtual modules
JessicaSachs Mar 8, 2022
19045fe
Update package.json
JessicaSachs Mar 8, 2022
5410eb3
Update cypress.config.ts
JessicaSachs Mar 8, 2022
c4b012a
Update package.json
JessicaSachs Mar 8, 2022
eb3d717
Update vite.config.ts
JessicaSachs Mar 8, 2022
ebd044c
Merge remote-tracking branch 'origin/10.0-release' into chore/vite-de…
JessicaSachs Mar 8, 2022
44ef9a7
types
JessicaSachs Mar 8, 2022
d442dd2
deps
JessicaSachs Mar 8, 2022
070c2af
fixing tests
JessicaSachs Mar 9, 2022
cf653b9
Merge remote-tracking branch 'origin/10.0-release' into chore/vite-de…
JessicaSachs Mar 9, 2022
0223ac2
fixing system tests
JessicaSachs Mar 9, 2022
9402ea7
Merge branch '10.0-release' into chore/vite-dev-server
elevatebart Mar 9, 2022
91b47fe
removing deps from package.json
JessicaSachs Mar 9, 2022
69989d1
Merge branch 'chore/vite-dev-server' of github.com:cypress-io/cypress…
JessicaSachs Mar 9, 2022
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
2 changes: 1 addition & 1 deletion npm/design-system/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@
"tsconfig-paths-webpack-plugin": "^3.5.1",
"typed-scss-modules": "^4.1.1",
"typescript": "^4.2.3",
"vite": "2.5.0",
"vite": "2.8.4",
"webpack": "^4.44.2"
},
"peerDependencies": {
Expand Down
30 changes: 22 additions & 8 deletions npm/vite-dev-server/client/initCypressTests.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,32 @@
// This file is merged in a <script type=module> into index.html
// it will be used to load and kick start the selected spec
import specLoaders from 'cypress:spec-loaders'
import { hasSupportPath, originAutUrl } from 'cypress:config'

const specPath = window.location.pathname.replace(originAutUrl, '')
const CypressInstance = window.Cypress = parent.Cypress

const importsToLoad = []

/* Support file import logic, this should be removed once we
* are able to return relative paths from the supportFile
* Jira #UNIFY-1260
*/
const supportFile = CypressInstance.config('supportFile')
const projectRoot = CypressInstance.config('projectRoot')

const specLoader = specLoaders[specPath]
const importsToLoad = [specLoader || (() => import(/* @vite-ignore */ specPath))]
let supportRelativeToProjectRoot = supportFile.replace(projectRoot, '')

if (hasSupportPath) {
importsToLoad.unshift(() => import('cypress:support-path'))
if (CypressInstance.config('platform') === 'win32') {
supportRelativeToProjectRoot = supportFile.replace(projectRoot.replaceAll('/', '\\'))
}

const CypressInstance = window.Cypress = parent.Cypress
if (supportFile) {
// We need a slash before /cypress/supportFile.js, this happens by default
// with the current string replacement logic.
importsToLoad.push(() => import(`${supportRelativeToProjectRoot}`))
}

/* Spec file import logic */
// We need a slash before /src/my-spec.js, this does not happen by default.
importsToLoad.push(() => import(`/${CypressInstance.spec.relative}`))

if (!CypressInstance) {
throw new Error('Tests cannot run without a reference to Cypress!')
Expand Down
12 changes: 8 additions & 4 deletions npm/vite-dev-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,25 @@
"watch": "tsc -w"
},
"dependencies": {
"debug": "^4.3.2",
"get-port": "^5.1.1"
"debug": "4.3.3",
"find-up": "6.3.0",
"get-port": "5.1.1",
"local-pkg": "0.4.1",
"pathe": "0.2.0"
},
"devDependencies": {
"@cypress/react": "0.0.0-development",
"@cypress/vue": "0.0.0-development",
"@testing-library/cypress": "7.0.4",
"@vitejs/plugin-vue": "1.2.4",
"@vitejs/plugin-vue": "2.2.4",
"@vue/compiler-sfc": "3.2.31",
"cypress": "0.0.0-development",
"eslint-plugin-vue": "7.18.0",
"mocha-junit-reporter": "^2.0.0",
"mocha-multi-reporters": "^1.5.1",
"react": "17.0.2",
"vite": "2.5.0",
"vite": "2.8.4",
"vite-plugin-inspect": "0.4.3",
"vue": "3.2.31",
"vue-eslint-parser": "7.11.0"
},
Expand Down
6 changes: 6 additions & 0 deletions npm/vite-dev-server/src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const configFiles = [
'vite.config.ts',
'vite.config.js',
'vite.config.mjs',
'vite.config.cjs',
]
48 changes: 23 additions & 25 deletions npm/vite-dev-server/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,33 @@
import { debug as debugFn } from 'debug'
import { createServer, InlineConfig } from 'vite'
import { resolveServerConfig, StartDevServerOptions } from './resolveServerConfig'
const debug = debugFn('cypress:vite-dev-server:vite')
import debugFn from 'debug'
import getPort from 'get-port'
import { createServer as viteCreateServer } from 'vite'
import { createConfig } from './resolveConfig'
import type { CypressViteDevServerConfig, StartDevServer } from './types'

export { StartDevServerOptions }
const debug = debugFn('cypress:vite-dev-server:index')

export async function startDevServer (startDevServerArgs: StartDevServerOptions): Promise<Cypress.ResolvedDevServerConfig> {
if (!startDevServerArgs.viteConfig) {
debug('User did not pass in any Vite dev server configuration')
startDevServerArgs.viteConfig = {}
}
export const startDevServer = async ({ options, viteConfig = {} }: StartDevServer) => {
debug('Starting Vite Server')
let server

debug('starting vite dev server')
const resolvedConfig = await resolveServerConfig(startDevServerArgs)
const port = resolvedConfig.server!.port!
try {
const config = await createConfig({ options, viteConfig })

const viteDevServer = await createServer(resolvedConfig)
server = await viteCreateServer(config)
} catch (err) {
throw new Error(err as string)
}

await viteDevServer.listen()
debug('Vite server created')
const port = await getPort({ port: 3000 })

debug('Component testing vite server started on port', port)
await server.listen(port)
debug('Successfully launched the vite server on port', port)

return { port, close: viteDevServer.close }
}

export type CypressViteDevServerConfig = Omit<InlineConfig, 'base' | 'root'> & {
/**
* Path to an index.html file that will serve as the template in
* which your components will be rendered.
*/
indexHtmlFile?: string
return {
port,
close: server.close,
}
}

export function devServer (cypressDevServerConfig: Cypress.DevServerConfig, devServerConfig?: CypressViteDevServerConfig) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,102 +1,69 @@
import { resolve, sep } from 'path'
import debugFn from 'debug'
import { readFile } from 'fs/promises'
import Debug from 'debug'
import { ModuleNode, normalizePath, Plugin, ViteDevServer } from 'vite'
import { resolve } from 'pathe'
import type { ModuleNode, Plugin, ViteDevServer } from 'vite'
import { normalizePath } from 'vite'

const debug = Debug('cypress:vite-dev-server:plugin')
const debug = debugFn('cypress:vite-dev-server:plugins:cypress')

const pluginName = 'cypress-transform-html'
const OSSepRE = new RegExp(`\\${sep}`, 'g')

function convertPathToPosix (path: string): string {
return sep === '/'
? path
: path.replace(OSSepRE, '/')
}

const INIT_FILEPATH = resolve(__dirname, '../client/initCypressTests.js')
const INIT_FILEPATH = resolve(__dirname, '../../client/initCypressTests.js')

const HMR_DEPENDENCY_LOOKUP_MAX_ITERATION = 50

interface Spec {
absolute: string
relative: string
}

function getSpecsPathsSet (specs: Spec[]) {
return new Set<string>(
specs.map((spec) => spec.absolute),
)
}

interface Spec{
absolute: string
relative: string
}

export const makeCypressPlugin = (
projectRoot: string,
supportFilePath: string | false,
devServerEvents: NodeJS.EventEmitter,
specs: Spec[],
namespace: string,
indexHtmlFile?: string,
export const Cypress = (
options,
): Plugin => {
let base = '/'

const projectRoot = options.config.projectRoot
const supportFilePath = options.config.supportFile
const devServerEvents = options.devServerEvents
const specs = options.specs
const indexHtmlFile = options.config.devServerConfig?.indexHtmlFile

let specsPathsSet = getSpecsPathsSet(specs)
let loader

devServerEvents.on('dev-server:specs:changed', (specs: Spec[]) => {
specsPathsSet = getSpecsPathsSet(specs)
})

const posixSupportFilePath = supportFilePath ? convertPathToPosix(resolve(projectRoot, supportFilePath)) : undefined
const posixIndexHtml = indexHtmlFile ? convertPathToPosix(resolve(projectRoot, indexHtmlFile)) : undefined

return {
name: pluginName,
name: 'cypress:main',
enforce: 'pre',
configResolved (config) {
base = config.base
},
async transformIndexHtml () {
const indexHtmlPath = indexHtmlFile ? resolve(projectRoot, indexHtmlFile) : resolve(__dirname, '..', 'index.html')
const indexHtmlPath = indexHtmlFile ? resolve(projectRoot, indexHtmlFile) : resolve(__dirname, '..', '..', 'index.html')

debug('resolved the indexHtmlPath as', indexHtmlPath, 'from', indexHtmlFile)
const indexHtmlContent = await readFile(indexHtmlPath, { encoding: 'utf8' })
// find </body> last index
const endOfBody = indexHtmlContent.lastIndexOf('</body>')

// insert the script in the end of the body
return `${indexHtmlContent.substring(0, endOfBody)
}<script src="${base}cypress:client-init-test" type="module"></script>${
}<script>
${loader}
</script>${
indexHtmlContent.substring(endOfBody)
}`
},
resolveId (id) {
if (id === 'cypress:config') {
return id
}

if (id === 'cypress:support-path') {
return posixSupportFilePath
}

if (id === 'cypress:spec-loaders') {
return id
}

if (id === '/cypress:client-init-test') {
return INIT_FILEPATH
}
},
load (id) {
if (id === 'cypress:spec-loaders') {
return `export default {\n${specs.map((s) => {
return `${JSON.stringify(s.relative)}:()=>import(${JSON.stringify(s.absolute)})`
}).join(',\n')}\n}`
}

if (id === 'cypress:config') {
return `
export const hasSupportPath = ${JSON.stringify(!!supportFilePath)}
export const originAutUrl = ${JSON.stringify(`/${namespace}/iframes/${normalizePath(projectRoot)}/`)}`
}
},
configureServer: async (server: ViteDevServer) => {
loader = await readFile(INIT_FILEPATH)

server.middlewares.use(`${base}index.html`, async (req, res) => {
const transformedIndexHtml = await server.transformIndexHtml(base, '')

Expand All @@ -107,7 +74,7 @@ export const originAutUrl = ${JSON.stringify(`/${namespace}/iframes/${normalizeP
debug('handleHotUpdate - file', file)

// If the user provided IndexHtml is changed, do a full-reload
if (file === posixIndexHtml) {
if (normalizePath(file) === resolve(projectRoot, indexHtmlFile)) {
server.ws.send({
type: 'full-reload',
})
Expand Down Expand Up @@ -137,7 +104,7 @@ export const originAutUrl = ${JSON.stringify(`/${namespace}/iframes/${normalizeP
devServerEvents.emit('dev-server:compile:success')

// if we update support we know we have to re-run it all
// no need to ckeck further
// no need to check further
return []
}

Expand Down
3 changes: 3 additions & 0 deletions npm/vite-dev-server/src/plugins/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './inspect'

export * from './cypress'
25 changes: 25 additions & 0 deletions npm/vite-dev-server/src/plugins/inspect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import debugFn from 'debug'
import type { PluginOption } from 'vite'

const debug = debugFn('cypress:vite-dev-server:plugins:inspect')

export const CypressInspect = async (): Promise<(() => PluginOption) | null> => {
if (!process.env.DEBUG) return null

let Inspect

try {
Inspect = (await import('vite-plugin-inspect')).default
debug('inspect was found', Inspect)
} catch (err) {
debug(`Tried to import the inspect plugin 'vite-plugin-inspect'. It's an optional peerDependency so install it if you'd like.`)
debug(err)

return null
}

return {
...Inspect(),
name: 'cypress:inspect',
}
}
55 changes: 55 additions & 0 deletions npm/vite-dev-server/src/resolveConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
* The logic inside of this file is heavily reused from
* Vitest's own config resolution logic.
* You can find it here https://github.com/vitest-dev/vitest/blob/main/packages/vitest/src/node/create.ts
*/
import debugFn from 'debug'
import { importModule } from 'local-pkg'
import { relative, resolve } from 'pathe'
import { mergeConfig } from 'vite'
import { configFiles } from './constants'
import { Cypress, CypressInspect } from './plugins/index'
import type { StartDevServer } from './types'

const debug = debugFn('cypress:vite-dev-server:resolve-config')

export const createConfig = async ({ options, viteConfig: viteOverrides = {} }: StartDevServer) => {
const root = options.config.projectRoot || resolve(process.cwd())
const { default: findUp } = await importModule('find-up')
const configFile = await findUp(configFiles, { cwd: root } as { cwd: string })

// INFO logging, a lot is logged here.
// debug('all dev-server options are', options)

if (configFile) {
debug('resolved config file at', configFile, 'using root', root)
} else if (viteOverrides) {
debug('Couldn\'t find a Vite config file, however we received a custom viteConfig', viteOverrides)
} else {
debug(`
Didn\'t resolve a Vite config AND the user didn\'t pass in a custom viteConfig.
Falling back to Vite\'s defaults.`)
}

const config = {
root,
base: `/${options.config.namespace}/src/`,
configFile,
optimizeDeps: {
entries: [
...options.specs.map((s) => relative(root, s.relative)),
options.config.supportFile ?? resolve(root, options.config.supportFile),
].filter((v) => v != null),
},
plugins: [
Cypress(options),
await CypressInspect(),
],
}

const finalConfig = mergeConfig(config, viteOverrides)

debug('The resolved server config is', JSON.stringify(finalConfig, null, 2))

return finalConfig
}
Loading