rsnext/packages/next/build/output/store.ts
Tim Neutkens fccaa8e27f
Fix initial compile timing incorrect measurment (#31733)
Co-authored-by: Tobias Koppers <1365881+sokra@users.noreply.github.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2021-11-23 18:47:36 +01:00

144 lines
3.6 KiB
TypeScript

import createStore from 'next/dist/compiled/unistore'
import stripAnsi from 'next/dist/compiled/strip-ansi'
import { flushAllTraces } from '../../trace'
import { getUnresolvedModuleFromError } from '../utils'
import * as Log from './log'
export type OutputState =
| { bootstrap: true; appUrl: string | null; bindAddr: string | null }
| ({ bootstrap: false; appUrl: string | null; bindAddr: string | null } & (
| {
loading: true
trigger: string | undefined
}
| {
loading: false
typeChecking: boolean
partial: 'client and server' | undefined
modules: number
errors: string[] | null
warnings: string[] | null
hasServerWeb: boolean
}
))
export const store = createStore<OutputState>({
appUrl: null,
bindAddr: null,
bootstrap: true,
})
let lastStore: OutputState = { appUrl: null, bindAddr: null, bootstrap: true }
function hasStoreChanged(nextStore: OutputState) {
if (
(
[
...new Set([...Object.keys(lastStore), ...Object.keys(nextStore)]),
] as Array<keyof OutputState>
).every((key) => Object.is(lastStore[key], nextStore[key]))
) {
return false
}
lastStore = nextStore
return true
}
let startTime = 0
store.subscribe((state) => {
if (!hasStoreChanged(state)) {
return
}
if (state.bootstrap) {
if (state.appUrl) {
Log.ready(`started server on ${state.bindAddr}, url: ${state.appUrl}`)
}
return
}
if (state.loading) {
if (state.trigger) {
if (state.trigger !== 'initial') {
Log.wait(`compiling ${state.trigger}...`)
}
} else {
Log.wait('compiling...')
}
if (startTime === 0) {
startTime = Date.now()
}
return
}
if (state.errors) {
Log.error(state.errors[0])
const cleanError = stripAnsi(state.errors[0])
if (cleanError.indexOf('SyntaxError') > -1) {
const matches = cleanError.match(/\[.*\]=/)
if (matches) {
for (const match of matches) {
const prop = (match.split(']').shift() || '').substr(1)
console.log(
`AMP bind syntax [${prop}]='' is not supported in JSX, use 'data-amp-bind-${prop}' instead. https://nextjs.org/docs/messages/amp-bind-jsx-alt`
)
}
return
}
}
const moduleName = getUnresolvedModuleFromError(cleanError)
if (state.hasServerWeb && moduleName) {
console.error(
`Native Node.js APIs are not supported in the Edge Runtime with \`concurrentFeatures\` enabled. Found \`${moduleName}\` imported.\n`
)
return
}
// Ensure traces are flushed after each compile in development mode
flushAllTraces()
return
}
let timeMessage = ''
if (startTime) {
const time = Date.now() - startTime
startTime = 0
timeMessage =
time > 2000 ? ` in ${Math.round(time / 100) / 10}s` : ` in ${time} ms`
}
let modulesMessage = ''
if (state.modules) {
modulesMessage = ` (${state.modules} modules)`
}
let partialMessage = ''
if (state.partial) {
partialMessage = ` ${state.partial}`
}
if (state.warnings) {
Log.warn(state.warnings.join('\n\n'))
// Ensure traces are flushed after each compile in development mode
flushAllTraces()
return
}
if (state.typeChecking) {
Log.info(
`bundled${partialMessage} successfully${timeMessage}${modulesMessage}, waiting for typecheck results...`
)
return
}
Log.event(
`compiled${partialMessage} successfully${timeMessage}${modulesMessage}`
)
// Ensure traces are flushed after each compile in development mode
flushAllTraces()
})