Skip to content

Commit

Permalink
perf: simplify code
Browse files Browse the repository at this point in the history
  • Loading branch information
hemengke1997 committed Oct 26, 2023
1 parent 847db57 commit f46a19b
Show file tree
Hide file tree
Showing 15 changed files with 46 additions and 910 deletions.
4 changes: 0 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,6 @@ jobs:
key: ${{ runner.os }}-playwright-bin-v1
path: ${{ env.PLAYWRIGHT_BROWSERS_PATH }}

- name: Install Playwright
# does not need to explicitly set chromium after https://github.com/microsoft/playwright/issues/14862 is solved
run: pnpm playwright install chromium

- name: Build
run: pnpm run build

Expand Down
13 changes: 5 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
}
},
"scripts": {
"dev": "tsup --watch",
"dev": "simple-git-hooks && tsup --watch",
"build": "tsup",
"build:pages": "pnpm run build && cd playground/spa && pnpm run build",
"test": "run-s test:unit test:serve test:build",
Expand All @@ -42,14 +42,13 @@
"test:build": "cross-env VITE_TEST_BUILD=1 vitest run -c vitest.config.e2e.ts",
"lint": "eslint . --fix",
"preinstall": "npx only-allow pnpm",
"postinstall": "simple-git-hooks",
"up": "pnpm update --i --L",
"taze": "taze -I -r -w",
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0",
"bump": "bumpp package.json -c -p -t --all -x \"pnpm run changelog\""
},
"peerDependencies": {
"vite": "3 || 4"
"vite": ">=4"
},
"dependencies": {
"debug": "^4.3.4",
Expand All @@ -69,7 +68,6 @@
"@types/debug": "^4.1.9",
"@types/fs-extra": "^11.0.2",
"@types/node": "^20.8.6",
"@vitest/coverage-v8": "^0.34.6",
"bumpp": "^9.2.0",
"conventional-changelog-cli": "^4.1.0",
"cross-env": "^7.0.3",
Expand All @@ -79,16 +77,15 @@
"playwright-chromium": "^1.39.0",
"rollup": "^4.1.4",
"simple-git-hooks": "^2.9.0",
"sirv": "^2.0.3",
"taze": "^0.11.4",
"tsup": "^7.2.0",
"typescript": "^5.2.2",
"vite": "^4.4.11",
"vitest": "^0.34.6"
"vitest": "^0.34.5",
"vitest-e2e": "^0.0.8"
},
"engines": {
"pnpm": ">=8.6.2",
"node": ">=18.0.0"
"node": ">=16.0.0"
},
"simple-git-hooks": {
"commit-msg": "pnpm exec commitlint -e"
Expand Down
7 changes: 1 addition & 6 deletions playground/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,5 @@
"version": "1.0.0",
"private": true,
"dependencies": {},
"devDependencies": {
"kill-port": "^1.6.1",
"node-fetch": "^3.3.2",
"sirv": "^2.0.3",
"tree-kill": "^1.2.2"
}
"devDependencies": {}
}
4 changes: 0 additions & 4 deletions playground/shims.d.ts

This file was deleted.

72 changes: 1 addition & 71 deletions playground/ssr/__tests__/serve.ts
Original file line number Diff line number Diff line change
@@ -1,71 +1 @@
// this is automatically detected by playground/vitestSetup.ts and will replace
// the default e2e test serve behavior

import { hmrPorts, isBuild, ports, rootDir } from '~utils'
import kill from 'kill-port'
import path from 'node:path'
import { type ViteDevServer } from 'vite'

export const port = ports['ssr']

export let viteServer: ViteDevServer

