-
Notifications
You must be signed in to change notification settings - Fork 77
/
listening.js
160 lines (128 loc) · 3.61 KB
/
listening.js
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// Native
const path = require('path')
const debounce = require('debounce')
// Packages
const { write: copy } = require('clipboardy')
const ip = require('ip')
const chalk = require('chalk')
const boxen = require('boxen')
const { watch } = require('chokidar')
const pkgUp = require('pkg-up')
const copyToClipboard = async text => {
try {
await copy(text)
return true
} catch (err) {
return false
}
}
const restartServer = (file, flags, watcher) => {
const watched = watcher.getWatched()
const toDelete = []
for (const mainPath in watched) {
if (!{}.hasOwnProperty.call(watched, mainPath)) {
continue
}
const subPaths = watched[mainPath]
for (const subPath of subPaths) {
const full = path.join(mainPath, subPath)
toDelete.push(full)
}
}
// Remove file that changed from the `require` cache
for (const item of toDelete) {
let location
try {
location = require.resolve(item)
} catch (err) {
continue
}
delete require.cache[location]
}
// Restart the server
require('./serve')(file, flags, true)
}
const destroySockets = list => {
// Destroy all sockets before closing the server
// Otherwise it will gracefully exit and take a long time
for (const socket of list) {
socket.destroy()
}
}
module.exports = async (server, inUse, flags, sockets) => {
const details = server.address()
const ipAddress = ip.address()
const url = `http://${ipAddress}:${details.port}`
const { isTTY } = process.stdout
const file = flags._[0]
if (!flags.cold) {
let toWatch = flags.watch || false
const watchConfig = {
usePolling: flags.poll,
ignoreInitial: true,
ignored: [
/\.git|node_modules|\.nyc_output|\.sass-cache|coverage|\.cache/,
/\.swp$/
]
}
// Ignore globs
if (flags.ignore) {
watchConfig.ignored = watchConfig.ignored.concat(new RegExp(flags.ignore))
}
if (Array.isArray(toWatch)) {
toWatch.push(file)
} else if (toWatch) {
toWatch = [toWatch, file]
} else {
// Find out which directory to watch
const closestPkg = await pkgUp(path.dirname(file))
toWatch = [closestPkg ? path.dirname(closestPkg) : process.cwd()]
}
// Start watching the project files
const watcher = watch(toWatch, watchConfig)
// Ensure that the server gets restarted if a file changes
watcher.once(
'all',
debounce((event, filePath) => {
const location = path.relative(process.cwd(), filePath)
console.log(
`\n${chalk.blue('File changed:')} ${location} - Restarting server...`
)
destroySockets(sockets)
// Ensure the same port when restarting server
flags.port = details.port
// Restart server
server.close(restartServer.bind(this, file, flags, watcher))
}, 10)
)
}
if (flags.restarted) {
console.log(chalk.green('Restarted!'))
return
}
let message = chalk.green('Micro is running!')
if (inUse) {
message +=
' ' +
chalk.red(
`(on port ${inUse.open}, because ${inUse.old} is already in use)`
)
}
message += '\n\n'
const localURL = `http://localhost:${details.port}`
message += `• ${chalk.bold('Local: ')} ${localURL}\n`
message += `• ${chalk.bold('On Your Network: ')} ${url}\n\n`
if (isTTY) {
const copied = await copyToClipboard(localURL)
if (copied) {
message += `${chalk.grey('Copied local address to clipboard!')}`
}
}
const box = boxen(message, {
padding: 1,
borderColor: 'green',
margin: 1
})
// Print out the message
console.log(box)
}