Skip to content

Commit e419776

Browse files
author
LessJS Bot
committed
refactor: eliminate all resolve.alias — use workspace root for Deno native resolution
Instead of auto-generating or hardcoding Vite resolve.alias entries, set root = workspace root (parent of user project) in Phase 2/3 Vite build configs. This lets Vite discover the workspace deno.json and resolve all @lessjs/* packages through Deno's native module graph. Changes: - build-client.ts: root → resolve(userRoot, '..'), remove alias code - build-ssg.ts: root → resolve(root, '..') in viteBuild config - Zero resolve.alias anywhere — not in config, not auto-generated
1 parent 67b94c6 commit e419776

2 files changed

Lines changed: 19 additions & 115 deletions

File tree

packages/adapter-vite/src/cli/build-client.ts

Lines changed: 16 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,16 @@
88
* closeBundle() in less:build plugin. No longer a standalone CLI entry.
99
* ctx parameter is required (no globalThis fallback).
1010
*
11+
* Resolution: No Vite resolve.alias. The client build runs with
12+
* root = workspace root so Vite finds the workspace deno.json
13+
* and resolves all @lessjs/* packages through Deno natively.
14+
*
1115
* Usage:
1216
* deno task build (unified entry — runs all 3 phases)
1317
*/
1418

1519
import { build as viteBuild, type InlineConfig } from 'vite';
16-
import { resolve } from 'node:path';
20+
import { basename, resolve } from 'node:path';
1721
import process from 'node:process';
1822
import { type ClientIslandEntry, generateClientEntry } from '../entry-generators.js';
1923
import type { LessBuildContext } from '../build-context.js';
@@ -24,121 +28,17 @@ const log = createLogger('ssg');
2428
const VIRTUAL_CLIENT_ENTRY_ID = 'virtual:less-client-entry';
2529
const RESOLVED_CLIENT_ENTRY_ID = '\0' + VIRTUAL_CLIENT_ENTRY_ID;
2630

