Skip to content
This repository was archived by the owner on Jul 6, 2025. It is now read-only.

Commit 789493a

Browse files
author
Wenjie Xia
committed
refactor: simplify server mod export
1 parent 393cb5c commit 789493a

File tree

5 files changed

+199
-200
lines changed

5 files changed

+199
-200
lines changed

cli/build.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Appliaction } from '../server/app.ts'
1+
import { Appliaction } from '../server/mod.ts'
22

33
export const helpMessage = `
44
Usage:
@@ -14,11 +14,7 @@ Options:
1414
`
1515

1616
export default async function (workingDir: string, options: Record<string, string | boolean>) {
17-
const app = new Appliaction({
18-
workingDir,
19-
mode: 'production',
20-
reload: Boolean(options.r || options.reload)
21-
})
17+
const app = new Appliaction(workingDir, 'production', Boolean(options.r || options.reload))
2218
await app.build()
2319
Deno.exit(0)
2420
}

cli/dev.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
import { Appliaction } from '../server/app.ts'
2-
import { serve } from '../server/mod.ts'
3-
import { parsePortNumber } from '../server/util.ts'
1+
import { Appliaction, parsePortNumber, serve } from '../server/mod.ts'
42

53
export const helpMessage = `
64
Usage:
@@ -18,10 +16,6 @@ Options:
1816

1917
export default async function (workingDir: string, options: Record<string, string | boolean>) {
2018
const port = parsePortNumber(String(options.p || options.port || '8080'))
21-
const app = new Appliaction({
22-
workingDir,
23-
mode: 'development',
24-
reload: Boolean(options.r || options.reload)
25-
})
19+
const app = new Appliaction(workingDir, 'development', Boolean(options.r || options.reload))
2620
serve('localhost', port, app)
2721
}

cli/start.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
import { Appliaction } from '../server/app.ts'
2-
import { serve } from '../server/mod.ts'
3-
import { parsePortNumber } from '../server/util.ts'
1+
import { Appliaction, parsePortNumber, serve } from '../server/mod.ts'
42

53
export const helpMessage = `
64
Usage:
@@ -20,10 +18,6 @@ Options:
2018
export default async function (workingDir: string, options: Record<string, string | boolean>) {
2119
const host = String(options.hn || options.hostname || 'localhost')
2220
const port = parsePortNumber(String(options.p || options.port || '8080'))
23-
const app = new Appliaction({
24-
workingDir,
25-
mode: 'production',
26-
reload: Boolean(options.r || options.reload)
27-
})
21+
const app = new Appliaction(workingDir, 'production', Boolean(options.r || options.reload))
2822
serve(host, port, app)
2923
}

server/mod.ts

Lines changed: 2 additions & 178 deletions
Original file line numberDiff line numberDiff line change
@@ -1,179 +1,3 @@
1-
import { path, serve as stdServe, ws } from '../deps.ts'
2-
import { hashShort, reHashJs, reModuleExt } from '../shared/constants.ts'
3-
import { existsFileSync } from '../shared/fs.ts'
4-
import log from '../shared/log.ts'
5-
import util from '../shared/util.ts'
6-
import type { ServerRequest } from '../types.ts'
7-
import { Request } from './api.ts'
8-
import { Appliaction } from './app.ts'
9-
import { getContentType } from './mime.ts'
10-
import { createHtml } from './util.ts'
1+
export * from './app.ts'
2+
export * from './server.ts'
113

