Fix github checks (#263)

* Update dependencies which pass tests locally

* Break the yarn cache in an attempt to fix checks

* playground: Add wrapping error info for build.ts

* playground: Don't use dev mode in CI tests

* playground: Use tsc for typecheck

* playground: Specify working esbuild version 0.13.15

* playground: Use only promises in build.ts

* playground: Ensure serving in ci e2e

 * Add echo for vercel for build:static
This commit is contained in:
Cole Lawrence 2022-07-25 04:37:34 -04:00 committed by GitHub
parent 00265471ba
commit 11b5d175f4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 2981 additions and 1265 deletions

View file

@ -35,9 +35,11 @@ jobs:
path: |
${{ steps.yarn-cache-dir-path.outputs.dir }}
${{ github.workspace }}/compatibility-tests/*/.yarn/cache
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
key:
${{ runner.os }}-${{ matrix.node-version }}-yarn-${{
hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
${{ runner.os }}-${{ matrix.node-version }}-yarn-
- run: yarn install
- run: yarn test:compatibility:ci

View file

@ -35,9 +35,11 @@ jobs:
path: |
${{ steps.yarn-cache-dir-path.outputs.dir }}
${{ github.workspace }}/compatibility-tests/*/.yarn/cache
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
key:
${{ runner.os }}-${{ matrix.node-version }}-yarn-${{
hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
${{ runner.os }}-${{ matrix.node-version }}-yarn-
- run: yarn install
- run: yarn lint:all --max-warnings 0

View file

@ -1,3 +1,4 @@
/** @type {import('jest').Config} */
module.exports = {
testMatch: [
'<rootDir>/packages/*/src/**/*.test.ts',

View file

@ -32,31 +32,31 @@
]
},
"devDependencies": {
"@babel/core": "^7.15.0",
"@babel/plugin-proposal-class-properties": "^7.14.5",
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.14.5",
"@babel/plugin-proposal-optional-chaining": "^7.14.5",
"@babel/preset-env": "^7.15.0",
"@babel/preset-react": "^7.14.5",
"@babel/preset-typescript": "^7.15.0",
"@microsoft/api-documenter": "^7.13.54",
"@microsoft/api-extractor": "^7.18.11",
"@typescript-eslint/eslint-plugin": "^4.30.0",
"@typescript-eslint/parser": "^4.30.0",
"esbuild": "^0.12.24",
"@babel/core": "^7.18.9",
"@babel/plugin-proposal-class-properties": "^7.18.6",
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6",
"@babel/plugin-proposal-optional-chaining": "^7.18.9",
"@babel/preset-env": "^7.18.9",
"@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.18.6",
"@microsoft/api-documenter": "^7.19.0",
"@microsoft/api-extractor": "^7.28.6",
"@typescript-eslint/eslint-plugin": "^5.30.7",
"@typescript-eslint/parser": "^5.30.7",
"esbuild": "^0.14.49",
"esbuild-jest": "^0.5.0",
"eslint": "^7.32.0",
"eslint-plugin-jsx-a11y": "^6.4.1",
"eslint-plugin-react": "^7.25.1",
"eslint-plugin-tsdoc": "^0.2.14",
"eslint-plugin-unused-imports": "^1.1.4",
"eslint": "^8.20.0",
"eslint-plugin-jsx-a11y": "^6.6.1",
"eslint-plugin-react": "^7.30.1",
"eslint-plugin-tsdoc": "^0.2.16",
"eslint-plugin-unused-imports": "^2.0.0",
"husky": "^6.0.0",
"jest": "^27.1.0",
"jsonc-parser": "^3.0.0",
"lint-staged": "^11.1.2",
"node-gyp": "^8.1.0",
"jsonc-parser": "^3.1.0",
"lint-staged": "^13.0.3",
"node-gyp": "^9.1.0",
"prettier": "^2.3.2",
"typescript": "^4.4.2",
"typescript": "4.6.x",
"zx": "^2.0.0"
},
"packageManager": "yarn@3.2.0",

View file

@ -1,20 +1,19 @@
import {readdirSync, readFileSync, statSync, writeFileSync} from 'fs'
import {writeFile, readFile} from 'fs/promises'
import path from 'path'
import type {BuildOptions} from 'esbuild'
import esbuild from 'esbuild'
import {definedGlobals} from '../../../theatre/devEnv/definedGlobals'
import {readdir, readFile, stat, writeFile} from 'fs/promises'
import {mapValues} from 'lodash-es'
import path from 'path'
import React from 'react'
import {renderToStaticMarkup} from 'react-dom/server'
import {ServerStyleSheet} from 'styled-components'
import {PlaygroundPage} from './home/PlaygroundPage'
import {timer} from './timer'
import {openForOS} from './openForOS'
import {tryMultiplePorts} from './tryMultiplePorts'
import {createProxyServer} from './createProxyServer'
import {definedGlobals} from '../../../theatre/devEnv/definedGlobals'
import {createEsbuildLiveReloadTools} from './createEsbuildLiveReloadTools'
import {createProxyServer} from './createProxyServer'
import {createServerForceClose} from './createServerForceClose'
import {PlaygroundPage} from './home/PlaygroundPage'
import {openForOS} from './openForOS'
import {timer} from './timer'
import {tryMultiplePorts} from './tryMultiplePorts'
const playgroundDir = (folder: string) => path.join(__dirname, '..', folder)
const buildDir = playgroundDir('build')
@ -24,16 +23,20 @@ const personalDir = playgroundDir('src/personal')
const testDir = playgroundDir('src/tests')
export async function start(options: {
/** enable live reload and watching stuff */
dev: boolean
findAvailablePort: boolean
openBrowser: boolean
waitBeforeStartingServer?: Promise<void>
/** defaults to 8080 */
defaultPort?: number
serve?: {
findAvailablePort: boolean
openBrowser: boolean
waitBeforeStartingServer?: Promise<void>
/** defaults to 8080 */
defaultPort?: number
}
}): Promise<{stop(): Promise<void>}> {
const defaultPort = options.defaultPort ?? 8080
const defaultPort = options.serve?.defaultPort ?? 8080
const liveReload = options.dev ? createEsbuildLiveReloadTools() : undefined
const liveReload =
options.serve && options.dev ? createEsbuildLiveReloadTools() : undefined
type PlaygroundExample = {
useHtml?: string
@ -48,62 +51,72 @@ export async function start(options: {
}
// Collect all entry directories per module per group
const groups: Groups = Object.fromEntries(
[sharedDir, personalDir, testDir]
.map((groupDir) => {
try {
return [
path.basename(groupDir),
Object.fromEntries(
readdirSync(groupDir)
.map(
(moduleDirName): [string, PlaygroundExample | undefined] => {
const entryKey = path.basename(moduleDirName)
const entryFilePath = path.join(
groupDir,
moduleDirName,
'index.tsx',
)
if (!tryOrUndefined(() => statSync(entryFilePath).isFile()))
return [entryKey, undefined]
return [
entryKey,
{
// Including your own html file for playground is an experimental feature,
// it's not quite ready for "prime time" and advertising to the masses until
// it properly handles file watching.
// It's good for now, since we can use it for some demos, just make sure that
// you add a comment to the custom index.html file saying that you have to
// restart playground server entirely to see changes.
useHtml: tryOrUndefined(() =>
readFileSync(
path.join(groupDir, moduleDirName, 'index.html'),
'utf-8',
),
),
entryFilePath,
outDir: path.join(
buildDir,
path.basename(groupDir),
moduleDirName,
),
},
]
},
const groups: Groups = await Promise.all(
[sharedDir, personalDir, testDir].map(async (groupDir) =>
readdir(groupDir)
.then(async (groupDirItems) => [
path.basename(groupDir),
await Promise.all(
groupDirItems.map(
async (
moduleDirName,
): Promise<[string, PlaygroundExample | undefined]> => {
const entryKey = path.basename(moduleDirName)
const entryFilePath = path.join(
groupDir,
moduleDirName,
'index.tsx',
)
.filter((entry) => entry[1] !== undefined),
if (
!(await stat(entryFilePath)
.then((s) => s.isFile())
.catch(() => false))
)
return [entryKey, undefined]
return [
entryKey,
{
// Including your own html file for playground is an experimental feature,
// it's not quite ready for "prime time" and advertising to the masses until
// it properly handles file watching.
// It's good for now, since we can use it for some demos, just make sure that
// you add a comment to the custom index.html file saying that you have to
// restart playground server entirely to see changes.
useHtml: await readFile(
path.join(groupDir, moduleDirName, 'index.html'),
'utf-8',
).catch(() => undefined),
entryFilePath,
outDir: path.join(
buildDir,
path.basename(groupDir),
moduleDirName,
),
},
]
},
),
]
} catch (e) {
).then((entries) =>
Object.fromEntries(
entries.filter((entry) => entry[1] !== undefined),
),
),
])
.catch(() =>
// If the group dir doesn't exist, we just set its entry to undefined
return [path.basename(groupDir), undefined]
}
})
// and then filter it out.
.filter((entry) => entry[1] !== undefined),
[path.basename(groupDir), undefined],
),
),
)
.then((entries) =>
Object.fromEntries(
// and then filter it out.
entries.filter((entry) => entry[1] !== undefined),
),
)
.catch(wrapCatch('reading group dirs'))
// Collect all entry files
const entryPoints = Object.values(groups)
@ -174,7 +187,7 @@ export async function start(options: {
{
filter: /index\.tsx?$/,
},
(loadFile) => {
async (loadFile) => {
const indexHtmlPath = loadFile.path.replace(
/index\.tsx?$/,
'index.html',
@ -182,11 +195,11 @@ export async function start(options: {
const relToSrc = path.relative(srcDir, indexHtmlPath)
const isInSrcFolder = !relToSrc.startsWith('..')
if (isInSrcFolder) {
const newHtml = tryOrUndefined(() =>
readFileSync(indexHtmlPath, 'utf-8'),
const newHtml = await readFile(indexHtmlPath, 'utf-8').catch(
() => undefined,
)
if (newHtml) {
writeFileSync(
await writeFile(
path.resolve(buildDir, relToSrc),
newHtml.replace(
/<\/body>/,
@ -196,6 +209,10 @@ export async function start(options: {
'../index.js',
)}"></script></body>`,
),
).catch(
wrapCatch(
`loading index.tsx creates corresponding index.html for ${relToSrc}`,
),
)
}
@ -215,14 +232,19 @@ export async function start(options: {
await esbuild
.build(esbuildConfig)
.finally(() => _initialBuild.stop())
.catch((err) => {
.catch(
// if in dev mode, permit continuing to watch even if there was an error
return options.dev ? Promise.resolve() : Promise.reject(err)
})
options.dev
? () => Promise.resolve()
: wrapCatch(`failed initial esbuild.build`),
)
.then(async (buildResult) => {
esbuildWatchStop = buildResult?.stop
// Read index.html template
const index = await readFile(path.join(__dirname, 'index.html'), 'utf8')
const index = await readFile(
path.join(__dirname, 'index.html'),
'utf8',
).catch(wrapCatch('reading index.html template'))
await Promise.all([
// Write home page
writeFile(
@ -231,7 +253,7 @@ export async function start(options: {
.replace(/<\/head>/, `${homeHtml.head}<\/head>`)
.replace(/<body>/, `<body>${homeHtml.html}`),
'utf-8',
),
).catch(wrapCatch('writing build index.html')),
// Write module pages
...outModules.map((outModule) =>
writeFile(
@ -246,17 +268,24 @@ export async function start(options: {
)}"></script></body>`,
),
'utf-8',
).catch(
wrapCatch(
`writing index.html for ${path.relative(
buildDir,
outModule.outDir,
)}`,
),
),
),
])
})
.catch((err) => {
console.error(err)
console.error('build.ts: esbuild or html files writing error', err)
return process.exit(1)
})
// Only start dev server in dev, otherwise just run build and that's it
if (!options.dev) {
// Only start dev server in serve, otherwise just run build and that's it
if (!options.serve) {
return {
stop() {
esbuildWatchStop?.()
@ -265,7 +294,8 @@ export async function start(options: {
}
}
await options.waitBeforeStartingServer
const {serve} = options
await serve.waitBeforeStartingServer
// We start ESBuild serve with no build config because it doesn't need to build
// anything, we are already using ESBuild watch.
@ -278,14 +308,14 @@ export async function start(options: {
})
const proxyForceExit = createServerForceClose(proxyServer)
const portTries = options.findAvailablePort ? 10 : 1
const portTries = serve.findAvailablePort ? 10 : 1
const portChosen = await tryMultiplePorts(defaultPort, portTries, proxyServer)
const hostedAt = `http://localhost:${portChosen}`
console.log('Playground running at', hostedAt)
if (options.openBrowser) {
if (serve.openBrowser) {
setTimeout(() => {
if (!liveReload?.hasOpenConnections()) openForOS(hostedAt)
}, 1000)
@ -302,10 +332,8 @@ export async function start(options: {
}
}
function tryOrUndefined<T>(fn: () => T): T | undefined {
try {
return fn()
} catch (err) {
return undefined
function wrapCatch(message: string) {
return (err: any) => {
return Promise.reject(`Rejected "${message}":\n ${err.toString()}`)
}
}

View file

@ -1,9 +1,17 @@
// @ts-check
const {timer} = require('./timer')
const dev = process.argv.find((arg) => ['--dev', '-d'].includes(arg)) != null
const serve =
process.argv.find((arg) => ['--serve'].includes(arg)) != null || undefined
const isCI = Boolean(process.env.CI)
/** Currently running server that can be stopped before restarting */
let current
console.log('cli.js', {dev, serve, isCI})
function onUpdatedBuildScript(rebuild) {
delete require.cache[require.resolve('./build.compiled')]
/** @type {import("./build")} */
@ -12,11 +20,13 @@ function onUpdatedBuildScript(rebuild) {
try {
module
.start({
dev,
findAvailablePort: !isCI,
// If not in CI, try to spawn a browser
openBrowser: !isCI && !rebuild,
waitBeforeStartingServer: current?.stop(),
dev: !isCI && dev,
serve: serve && {
findAvailablePort: !isCI,
// If not in CI, try to spawn a browser
openBrowser: !isCI && !rebuild,
waitBeforeStartingServer: current?.stop(),
},
})
.then((running) => {
current = running

View file

@ -68,7 +68,7 @@ const config: PlaywrightTestConfig = {
TODO 👆
*/
webServer: {
command: 'yarn run serve',
command: 'yarn run serve:ci',
port: 8080,
reuseExistingServer: !process.env.CI,
},

View file

@ -8,10 +8,11 @@
"dist/**/*"
],
"scripts": {
"serve": "node devEnv/cli.js --dev",
"serve": "node devEnv/cli.js --serve --dev",
"serve:ci": "node devEnv/cli.js --serve",
"build": "node devEnv/cli.js",
"build:static": "yarn build",
"typecheck": "yarn run build",
"build:static": "echo 'building for vercel' && yarn run build",
"typecheck": "tsc --noEmit",
"test": "playwright test --config=devEnv/playwright.config.ts",
"test:ci": "percy exec -- playwright test --reporter=dot --config=devEnv/playwright.config.ts --project=chromium"
},
@ -28,6 +29,7 @@
"@types/lodash-es": "^4.17.4",
"@types/node": "^15.6.2",
"@types/react": "^17.0.9",
"esbuild": "^0.13.15",
"three": "^0.130.1",
"typescript": "^4.4.2"
}

3957
yarn.lock

File diff suppressed because it is too large Load diff