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

Commit 3f73035

Browse files
committed
refactor: clean up
1 parent 65a0909 commit 3f73035

File tree

3 files changed

+93
-41
lines changed

3 files changed

+93
-41
lines changed

server/app.ts

Lines changed: 69 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ import util from '../shared/util.ts'
1111
import type { Config, LoaderPlugin, LoaderTransformResult, ModuleOptions, RouterURL, ServerApplication, TransformFn } from '../types.ts'
1212
import { VERSION } from '../version.ts'
1313
import { Bundler } from './bundler.ts'
14-
import { defaultConfig, loadConfig } from './config.ts'
15-
import { clearCompilation, computeHash, createHtml, formatBytesWithColor, getAlephPkgUri, getRelativePath, isLoaderPlugin, reFullVersion, reHashJs, reHashResolve, toLocalUrl, trimModuleExt } from './helper.ts'
14+
import { defaultConfig, loadConfig, loadImportMap } from './config.ts'
15+
import { clearCompilation, computeHash, createHtml, formatBytesWithColor, getAlephPkgUri, getRelativePath, getDenoDir, isLoaderPlugin, reFullVersion, reHashJs, reHashResolve, toLocalUrl, trimModuleExt } from './helper.ts'
1616

1717
/** A module includes the compilation details. */
1818
export type Module = {
@@ -75,6 +75,7 @@ export class Application implements ServerApplication {
7575
const walkOptions = { includeDirs: false, skip: [/(^|\/|\\)\./, /\.d\.ts$/i, /(\.|_)(test|spec|e2e)\.(tsx?|jsx?|mjs)?$/i] }
7676
const apiDir = path.join(this.srcDir, 'api')
7777
const pagesDir = path.join(this.srcDir, 'pages')
78+
const buildManifestFile = path.join(this.buildDir, 'build.manifest.json')
7879

7980
if (!(existsDirSync(pagesDir))) {
8081
log.fatal(`'pages' directory not found.`)
@@ -84,21 +85,21 @@ export class Application implements ServerApplication {
8485
log.fatal(`need Deno ${minDenoVersion}+, but got ${Deno.version.deno}`)
8586
}
8687

87-
const p = Deno.run({
88-
cmd: [Deno.execPath(), 'info', '--unstable', '--json'],
89-
stdout: 'piped',
90-
stderr: 'null'
91-
})
92-
const output = (new TextDecoder).decode(await p.output())
93-
const { denoDir } = JSON.parse(output)
94-
p.close()
95-
if (!existsDirSync(denoDir)) {
96-
log.fatal(`can't find the deno dir`)
88+
let shouldRebuild = !existsFileSync(buildManifestFile)
89+
if (!shouldRebuild) {
90+
try {
91+
const bm = JSON.parse(await Deno.readTextFile(buildManifestFile))
92+
shouldRebuild = bm.compiler !== buildChecksum
93+
if (shouldRebuild) {
94+
log.debug('rebuild...')
95+
}
96+
} catch (e) { }
9797
}
98-
this.#dirs.set('denoDir', denoDir)
9998

100-
if (reload) {
101-
this.#reloading = true
99+
if (reload || shouldRebuild) {
100+
if (reload && !shouldRebuild) {
101+
this.#reloading = true
102+
}
102103
if (existsDirSync(this.buildDir)) {
103104
await Deno.remove(this.buildDir, { recursive: true })
104105
}
@@ -113,9 +114,14 @@ export class Application implements ServerApplication {
113114
Deno.env.set('ALEPH_VERSION', VERSION)
114115
Deno.env.set('BUILD_MODE', this.mode)
115116

116-
const [config, importMap] = await loadConfig(this.workingDir)
117+
const [config, importMap, denoDir] = await Promise.all([
118+
loadConfig(this.workingDir),
119+
loadImportMap(this.workingDir),
120+
getDenoDir()
121+
])
117122
Object.assign(this.config, config)
118123
Object.assign(this.importMap, importMap)
124+
this.#dirs.set('denoDir', denoDir)
119125

120126
// apply server plugins
121127
for (const plugin of plugins) {
@@ -195,6 +201,12 @@ export class Application implements ServerApplication {
195201
this.#reloading = false
196202
}
197203

204+
ensureTextFile(buildManifestFile, JSON.stringify({
205+
aleph: VERSION,
206+
compiler: buildChecksum,
207+
deno: Deno.version.deno,
208+
}))
209+
198210
log.debug(`init project in ${Math.round(performance.now() - t)}ms`)
199211

200212
if (this.isDev) {
@@ -612,8 +624,8 @@ export class Application implements ServerApplication {
612624
}
613625
try {
614626
if (existsFileSync(metaFile)) {
615-
const { url, sourceHash, deps } = JSON.parse(await Deno.readTextFile(metaFile))
616-
if (url === url && util.isNEString(sourceHash) && util.isArray(deps)) {
627+
const { sourceHash, deps } = JSON.parse(await Deno.readTextFile(metaFile))
628+
if (util.isNEString(sourceHash) && util.isArray(deps)) {
617629
mod.sourceHash = sourceHash
618630
mod.deps = deps
619631
} else {
@@ -625,9 +637,9 @@ export class Application implements ServerApplication {
625637
}
626638

627639
let sourceContent = new Uint8Array()
628-
let contentType: string | null = null
640+
let contentType: null | string = null
629641
let jsContent = ''
630-
let jsSourceMap: string | null = null
642+
let jsSourceMap: null | string = null
631643
let shouldCompile = false
632644
let fsync = false
633645

@@ -639,7 +651,14 @@ export class Application implements ServerApplication {
639651
shouldCompile = true
640652
}
641653
} else if (isRemote) {
642-
try {
654+
let shouldFetch = true
655+
if (mod.sourceHash !== '' && !url.startsWith('http://localhost:')) {
656+
const jsFile = util.cleanPath(saveDir + '/' + name + '.js')
657+
if (existsFileSync(jsFile)) {
658+
shouldFetch = false
659+
}
660+
}
661+
if (shouldFetch) {
643662
const [content, headers] = await this.fetchModule(url)
644663
const sourceHash = computeHash(content)
645664
sourceContent = content
@@ -648,9 +667,6 @@ export class Application implements ServerApplication {
648667
mod.sourceHash = sourceHash
649668
shouldCompile = true
650669
}
651-
} catch (err) {
652-
log.error(`Download ${url}:`, err)
653-
return mod
654670
}
655671
} else {
656672
const filepath = path.join(this.srcDir, url)
@@ -671,7 +687,7 @@ export class Application implements ServerApplication {
671687
}
672688

673689
// compute hash
674-
mod.hash = computeHash(mod.sourceHash + buildChecksum + JSON.stringify(this.defaultCompileOptions))
690+
mod.hash = isRemote ? mod.sourceHash : computeHash(mod.sourceHash + JSON.stringify(this.defaultCompileOptions))
675691
mod.jsFile = util.cleanPath(saveDir + '/' + name + (isRemote ? '' : `.${mod.hash.slice(0, hashShortLength)}`) + '.js')
676692

677693
// check previous compilation output if the source content doesn't changed.
@@ -711,7 +727,10 @@ export class Application implements ServerApplication {
711727

712728
for (const plugin of this.config.plugins) {
713729
if (plugin.type === 'loader' && plugin.test.test(url)) {
714-
const { code, type = 'js' } = await this.applyLoader(plugin, { url, content: sourceContent })
730+
const { code, type = 'js' } = await this.applyLoader(
731+
plugin,
732+
{ url, content: sourceContent }
733+
)
715734
sourceCode = code
716735
sourceType = type
717736
break
@@ -778,13 +797,16 @@ export class Application implements ServerApplication {
778797
if (jsContent === '') {
779798
jsContent = await Deno.readTextFile(mod.jsFile)
780799
}
781-
const newContent = jsContent.replace(reHashResolve, (s, key, spaces, ql, importPath, qr) => {
782-
const importPathname = importPath.replace(reHashJs, '')
783-
if (importPathname == dep.url || importPathname === relativePathname) {
784-
return `${key}${spaces}${ql}${importPathname}.${dep.hash.slice(0, hashShortLength)}.js${qr}`
800+
const newContent = jsContent.replace(
801+
reHashResolve,
802+
(s, key, spaces, ql, importPath, qr) => {
803+
const importPathname = importPath.replace(reHashJs, '')
804+
if (importPathname == dep.url || importPathname === relativePathname) {
805+
return `${key}${spaces}${ql}${importPathname}.${dep.hash.slice(0, hashShortLength)}.js${qr}`
806+
}
807+
return s
785808
}
786-
return s
787-
})
809+
)
788810
if (newContent !== jsContent) {
789811
jsContent = newContent
790812
if (!fsync) {
@@ -841,11 +863,16 @@ export class Application implements ServerApplication {
841863
}
842864
})
843865
})
844-
this.#pageRouting.lookup(routes => routes.forEach(({ module: { url } }) => entryMods.add(url)))
866+
this.#pageRouting.lookup(routes => {
867+
routes.forEach(({ module: { url } }) => entryMods.add(url))
868+
})
845869
refCounter.forEach((refers, url) => {
846870
if (refers.size > 1) {
847-
const localDepEntryMods = Array.from(depMods.entries()).filter(([url, isEntry]) => !util.isLikelyHttpURL(url) && isEntry).map(([url]) => url)
848-
const exported = Array.from(refers).filter(url => entryMods.has(url) || localDepEntryMods.includes(url)).length > 1
871+
const localDepEntryMods = Array.from(depMods.entries())
872+
.filter(([url, isEntry]) => !util.isLikelyHttpURL(url) && isEntry)
873+
.map(([url]) => url)
874+
const exported = Array.from(refers)
875+
.some(url => entryMods.has(url) || localDepEntryMods.includes(url))
849876
if (exported) {
850877
addDepEntry(url)
851878
} else if (!depMods.has(url)) {
@@ -885,7 +912,11 @@ export class Application implements ServerApplication {
885912
const htmlFile = path.join(outputDir, pathname, 'index.html')
886913
await ensureTextFile(htmlFile, html)
887914
if (data) {
888-
const dataFile = path.join(outputDir, '_aleph/data', (pathname === '/' ? 'index' : pathname) + '.json')
915+
const dataFile = path.join(
916+
outputDir,
917+
'_aleph/data',
918+
(pathname === '/' ? 'index' : pathname) + '.json'
919+
)
889920
await ensureTextFile(dataFile, JSON.stringify(data))
890921
}
891922
log.info(' ○', pathname, colors.dim('• ' + util.formatBytes(html.length)))
@@ -922,7 +953,7 @@ export class Application implements ServerApplication {
922953
}
923954

924955
/** fetch remote module content */
925-
private async fetchModule(url: string): Promise<[Uint8Array, Headers]> {
956+
async fetchModule(url: string): Promise<[Uint8Array, Headers]> {
926957
const u = new URL(url)
927958
if (url.startsWith('https://esm.sh/')) {
928959
if (this.isDev && !u.searchParams.has('dev')) {
@@ -934,7 +965,7 @@ export class Application implements ServerApplication {
934965
const { protocol, hostname, port, pathname, search } = u
935966
const versioned = reFullVersion.test(pathname)
936967
const reload = this.#reloading || !versioned
937-
const isLocalhost = /^https?:\/\/localhost(:\d+)?\//.test(url)
968+
const isLocalhost = url.startsWith('http://localhost:')
938969
const cacheDir = path.join(
939970
this.#dirs.get('denoDir')!,
940971
'deps',

server/config.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export const defaultConfig: Readonly<Required<Config>> = {
2424
}
2525

2626
/** load config from `aleph.config.(ts|js|json)` */
27-
export async function loadConfig(workingDir: string): Promise<[Config, ImportMap]> {
27+
export async function loadConfig(workingDir: string): Promise<Config> {
2828
let data: Config = {}
2929
for (const name of ['ts', 'js', 'json'].map(ext => 'aleph.config.' + ext)) {
3030
const p = path.join(workingDir, name)
@@ -109,7 +109,11 @@ export async function loadConfig(workingDir: string): Promise<[Config, ImportMap
109109

110110
// todo: load ssr.config.ts
111111

112-
// load import maps
112+
return config
113+
}
114+
115+
/** load import maps from `import_map.json` */
116+
export async function loadImportMap(workingDir: string): Promise<ImportMap> {
113117
const importMap: ImportMap = { imports: {}, scopes: {} }
114118
for (const filename of Array.from(['import_map', 'import-map', 'importmap']).map(name => `${name}.json`)) {
115119
const importMapFile = path.join(workingDir, filename)
@@ -140,7 +144,7 @@ export async function loadConfig(workingDir: string): Promise<[Config, ImportMap
140144
Object.assign(importMap.imports, imports)
141145
}
142146

143-
return [config, importMap]
147+
return importMap
144148
}
145149

146150
function isFramework(v: any): v is 'react' {

server/helper.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,23 @@ export function isLoaderPlugin(plugin: Plugin): plugin is LoaderPlugin {
4848
return plugin.type === 'loader'
4949
}
5050

51+
/** get deno dir. */
52+
export async function getDenoDir() {
53+
const p = Deno.run({
54+
cmd: [Deno.execPath(), 'info', '--json', '--unstable'],
55+
stdout: 'piped',
56+
stderr: 'null'
57+
})
58+
const output = (new TextDecoder).decode(await p.output())
59+
const { denoDir } = JSON.parse(output)
60+
p.close()
61+
if (denoDir === undefined || !existsDirSync(denoDir)) {
62+
throw new Error(`can't find the deno dir`)
63+
}
64+
return denoDir
65+
}
66+
67+
5168
/** get aleph pkg uri. */
5269
export function getAlephPkgUri() {
5370
const DEV_PORT = Deno.env.get('ALEPH_DEV_PORT')

0 commit comments

Comments
 (0)