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

Commit 306c639

Browse files
committed
refactor(server): [wip] rewrite bundler
1 parent db7853e commit 306c639

File tree

6 files changed

+178
-192
lines changed

6 files changed

+178
-192
lines changed

server/app.ts

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import type {
2727
TransformFn
2828
} from '../types.ts'
2929
import { VERSION } from '../version.ts'
30-
import { Bundler } from './bundler.ts'
30+
import { Bundler, bundlerRuntimeCode } from './bundler.ts'
3131
import { defaultConfig, loadConfig, loadImportMap } from './config.ts'
3232
import {
3333
computeHash,
@@ -432,6 +432,26 @@ export class Application implements ServerApplication {
432432
return [status, html]
433433
}
434434

435+
getSSRHTMLScripts() {
436+
const { baseUrl } = this.config
437+
438+
if (this.isDev) {
439+
return [
440+
{ src: util.cleanPath(`${baseUrl}/_aleph/main.js`), type: 'module' },
441+
{ src: util.cleanPath(`${baseUrl}/_aleph/-/deno.land/x/aleph/nomodule.js`), nomodule: true },
442+
]
443+
}
444+
445+
return [
446+
bundlerRuntimeCode,
447+
...['polyfill', 'deps', 'shared', 'main']
448+
.filter(name => this.#bundler.getBundledFile(name) !== null)
449+
.map(name => ({
450+
src: util.cleanPath(`${baseUrl}/_aleph/${this.#bundler.getBundledFile(name)}`)
451+
}))
452+
]
453+
}
454+
435455
createFSWatcher(): EventEmitter {
436456
const e = new EventEmitter()
437457
this.#fsWatchListeners.push(e)
@@ -517,7 +537,7 @@ export class Application implements ServerApplication {
517537
return [
518538
`__ALEPH.baseURL = ${JSON.stringify(baseURL)};`,
519539
`__ALEPH.pack["${alephPkgUri}/framework/${framework}/bootstrap.ts"].default(${JSON.stringify(config)});`
520-
].join('\n')
540+
].join('')
521541
}
522542

523543
let code = [
@@ -632,15 +652,12 @@ export class Application implements ServerApplication {
632652
}
633653
await ensureDir(distDir)
634654

635-
// optimizing
636-
await this.optimize()
655+
// copy bundle dist
656+
await this.#bundler.copyDist()
637657

638658
// ssg
639659
await this.ssg()
640660

641-
// copy bundle dist
642-
await this.#bundler.copyDist()
643-
644661
// copy public assets
645662
const publicDir = path.join(this.workingDir, 'public')
646663
if (existsDirSync(publicDir)) {
@@ -1064,11 +1081,6 @@ export class Application implements ServerApplication {
10641081
await this.#bundler.bundle(concatAllEntries())
10651082
}
10661083

1067-
/** optimize for production. */
1068-
private async optimize() {
1069-
// todo: optimize
1070-
}
1071-
10721084
/** render all pages in routing. */
10731085
private async ssg() {
10741086
const { ssr } = this.config
@@ -1171,7 +1183,7 @@ export class Application implements ServerApplication {
11711183
}
11721184

11731185
/** lookup deps recurively. */
1174-
lookupDeps(
1186+
private lookupDeps(
11751187
url: string,
11761188
callback: (dep: DependencyDescriptor) => false | void,
11771189
__tracing: Set<string> = new Set()

server/bundler.ts

Lines changed: 70 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { minify as terser, ECMA } from 'https://esm.sh/[email protected]'
22
import { transform } from '../compiler/mod.ts'
3-
import { colors, path } from '../deps.ts'
3+
import { colors, ensureDir, path } from '../deps.ts'
44
import { defaultReactVersion } from '../shared/constants.ts'
55
import { ensureTextFile, existsFileSync, lazyRemove } from '../shared/fs.ts'
66
import log from '../shared/log.ts'
@@ -16,9 +16,9 @@ import {
1616
trimModuleExt
1717
} from './helper.ts'
1818

19-
export const createBundlerRuntimeCode = () => minify(`
19+
export const bundlerRuntimeCode = `
2020
window.__ALEPH = {
21-
baseURL: '/'
21+
baseURL: '/',
2222
pack: {},
2323
import: function(src, specifier) {
2424
var pack = this.pack
@@ -40,14 +40,18 @@ export const createBundlerRuntimeCode = () => minify(`
4040
})
4141
}
4242
}
43-
`)
43+
`
4444

4545
/** The bundler class for aleph server. */
4646
export class Bundler {
4747
#app: Application
48+
#compiledModules: Set<string>
49+
#bundledFiles: Map<string, string>
4850

4951
constructor(app: Application) {
5052
this.#app = app
53+
this.#compiledModules = new Set()
54+
this.#bundledFiles = new Map()
5155
}
5256

5357
async bundle(entryMods: Array<{ url: string, shared: boolean }>) {
@@ -67,50 +71,62 @@ export class Bundler {
6771
}
6872
})
6973

70-
await Promise.all([
71-
// this.createPolyfillBundle(),
72-
this.createBundleChunk(
73-
'deps',
74-
remoteEntries,
75-
[]
76-
),
77-
this.createBundleChunk(
74+
await this.createPolyfillBundle()
75+
await this.createBundleChunk(
76+
'deps',
77+
remoteEntries,
78+
[]
79+
)
80+
if (sharedEntries.length > 0) {
81+
await this.createBundleChunk(
7882
'shared',
7983
sharedEntries,
8084
remoteEntries
81-
),
82-
...entries.map(url => {
83-
this.createBundleChunk(
84-
trimModuleExt(url),
85-
[url],
86-
[
87-
...remoteEntries,
88-
...sharedEntries
89-
]
90-
)
91-
})
85+
)
86+
}
87+
for (const url of entries) {
88+
await this.createBundleChunk(
89+
trimModuleExt(url),
90+
[url],
91+
[remoteEntries, sharedEntries].flat()
92+
)
93+
}
94+
}
95+
96+
getBundledFile(name: string): string | null {
97+
return this.#bundledFiles.get(name) || null
98+
}
99+
100+
async copyDist() {
101+
await Promise.all([
102+
...Array.from(this.#bundledFiles.values()).map(jsFile => this.copyBundleFile(jsFile)),
103+
this.copyMainJS(),
92104
])
93105
}
94106

95-
#compiled = new Set<string>()
107+
private async copyMainJS() {
108+
const mainJS = this.#app.getMainJS(true)
109+
const hash = computeHash(mainJS)
110+
const jsFilename = `main.bundle.${hash.slice(0, 8)}.js`
111+
const saveAs = path.join(this.#app.outputDir, '_aleph', jsFilename)
112+
this.#bundledFiles.set('main', jsFilename)
113+
await ensureTextFile(saveAs, mainJS)
114+
}
115+
116+
private async copyBundleFile(jsFilename: string) {
117+
const { buildDir, outputDir } = this.#app
118+
const bundleFile = path.join(buildDir, jsFilename)
119+
const saveAs = path.join(outputDir, '_aleph', jsFilename)
120+
await ensureDir(path.dirname(saveAs))
121+
await Deno.copyFile(bundleFile, saveAs)
122+
}
96123

97-
private async compile(mod: Module, external: string[]): Promise<[string, Boolean]> {
124+
private async compile(mod: Module, external: string[]): Promise<string> {
98125
const bundlingFile = util.trimSuffix(mod.jsFile, '.js') + '.bundling.js'
99126

100-
if (this.#compiled.has(mod.url)) {
101-
return [bundlingFile, false]
127+
if (this.#compiledModules.has(mod.url)) {
128+
return bundlingFile
102129
}
103-
this.#compiled.add(mod.url)
104-
// let shouldCompile = false
105-
// this.#app.lookupDeps(mod.url, dep => {
106-
// if (external.includes(dep.url)) {
107-
// shouldCompile = true
108-
// return false
109-
// }
110-
// })
111-
// if (!shouldCompile) {
112-
// return [mod.jsFile, false]
113-
// }
114130

115131
const { content, contentType } = await this.#app.fetchModule(mod.url)
116132
const source = await this.#app.precompile(mod.url, content, contentType)
@@ -141,8 +157,8 @@ export class Bundler {
141157
if (!dep.url.startsWith('#') && !external.includes(dep.url)) {
142158
const depMod = this.#app.getModule(dep.url)
143159
if (depMod !== null) {
144-
const [_, isBundling] = await this.compile(depMod, external)
145160
const s = `.bundling.js#${dep.url}@`
161+
await this.compile(depMod, external)
146162
code = code.split(s).map((p, i) => {
147163
if (i > 0 && p.charAt(6) === '"') {
148164
return dep.hash.slice(0, 6) + p.slice(6)
@@ -154,42 +170,9 @@ export class Bundler {
154170
}
155171

156172
await ensureTextFile(bundlingFile, code)
157-
return [bundlingFile, true]
158-
}
173+
this.#compiledModules.add(mod.url)
159174

160-
async copyDist() {
161-
// const pageModules: Module[] = []
162-
// this.#pageRouting.lookup(routes => routes.forEach(({ module: { url } }) => {
163-
// const mod = this.getModule(url)
164-
// if (mod) {
165-
// pageModules.push(mod)
166-
// }
167-
// }))
168-
// await Promise.all([
169-
// (async () => {
170-
// const mainJS = this.getMainJS(true)
171-
// const filename = `main.bundle.${util.shortHash(computeHash(mainJS))}.js`
172-
// const saveAs = path.join(this.outputDir, '_aleph', filename)
173-
// await Deno.writeTextFile(saveAs, mainJS)
174-
// })(),
175-
// ...['deps', 'shared', 'polyfill'].map(async name => {
176-
// const mod = this.#modules.get(`/${name}.js`)
177-
// if (mod) {
178-
// const { hash } = mod
179-
// const bundleFile = path.join(this.buildDir, `${name}.bundle.${util.shortHash(hash)}.js`)
180-
// const saveAs = path.join(this.outputDir, '_aleph', `${name}.bundle.${util.shortHash(hash)}.js`)
181-
// await Deno.copyFile(bundleFile, saveAs)
182-
// }
183-
// }),
184-
// ...pageModules.map(async mod => {
185-
// const { jsFile, hash } = mod
186-
// const pathname = util.trimSuffix(jsFile.replace(reHashJS, ''), '.bundling')
187-
// const bundleFile = pathname + `.bundle.${util.shortHash(hash)}.js`
188-
// const saveAs = path.join(this.outputDir, `/_aleph/`, util.trimPrefix(pathname, this.buildDir) + `.bundle.${util.shortHash(hash)}.js`)
189-
// await ensureDir(path.dirname(saveAs))
190-
// await Deno.copyFile(bundleFile, saveAs)
191-
// })
192-
// ])
175+
return bundlingFile
193176
}
194177

195178
/** create bundle chunk. */
@@ -203,7 +186,7 @@ export class Bundler {
203186
`__ALEPH.pack[${JSON.stringify(url)}] = mod_${i}`
204187
]
205188
} else {
206-
const [jsFile] = await this.compile(mod, external)
189+
const jsFile = await this.compile(mod, external)
207190
return [
208191
`import * as mod_${i} from ${JSON.stringify('file://' + jsFile)}`,
209192
`__ALEPH.pack[${JSON.stringify(url)}] = mod_${i}`
@@ -213,13 +196,15 @@ export class Bundler {
213196
return []
214197
}))).flat().join('\n')
215198
const hash = computeHash(entryCode + VERSION + Deno.version.deno)
199+
const bundleFilename = `${name}.bundle.${hash.slice(0, 8)}.js`
216200
const bundleEntryFile = path.join(this.#app.buildDir, `${name}.bundle.entry.js`)
217-
const bundleFile = path.join(this.#app.buildDir, `${name}.bundle.${hash.slice(0, 8)}.js`)
201+
const bundleFile = path.join(this.#app.buildDir, bundleFilename)
218202
if (!existsFileSync(bundleFile)) {
219203
await Deno.writeTextFile(bundleEntryFile, entryCode)
220-
await this.runDenoBundle(bundleEntryFile, bundleFile)
204+
await this._bundle(bundleEntryFile, bundleFile)
221205
lazyRemove(bundleEntryFile)
222206
}
207+
this.#bundledFiles.set(name, bundleFilename)
223208
log.info(` {} ${name} ${colors.dim('• ' + util.formatBytes(Deno.statSync(bundleFile).size))}`)
224209
}
225210

@@ -228,16 +213,18 @@ export class Bundler {
228213
const alephPkgUri = getAlephPkgUri()
229214
const { buildTarget } = this.#app.config
230215
const hash = computeHash(buildTarget + Deno.version.deno + VERSION)
231-
const bundleFile = path.join(this.#app.buildDir, `polyfill.bundle.${hash.slice(0, 8)}.js`)
216+
const bundleFilename = `polyfill.bundle.${hash.slice(0, 8)}.js`
217+
const bundleFile = path.join(this.#app.buildDir, bundleFilename)
232218
if (!existsFileSync(bundleFile)) {
233219
const rawPolyfillFile = `${alephPkgUri}/compiler/polyfills/${buildTarget}/mod.ts`
234-
await this.runDenoBundle(rawPolyfillFile, bundleFile)
220+
await this._bundle(rawPolyfillFile, bundleFile)
235221
}
222+
this.#bundledFiles.set('polyfill', bundleFilename)
236223
log.info(` {} polyfill (${buildTarget.toUpperCase()}) ${colors.dim('• ' + util.formatBytes(Deno.statSync(bundleFile).size))}`)
237224
}
238225

239226
/** run deno bundle and compress the output using terser. */
240-
private async runDenoBundle(bundleEntryFile: string, bundleFile: string) {
227+
private async _bundle(bundleEntryFile: string, bundleFile: string) {
241228
// todo: use Deno.emit()
242229
const p = Deno.run({
243230
cmd: [Deno.execPath(), 'bundle', '--no-check', bundleEntryFile, bundleFile],
@@ -282,10 +269,11 @@ export class Bundler {
282269
}
283270

284271
async function minify(code: string, ecma: ECMA = 5) {
285-
return (await terser(code, {
272+
const ret = await terser(code, {
286273
compress: true,
287274
mangle: true,
288275
ecma,
289276
sourceMap: false
290-
})).code
277+
})
278+
return ret.code
291279
}

0 commit comments

Comments
 (0)