27-
// ─── Alias auto-generation from workspace ────────────────────────────
28-
29-
interface AliasEntry {
30-
find: string;
31-
replacement: string;
32-
}
33-
34-
/**
35-
* Walk up from startDir to find a deno.json with a "workspace" field.
36-
* Returns the directory containing the workspace deno.json, or null.
37-
*/
38-
async function findWorkspaceRoot(startDir: string): Promise<string | null> {
39-
let dir = resolve(startDir);
40-
const fsRoot = resolve('/');
41-
while (dir !== fsRoot && dir !== resolve(dir, '..')) {
42-
try {
43-
const path = resolve(dir, 'deno.json');
44-
const raw = await Deno.readTextFile(path);
45-
const cfg = JSON.parse(raw);
46-
if (cfg.workspace && Array.isArray(cfg.workspace)) return dir;
47-
} catch { /* not found or no workspace */ }
48-
dir = resolve(dir, '..');
49-
}
50-
return null;
51-
}
52-
53-
/**
54-
* Generate Vite resolve.alias entries from all @lessjs/* workspace packages.
55-
* Each package's deno.json exports become aliases:
56-
* "." → { find: "@lessjs/pkg", replacement: "<dir>/src/index.ts" }
57-
* "./foo" → { find: "@lessjs/pkg/foo", replacement: "<dir>/src/foo.ts" }
58-
*/
59-
async function generateWorkspaceAliases(workspaceRoot: string): Promise<AliasEntry[]> {
60-
const rootConfig = JSON.parse(
61-
await Deno.readTextFile(resolve(workspaceRoot, 'deno.json')),
62-
);
63-
const members: string[] = rootConfig.workspace || [];
64-
const aliases: AliasEntry[] = [];
65-
66-
for (const member of members) {
67-
const memberDir = resolve(workspaceRoot, member);
68-
let memberCfg: Record<string, unknown>;
69-
try {
70-
memberCfg = JSON.parse(await Deno.readTextFile(resolve(memberDir, 'deno.json')));
71-
} catch {
72-
continue;
73-
}
74-
75-
const name = memberCfg.name as string | undefined;
76-
const exports = memberCfg.exports as Record<string, string> | string | undefined;
77-
if (!name || !exports) continue;
78-
79-
if (typeof exports === 'string') {
80-
// Single export — no subpaths
81-
aliases.push({ find: name, replacement: resolve(memberDir, exports) });
82-
continue;
83-
}
84-
85-
// Build subpath aliases first (Vite prefix matching: subpath before parent)
86-
for (const [exportPath, sourcePath] of Object.entries(exports)) {
87-
if (exportPath === '.') continue; // parent alias added last
88-
// "./foo" → "@lessjs/pkg/foo"
89-
const subpath = exportPath.replace(/^\.\//, '/');
90-
aliases.push({
91-
find: `${name}${subpath}`,
92-
replacement: resolve(memberDir, sourcePath as string),
93-
});
94-
}
95-
96-
// Parent alias last
97-
if (exports['.']) {
98-
aliases.push({ find: name, replacement: resolve(memberDir, exports['.'] as string) });
99-
}
100-
}
101-
102-
return aliases;
103-
}
104-
105-
// ─── Build function ──────────────────────────────────────────────────
106-
10731
async function buildClient(ctx: LessBuildContext): Promise<void> {
108-
const root = ctx.root || process.cwd();
32+
const userRoot = ctx.root || process.cwd();
33+
const workspaceRoot = resolve(userRoot, '..');
34+
const wwwRel = basename(userRoot); // e.g. "www"
35+
10936
const outDir = ctx.outDir || 'dist';
11037
const islandsDir = ctx.islandsDir || 'app/islands';
11138
const localIslands = ctx.islandTagNames || [];
11239
const localIslandFiles = ctx.islandFiles || [];
11340
const packageIslands = ctx.packageIslands || [];
11441

115-
// Resolve alias for client build
116-
// 1. Prefer user-provided aliases (vite.config.ts resolve.alias)
117-
// 2. Otherwise, auto-generate from Deno workspace packages
118-
const resolveAlias = ctx.userResolveAlias;
119-
let serializedAlias: AliasEntry[] | null = null;
120-
121-
if (resolveAlias) {
122-
serializedAlias = Array.isArray(resolveAlias)
123-
? resolveAlias.filter((a) => typeof a.find === 'string').map((a) => ({
124-
find: a.find as string,
125-
replacement: a.replacement,
126-
}))
127-
: Object.entries(resolveAlias).map(([find, replacement]) => ({ find, replacement }));
128-
log.info('resolveAlias: ' + JSON.stringify(serializedAlias, null, 2));
129-
} else {
130-
// Auto-generate from workspace packages
131-
const workspaceRoot = await findWorkspaceRoot(root);
132-
if (workspaceRoot) {
133-
serializedAlias = await generateWorkspaceAliases(workspaceRoot);
134-
log.info(
135-
`Auto-generated ${serializedAlias.length} alias(es) from workspace: ${workspaceRoot}`,
136-
);
137-
} else {
138-
log.info('WARNING: no resolveAlias and no workspace found — island imports may fail');
139-
}
140-
}
141-
14242
if (localIslands.length === 0 && packageIslands.length === 0) {
14343
log.info('No islands found — zero client JS output');
14444
return;
@@ -152,7 +52,7 @@ async function buildClient(ctx: LessBuildContext): Promise<void> {
15252
...localIslands.map((tagName: string, i: number) => ({
15353
tagName,
15454
modulePath: resolve(
155-
root,
55+
userRoot,
15656
localIslandFiles[i]
15757
? `${islandsDir}/${localIslandFiles[i]}`
15858
: `${islandsDir}/${tagName}.ts`,
@@ -187,11 +87,13 @@ async function buildClient(ctx: LessBuildContext): Promise<void> {
18787
return item;
18888
});
18989

190-
const clientOutDir = resolve(root, outDir, 'client');
90+
const clientOutDir = resolve(userRoot, outDir, 'client');
19191
const clientBase = ctx.base || '/';
19292
const clientConfig: InlineConfig = {
19393
configFile: false,
194-
root,
94+
// Use workspace root so Vite finds workspace deno.json
95+
// and resolves @lessjs/* through Deno natively (zero aliases).
96+
root: workspaceRoot,
19597
base: `${clientBase}client/`,
19698
logLevel: 'warn',
19799
build: {
@@ -207,7 +109,8 @@ async function buildClient(ctx: LessBuildContext): Promise<void> {
207109
entryFileNames: 'islands/[name].js',
208110
chunkFileNames: 'islands/[name]-[hash].js',
209111
manualChunks(id: string) {
210-
if (id.includes(`/${islandsDir}/`)) {
112+
// Match local islands under www/ (root is workspace root)
113+
if (id.includes(`/${wwwRel}/${islandsDir}/`)) {
211114
const match = id.match(/\/([^/]+)\.(ts|js)$/);
212115
if (match) return `island-${match[1]}`;
213116
}
@@ -218,7 +121,6 @@ async function buildClient(ctx: LessBuildContext): Promise<void> {
218121
},
219122
},
220123
},
221-
resolve: serializedAlias ? { alias: serializedAlias } : undefined,
222124
ssr: {
223125
noExternal: (noExternalPatterns.length > 0 ? noExternalPatterns : undefined) as
224126
| (string | RegExp)[]

packages/adapter-vite/src/cli/build-ssg.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,9 @@ async function buildSSG(options: BuildSSGOptions = {}, ctx: LessBuildContext): P
218218

219219
await viteBuild({
220220
configFile: false,
221-
root,
221+
// Use workspace root so Vite finds workspace deno.json
222+
// and resolves @lessjs/* through Deno natively (zero aliases).
223+
root: resolve(root, '..'),
222224
build: {
223225
ssr: true,
224226
outDir: ssrOutDir,

0 commit comments

Comments
 (0)