export async function serve(): Promise<{ close(): Promise<void> }> {
if (isBuild) {
// build first
const { build } = await import('vite')
// client build
await build({
root: rootDir,
logLevel: 'silent', // exceptions are logged by Vitest
build: {
target: 'esnext',
minify: false,
ssrManifest: true,
outDir: 'dist/client',
},
})
// server build
await build({
root: rootDir,
logLevel: 'silent',
build: {
target: 'esnext',
ssr: 'src/entry-server.tsx',
outDir: 'dist/server',
rollupOptions: {
output: {
entryFileNames: 'entry-server.js',
},
},
},
})
}

await kill(port)

const { createServer } = await import(path.resolve(rootDir, 'server.js'))
const { app, vite } = await createServer(rootDir, isBuild, hmrPorts['ssr'])

viteServer = vite

return new Promise((resolve, reject) => {
try {
const server = app.listen(port, () => {
resolve({
// for test teardown
async close() {
await new Promise((resolve) => {
server.close(resolve)
})
if (vite) {
await vite.close()
}
},
})
})
} catch (e) {
reject(e)
}
})
}
export * from 'vitest-e2e/ssr-serve'
1 change: 0 additions & 1 deletion playground/ssr/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ export async function createServer(root = process.cwd(), isProd = process.env.NO
render = (await vite.ssrLoadModule('/src/entry-server.tsx')).render
} else {
template = indexProd
// @ts-ignore
render = (await import('./dist/server/entry-server.js')).render
}

Expand Down
227 changes: 3 additions & 224 deletions playground/test-utils.ts
Original file line number Diff line number Diff line change
@@ -1,229 +1,8 @@
// test utils used in e2e tests for playgrounds.
// `import { getColor } from '~utils'`
export * from 'vitest-e2e/test-utils'

import { type ExecaChildProcess } from 'execa'
import fs from 'node:fs'
import path from 'node:path'
import { type ConsoleMessage } from 'playwright-chromium'
import { type Manifest, normalizePath } from 'vite'
import { expect } from 'vitest'
import { isBuild, isWindows, page, testDir } from './vitestSetup'

export * from './vitestSetup'

// make sure these ports are unique
export const ports = {
spa: 9524,
ssr: 9525,
ssr: 9604,
}
export const hmrPorts = {
spa: 24680,
ssr: 24681,
}

const timeout = (n: number) => new Promise((r) => setTimeout(r, n))

export function readFile(filename: string): string {
return fs.readFileSync(path.resolve(testDir, filename), 'utf-8')
}

export function editFile(filename: string, replacer: (str: string) => string, runInBuild: boolean = false) {
if (isBuild && !runInBuild) return
filename = path.resolve(testDir, filename)
const content = fs.readFileSync(filename, 'utf-8')
const modified = replacer(content)
fs.writeFileSync(filename, modified)
}

export function addFile(filename: string, content: string): void {
fs.writeFileSync(path.resolve(testDir, filename), content)
}

export function removeFile(filename: string): void {
fs.unlinkSync(path.resolve(testDir, filename))
}

export function listFiles(dir = ''): string[] {
const filesDir = path.join(testDir, dir)
return fs.readdirSync(filesDir)
}

export function listAssets(base = '', assets = 'assets'): string[] {
const assetsDir = path.join(testDir, 'dist', base, assets)
return fs.readdirSync(assetsDir)
}

export function findAssetFile(match: string | RegExp, base = '', assets = 'assets'): string {
const assetsDir = path.join(testDir, 'dist', base, assets)
let files: string[]
try {
files = fs.readdirSync(assetsDir)
} catch (e) {
if (e.code === 'ENOENT') {
return ''
}
throw e
}
const file = files.find((file) => {
return file.match(match)
})
return file ? fs.readFileSync(path.resolve(assetsDir, file), 'utf-8') : ''
}

export function readManifest(base = ''): Manifest {
return JSON.parse(fs.readFileSync(path.join(testDir, 'dist', base, 'manifest.json'), 'utf-8'))
}

/**
* Poll a getter until the value it returns includes the expected value.
*/
export async function untilUpdated(
poll: () => string | Promise<string>,
expected: string,
runInBuild = false,
): Promise<void> {
if (isBuild && !runInBuild) return
const maxTries = process.env.CI ? 200 : 50
for (let tries = 0; tries < maxTries; tries++) {
const actual = (await poll()) ?? ''
if (actual.includes(expected) || tries === maxTries - 1) {
expect(actual).toMatch(expected)
break
} else {
await timeout(50)
}
}
}

