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

Commit 82c0ff7

Browse files
committed
Optimize esm bundling
1 parent 6596173 commit 82c0ff7

File tree

1 file changed

+36
-59
lines changed

1 file changed

+36
-59
lines changed

server/build.ts

Lines changed: 36 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -275,8 +275,8 @@ export async function build(serverEntry?: string) {
275275
}
276276
tasks.push(`${alephPkgUri}/framework/core/nomodule.ts`);
277277

278-
const entryModules = new Set(tasks);
279-
const allModules = new Set<string>();
278+
const entryModules = new Map(tasks.map((task) => [task, 0]));
279+
const tracing = new Set<string>();
280280

281281
// transform client modules
282282
const serverHandler: FetchHandler | undefined = Reflect.get(globalThis, "__ALEPH_SERVER")?.handler;
@@ -302,7 +302,7 @@ export async function build(serverEntry?: string) {
302302
if (!isCSS) {
303303
clientDependencyGraph?.get(specifier)?.deps?.forEach(({ specifier, dynamic }) => {
304304
if (dynamic) {
305-
entryModules.add(specifier);
305+
entryModules.set(specifier, 1);
306306
}
307307
if (specifier.endsWith(".css")) {
308308
deps.add(specifier + "?module");
@@ -313,15 +313,15 @@ export async function build(serverEntry?: string) {
313313
} else if (url.searchParams.has("module")) {
314314
deps.add(`${alephPkgUri}/framework/core/style.ts`);
315315
}
316-
allModules.add(specifier);
316+
tracing.add(specifier);
317317
}));
318-
tasks = Array.from(deps).filter((specifier) => !allModules.has(specifier));
318+
tasks = Array.from(deps).filter((specifier) => !tracing.has(specifier));
319319
}
320320
}
321321

322322
// count client module refs
323323
const refs = new Map<string, Set<string>>();
324-
for (const name of entryModules) {
324+
for (const [name] of entryModules) {
325325
clientDependencyGraph?.walk(name, ({ specifier }, importer) => {
326326
if (importer) {
327327
let set = refs.get(specifier);
@@ -334,70 +334,47 @@ export async function build(serverEntry?: string) {
334334
});
335335
}
336336

337-
// hygiene 1
338-
/*
339-
B(1) <-
340-
A <- <- <- D(1+) :: A <- D(1)
341-
C(1) <-
342-
*/
343-
refs.forEach((counter, specifier) => {
337+
const clientModules = new Map(entryModules);
338+
339+
// find shared modules
340+
for (const [specifier, counter] of refs) {
344341
if (counter.size > 1) {
345-
const a = Array.from(counter).filter((specifier) => {
346-
const set = refs.get(specifier);
347-
if (set?.size === 1) {
348-
const name = set.values().next().value;
349-
if (name && counter.has(name)) {
350-
return false;
351-
}
352-
}
353-
return true;
354-
});
355-
refs.set(specifier, new Set(a));
342+
clientModules.set(specifier, 2);
356343
}
357-
});
344+
}
358345

359-
// hygiene 2 (twice)
360-
/*
361-
B(1) <-
362-
A <- C(1) <- E(1+) :: A <- E(1)
363-
D(1) <-
364-
*/
365-
for (let i = 0; i < 2; i++) {
366-
refs.forEach((counter, specifier) => {
367-
if (counter.size > 0) {
368-
const a = Array.from(counter);
369-
if (a.every((specifier) => refs.get(specifier)?.size === 1)) {
370-
const set = new Set(a.map((specifier) => refs.get(specifier)?.values().next().value));
371-
if (set.size === 1) {
372-
refs.set(specifier, set);
346+
// hygiene check, make sure all shared modules are not only referenced by other shared modules
347+
for (let i = 0; i < 100; i++) {
348+
const toHygiene = new Set<string>();
349+
for (const [specifier, type] of clientModules) {
350+
if (type === 2) {
351+
const sharedBy = new Set<string>();
352+
clientDependencyGraph?.lookup(specifier, (specifier) => {
353+
if (clientModules.has(specifier)) {
354+
sharedBy.add(specifier);
355+
return false;
373356
}
357+
});
358+
if (sharedBy.size === 1) {
359+
toHygiene.add(specifier);
374360
}
375361
}
376-
});
377-
}
378-
379-
// find client modules
380-
const clientModules = new Set<string>(entryModules);
381-
refs.forEach((counter, specifier) => {
382-
if (counter.size > 1) {
383-
clientModules.add(specifier);
384362
}
385-
// console.log(`[${specifier}] \n - ${Array.from(counter).join("\n - ")}`);
386-
});
363+
// break the loop when there are no more modules to hygiene
364+
if (toHygiene.size === 0) {
365+
break;
366+
}
367+
toHygiene.forEach((specifier) => clientModules.delete(specifier));
368+
log.debug(`hygiene#${i + 1}`, toHygiene);
369+
}
387370

388371
// bundle client modules
389-
const bundling = new Set<string>();
390-
clientModules.forEach((specifier) => {
391-
if (
392-
clientDependencyGraph?.get(specifier)?.deps?.some(({ specifier }) => !clientModules.has(specifier)) &&
393-
!util.splitBy(specifier, "?")[0].endsWith(".css")
394-
) {
395-
bundling.add(specifier);
396-
}
397-
});
398372
await Promise.all(
399-
Array.from(bundling).map(async (entryPoint) => {
373+
Array.from(clientModules.keys()).map(async (entryPoint) => {
400374
const url = new URL(util.isLikelyHttpURL(entryPoint) ? toLocalPath(entryPoint) : entryPoint, "http://localhost");
375+
if (url.pathname.endsWith(".css")) {
376+
return;
377+
}
401378
let jsFile = join(outputDir, url.pathname);
402379
if (isEsmPkg(entryPoint)) {
403380
jsFile += ".js";

0 commit comments

Comments
 (0)