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

Commit 5cf9fd7

Browse files
committed
Clean up
1 parent 35e74da commit 5cf9fd7

File tree

2 files changed

+65
-40
lines changed

2 files changed

+65
-40
lines changed

bundler/mod.ts

Lines changed: 63 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
1-
import { dim } from 'https://deno.land/[email protected]/fmt/colors.ts'
2-
import { dirname, join } from 'https://deno.land/[email protected]/path/mod.ts'
3-
import { ensureDir } from 'https://deno.land/[email protected]/fs/ensure_dir.ts'
41
// @deno-types="https://deno.land/x/[email protected]/mod.d.ts"
52
import { build, stop as stopEsbuild } from 'https://deno.land/x/[email protected]/mod.js'
3+
import { dim } from 'https://deno.land/[email protected]/fmt/colors.ts'
4+
import { basename, dirname, join } from 'https://deno.land/[email protected]/path/mod.ts'
5+
import { ensureDir, } from 'https://deno.land/[email protected]/fs/ensure_dir.ts'
66
import { parseExportNames, transform } from '../compiler/mod.ts'
77
import { trimModuleExt } from '../framework/core/module.ts'
8-
import { ensureTextFile, existsFileSync, lazyRemove } from '../shared/fs.ts'
8+
import { ensureTextFile, existsDirSync, existsFileSync, lazyRemove } from '../shared/fs.ts'
99
import log from '../shared/log.ts'
1010
import util from '../shared/util.ts'
1111
import { VERSION } from '../version.ts'
1212
import type { Application, Module } from '../server/app.ts'
13-
import { computeHash, getAlephPkgUri } from '../server/helper.ts'
1413
import { cache } from '../server/cache.ts'
14+
import { computeHash, getAlephPkgUri } from '../server/helper.ts'
15+
16+
const hashShort = 8
17+
const reHashJS = new RegExp(`\\.[0-9a-fx]{${hashShort}}\\.js$`, 'i')
1518

