/
store.ts
141 lines (121 loc) · 3.58 KB
/
store.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
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}`)
}
if (startTime === 0) startTime = Date.now()
return
}
if (state.loading) {
if (state.trigger) {
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()
})