12-
export class Server {
13-
#app: Appliaction
14-
#ready: boolean
15-
16-
constructor(app: Appliaction) {
17-
this.#app = app
18-
this.#ready = false
19-
}
20-
21-
async handle(r: ServerRequest) {
22-
if (!this.#ready) {
23-
await this.#app.ready
24-
this.#ready = true
25-
}
26-
27-
const app = this.#app
28-
const url = new URL('http://localhost' + r.url)
29-
const pathname = util.cleanPath(decodeURI(url.pathname))
30-
const req = new Request(r, pathname, {}, url.searchParams)
31-
32-
try {
33-
// serve hmr ws
34-
if (pathname === '/_hmr') {
35-
const { conn, r: bufReader, w: bufWriter, headers } = r
36-
ws.acceptWebSocket({ conn, bufReader, bufWriter, headers }).then(async socket => {
37-
const watcher = app.createFSWatcher()
38-
watcher.on('add', (url: string, hash: string) => socket.send(JSON.stringify({
39-
type: 'add',
40-
url,
41-
hash
42-
})))
43-
watcher.on('remove', (url: string) => {
44-
watcher.removeAllListeners('modify-' + url)
45-
socket.send(JSON.stringify({
46-
type: 'remove',
47-
url
48-
}))
49-
})
50-
for await (const e of socket) {
51-
if (util.isNEString(e)) {
52-
try {
53-
const data = JSON.parse(e)
54-
if (data.type === 'hotAccept' && util.isNEString(data.url)) {
55-
const mod = app.getModule(data.url)
56-
if (mod) {
57-
watcher.on('modify-' + mod.url, (hash: string) => socket.send(JSON.stringify({
58-
type: 'update',
59-
url: mod.url,
60-
updateUrl: util.cleanPath(`${app.config.baseUrl}/_aleph/${mod.url.replace(reModuleExt, '')}.${hash!.slice(0, hashShort)}.js`),
61-
hash,
62-
})))
63-
}
64-
}
65-
} catch (e) { }
66-
} else if (ws.isWebSocketCloseEvent(e)) {
67-
break
68-
}
69-
}
70-
app.removeFSWatcher(watcher)
71-
})
72-
return
73-
}
74-
75-
// serve public files
76-
const filePath = path.join(app.workingDir, 'public', pathname)
77-
if (existsFileSync(filePath)) {
78-
const info = Deno.lstatSync(filePath)
79-
const lastModified = info.mtime?.toUTCString() ?? new Date().toUTCString()
80-
if (lastModified === r.headers.get('If-Modified-Since')) {
81-
req.status(304).send('')
82-
return
83-
}
84-
85-
const body = Deno.readFileSync(filePath)
86-
req.setHeader('Last-Modified', lastModified)
87-
req.send(body, getContentType(filePath))
88-
return
89-
}
90-
91-
// serve APIs
92-
if (pathname.startsWith('/api/')) {
93-
app.callAPI(r, { pathname, search: url.search })
94-
return
95-
}
96-
97-
// serve dist files
98-
if (pathname.startsWith('/_aleph/')) {
99-
if (pathname.startsWith('/_aleph/data/') && pathname.endsWith('.json')) {
100-
let p = util.trimSuffix(util.trimPrefix(pathname, '/_aleph/data'), '.json')
101-
if (p === '/index') {
102-
p = '/'
103-
}
104-
const [status, data] = await app.getSSRData({ pathname: p })
105-
if (status === 200) {
106-
req.send(JSON.stringify(data), 'application/json; charset=utf-8')
107-
} else {
108-
req.status(status).send('')
109-
}
110-
return
111-
} else {
112-
const reqMap = pathname.endsWith('.js.map')
113-
const fixedPath = util.trimPrefix(reqMap ? pathname.slice(0, -4) : pathname, '/_aleph/')
114-
const metaFile = path.join(app.buildDir, util.trimSuffix(fixedPath.replace(reHashJs, ''), '.js') + '.meta.json')
115-
if (existsFileSync(metaFile)) {
116-
const { url } = JSON.parse(await Deno.readTextFile(metaFile))
117-
const mod = app.getModule(url)
118-
if (mod) {
119-
const etag = req.headers.get('If-None-Match')
120-
if (etag && etag === mod.hash) {
121-
req.status(304).send('')
122-
return
123-
}
124-
let body = ''
125-
if (reqMap) {
126-
if (existsFileSync(mod.jsFile + '.map')) {
127-
body = await Deno.readTextFile(mod.jsFile + '.map')
128-
} else {
129-
req.status(404).send('file not found')
130-
return
131-
}
132-
} else {
133-
body = await Deno.readTextFile(mod.jsFile)
134-
if (app.isHMRable(mod.url)) {
135-
body = app.injectHmr(mod, body)
136-
}
137-
}
138-
req.setHeader('ETag', mod.hash)
139-
req.send(body, `application/${reqMap ? 'json' : 'javascript'}; charset=utf-8`)
140-
return
141-
}
142-
}
143-
}
144-
req.status(404).send('file not found')
145-
return
146-
}
147-
148-
// ssr
149-
const [status, html] = await app.getPageHtml({ pathname, search: url.search })
150-
req.status(status).send(html, 'text/html; charset=utf-8')
151-
} catch (err) {
152-
req.status(500).send(createHtml({
153-
lang: 'en',
154-
head: ['<title>500 - internal server error</title>'],
155-
body: `<p><strong><code>500</code></strong><small> - </small><span>${err.message}</span></p>`
156-
}), 'text/html; charset=utf-8')
157-
}
158-
}
159-
}
160-
161-
export async function serve(hostname: string, port: number, app: Appliaction) {
162-
const server = new Server(app)
163-
while (true) {
164-
try {
165-
const s = stdServe({ hostname, port })
166-
log.info(`Server ready on http://${hostname}:${port}`)
167-
for await (const r of s) {
168-
server.handle(r)
169-
}
170-
} catch (err) {
171-
if (err instanceof Deno.errors.AddrInUse) {
172-
log.warn(`port ${port} already in use, try ${port + 1}`)
173-
port++
174-
} else {
175-
log.fatal(err.message)
176-
}
177-
}
178-
}
179-
}

0 commit comments

Comments
 (0)