16-
export const bundlerRuntimeCode = (`
19+
export const bundlerRuntimeCode = `
1720
window.__ALEPH = {
1821
basePath: '/',
1922
pack: {},
@@ -46,22 +49,15 @@ export const bundlerRuntimeCode = (`
4649
})
4750
}
4851
}
49-
`).split('\n')
50-
.map(l => l.trim()
51-
.replaceAll(') {', '){')
52-
.replace(/\s*([,:=|+]{1,2})\s+/g, '$1')
53-
)
54-
.join('')
52+
`
5553

5654
/** The bundler class for aleph server. */
5755
export class Bundler {
5856
#app: Application
59-
#compiledModules: Set<string>
6057
#bundledFiles: Map<string, string>
6158

6259
constructor(app: Application) {
6360
this.#app = app
64-
this.#compiledModules = new Set()
6561
this.#bundledFiles = new Map()
6662
}
6763

@@ -82,21 +78,21 @@ export class Bundler {
8278
}
8379
})
8480

85-
await this.createPolyfillBundle()
86-
await this.createBundleChunk(
81+
await this.bundlePolyfillChunck()
82+
await this.bundleChunk(
8783
'deps',
8884
Array.from(remoteEntries),
8985
[]
9086
)
9187
if (sharedEntries.size > 0) {
92-
await this.createBundleChunk(
88+
await this.bundleChunk(
9389
'shared',
9490
Array.from(sharedEntries),
9591
Array.from(remoteEntries)
9692
)
9793
}
9894
for (const url of entries) {
99-
await this.createBundleChunk(
95+
await this.bundleChunk(
10096
trimModuleExt(url),
10197
[url],
10298
[
@@ -105,7 +101,12 @@ export class Bundler {
105101
].flat()
106102
)
107103
}
104+
105+
// create main.js after all chunks are bundled
108106
await this.createMainJS()
107+
108+
// unlike nodejs, Deno doesn't provide the necessary APIs to allow Deno to
109+
// exit while esbuild's internal child process is still running.
109110
stopEsbuild()
110111
}
111112

@@ -128,9 +129,10 @@ export class Bundler {
128129
}
129130

130131
private async compile(mod: Module, external: string[]): Promise<string> {
131-
const bundlingFile = util.trimSuffix(mod.jsFile, '.js') + '.bundling.js'
132+
const hash = mod.deps.length > 0 ? computeHash(mod.sourceHash + mod.deps.map(({ hash }) => hash).join('')) : mod.sourceHash
133+
const bundlingFile = util.trimSuffix(mod.jsFile, '.js') + `.bundling.${hash.slice(0, hashShort)}.js`
132134

133-
if (this.#compiledModules.has(mod.url)) {
135+
if (existsFileSync(bundlingFile)) {
134136
return bundlingFile
135137
}
136138

@@ -179,8 +181,8 @@ export class Bundler {
179181
}
180182
}
181183

184+
await clearBuildCache(bundlingFile)
182185
await ensureTextFile(bundlingFile, code)
183-
this.#compiledModules.add(mod.url)
184186

185187
return bundlingFile
186188
}
@@ -194,30 +196,30 @@ export class Bundler {
194196
}, {} as Record<string, string>)
195197
const mainJS = `__ALEPH.bundledFiles=${JSON.stringify(bundledFiles)};` + this.#app.getMainJS(true)
196198
const hash = computeHash(mainJS)
197-
const bundleFilename = `main.bundle.${hash.slice(0, 8)}.js`
198-
const bundleFile = join(this.#app.buildDir, bundleFilename)
199-
await Deno.writeTextFile(bundleFile, mainJS)
199+
const bundleFilename = `main.bundle.${hash.slice(0, hashShort)}.js`
200+
const bundleFilePath = join(this.#app.buildDir, bundleFilename)
201+
await Deno.writeTextFile(bundleFilePath, mainJS)
200202
this.#bundledFiles.set('main', bundleFilename)
201203
log.info(` {} main.js ${dim('• ' + util.formatBytes(mainJS.length))}`)
202204
}
203205

204206
/** create polyfill bundle. */
205-
private async createPolyfillBundle() {
207+
private async bundlePolyfillChunck() {
206208
const alephPkgUri = getAlephPkgUri()
207209
const { buildTarget } = this.#app.config
208210
const hash = computeHash(buildTarget + Deno.version.deno + VERSION)
209-
const bundleFilename = `polyfill.bundle.${hash.slice(0, 8)}.js`
210-
const bundleFile = join(this.#app.buildDir, bundleFilename)
211-
if (!existsFileSync(bundleFile)) {
211+
const bundleFilename = `polyfill.bundle.${hash.slice(0, hashShort)}.js`
212+
const bundleFilePath = join(this.#app.buildDir, bundleFilename)
213+
if (!existsFileSync(bundleFilePath)) {
212214
const rawPolyfillFile = `${alephPkgUri}/bundler/polyfills/${buildTarget}/mod.ts`
213-
await this.build(rawPolyfillFile, bundleFile)
215+
await this.build(rawPolyfillFile, bundleFilePath)
214216
}
215217
this.#bundledFiles.set('polyfill', bundleFilename)
216-
log.info(` {} polyfill.js (${buildTarget.toUpperCase()}) ${dim('• ' + util.formatBytes(Deno.statSync(bundleFile).size))}`)
218+
log.info(` {} polyfill.js (${buildTarget.toUpperCase()}) ${dim('• ' + util.formatBytes(Deno.statSync(bundleFilePath).size))}`)
217219
}
218220

219221
/** create bundle chunk. */
220-
private async createBundleChunk(name: string, entry: string[], external: string[]) {
222+
private async bundleChunk(name: string, entry: string[], external: string[]) {
221223
const entryCode = (await Promise.all(entry.map(async (url, i) => {
222224
let mod = this.#app.getModule(url)
223225
if (mod && mod.jsFile !== '') {
@@ -237,23 +239,23 @@ export class Bundler {
237239
return []
238240
}))).flat().join('\n')
239241
const hash = computeHash(entryCode + VERSION + Deno.version.deno)
240-
const bundleFilename = `${name}.bundle.${hash.slice(0, 8)}.js`
242+
const bundleFilename = `${name}.bundle.${hash.slice(0, hashShort)}.js`
241243
const bundleEntryFile = join(this.#app.buildDir, `${name}.bundle.entry.js`)
242-
const bundleFile = join(this.#app.buildDir, bundleFilename)
243-
if (!existsFileSync(bundleFile)) {
244+
const bundleFilePath = join(this.#app.buildDir, bundleFilename)
245+
if (!existsFileSync(bundleFilePath)) {
244246
await Deno.writeTextFile(bundleEntryFile, entryCode)
245-
await this.build(bundleEntryFile, bundleFile)
247+
await this.build(bundleEntryFile, bundleFilePath)
246248
lazyRemove(bundleEntryFile)
247249
}
248250
this.#bundledFiles.set(name, bundleFilename)
249-
log.info(` {} ${name}.js ${dim('• ' + util.formatBytes(Deno.statSync(bundleFile).size))}`)
251+
log.info(` {} ${name}.js ${dim('• ' + util.formatBytes(Deno.statSync(bundleFilePath).size))}`)
250252
}
251253

252254
/** run deno bundle and compress the output using terser. */
253255
private async build(entryFile: string, bundleFile: string) {
254256
const { buildTarget, browserslist } = this.#app.config
255257

256-
await clearBundle(bundleFile)
258+
await clearBuildCache(bundleFile)
257259
await build({
258260
entryPoints: [entryFile],
259261
outfile: bundleFile,
@@ -263,6 +265,8 @@ export class Bundler {
263265
})),
264266
bundle: true,
265267
minify: true,
268+
treeShaking: true,
269+
sourcemap: false,
266270
plugins: [{
267271
name: 'http-loader',
268272
setup(build) {
@@ -295,6 +299,27 @@ export class Bundler {
295299
}
296300
}
297301

298-
async function clearBundle(filename: string) {
302+
export function simpleJSMinify(code: string) {
303+
return code.split('\n').map(l => l.trim()
304+
.replace(/\s*([,:=|+]{1,2})\s+/g, '$1')
305+
.replaceAll(') {', '){')
306+
).join('')
307+
}
308+
309+
async function clearBuildCache(filename: string) {
310+
const dir = dirname(filename)
311+
const hashname = basename(filename)
312+
if (!reHashJS.test(hashname) || !existsDirSync(dir)) {
313+
return
314+
}
299315

316+
const jsName = hashname.split('.').slice(0, -2).join('.') + '.js'
317+
for await (const entry of Deno.readDir(dir)) {
318+
if (entry.isFile && reHashJS.test(entry.name)) {
319+
const _jsName = entry.name.split('.').slice(0, -2).join('.') + '.js'
320+
if (_jsName === jsName && hashname !== entry.name) {
321+
await Deno.remove(join(dir, entry.name))
322+
}
323+
}
324+
}
300325
}

server/app.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
join,
99
resolve
1010
} from 'https://deno.land/[email protected]/path/mod.ts'
11-
import { Bundler, bundlerRuntimeCode } from '../bundler/mod.ts'
11+
import { Bundler, bundlerRuntimeCode, simpleJSMinify } from '../bundler/mod.ts'
1212
import {
1313
buildChecksum,
1414
ImportMap,
@@ -720,7 +720,7 @@ export class Application implements ServerApplication {
720720
}
721721

722722
return [
723-
bundlerRuntimeCode,
723+
simpleJSMinify(bundlerRuntimeCode),
724724
...['polyfill', 'deps', 'shared', 'main', entryFile ? util.trimSuffix(entryFile, '.js') : '']
725725
.filter(name => name !== "" && this.#bundler.getBundledFile(name) !== null)
726726
.map(name => ({

0 commit comments

Comments
 (0)