/**
* Retry `func` until it does not throw error.
*/
export async function withRetry(func: () => Promise<void>, runInBuild = false): Promise<void> {
if (isBuild && !runInBuild) return
const maxTries = process.env.CI ? 200 : 50
for (let tries = 0; tries < maxTries; tries++) {
try {
await func()
return
} catch {}
await timeout(50)
}
await func()
}

type UntilBrowserLogAfterCallback = (logs: string[]) => PromiseLike<void> | void

export async function untilBrowserLogAfter(
operation: () => any,
target: string | RegExp | (string | RegExp)[],
expectOrder?: boolean,
callback?: UntilBrowserLogAfterCallback,
): Promise<string[]>
export async function untilBrowserLogAfter(
operation: () => any,
target: string | RegExp | (string | RegExp)[],
callback?: UntilBrowserLogAfterCallback,
): Promise<string[]>
export async function untilBrowserLogAfter(
operation: () => any,
target: string | RegExp | (string | RegExp)[],
arg3?: boolean | UntilBrowserLogAfterCallback,
arg4?: UntilBrowserLogAfterCallback,
): Promise<string[]> {
const expectOrder = typeof arg3 === 'boolean' ? arg3 : false
const callback = typeof arg3 === 'boolean' ? arg4 : arg3

const promise = untilBrowserLog(target, expectOrder)
await operation()
const logs = await promise
if (callback) {
await callback(logs)
}
return logs
}

async function untilBrowserLog(target?: string | RegExp | (string | RegExp)[], expectOrder = true): Promise<string[]> {
let resolve: () => void
let reject: (reason: any) => void
const promise = new Promise<void>((_resolve, _reject) => {
resolve = _resolve
reject = _reject
})

const logs = []

try {
const isMatch = (matcher: string | RegExp) => (text: string) =>
typeof matcher === 'string' ? text === matcher : matcher.test(text)

let processMsg: (text: string) => boolean

if (!target) {
processMsg = () => true
} else if (Array.isArray(target)) {
if (expectOrder) {
const remainingTargets = [...target]
processMsg = (text: string) => {
const nextTarget = remainingTargets.shift()
expect(text).toMatch(nextTarget)
return remainingTargets.length === 0
}
} else {
const remainingMatchers = target.map((element) => isMatch(element))
processMsg = (text: string) => {
const nextIndex = remainingMatchers.findIndex((matcher) => matcher(text))
if (nextIndex >= 0) {
remainingMatchers.splice(nextIndex, 1)
}
return remainingMatchers.length === 0
}
}
} else {
processMsg = isMatch(target)
}

const handleMsg = (msg: ConsoleMessage) => {
try {
const text = msg.text()
logs.push(text)
const done = processMsg(text)
if (done) {
resolve()
}
} catch (err) {
reject(err)
}
}

page.on('console', handleMsg)
} catch (err) {
reject(err)
}

await promise

return logs
}

export const formatSourcemapForSnapshot = (map: any): any => {
const root = normalizePath(testDir)
const m = { ...map }
delete m.file
delete m.names
m.sources = m.sources.map((source) => source.replace(root, '/root'))
return m
}

// helper function to kill process, uses taskkill on windows to ensure child process is killed too
export async function killProcess(serverProcess: ExecaChildProcess): Promise<void> {
if (isWindows) {
try {
const { execaCommandSync } = await import('execa')
execaCommandSync(`taskkill /pid ${serverProcess.pid} /T /F`)
} catch (e) {
console.error('failed to taskkill:', e)
}
} else {
serverProcess.kill('SIGTERM', { forceKillAfterTimeout: 2000 })
}
ssr: 24685,
}
Loading

0 comments on commit f46a19b

Please sign in to comment.