@blinkk/root 1.0.0-alpha.13 → 1.0.0-alpha.15

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,84 @@ 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
+ async 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
  }
134
+ await updateElementMap();
109
135
  async function getElementImport(tagname) {
110
- if (!elementMap) {
136
+ if (!tagNameToElement) {
111
137
  await updateElementMap();
112
138
  }
113
- if (tagname in elementMap) {
114
- return elementMap[tagname];
139
+ if (tagname in tagNameToElement) {
140
+ const elementModule = tagNameToElement[tagname];
141
+ if (elementModule.filePath === elementModule.realPath) {
142
+ return elementModule.src;
143
+ }
115
144
  }
116
145
  return null;
117
146
  }
@@ -119,9 +148,7 @@ function pluginRoot(options) {
119
148
  if (!isJsFile(id)) {
120
149
  return false;
121
150
  }
122
- return elementsDirs.some((elementsDir) => {
123
- return id.startsWith(elementsDir);
124
- });
151
+ return customElementFiles.has(id);
125
152
  }
126
153
  return {
127
154
  name: "vite-plugin-root",
@@ -134,13 +161,13 @@ function pluginRoot(options) {
134
161
  async load(id) {
135
162
  if (id === resolvedElementsVirtualId) {
136
163
  await updateElementMap();
137
- return `export const elementsMap = ${JSON.stringify(elementMap)}`;
164
+ return `export const elementsMap = ${JSON.stringify(tagNameToElement)}`;
138
165
  }
139
166
  return null;
140
167
  },
141
168
  async transform(src, id) {
142
169
  if (isCustomElement(id)) {
143
- const idParts = path2.parse(id);
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);
231
+ return {
232
+ src,
233
+ assetUrl,
234
+ getCssDeps: async () => [],
235
+ getJsDeps: async () => [assetUrl]
236
+ };
237
+ }
238
+ const workspaceRoot = searchForWorkspaceRoot2(this.rootConfig.rootDir);
239
+ if (await directoryContains(workspaceRoot, file)) {
240
+ const assetUrl = `/@fs/${file}`;
193
241
  return {
194
- moduleId,
195
- assetUrl: moduleId,
242
+ src,
243
+ assetUrl,
196
244
  getCssDeps: async () => [],
197
- getJsDeps: async () => [moduleId]
245
+ getJsDeps: async () => [assetUrl]
198
246
  };
199
247
  }
200
- return new DevServerAsset(this, viteModule);
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,102 +458,83 @@ 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
  }
414
489
  });
415
490
  }
416
- const vitePlugins = [
417
- pluginRoot({ rootDir, rootConfig }),
418
- ...viteConfig.plugins || [],
419
- ...getVitePlugins(rootConfig.plugins || [])
420
- ];
421
491
  const viteServer = await createViteServer({
422
492
  ...viteConfig,
423
493
  mode: "development",
424
494
  root: rootDir,
425
- publicDir: path4.join(rootDir, "public"),
426
- server: { middlewareMode: true },
495
+ publicDir: path5.join(rootDir, "public"),
496
+ server: {
497
+ ...viteConfig.server || {},
498
+ middlewareMode: true,
499
+ hmr: hmrOptions
500
+ },
427
501
  appType: "custom",
428
502
  optimizeDeps: {
503
+ ...viteConfig.optimizeDeps || {},
429
504
  include: [
430
505
  ...routeFiles,
431
506
  ...elements,
432
507
  ...bundleScripts,
433
- ...((_c = viteConfig.optimizeDeps) == null ? void 0 : _c.include) || []
508
+ ...((_b = viteConfig.optimizeDeps) == null ? void 0 : _b.include) || []
434
509
  ]
435
510
  },
436
511
  ssr: {
512
+ ...viteConfig.ssr || {},
437
513
  noExternal: ["@blinkk/root"]
438
514
  },
439
515
  esbuild: {
516
+ ...viteConfig.esbuild || {},
440
517
  jsx: "automatic",
441
518
  jsxImportSource: "preact"
442
519
  },
443
- plugins: vitePlugins
520
+ plugins: [
521
+ pluginRoot({ rootConfig }),
522
+ ...viteConfig.plugins || [],
523
+ ...getVitePlugins(rootConfig.plugins || [])
524
+ ]
444
525
  });
