@blinkk/root 1.0.0-alpha.14 → 1.0.0-alpha.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -4,14 +4,19 @@ import {
4
4
  } from "./chunk-ZB7R6ZOY.js";
5
5
 
6
6
  // src/cli/commands/dev.ts
7
- import path4 from "node:path";
7
+ import path5 from "node:path";
8
8
  import { fileURLToPath } from "node:url";
9
9
  import { default as express } from "express";
10
10
  import { createServer as createViteServer } from "vite";
11
11
 
12
12
  // src/render/vite-plugin-root.ts
13
- import path2 from "path";
13
+ import path3 from "node:path";
14
+
15
+ // src/core/elements.ts
16
+ import fs2 from "node:fs";
17
+ import path2 from "node:path";
14
18
  import glob from "tiny-glob";
19
+ import { searchForWorkspaceRoot } from "vite";
15
20
 
16
21
  // src/core/fsutils.ts
17
22
  import { promises as fs } from "node:fs";
@@ -58,60 +63,83 @@ async function isDirectory(dirpath) {
58
63
  function fileExists(filepath) {
59
64
  return fs.access(filepath).then(() => true).catch(() => false);
60
65
  }
66
+ async function directoryContains(dirpath, subpath) {
67
+ const outer = await fs.realpath(dirpath);
68
+ const inner = await fs.realpath(subpath);
69
+ const rel = path.relative(outer, inner);
70
+ return !rel.startsWith("..");
71
+ }
61
72
 
62
- // src/render/vite-plugin-root.ts
63
- var JSX_ELEMENTS_REGEX = /jsxs?\("(\w[\w-]+\w)"/g;
64
- var HTML_ELEMENTS_REGEX = /<(\w[\w-]+\w)/g;
65
- function pluginRoot(options) {
73
+ // src/core/elements.ts
74
+ async function getElements(rootConfig) {
66
75
  var _a, _b;
67
- const elementsVirtualId = "virtual:root-elements";
68
- const resolvedElementsVirtualId = "\0" + elementsVirtualId;
69
- const rootDir = (options == null ? void 0 : options.rootDir) || process.cwd();
70
- const rootConfig = (options == null ? void 0 : options.rootConfig) || {};
76
+ const rootDir = rootConfig.rootDir;
77
+ const workspaceRoot = searchForWorkspaceRoot(rootDir);
71
78
  const elementsDirs = [path2.join(rootDir, "elements")];
72
- const includeDirs = ((_a = rootConfig.elements) == null ? void 0 : _a.include) || [];
73
- includeDirs.forEach((dirPath) => {
79
+ const elementsInclude = ((_a = rootConfig.elements) == null ? void 0 : _a.include) || [];
80
+ const excludePatterns = ((_b = rootConfig.elements) == null ? void 0 : _b.exclude) || [];
81
+ const excludeElement = (moduleId) => {
82
+ return excludePatterns.some((pattern) => Boolean(moduleId.match(pattern)));
83
+ };
84
+ for (const dirPath of elementsInclude) {
74
85
  const elementsDir = path2.resolve(rootDir, dirPath);
75
- if (!elementsDir.startsWith(rootDir)) {
86
+ if (!directoryContains(rootDir, elementsDir)) {
76
87
  throw new Error(
77
- `the elements dir (${dirPath}) should be relative to the project's root dir (${rootDir})`
88
+ `the elements dir (${dirPath}) should be within the project's workspace (${workspaceRoot})`
78
89
  );
79
90
  }
80
91
  elementsDirs.push(elementsDir);
81
- });
82
- const excludePatterns = ((_b = rootConfig.elements) == null ? void 0 : _b.exclude) || [];
83
- const excludeElement = (moduleId) => {
84
- return excludePatterns.some((pattern) => Boolean(moduleId.match(pattern)));
85
- };
86
- let elementMap;
87
- async function updateElementMap() {
88
- elementMap = {};
89
- await Promise.all(
90
- elementsDirs.map(async (dirPath) => {
91
- const dirExists = await isDirectory(dirPath);
92
- if (!dirExists) {
93
- return;
94
- }
95
- const files = await glob("**/*", { cwd: dirPath });
96
- files.forEach((file) => {
97
- const parts = path2.parse(file);
98
- if (isJsFile(parts.base)) {
99
- const fullPath = path2.join(dirPath, file);
100
- const moduleId = fullPath.slice(rootDir.length);
101
- if (!excludeElement(moduleId)) {
102
- elementMap[parts.name] = moduleId;
103
- }
92
+ }
93
+ const elementMap = {};
94
+ for (const dirPath of elementsDirs) {
95
+ if (await isDirectory(dirPath)) {
96
+ const elementFiles = await glob("**/*", { cwd: dirPath });
97
+ elementFiles.forEach((file) => {
98
+ const parts = path2.parse(file);
99
+ if (isJsFile(parts.base)) {
100
+ const filePath = path2.join(dirPath, file);
101
+ const src = path2.relative(rootDir, filePath);
102
+ const realPath = fs2.realpathSync(filePath);
103
+ if (!excludeElement(src)) {
104
+ elementMap[parts.name] = {
105
+ src,
106
+ filePath,
107
+ realPath
108
+ };
104
109
  }
105
- });
106
- })
107
- );
110
+ }
111
+ });
112
+ }
113
+ }
114
+ return elementMap;
115
+ }
116
+
117
+ // src/render/vite-plugin-root.ts
118
+ var JSX_ELEMENTS_REGEX = /jsxs?\("(\w[\w-]+\w)"/g;
119
+ var HTML_ELEMENTS_REGEX = /<(\w[\w-]+\w)/g;
120
+ function pluginRoot(options) {
121
+ const elementsVirtualId = "virtual:root-elements";
122
+ const resolvedElementsVirtualId = "\0" + elementsVirtualId;
123
+ const rootConfig = options.rootConfig;
124
+ let tagNameToElement;
125
+ const customElementFiles = /* @__PURE__ */ new Set();
126
+ async function updateElementMap() {
127
+ tagNameToElement = await getElements(rootConfig);
128
+ customElementFiles.clear();
129
+ Object.values(tagNameToElement).forEach((elementModule) => {
130
+ customElementFiles.add(elementModule.filePath);
131
+ customElementFiles.add(elementModule.realPath);
132
+ });
108
133
  }
109
134
  async function getElementImport(tagname) {
110
- if (!elementMap) {
135
+ if (!tagNameToElement) {
111
136
  await updateElementMap();
112
137
  }
113
- if (tagname in elementMap) {
114
- return elementMap[tagname];
138
+ if (tagname in tagNameToElement) {
139
+ const elementModule = tagNameToElement[tagname];
140
+ if (elementModule.filePath === elementModule.realPath) {
141
+ return elementModule.src;
142
+ }
115
143
  }
116
144
  return null;
117
145
  }
@@ -119,9 +147,7 @@ function pluginRoot(options) {
119
147
  if (!isJsFile(id)) {
120
148
  return false;
121
149
  }
122
- return elementsDirs.some((elementsDir) => {
123
- return id.startsWith(elementsDir);
124
- });
150
+ return customElementFiles.has(id);
125
151
  }
126
152
  return {
127
153
  name: "vite-plugin-root",
@@ -134,13 +160,14 @@ function pluginRoot(options) {
134
160
  async load(id) {
135
161
  if (id === resolvedElementsVirtualId) {
136
162
  await updateElementMap();
137
- return `export const elementsMap = ${JSON.stringify(elementMap)}`;
163
+ return `export const elementsMap = ${JSON.stringify(tagNameToElement)}`;
138
164
  }
139
165
  return null;
140
166
  },
141
167
  async transform(src, id) {
142
168
  if (isCustomElement(id)) {
143
- const idParts = path2.parse(id);
169
+ await updateElementMap();
170
+ const idParts = path3.parse(id);
144
171
  const deps = /* @__PURE__ */ new Set();
145
172
  const tagnames = [
146
173
  ...src.matchAll(JSX_ELEMENTS_REGEX),
@@ -166,7 +193,7 @@ function pluginRoot(options) {
166
193
  })
167
194
  );
168
195
  if (importUrls.length > 0) {
169
- const importLines = importUrls.map((url) => `import '${url}';`).join("\n");
196
+ const importLines = importUrls.map((url) => `import '/${url}';`).join("\n");
170
197
  const code = `${src}
171
198
 
172
199
  // autogenerated by root:
@@ -182,28 +209,54 @@ ${importLines}
182
209
  }
183
210
 
184
211
  // src/render/asset-map/dev-asset-map.ts
185
- import path3 from "node:path";
212
+ import path4 from "node:path";
213
+ import { searchForWorkspaceRoot as searchForWorkspaceRoot2 } from "vite";
186
214
  var DevServerAssetMap = class {
187
- constructor(moduleGraph) {
215
+ constructor(rootConfig, moduleGraph) {
216
+ this.rootConfig = rootConfig;
188
217
  this.moduleGraph = moduleGraph;
189
218
  }
190
- async get(moduleId) {
191
- const viteModule = await this.moduleGraph.getModuleByUrl(moduleId);
192
- if (!viteModule || !viteModule.id) {
219
+ async get(src) {
220
+ const file = path4.resolve(this.rootConfig.rootDir, src);
221
+ const viteModules = this.moduleGraph.getModulesByFile(file);
222
+ if (viteModules && viteModules.size > 0) {
223
+ const [viteModule] = viteModules;
224
+ return new DevServerAsset(src, {
225
+ assetMap: this,
226
+ viteModule
227
+ });
228
+ }
229
+ if (file.startsWith(this.rootConfig.rootDir)) {
230
+ const assetUrl = file.slice(this.rootConfig.rootDir.length);
193
231
  return {
194
- moduleId,
195
- assetUrl: moduleId,
232
+ src,
233
+ assetUrl,
196
234
  getCssDeps: async () => [],
197
- getJsDeps: async () => [moduleId]
235
+ getJsDeps: async () => [assetUrl]
198
236
  };
199
237
  }
200
- return new DevServerAsset(this, viteModule);
238
+ const workspaceRoot = searchForWorkspaceRoot2(this.rootConfig.rootDir);
239
+ if (await directoryContains(workspaceRoot, file)) {
240
+ const assetUrl = `/@fs/${file}`;
241
+ return {
242
+ src,
243
+ assetUrl,
244
+ getCssDeps: async () => [],
245
+ getJsDeps: async () => [assetUrl]
246
+ };
247
+ }
248
+ console.log(`could not find asset in asset map: ${src}`);
249
+ return null;
250
+ }
251
+ filePathToSrc(file) {
252
+ return path4.relative(this.rootConfig.rootDir, file);
201
253
  }
202
254
  };
203
255
  var DevServerAsset = class {
204
- constructor(assetMap, viteModule) {
205
- this.assetMap = assetMap;
206
- this.viteModule = viteModule;
256
+ constructor(src, options) {
257
+ this.src = src;
258
+ this.assetMap = options.assetMap;
259
+ this.viteModule = options.viteModule;
207
260
  this.moduleId = this.viteModule.id;
208
261
  this.assetUrl = this.viteModule.url;
209
262
  }
@@ -233,13 +286,17 @@ var DevServerAsset = class {
233
286
  return;
234
287
  }
235
288
  visited.add(asset.moduleId);
236
- const parts = path3.parse(asset.assetUrl);
289
+ const parts = path4.parse(asset.assetUrl);
237
290
  if ([".js", ".jsx", ".ts", ".tsx"].includes(parts.ext) && asset.moduleId.includes("/elements/")) {
238
291
  urls.add(asset.assetUrl);
239
292
  }
240
293
  asset.getImportedModules().forEach((viteModule) => {
241
- if (viteModule.id) {
242
- const importedAsset = new DevServerAsset(this.assetMap, viteModule);
294
+ if (viteModule.file) {
295
+ const src = this.assetMap.filePathToSrc(viteModule.file);
296
+ const importedAsset = new DevServerAsset(src, {
297
+ assetMap: this.assetMap,
298
+ viteModule
299
+ });
243
300
  this.collectJs(importedAsset, urls, visited);
244
301
  }
245
302
  });
@@ -255,15 +312,19 @@ var DevServerAsset = class {
255
312
  return;
256
313
  }
257
314
  visited.add(asset.assetUrl);
258
- if (asset.moduleId.endsWith(".scss")) {
259
- const parts = path3.parse(asset.assetUrl);
315
+ if (asset.src.endsWith(".scss")) {
316
+ const parts = path4.parse(asset.src);
260
317
  if (!parts.name.startsWith("_")) {
261
318
  urls.add(asset.assetUrl);
262
319
  }
263
320
  }
264
321
  asset.getImportedModules().forEach((viteModule) => {
265
- if (viteModule.id) {
266
- const importedAsset = new DevServerAsset(this.assetMap, viteModule);
322
+ if (viteModule.file) {
323
+ const src = this.assetMap.filePathToSrc(viteModule.file);
324
+ const importedAsset = new DevServerAsset(src, {
325
+ assetMap: this.assetMap,
326
+ viteModule
327
+ });
267
328
  this.collectCss(importedAsset, urls, visited);
268
329
  }
269
330
  });
@@ -283,9 +344,9 @@ async function loadRootConfig(rootDir) {
283
344
  const configBundle = await bundleRequire({
284
345
  filepath: configPath
285
346
  });
286
- return configBundle.mod.default || {};
347
+ return Object.assign({}, configBundle.mod.default || {}, { rootDir });
287
348
  }
288
- return {};
349
+ return { rootDir };
289
350
  }
290
351
 
291
352
  // src/render/html-minify.ts
@@ -318,27 +379,66 @@ function rootProjectMiddleware(options) {
318
379
  };
319
380
  }
320
381
 
382
+ // src/cli/ports.ts
383
+ import { createServer } from "node:net";
384
+ function isPortOpen(port) {
385
+ return new Promise((resolve, reject) => {
386
+ const server = createServer();
387
+ server.on("error", (err) => {
388
+ if (err.code === "EADDRINUSE") {
389
+ resolve(false);
390
+ return;
391
+ }
392
+ reject(err);
393
+ });
394
+ server.on("close", () => {
395
+ resolve(true);
396
+ });
397
+ server.listen(port, () => {
398
+ server.close((err) => {
399
+ if (err) {
400
+ console.log(`error closing server: ${err}`);
401
+ reject(err);
402
+ }
403
+ });
404
+ });
405
+ });
406
+ }
407
+ async function findOpenPort(min, max) {
408
+ let port = min;
409
+ while (port <= max) {
410
+ const isOpen = await isPortOpen(port);
411
+ if (isOpen) {
412
+ return port;
413
+ }
414
+ port += 1;
415
+ }
416
+ throw new Error(`no ports open between ${min} and ${max}`);
417
+ }
418
+
321
419
  // src/cli/commands/dev.ts
322
- var __dirname = path4.dirname(fileURLToPath(import.meta.url));
420
+ var __dirname = path5.dirname(fileURLToPath(import.meta.url));
323
421
  async function dev(rootProjectDir) {
324
422
  process.env.NODE_ENV = "development";
325
- const rootDir = path4.resolve(rootProjectDir || process.cwd());
326
- const server = await createServer({ rootDir });
327
- const port = parseInt(process.env.PORT || "4007");
423
+ const rootDir = path5.resolve(rootProjectDir || process.cwd());
424
+ const defaultPort = parseInt(process.env.PORT || "4007");
425
+ const port = await findOpenPort(defaultPort, defaultPort + 10);
328
426
  console.log();
329
427
  console.log(`${dim("\u2503")} project: ${rootDir}`);
330
428
  console.log(`${dim("\u2503")} server: http://localhost:${port}`);
331
429
  console.log(`${dim("\u2503")} mode: development`);
332
430
  console.log();
431
+ const server = await createServer2({ rootDir, port });
333
432
  server.listen(port);
334
433
  }
335
- async function createServer(options) {
336
- const rootDir = path4.resolve((options == null ? void 0 : options.rootDir) || process.cwd());
434
+ async function createServer2(options) {
435
+ const rootDir = path5.resolve((options == null ? void 0 : options.rootDir) || process.cwd());
337
436
  const rootConfig = await loadRootConfig(rootDir);
437
+ const port = options == null ? void 0 : options.port;
338
438
  const server = express();
339
439
  server.disable("x-powered-by");
340
440
  server.use(rootProjectMiddleware({ rootDir, rootConfig }));
341
- server.use(await viteServerMiddleware({ rootDir, rootConfig }));
441
+ server.use(await viteServerMiddleware({ rootDir, rootConfig, port }));
342
442
  server.use(rootDevRendererMiddleware());
343
443
  const plugins = rootConfig.plugins || [];
344
444
  await configureServerPlugins(
@@ -358,56 +458,31 @@ async function createServer(options) {
358
458
  return server;
359
459
  }
360
460
  async function viteServerMiddleware(options) {
361
- var _a, _b, _c;
461
+ var _a, _b;
362
462
  const rootDir = options.rootDir;
363
463
  const rootConfig = options.rootConfig;
364
464
  const viteConfig = rootConfig.vite || {};
465
+ let hmrOptions = (_a = viteConfig.server) == null ? void 0 : _a.hmr;
466
+ if (typeof hmrOptions === "undefined" && options.port) {
467
+ hmrOptions = { port: options.port + 10 };
468
+ }
365
469
  const routeFiles = [];
366
- if (await isDirectory(path4.join(rootDir, "routes"))) {
470
+ if (await isDirectory(path5.join(rootDir, "routes"))) {
367
471
  const pageFiles = await glob2("routes/**/*", { cwd: rootDir });
368
472
  pageFiles.forEach((file) => {
369
- const parts = path4.parse(file);
473
+ const parts = path5.parse(file);
370
474
  if (!parts.name.startsWith("_") && isJsFile(parts.base)) {
371
475
  routeFiles.push(file);
372
476
  }
373
477
  });
374
478
  }
375
- const elementsDirs = [path4.join(rootDir, "elements")];
376
- const elementsInclude = ((_a = rootConfig.elements) == null ? void 0 : _a.include) || [];
377
- const excludePatterns = ((_b = rootConfig.elements) == null ? void 0 : _b.exclude) || [];
378
- const excludeElement = (moduleId) => {
379
- return excludePatterns.some((pattern) => Boolean(moduleId.match(pattern)));
380
- };
381
- for (const dirPath of elementsInclude) {
382
- const elementsDir = path4.resolve(rootDir, dirPath);
383
- if (!elementsDir.startsWith(rootDir)) {
384
- throw new Error(
385
- `the elements dir (${dirPath}) should be relative to the project's root dir (${rootDir})`
386
- );
387
- }
388
- elementsDirs.push(elementsDir);
389
- }
390
- const elements = [];
391
- for (const dirPath of elementsDirs) {
392
- if (await isDirectory(dirPath)) {
393
- const elementFiles = await glob2("**/*", { cwd: dirPath });
394
- elementFiles.forEach((file) => {
395
- const parts = path4.parse(file);
396
- if (isJsFile(parts.base)) {
397
- const fullPath = path4.join(dirPath, file);
398
- const moduleId = fullPath.slice(rootDir.length);
399
- if (!excludeElement(moduleId)) {
400
- elements.push(moduleId.slice(1));
401
- }
402
- }
403
- });
404
- }
405
- }
479
+ const elementsMap = await getElements(rootConfig);
480
+ const elements = Object.values(elementsMap).map((mod) => mod.src);
406
481
  const bundleScripts = [];
407
- if (await isDirectory(path4.join(rootDir, "bundles"))) {
408
- const bundleFiles = await glob2(path4.join(rootDir, "bundles/*"));
482
+ if (await isDirectory(path5.join(rootDir, "bundles"))) {
483
+ const bundleFiles = await glob2("bundles/*", { cwd: rootDir });
409
484
  bundleFiles.forEach((file) => {
410
- const parts = path4.parse(file);
485
+ const parts = path5.parse(file);
411
486
  if (isJsFile(parts.base)) {
412
487
  bundleScripts.push(file);
413
488
  }
@@ -417,10 +492,11 @@ async function viteServerMiddleware(options) {
417
492
  ...viteConfig,
418
493
  mode: "development",
419
494
  root: rootDir,
420
- publicDir: path4.join(rootDir, "public"),
495
+ publicDir: path5.join(rootDir, "public"),
421
496
  server: {
422
497
  ...viteConfig.server || {},
423
- middlewareMode: true
498
+ middlewareMode: true,
499
+ hmr: hmrOptions
424
500
  },
425
501
  appType: "custom",
426
502
  optimizeDeps: {
@@ -429,7 +505,7 @@ async function viteServerMiddleware(options) {
429
505
  ...routeFiles,
430
506
  ...elements,
431
507
  ...bundleScripts,
432
- ...((_c = viteConfig.optimizeDeps) == null ? void 0 : _c.include) || []
508
+ ...((_b = viteConfig.optimizeDeps) == null ? void 0 : _b.include) || []
433
509
  ]
434
510
  },
435
511
  ssr: {
@@ -442,23 +518,23 @@ async function viteServerMiddleware(options) {
442
518
  jsxImportSource: "preact"
443
519
  },
444
520
  plugins: [
445
- pluginRoot({ rootDir, rootConfig }),
521
+ await pluginRoot({ rootConfig }),
446
522
  ...viteConfig.plugins || [],
447
523
  ...getVitePlugins(rootConfig.plugins || [])
448
524
  ]
449
525
  });
450
- return async (req, res, next) => {
526
+ return (req, res, next) => {
451
527
  req.viteServer = viteServer;
452
528
  viteServer.middlewares(req, res, next);
453
529
  };
454
530
  }
455
531
  function rootDevRendererMiddleware() {
456
- const renderModulePath = path4.resolve(__dirname, "./render.js");
532
+ const renderModulePath = path5.resolve(__dirname, "./render.js");
457
533
  return async (req, _, next) => {
458
534
  const rootConfig = req.rootConfig;
459
535
  const viteServer = req.viteServer;
460
536
  const render = await viteServer.ssrLoadModule(renderModulePath);
461
- const assetMap = new DevServerAssetMap(viteServer.moduleGraph);
537
+ const assetMap = new DevServerAssetMap(rootConfig, viteServer.moduleGraph);
462
538
  req.renderer = new render.Renderer(rootConfig, { assetMap });
463
539
  next();
464
540
  };
@@ -501,7 +577,7 @@ function rootDevServerMiddleware() {
501
577
  function rootDevServer404Middleware() {
502
578
  return async (req, res) => {
503
579
  const url = req.originalUrl;
504
- const ext = path4.extname(url);
580
+ const ext = path5.extname(url);
505
581
  const renderer = req.renderer;
506
582
  if (!ext) {
507
583
  const data = await renderer.renderDevServer404();
@@ -514,46 +590,66 @@ function rootDevServer404Middleware() {
514
590
  }
515
591
 
516
592
  // src/cli/commands/build.ts
517
- import path5 from "node:path";
593
+ import path7 from "node:path";
518
594
  import { fileURLToPath as fileURLToPath2 } from "node:url";
519
595
  import fsExtra2 from "fs-extra";
520
596
  import glob3 from "tiny-glob";
521
597
  import { build as viteBuild } from "vite";
522
598
 
523
599
  // src/render/asset-map/build-asset-map.ts
600
+ import fs3 from "node:fs";
601
+ import path6 from "node:path";
524
602
  var BuildAssetMap = class {
525
- constructor() {
526
- this.moduleIdToAsset = /* @__PURE__ */ new Map();
603
+ constructor(rootConfig) {
604
+ this.rootConfig = rootConfig;
605
+ this.srcToAsset = /* @__PURE__ */ new Map();
527
606
  }
528
- async get(moduleId) {
529
- return this.moduleIdToAsset.get(moduleId) || null;
607
+ async get(src) {
608
+ const asset = this.srcToAsset.get(src);
609
+ if (asset) {
610
+ return asset;
611
+ }
612
+ const realSrc = realPathRelativeTo(this.rootConfig.rootDir, src);
613
+ if (realSrc !== src) {
614
+ const asset2 = this.srcToAsset.get(realSrc);
615
+ if (asset2) {
616
+ return asset2;
617
+ }
618
+ }
619
+ console.log(`could not find build asset: ${src}`);
620
+ return null;
530
621
  }
531
622
  add(asset) {
532
- this.moduleIdToAsset.set(asset.moduleId, asset);
623
+ this.srcToAsset.set(asset.src, asset);
533
624
  }
534
625
  toJson() {
535
626
  const result = {};
536
- for (const moduleId of this.moduleIdToAsset.keys()) {
537
- result[moduleId] = this.moduleIdToAsset.get(moduleId).toJson();
627
+ for (const src of this.srcToAsset.keys()) {
628
+ result[src] = this.srcToAsset.get(src).toJson();
538
629
  }
539
630
  return result;
540
631
  }
541
- static fromViteManifest(viteManifest, elementMap) {
542
- const assetMap = new BuildAssetMap();
543
- const elementModuleIds = /* @__PURE__ */ new Set();
544
- Object.values(elementMap).forEach(
545
- (moduleId) => elementModuleIds.add(moduleId)
546
- );
632
+ static fromViteManifest(rootConfig, viteManifest, elementMap) {
633
+ const assetMap = new BuildAssetMap(rootConfig);
634
+ const elementFiles = /* @__PURE__ */ new Set();
635
+ Object.values(elementMap).forEach((elementModule) => {
636
+ elementFiles.add(elementModule.src);
637
+ const realSrc = realPathRelativeTo(
638
+ rootConfig.rootDir,
639
+ elementModule.src
640
+ );
641
+ if (realSrc !== elementModule.src) {
642
+ elementFiles.add(realSrc);
643
+ }
644
+ });
547
645
  Object.keys(viteManifest).forEach((manifestKey) => {
548
- const moduleId = `/${manifestKey}`;
646
+ const src = manifestKey;
549
647
  const manifestChunk = viteManifest[manifestKey];
550
- const isElement = elementModuleIds.has(moduleId);
648
+ const isElement = elementFiles.has(src);
551
649
  const assetData = {
552
- moduleId,
650
+ src,
553
651
  assetUrl: `/${manifestChunk.file}`,
554
- importedModules: (manifestChunk.imports || []).map(
555
- (relPath) => `/${relPath}`
556
- ),
652
+ importedModules: manifestChunk.imports || [],
557
653
  importedCss: (manifestChunk.css || []).map((relPath) => `/${relPath}`),
558
654
  isElement
559
655
  };
@@ -561,8 +657,8 @@ var BuildAssetMap = class {
561
657
  });
562
658
  return assetMap;
563
659
  }
564
- static fromRootManifest(rootManifest) {
565
- const assetMap = new BuildAssetMap();
660
+ static fromRootManifest(rootConfig, rootManifest) {
661
+ const assetMap = new BuildAssetMap(rootConfig);
566
662
  Object.keys(rootManifest).forEach((moduleId) => {
567
663
  const assetData = rootManifest[moduleId];
568
664
  assetMap.add(new BuildAsset(assetMap, assetData));
@@ -570,10 +666,18 @@ var BuildAssetMap = class {
570
666
  return assetMap;
571
667
  }
572
668
  };
669
+ function realPathRelativeTo(rootDir, src) {
670
+ const fullPath = path6.resolve(rootDir, src);
671
+ if (!fs3.existsSync(fullPath)) {
672
+ return src;
673
+ }
674
+ const realpath = fs3.realpathSync(path6.resolve(rootDir, src));
675
+ return path6.relative(rootDir, realpath);
676
+ }
573
677
  var BuildAsset = class {
574
678
  constructor(assetMap, assetData) {
575
679
  this.assetMap = assetMap;
576
- this.moduleId = assetData.moduleId;
680
+ this.src = assetData.src;
577
681
  this.assetUrl = assetData.assetUrl;
578
682
  this.importedModules = assetData.importedModules;
579
683
  this.importedCss = assetData.importedCss;
@@ -595,19 +699,19 @@ var BuildAsset = class {
595
699
  if (!asset) {
596
700
  return;
597
701
  }
598
- if (!asset.moduleId) {
702
+ if (!asset.src) {
599
703
  return;
600
704
  }
601
- if (visited.has(asset.moduleId)) {
705
+ if (visited.has(asset.src)) {
602
706
  return;
603
707
  }
604
- visited.add(asset.moduleId);
708
+ visited.add(asset.src);
605
709
  if (asset.isElement) {
606
710
  urls.add(asset.assetUrl);
607
711
  }
608
712
  await Promise.all(
609
- asset.importedModules.map(async (moduleId) => {
610
- const importedAsset = await this.assetMap.get(moduleId);
713
+ asset.importedModules.map(async (src) => {
714
+ const importedAsset = await this.assetMap.get(src);
611
715
  this.collectJs(importedAsset, urls, visited);
612
716
  })
613
717
  );
@@ -619,10 +723,10 @@ var BuildAsset = class {
619
723
  if (!asset.assetUrl) {
620
724
  return;
621
725
  }
622
- if (visited.has(asset.moduleId)) {
726
+ if (visited.has(asset.src)) {
623
727
  return;
624
728
  }
625
- visited.add(asset.moduleId);
729
+ visited.add(asset.src);
626
730
  if (asset.importedCss) {
627
731
  asset.importedCss.forEach((cssUrl) => urls.add(cssUrl));
628
732
  }
@@ -635,7 +739,7 @@ var BuildAsset = class {
635
739
  }
636
740
  toJson() {
637
741
  return {
638
- moduleId: this.moduleId,
742
+ src: this.src,
639
743
  assetUrl: this.assetUrl,
640
744
  importedModules: this.importedModules,
641
745
  importedCss: this.importedCss,
@@ -646,12 +750,11 @@ var BuildAsset = class {
646
750
 
647
751
  // src/cli/commands/build.ts
648
752
  import { dim as dim2 } from "kleur/colors";
649
- var __dirname2 = path5.dirname(fileURLToPath2(import.meta.url));
753
+ var __dirname2 = path7.dirname(fileURLToPath2(import.meta.url));
650
754
  async function build(rootProjectDir, options) {
651
- var _a, _b;
652
- const rootDir = path5.resolve(rootProjectDir || process.cwd());
755
+ const rootDir = path7.resolve(rootProjectDir || process.cwd());
653
756
  const rootConfig = await loadRootConfig(rootDir);
654
- const distDir = path5.join(rootDir, "dist");
757
+ const distDir = path7.join(rootDir, "dist");
655
758
  const ssrOnly = (options == null ? void 0 : options.ssrOnly) || false;
656
759
  const mode = (options == null ? void 0 : options.mode) || "production";
657
760
  console.log();
@@ -661,62 +764,33 @@ async function build(rootProjectDir, options) {
661
764
  console.log();
662
765
  await rmDir(distDir);
663
766
  await makeDir(distDir);
664
- const pages = [];
665
- if (await isDirectory(path5.join(rootDir, "routes"))) {
666
- const pageFiles = await glob3(path5.join(rootDir, "routes/**/*"));
767
+ const routeFiles = [];
768
+ if (await isDirectory(path7.join(rootDir, "routes"))) {
769
+ const pageFiles = await glob3("routes/**/*", { cwd: rootDir });
667
770
  pageFiles.forEach((file) => {
668
- const parts = path5.parse(file);
771
+ const parts = path7.parse(file);
669
772
  if (!parts.name.startsWith("_") && isJsFile(parts.base)) {
670
- pages.push(file);
773
+ routeFiles.push(path7.resolve(rootDir, file));
671
774
  }
672
775
  });
673
776
  }
674
- const elementsDirs = [path5.join(rootDir, "elements")];
675
- const elementsInclude = ((_a = rootConfig.elements) == null ? void 0 : _a.include) || [];
676
- const excludePatterns = ((_b = rootConfig.elements) == null ? void 0 : _b.exclude) || [];
677
- const excludeElement = (moduleId) => {
678
- return excludePatterns.some((pattern) => Boolean(moduleId.match(pattern)));
679
- };
680
- for (const dirPath of elementsInclude) {
681
- const elementsDir = path5.resolve(rootDir, dirPath);
682
- if (!elementsDir.startsWith(rootDir)) {
683
- throw new Error(
684
- `the elements dir (${dirPath}) should be relative to the project's root dir (${rootDir})`
685
- );
686
- }
687
- elementsDirs.push(elementsDir);
688
- }
689
- const elements = [];
690
- const elementMap = {};
691
- for (const dirPath of elementsDirs) {
692
- if (await isDirectory(dirPath)) {
693
- const elementFiles = await glob3("**/*", { cwd: dirPath });
694
- elementFiles.forEach((file) => {
695
- const parts = path5.parse(file);
696
- if (isJsFile(parts.base)) {
697
- const fullPath = path5.join(dirPath, file);
698
- const moduleId = fullPath.slice(rootDir.length);
699
- if (!excludeElement(moduleId)) {
700
- elements.push(fullPath);
701
- elementMap[parts.name] = moduleId;
702
- }
703
- }
704
- });
705
- }
706
- }
777
+ const elementsMap = await getElements(rootConfig);
778
+ const elements = Object.values(elementsMap).map(
779
+ (mod) => path7.resolve(rootDir, mod.src)
780
+ );
707
781
  const bundleScripts = [];
708
- if (await isDirectory(path5.join(rootDir, "bundles"))) {
709
- const bundleFiles = await glob3(path5.join(rootDir, "bundles/*"));
782
+ if (await isDirectory(path7.join(rootDir, "bundles"))) {
783
+ const bundleFiles = await glob3("bundles/*", { cwd: rootDir });
710
784
  bundleFiles.forEach((file) => {
711
- const parts = path5.parse(file);
785
+ const parts = path7.parse(file);
712
786
  if (isJsFile(parts.base)) {
713
- bundleScripts.push(file);
787
+ bundleScripts.push(path7.resolve(rootDir, file));
714
788
  }
715
789
  });
716
790
  }
717
791
  const viteConfig = rootConfig.vite || {};
718
792
  const vitePlugins = [
719
- pluginRoot({ rootDir, rootConfig }),
793
+ pluginRoot({ rootConfig }),
720
794
  ...viteConfig.plugins || [],
721
795
  ...getVitePlugins(rootConfig.plugins || [])
722
796
  ];
@@ -736,14 +810,14 @@ async function build(rootProjectDir, options) {
736
810
  publicDir: false,
737
811
  build: {
738
812
  rollupOptions: {
739
- input: [path5.resolve(__dirname2, "./render.js")],
813
+ input: [path7.resolve(__dirname2, "./render.js")],
740
814
  output: {
741
815
  format: "esm",
742
816
  chunkFileNames: "chunks/[name].[hash].js",
743
817
  assetFileNames: "assets/[name].[hash][extname]"
744
818
  }
745
819
  },
746
- outDir: path5.join(distDir, "server"),
820
+ outDir: path7.join(distDir, "server"),
747
821
  ssr: true,
748
822
  ssrManifest: false,
749
823
  cssCodeSplit: true,
@@ -761,14 +835,14 @@ async function build(rootProjectDir, options) {
761
835
  publicDir: false,
762
836
  build: {
763
837
  rollupOptions: {
764
- input: [...pages, ...elements, ...bundleScripts],
838
+ input: [...routeFiles, ...elements, ...bundleScripts],
765
839
  output: {
766
840
  format: "esm",
767
841
  chunkFileNames: "chunks/[name].[hash].js",
768
842
  assetFileNames: "assets/[name].[hash][extname]"
769
843
  }
770
844
  },
771
- outDir: path5.join(distDir, "client"),
845
+ outDir: path7.join(distDir, "client"),
772
846
  ssr: false,
773
847
  ssrManifest: false,
774
848
  manifest: true,
@@ -780,24 +854,28 @@ async function build(rootProjectDir, options) {
780
854
  }
781
855
  });
782
856
  const viteManifest = await loadJson(
783
- path5.join(distDir, "client/manifest.json")
857
+ path7.join(distDir, "client/manifest.json")
858
+ );
859
+ const assetMap = BuildAssetMap.fromViteManifest(
860
+ rootConfig,
861
+ viteManifest,
862
+ elementsMap
784
863
  );
785
- const assetMap = BuildAssetMap.fromViteManifest(viteManifest, elementMap);
786
864
  writeFile(
787
- path5.join(distDir, "client/root-manifest.json"),
865
+ path7.join(distDir, "client/root-manifest.json"),
788
866
  JSON.stringify(assetMap.toJson(), null, 2)
789
867
  );
790
- const buildDir = path5.join(distDir, "html");
791
- const publicDir = path5.join(rootDir, "public");
792
- if (fsExtra2.existsSync(path5.join(rootDir, "public"))) {
868
+ const buildDir = path7.join(distDir, "html");
869
+ const publicDir = path7.join(rootDir, "public");
870
+ if (fsExtra2.existsSync(path7.join(rootDir, "public"))) {
793
871
  fsExtra2.copySync(publicDir, buildDir);
794
872
  } else {
795
873
  makeDir(buildDir);
796
874
  }
797
- copyDir(path5.join(distDir, "client/assets"), path5.join(buildDir, "assets"));
798
- copyDir(path5.join(distDir, "client/chunks"), path5.join(buildDir, "chunks"));
875
+ copyDir(path7.join(distDir, "client/assets"), path7.join(buildDir, "assets"));
876
+ copyDir(path7.join(distDir, "client/chunks"), path7.join(buildDir, "chunks"));
799
877
  if (!ssrOnly) {
800
- const render = await import(path5.join(distDir, "server/render.js"));
878
+ const render = await import(path7.join(distDir, "server/render.js"));
801
879
  const renderer = new render.Renderer(rootConfig, { assetMap });
802
880
  const sitemap = await renderer.getSitemap();
803
881
  await Promise.all(
@@ -806,13 +884,13 @@ async function build(rootProjectDir, options) {
806
884
  const data = await renderer.renderRoute(route, {
807
885
  routeParams: params
808
886
  });
809
- let outPath = path5.join(distDir, `html${urlPath}`, "index.html");
887
+ let outPath = path7.join(distDir, `html${urlPath}`, "index.html");
810
888
  if (outPath.endsWith("404/index.html")) {
811
889
  outPath = outPath.replace("404/index.html", "404.html");
812
890
  }
813
891
  const html = await htmlMinify(data.html || "");
814
892
  await writeFile(outPath, html);
815
- const relPath = outPath.slice(path5.dirname(distDir).length + 1);
893
+ const relPath = outPath.slice(path7.dirname(distDir).length + 1);
816
894
  console.log(`saved ${relPath}`);
817
895
  })
818
896
  );
@@ -820,15 +898,15 @@ async function build(rootProjectDir, options) {
820
898
  }
821
899
 
822
900
  // src/cli/commands/preview.ts
823
- import path6 from "node:path";
901
+ import path8 from "node:path";
824
902
  import { default as express2 } from "express";
825
903
  import { dim as dim3 } from "kleur/colors";
826
904
  import sirv from "sirv";
827
905
  import compression from "compression";
828
906
  async function preview(rootProjectDir) {
829
907
  process.env.NODE_ENV = "development";
830
- const rootDir = path6.resolve(rootProjectDir || process.cwd());
831
- const server = await createServer2({ rootDir });
908
+ const rootDir = path8.resolve(rootProjectDir || process.cwd());
909
+ const server = await createServer3({ rootDir });
832
910
  const port = parseInt(process.env.PORT || "4007");
833
911
  console.log();
834
912
  console.log(`${dim3("\u2503")} project: ${rootDir}`);
@@ -837,10 +915,10 @@ async function preview(rootProjectDir) {
837
915
  console.log();
838
916
  server.listen(port);
839
917
  }
840
- async function createServer2(options) {
918
+ async function createServer3(options) {
841
919
  const rootDir = options.rootDir;
842
920
  const rootConfig = await loadRootConfig(rootDir);
843
- const distDir = path6.join(rootDir, "dist");
921
+ const distDir = path8.join(rootDir, "dist");
844
922
  const server = express2();
845
923
  server.disable("x-powered-by");
846
924
  server.use(compression());
@@ -855,7 +933,7 @@ async function createServer2(options) {
855
933
  userMiddlewares.forEach((middleware) => {
856
934
  server.use(middleware);
857
935
  });
858
- const publicDir = path6.join(distDir, "html");
936
+ const publicDir = path8.join(distDir, "html");
859
937
  server.use(sirv(publicDir, { dev: false }));
860
938
  server.use(rootPreviewServerMiddleware());
861
939
  },
@@ -866,15 +944,15 @@ async function createServer2(options) {
866
944
  }
867
945
  async function rootPreviewRendererMiddleware(options) {
868
946
  const { distDir, rootConfig } = options;
869
- const render = await import(path6.join(distDir, "server/render.js"));
870
- const manifestPath = path6.join(distDir, "client/root-manifest.json");
947
+ const render = await import(path8.join(distDir, "server/render.js"));
948
+ const manifestPath = path8.join(distDir, "client/root-manifest.json");
871
949
  if (!await fileExists(manifestPath)) {
872
950
  throw new Error(
873
951
  `could not find ${manifestPath}. run \`root build\` before \`root preview\`.`
874
952
  );
875
953
  }
876
954
  const rootManifest = await loadJson(manifestPath);
877
- const assetMap = BuildAssetMap.fromRootManifest(rootManifest);
955
+ const assetMap = BuildAssetMap.fromRootManifest(rootConfig, rootManifest);
878
956
  const renderer = new render.Renderer(rootConfig, { assetMap });
879
957
  return async (req, _, next) => {
880
958
  req.renderer = renderer;
@@ -911,15 +989,15 @@ function rootPreviewServerMiddleware() {
911
989
  }
912
990
 
913
991
  // src/cli/commands/start.ts
914
- import path7 from "node:path";
992
+ import path9 from "node:path";
915
993
  import { default as express3 } from "express";
916
994
  import { dim as dim4 } from "kleur/colors";
917
995
  import sirv2 from "sirv";
918
996
  import compression2 from "compression";
919
997
  async function start(rootProjectDir) {
920
998
  process.env.NODE_ENV = "production";
921
- const rootDir = path7.resolve(rootProjectDir || process.cwd());
922
- const server = await createServer3({ rootDir });
999
+ const rootDir = path9.resolve(rootProjectDir || process.cwd());
1000
+ const server = await createServer4({ rootDir });
923
1001
  const port = parseInt(process.env.PORT || "4007");
924
1002
  console.log();
925
1003
  console.log(`${dim4("\u2503")} project: ${rootDir}`);
@@ -928,10 +1006,10 @@ async function start(rootProjectDir) {
928
1006
  console.log();
929
1007
  server.listen(port);
930
1008
  }
931
- async function createServer3(options) {
1009
+ async function createServer4(options) {
932
1010
  const rootDir = options.rootDir;
933
1011
  const rootConfig = await loadRootConfig(rootDir);
934
- const distDir = path7.join(rootDir, "dist");
1012
+ const distDir = path9.join(rootDir, "dist");
935
1013
  const server = express3();
936
1014
  server.disable("x-powered-by");
937
1015
  server.use(compression2());
@@ -946,7 +1024,7 @@ async function createServer3(options) {
946
1024
  userMiddlewares.forEach((middleware) => {
947
1025
  server.use(middleware);
948
1026
  });
949
- const publicDir = path7.join(distDir, "html");
1027
+ const publicDir = path9.join(distDir, "html");
950
1028
  server.use(sirv2(publicDir, { dev: false }));
951
1029
  server.use(rootProdServerMiddleware());
952
1030
  },
@@ -957,15 +1035,15 @@ async function createServer3(options) {
957
1035
  }
958
1036
  async function rootProdRendererMiddleware(options) {
959
1037
  const { distDir, rootConfig } = options;
960
- const render = await import(path7.join(distDir, "server/render.js"));
961
- const manifestPath = path7.join(distDir, "client/root-manifest.json");
1038
+ const render = await import(path9.join(distDir, "server/render.js"));
1039
+ const manifestPath = path9.join(distDir, "client/root-manifest.json");
962
1040
  if (!await fileExists(manifestPath)) {
963
1041
  throw new Error(
964
1042
  `could not find ${manifestPath}. run \`root build\` before \`root preview\`.`
965
1043
  );
966
1044
  }
967
1045
  const rootManifest = await loadJson(manifestPath);
968
- const assetMap = BuildAssetMap.fromRootManifest(rootManifest);
1046
+ const assetMap = BuildAssetMap.fromRootManifest(rootConfig, rootManifest);
969
1047
  const renderer = new render.Renderer(rootConfig, { assetMap });
970
1048
  return async (req, _, next) => {
971
1049
  req.renderer = renderer;