445
- return async (req, res, next) => {
526
+ return (req, res, next) => {
446
527
  req.viteServer = viteServer;
447
528
  viteServer.middlewares(req, res, next);
448
529
  };
449
530
  }
450
531
  function rootDevRendererMiddleware() {
451
- const renderModulePath = path4.resolve(__dirname, "./render.js");
532
+ const renderModulePath = path5.resolve(__dirname, "./render.js");
452
533
  return async (req, _, next) => {
453
534
  const rootConfig = req.rootConfig;
454
535
  const viteServer = req.viteServer;
455
536
  const render = await viteServer.ssrLoadModule(renderModulePath);
456
- const assetMap = new DevServerAssetMap(viteServer.moduleGraph);
537
+ const assetMap = new DevServerAssetMap(rootConfig, viteServer.moduleGraph);
457
538
  req.renderer = new render.Renderer(rootConfig, { assetMap });
458
539
  next();
459
540
  };
@@ -496,7 +577,7 @@ function rootDevServerMiddleware() {
496
577
  function rootDevServer404Middleware() {
497
578
  return async (req, res) => {
498
579
  const url = req.originalUrl;
499
- const ext = path4.extname(url);
580
+ const ext = path5.extname(url);
500
581
  const renderer = req.renderer;
501
582
  if (!ext) {
502
583
  const data = await renderer.renderDevServer404();
@@ -509,7 +590,7 @@ function rootDevServer404Middleware() {
509
590
  }
510
591
 
511
592
  // src/cli/commands/build.ts
512
- import path5 from "node:path";
593
+ import path6 from "node:path";
513
594
  import { fileURLToPath as fileURLToPath2 } from "node:url";
514
595
  import fsExtra2 from "fs-extra";
515
596
  import glob3 from "tiny-glob";
@@ -518,37 +599,40 @@ import { build as viteBuild } from "vite";
518
599
  // src/render/asset-map/build-asset-map.ts
519
600
  var BuildAssetMap = class {
520
601
  constructor() {
521
- this.moduleIdToAsset = /* @__PURE__ */ new Map();
602
+ this.srcToAsset = /* @__PURE__ */ new Map();
522
603
  }
523
- async get(moduleId) {
524
- return this.moduleIdToAsset.get(moduleId) || null;
604
+ async get(src) {
605
+ const asset = this.srcToAsset.get(src);
606
+ if (asset) {
607
+ return asset;
608
+ }
609
+ console.log(`could not find build asset: ${src}`);
610
+ return null;
525
611
  }
526
612
  add(asset) {
527
- this.moduleIdToAsset.set(asset.moduleId, asset);
613
+ this.srcToAsset.set(asset.src, asset);
528
614
  }
529
615
  toJson() {
530
616
  const result = {};
531
- for (const moduleId of this.moduleIdToAsset.keys()) {
532
- result[moduleId] = this.moduleIdToAsset.get(moduleId).toJson();
617
+ for (const src of this.srcToAsset.keys()) {
618
+ result[src] = this.srcToAsset.get(src).toJson();
533
619
  }
534
620
  return result;
535
621
  }
536
622
  static fromViteManifest(viteManifest, elementMap) {
537
623
  const assetMap = new BuildAssetMap();
538
- const elementModuleIds = /* @__PURE__ */ new Set();
624
+ const elementFiles = /* @__PURE__ */ new Set();
539
625
  Object.values(elementMap).forEach(
540
- (moduleId) => elementModuleIds.add(moduleId)
626
+ (elementModule) => elementFiles.add(elementModule.src)
541
627
  );
542
628
  Object.keys(viteManifest).forEach((manifestKey) => {
543
- const moduleId = `/${manifestKey}`;
629
+ const src = manifestKey;
544
630
  const manifestChunk = viteManifest[manifestKey];
545
- const isElement = elementModuleIds.has(moduleId);
631
+ const isElement = elementFiles.has(src);
546
632
  const assetData = {
547
- moduleId,
633
+ src,
548
634
  assetUrl: `/${manifestChunk.file}`,
549
- importedModules: (manifestChunk.imports || []).map(
550
- (relPath) => `/${relPath}`
551
- ),
635
+ importedModules: manifestChunk.imports || [],
552
636
  importedCss: (manifestChunk.css || []).map((relPath) => `/${relPath}`),
553
637
  isElement
554
638
  };
@@ -568,7 +652,7 @@ var BuildAssetMap = class {
568
652
  var BuildAsset = class {
569
653
  constructor(assetMap, assetData) {
570
654
  this.assetMap = assetMap;
571
- this.moduleId = assetData.moduleId;
655
+ this.src = assetData.src;
572
656
  this.assetUrl = assetData.assetUrl;
573
657
  this.importedModules = assetData.importedModules;
574
658
  this.importedCss = assetData.importedCss;
@@ -590,19 +674,19 @@ var BuildAsset = class {
590
674
  if (!asset) {
591
675
  return;
592
676
  }
593
- if (!asset.moduleId) {
677
+ if (!asset.src) {
594
678
  return;
595
679
  }
596
- if (visited.has(asset.moduleId)) {
680
+ if (visited.has(asset.src)) {
597
681
  return;
598
682
  }
599
- visited.add(asset.moduleId);
683
+ visited.add(asset.src);
600
684
  if (asset.isElement) {
601
685
  urls.add(asset.assetUrl);
602
686
  }
603
687
  await Promise.all(
604
- asset.importedModules.map(async (moduleId) => {
605
- const importedAsset = await this.assetMap.get(moduleId);
688
+ asset.importedModules.map(async (src) => {
689
+ const importedAsset = await this.assetMap.get(src);
606
690
  this.collectJs(importedAsset, urls, visited);
607
691
  })
608
692
  );
@@ -614,10 +698,10 @@ var BuildAsset = class {
614
698
  if (!asset.assetUrl) {
615
699
  return;
616
700
  }
617
- if (visited.has(asset.moduleId)) {
701
+ if (visited.has(asset.src)) {
618
702
  return;
619
703
  }
620
- visited.add(asset.moduleId);
704
+ visited.add(asset.src);
621
705
  if (asset.importedCss) {
622
706
  asset.importedCss.forEach((cssUrl) => urls.add(cssUrl));
623
707
  }
@@ -630,7 +714,7 @@ var BuildAsset = class {
630
714
  }
631
715
  toJson() {
632
716
  return {
633
- moduleId: this.moduleId,
717
+ src: this.src,
634
718
  assetUrl: this.assetUrl,
635
719
  importedModules: this.importedModules,
636
720
  importedCss: this.importedCss,
@@ -641,12 +725,11 @@ var BuildAsset = class {
641
725
 
642
726
  // src/cli/commands/build.ts
643
727
  import { dim as dim2 } from "kleur/colors";
644
- var __dirname2 = path5.dirname(fileURLToPath2(import.meta.url));
728
+ var __dirname2 = path6.dirname(fileURLToPath2(import.meta.url));
645
729
  async function build(rootProjectDir, options) {
646
- var _a, _b;
647
- const rootDir = path5.resolve(rootProjectDir || process.cwd());
730
+ const rootDir = path6.resolve(rootProjectDir || process.cwd());
648
731
  const rootConfig = await loadRootConfig(rootDir);
649
- const distDir = path5.join(rootDir, "dist");
732
+ const distDir = path6.join(rootDir, "dist");
650
733
  const ssrOnly = (options == null ? void 0 : options.ssrOnly) || false;
651
734
  const mode = (options == null ? void 0 : options.mode) || "production";
652
735
  console.log();
@@ -656,62 +739,33 @@ async function build(rootProjectDir, options) {
656
739
  console.log();
657
740
  await rmDir(distDir);
658
741
  await makeDir(distDir);
659
- const pages = [];
660
- if (await isDirectory(path5.join(rootDir, "routes"))) {
661
- const pageFiles = await glob3(path5.join(rootDir, "routes/**/*"));
742
+ const routeFiles = [];
743
+ if (await isDirectory(path6.join(rootDir, "routes"))) {
744
+ const pageFiles = await glob3("routes/**/*", { cwd: rootDir });
662
745
  pageFiles.forEach((file) => {
663
- const parts = path5.parse(file);
746
+ const parts = path6.parse(file);
664
747
  if (!parts.name.startsWith("_") && isJsFile(parts.base)) {
665
- pages.push(file);
748
+ routeFiles.push(path6.resolve(rootDir, file));
666
749
  }
667
750
  });
668
751
  }
669
- const elementsDirs = [path5.join(rootDir, "elements")];
670
- const elementsInclude = ((_a = rootConfig.elements) == null ? void 0 : _a.include) || [];
671
- const excludePatterns = ((_b = rootConfig.elements) == null ? void 0 : _b.exclude) || [];
672
- const excludeElement = (moduleId) => {
673
- return excludePatterns.some((pattern) => Boolean(moduleId.match(pattern)));
674
- };
675
- for (const dirPath of elementsInclude) {
676
- const elementsDir = path5.resolve(rootDir, dirPath);
677
- if (!elementsDir.startsWith(rootDir)) {
678
- throw new Error(
679
- `the elements dir (${dirPath}) should be relative to the project's root dir (${rootDir})`
680
- );
681
- }
682
- elementsDirs.push(elementsDir);
683
- }
684
- const elements = [];
685
- const elementMap = {};
686
- for (const dirPath of elementsDirs) {
687
- if (await isDirectory(dirPath)) {
688
- const elementFiles = await glob3("**/*", { cwd: dirPath });
689
- elementFiles.forEach((file) => {
690
- const parts = path5.parse(file);
691
- if (isJsFile(parts.base)) {
692
- const fullPath = path5.join(dirPath, file);
693
- const moduleId = fullPath.slice(rootDir.length);
694
- if (!excludeElement(moduleId)) {
695
- elements.push(fullPath);
696
- elementMap[parts.name] = moduleId;
697
- }
698
- }
699
- });
700
- }
701
- }
752
+ const elementsMap = await getElements(rootConfig);
753
+ const elements = Object.values(elementsMap).map(
754
+ (mod) => path6.resolve(rootDir, mod.src)
755
+ );
702
756
  const bundleScripts = [];
703
- if (await isDirectory(path5.join(rootDir, "bundles"))) {
704
- const bundleFiles = await glob3(path5.join(rootDir, "bundles/*"));
757
+ if (await isDirectory(path6.join(rootDir, "bundles"))) {
758
+ const bundleFiles = await glob3("bundles/*", { cwd: rootDir });
705
759
  bundleFiles.forEach((file) => {
706
- const parts = path5.parse(file);
760
+ const parts = path6.parse(file);
707
761
  if (isJsFile(parts.base)) {
708
- bundleScripts.push(file);
762
+ bundleScripts.push(path6.resolve(rootDir, file));
709
763
  }
710
764
  });
711
765
  }
712
766
  const viteConfig = rootConfig.vite || {};
713
767
  const vitePlugins = [
714
- pluginRoot({ rootDir, rootConfig }),
768
+ pluginRoot({ rootConfig }),
715
769
  ...viteConfig.plugins || [],
716
770
  ...getVitePlugins(rootConfig.plugins || [])
717
771
  ];
@@ -731,14 +785,14 @@ async function build(rootProjectDir, options) {
731
785
  publicDir: false,
732
786
  build: {
733
787
  rollupOptions: {
734
- input: [path5.resolve(__dirname2, "./render.js")],
788
+ input: [path6.resolve(__dirname2, "./render.js")],
735
789
  output: {
736
790
  format: "esm",
737
791
  chunkFileNames: "chunks/[name].[hash].js",
738
792
  assetFileNames: "assets/[name].[hash][extname]"
739
793
  }
740
794
  },
741
- outDir: path5.join(distDir, "server"),
795
+ outDir: path6.join(distDir, "server"),
742
796
  ssr: true,
743
797
  ssrManifest: false,
744
798
  cssCodeSplit: true,
@@ -756,14 +810,14 @@ async function build(rootProjectDir, options) {
756
810
  publicDir: false,
757
811
  build: {
758
812
  rollupOptions: {
759
- input: [...pages, ...elements, ...bundleScripts],
813
+ input: [...routeFiles, ...elements, ...bundleScripts],
760
814
  output: {
761
815
  format: "esm",
762
816
  chunkFileNames: "chunks/[name].[hash].js",
763
817
  assetFileNames: "assets/[name].[hash][extname]"
764
818
  }
765
819
  },
766
- outDir: path5.join(distDir, "client"),
820
+ outDir: path6.join(distDir, "client"),
767
821
  ssr: false,
768
822
  ssrManifest: false,
769
823
  manifest: true,
@@ -775,24 +829,24 @@ async function build(rootProjectDir, options) {
775
829
  }
776
830
  });
777
831
  const viteManifest = await loadJson(
778
- path5.join(distDir, "client/manifest.json")
832
+ path6.join(distDir, "client/manifest.json")
779
833
  );
780
- const assetMap = BuildAssetMap.fromViteManifest(viteManifest, elementMap);
834
+ const assetMap = BuildAssetMap.fromViteManifest(viteManifest, elementsMap);
781
835
  writeFile(
782
- path5.join(distDir, "client/root-manifest.json"),
836
+ path6.join(distDir, "client/root-manifest.json"),
783
837
  JSON.stringify(assetMap.toJson(), null, 2)
784
838
  );
785
- const buildDir = path5.join(distDir, "html");
786
- const publicDir = path5.join(rootDir, "public");
787
- if (fsExtra2.existsSync(path5.join(rootDir, "public"))) {
839
+ const buildDir = path6.join(distDir, "html");
840
+ const publicDir = path6.join(rootDir, "public");
841
+ if (fsExtra2.existsSync(path6.join(rootDir, "public"))) {
788
842
  fsExtra2.copySync(publicDir, buildDir);
789
843
  } else {
790
844
  makeDir(buildDir);
791
845
  }
792
- copyDir(path5.join(distDir, "client/assets"), path5.join(buildDir, "assets"));
793
- copyDir(path5.join(distDir, "client/chunks"), path5.join(buildDir, "chunks"));
846
+ copyDir(path6.join(distDir, "client/assets"), path6.join(buildDir, "assets"));
847
+ copyDir(path6.join(distDir, "client/chunks"), path6.join(buildDir, "chunks"));
794
848
  if (!ssrOnly) {
795
- const render = await import(path5.join(distDir, "server/render.js"));
849
+ const render = await import(path6.join(distDir, "server/render.js"));
796
850
  const renderer = new render.Renderer(rootConfig, { assetMap });
797
851
  const sitemap = await renderer.getSitemap();
798
852
  await Promise.all(
@@ -801,13 +855,13 @@ async function build(rootProjectDir, options) {
801
855
  const data = await renderer.renderRoute(route, {
802
856
  routeParams: params
803
857
  });
804
- let outPath = path5.join(distDir, `html${urlPath}`, "index.html");
858
+ let outPath = path6.join(distDir, `html${urlPath}`, "index.html");
805
859
  if (outPath.endsWith("404/index.html")) {
806
860
  outPath = outPath.replace("404/index.html", "404.html");
807
861
  }
808
862
  const html = await htmlMinify(data.html || "");
809
863
  await writeFile(outPath, html);
810
- const relPath = outPath.slice(path5.dirname(distDir).length + 1);
864
+ const relPath = outPath.slice(path6.dirname(distDir).length + 1);
811
865
  console.log(`saved ${relPath}`);
812
866
  })
813
867
  );
@@ -815,15 +869,15 @@ async function build(rootProjectDir, options) {
815
869
  }
816
870
 
817
871
  // src/cli/commands/preview.ts
818
- import path6 from "node:path";
872
+ import path7 from "node:path";
819
873
  import { default as express2 } from "express";
820
874
  import { dim as dim3 } from "kleur/colors";
821
875
  import sirv from "sirv";
822
876
  import compression from "compression";
823
877
  async function preview(rootProjectDir) {
824
878
  process.env.NODE_ENV = "development";
825
- const rootDir = path6.resolve(rootProjectDir || process.cwd());
826
- const server = await createServer2({ rootDir });
879
+ const rootDir = path7.resolve(rootProjectDir || process.cwd());
880
+ const server = await createServer3({ rootDir });
827
881
  const port = parseInt(process.env.PORT || "4007");
828
882
  console.log();
829
883
  console.log(`${dim3("\u2503")} project: ${rootDir}`);
@@ -832,10 +886,10 @@ async function preview(rootProjectDir) {
832
886
  console.log();
833
887
  server.listen(port);
834
888
  }
835
- async function createServer2(options) {
889
+ async function createServer3(options) {
836
890
  const rootDir = options.rootDir;
837
891
  const rootConfig = await loadRootConfig(rootDir);
838
- const distDir = path6.join(rootDir, "dist");
892
+ const distDir = path7.join(rootDir, "dist");
839
893
  const server = express2();
840
894
  server.disable("x-powered-by");
841
895
  server.use(compression());
@@ -850,7 +904,7 @@ async function createServer2(options) {
850
904
  userMiddlewares.forEach((middleware) => {
851
905
  server.use(middleware);
852
906
  });
853
- const publicDir = path6.join(distDir, "html");
907
+ const publicDir = path7.join(distDir, "html");
854
908
  server.use(sirv(publicDir, { dev: false }));
855
909
  server.use(rootPreviewServerMiddleware());
856
910
  },
@@ -861,8 +915,8 @@ async function createServer2(options) {
861
915
  }
862
916
  async function rootPreviewRendererMiddleware(options) {
863
917
  const { distDir, rootConfig } = options;
864
- const render = await import(path6.join(distDir, "server/render.js"));
865
- const manifestPath = path6.join(distDir, "client/root-manifest.json");
918
+ const render = await import(path7.join(distDir, "server/render.js"));
919
+ const manifestPath = path7.join(distDir, "client/root-manifest.json");
866
920
  if (!await fileExists(manifestPath)) {
867
921
  throw new Error(
868
922
  `could not find ${manifestPath}. run \`root build\` before \`root preview\`.`
@@ -906,15 +960,15 @@ function rootPreviewServerMiddleware() {
906
960
  }
907
961
 
908
962
  // src/cli/commands/start.ts
909
- import path7 from "node:path";
963
+ import path8 from "node:path";
910
964
  import { default as express3 } from "express";
911
965
  import { dim as dim4 } from "kleur/colors";
912
966
  import sirv2 from "sirv";
913
967
  import compression2 from "compression";
914
968
  async function start(rootProjectDir) {
915
969
  process.env.NODE_ENV = "production";
916
- const rootDir = path7.resolve(rootProjectDir || process.cwd());
917
- const server = await createServer3({ rootDir });
970
+ const rootDir = path8.resolve(rootProjectDir || process.cwd());
971
+ const server = await createServer4({ rootDir });
918
972
  const port = parseInt(process.env.PORT || "4007");
919
973
  console.log();
920
974
  console.log(`${dim4("\u2503")} project: ${rootDir}`);
@@ -923,10 +977,10 @@ async function start(rootProjectDir) {
923
977
  console.log();
924
978
  server.listen(port);
925
979
  }
926
- async function createServer3(options) {
980
+ async function createServer4(options) {
927
981
  const rootDir = options.rootDir;
928
982
  const rootConfig = await loadRootConfig(rootDir);
929
- const distDir = path7.join(rootDir, "dist");
983
+ const distDir = path8.join(rootDir, "dist");
930
984
  const server = express3();
931
985
  server.disable("x-powered-by");
932
986
  server.use(compression2());
@@ -941,7 +995,7 @@ async function createServer3(options) {
941
995
  userMiddlewares.forEach((middleware) => {
942
996
  server.use(middleware);
943
997
  });
944
- const publicDir = path7.join(distDir, "html");
998
+ const publicDir = path8.join(distDir, "html");
945
999
  server.use(sirv2(publicDir, { dev: false }));
946
1000
  server.use(rootProdServerMiddleware());
947
1001
  },
@@ -952,8 +1006,8 @@ async function createServer3(options) {
952
1006
  }
953
1007
  async function rootProdRendererMiddleware(options) {
954
1008
  const { distDir, rootConfig } = options;
955
- const render = await import(path7.join(distDir, "server/render.js"));
956
- const manifestPath = path7.join(distDir, "client/root-manifest.json");
1009
+ const render = await import(path8.join(distDir, "server/render.js"));
1010
+ const manifestPath = path8.join(distDir, "client/root-manifest.json");
957
1011
  if (!await fileExists(manifestPath)) {
958
1012
  throw new Error(
959
1013
  `could not find ${manifestPath}. run \`root build\` before \`root preview\`.`