rari 0.5.15 → 0.5.17

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/client.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { C as fetchWithTimeout, S as createNavigationError, _ as LayoutErrorBoundary, a as LoadingSpinner, b as NavigationErrorOverlay, c as createHttpRuntimeClient, d as clearPropsCacheForComponent, f as extractMetadata, g as hasServerSideDataFetching, h as extractStaticParams, i as HttpRuntimeClient, l as createLoadingBoundary, m as extractServerPropsWithCache, n as DefaultLoading, o as NotFound, p as extractServerProps, r as ErrorBoundary, s as createErrorBoundary, t as DefaultError, u as clearPropsCache, v as ClientRouter, w as LayoutManager, x as NavigationErrorHandler, y as StatePreserver } from "./runtime-client-AtnJSL0q.mjs";
1
+ import { C as fetchWithTimeout, S as createNavigationError, _ as LayoutErrorBoundary, a as LoadingSpinner, b as NavigationErrorOverlay, c as createHttpRuntimeClient, d as clearPropsCacheForComponent, f as extractMetadata, g as hasServerSideDataFetching, h as extractStaticParams, i as HttpRuntimeClient, l as createLoadingBoundary, m as extractServerPropsWithCache, n as DefaultLoading, o as NotFound, p as extractServerProps, r as ErrorBoundary, s as createErrorBoundary, t as DefaultError, u as clearPropsCache, v as ClientRouter, w as LayoutManager, x as NavigationErrorHandler, y as StatePreserver } from "./runtime-client-DCkfDJpL.mjs";
2
2
 
3
3
  export { ClientRouter, DefaultError, DefaultLoading, ErrorBoundary, HttpRuntimeClient, LayoutErrorBoundary, LayoutManager, LoadingSpinner, NavigationErrorHandler, NavigationErrorOverlay, NotFound, StatePreserver, clearPropsCache, clearPropsCacheForComponent, createErrorBoundary, createHttpRuntimeClient, createLoadingBoundary, createNavigationError, extractMetadata, extractServerProps, extractServerPropsWithCache, extractStaticParams, fetchWithTimeout, hasServerSideDataFetching };
package/dist/index.d.mts CHANGED
@@ -1,3 +1,3 @@
1
1
  import { $ as RouteSegment, B as AppRouteManifest, C as extractStaticParams, G as GenerateStaticParams, H as ErrorEntry, J as LoadingEntry, K as LayoutEntry, Q as PageProps, S as extractServerPropsWithCache, U as ErrorProps, V as AppRouteMatch, W as GenerateMetadata, X as NotFoundEntry, Y as LoadingProps, Z as NotFoundProps, _ as StaticParamsResult, b as extractMetadata, et as RouteSegmentType, g as ServerPropsResult, h as MetadataResult, i as HttpRuntimeClient, l as createHttpRuntimeClient, q as LayoutProps, s as RuntimeClient, v as clearPropsCache, w as hasServerSideDataFetching, x as extractServerProps, y as clearPropsCacheForComponent, z as AppRouteEntry } from "./runtime-client-DrRcA8ca.mjs";
2
- import { a as rari, c as generateAppRouteManifest, d as headers, f as ApiRouteHandlers, h as RouteHandler, i as defineRariOptions, l as loadManifest, m as RouteContext, n as Response, o as rariRouter, p as RariResponse, r as defineRariConfig, s as AppRouteGenerator, t as Request, u as writeManifest } from "./vite-CEX_9o-t.mjs";
2
+ import { a as rari, c as generateAppRouteManifest, d as headers, f as ApiRouteHandlers, h as RouteHandler, i as defineRariOptions, l as loadManifest, m as RouteContext, n as Response, o as rariRouter, p as RariResponse, r as defineRariConfig, s as AppRouteGenerator, t as Request, u as writeManifest } from "./vite-BOlxeo_Q.mjs";
3
3
  export { ApiRouteHandlers, AppRouteEntry, AppRouteGenerator, AppRouteManifest, AppRouteMatch, ErrorEntry, ErrorProps, GenerateMetadata, GenerateStaticParams, HttpRuntimeClient, LayoutEntry, LayoutProps, LoadingEntry, LoadingProps, MetadataResult, NotFoundEntry, NotFoundProps, PageProps, RariResponse, Request, Response, RouteContext, RouteHandler, RouteSegment, RouteSegmentType, RuntimeClient, ServerPropsResult, StaticParamsResult, clearPropsCache, clearPropsCacheForComponent, createHttpRuntimeClient, defineRariConfig, defineRariOptions, extractMetadata, extractServerProps, extractServerPropsWithCache, extractStaticParams, generateAppRouteManifest, hasServerSideDataFetching, headers, loadManifest, rari, rariRouter, writeManifest };
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { a as headers, i as rariRouter, n as defineRariOptions, o as RariResponse, r as rari, t as defineRariConfig } from "./vite-7bcdKkub.mjs";
1
+ import { a as headers, i as rariRouter, n as defineRariOptions, o as RariResponse, r as rari, t as defineRariConfig } from "./vite-B_QMp3M4.mjs";
2
2
  import { i as writeManifest, n as generateAppRouteManifest, r as loadManifest, t as AppRouteGenerator } from "./app-routes-DZjfJPdB.mjs";
3
- import { c as createHttpRuntimeClient, d as clearPropsCacheForComponent, f as extractMetadata, g as hasServerSideDataFetching, h as extractStaticParams, i as HttpRuntimeClient, m as extractServerPropsWithCache, p as extractServerProps, u as clearPropsCache } from "./runtime-client-AtnJSL0q.mjs";
4
- import "./server-build-MmIJHCpL.mjs";
3
+ import { c as createHttpRuntimeClient, d as clearPropsCacheForComponent, f as extractMetadata, g as hasServerSideDataFetching, h as extractStaticParams, i as HttpRuntimeClient, m as extractServerPropsWithCache, p as extractServerProps, u as clearPropsCache } from "./runtime-client-DCkfDJpL.mjs";
4
+ import "./server-build-ChAPR3tl.mjs";
5
5
 
6
6
  export { AppRouteGenerator, HttpRuntimeClient, RariResponse, clearPropsCache, clearPropsCacheForComponent, createHttpRuntimeClient, defineRariConfig, defineRariOptions, extractMetadata, extractServerProps, extractServerPropsWithCache, extractStaticParams, generateAppRouteManifest, hasServerSideDataFetching, headers, loadManifest, rari, rariRouter, writeManifest };
@@ -923,6 +923,112 @@ var StatePreserver = class {
923
923
 
924
924
  //#endregion
925
925
  //#region src/router/ClientRouter.tsx
926
+ function updateDocumentMetadata(metadata) {
927
+ if (metadata.title) document.title = metadata.title;
928
+ const updateOrCreateMetaTag = (selector, attributes) => {
929
+ let element = document.querySelector(selector);
930
+ if (!element) {
931
+ element = document.createElement("meta");
932
+ for (const [key, value] of Object.entries(attributes)) element.setAttribute(key, value);
933
+ document.head.appendChild(element);
934
+ } else if (attributes.content) element.setAttribute("content", attributes.content);
935
+ };
936
+ if (metadata.description) updateOrCreateMetaTag("meta[name=\"description\"]", {
937
+ name: "description",
938
+ content: metadata.description
939
+ });
940
+ if (metadata.keywords && metadata.keywords.length > 0) updateOrCreateMetaTag("meta[name=\"keywords\"]", {
941
+ name: "keywords",
942
+ content: metadata.keywords.join(", ")
943
+ });
944
+ if (metadata.viewport) updateOrCreateMetaTag("meta[name=\"viewport\"]", {
945
+ name: "viewport",
946
+ content: metadata.viewport
947
+ });
948
+ if (metadata.canonical) {
949
+ let canonical = document.querySelector("link[rel=\"canonical\"]");
950
+ if (!canonical) {
951
+ canonical = document.createElement("link");
952
+ canonical.setAttribute("rel", "canonical");
953
+ document.head.appendChild(canonical);
954
+ }
955
+ canonical.setAttribute("href", metadata.canonical);
956
+ }
957
+ if (metadata.robots) {
958
+ const robotsContent = [];
959
+ if (metadata.robots.index !== void 0) robotsContent.push(metadata.robots.index ? "index" : "noindex");
960
+ if (metadata.robots.follow !== void 0) robotsContent.push(metadata.robots.follow ? "follow" : "nofollow");
961
+ if (metadata.robots.nocache) robotsContent.push("nocache");
962
+ if (robotsContent.length > 0) updateOrCreateMetaTag("meta[name=\"robots\"]", {
963
+ name: "robots",
964
+ content: robotsContent.join(", ")
965
+ });
966
+ }
967
+ if (metadata.openGraph) {
968
+ const og = metadata.openGraph;
969
+ if (og.title) updateOrCreateMetaTag("meta[property=\"og:title\"]", {
970
+ property: "og:title",
971
+ content: og.title
972
+ });
973
+ if (og.description) updateOrCreateMetaTag("meta[property=\"og:description\"]", {
974
+ property: "og:description",
975
+ content: og.description
976
+ });
977
+ if (og.url) updateOrCreateMetaTag("meta[property=\"og:url\"]", {
978
+ property: "og:url",
979
+ content: og.url
980
+ });
981
+ if (og.siteName) updateOrCreateMetaTag("meta[property=\"og:site_name\"]", {
982
+ property: "og:site_name",
983
+ content: og.siteName
984
+ });
985
+ if (og.type) updateOrCreateMetaTag("meta[property=\"og:type\"]", {
986
+ property: "og:type",
987
+ content: og.type
988
+ });
989
+ if (og.images && og.images.length > 0) {
990
+ document.querySelectorAll("meta[property=\"og:image\"]").forEach((el) => el.remove());
991
+ for (const image of og.images) {
992
+ const meta = document.createElement("meta");
993
+ meta.setAttribute("property", "og:image");
994
+ meta.setAttribute("content", image);
995
+ document.head.appendChild(meta);
996
+ }
997
+ }
998
+ }
999
+ if (metadata.twitter) {
1000
+ const twitter = metadata.twitter;
1001
+ if (twitter.card) updateOrCreateMetaTag("meta[name=\"twitter:card\"]", {
1002
+ name: "twitter:card",
1003
+ content: twitter.card
1004
+ });
1005
+ if (twitter.site) updateOrCreateMetaTag("meta[name=\"twitter:site\"]", {
1006
+ name: "twitter:site",
1007
+ content: twitter.site
1008
+ });
1009
+ if (twitter.creator) updateOrCreateMetaTag("meta[name=\"twitter:creator\"]", {
1010
+ name: "twitter:creator",
1011
+ content: twitter.creator
1012
+ });
1013
+ if (twitter.title) updateOrCreateMetaTag("meta[name=\"twitter:title\"]", {
1014
+ name: "twitter:title",
1015
+ content: twitter.title
1016
+ });
1017
+ if (twitter.description) updateOrCreateMetaTag("meta[name=\"twitter:description\"]", {
1018
+ name: "twitter:description",
1019
+ content: twitter.description
1020
+ });
1021
+ if (twitter.images && twitter.images.length > 0) {
1022
+ document.querySelectorAll("meta[name=\"twitter:image\"]").forEach((el) => el.remove());
1023
+ for (const image of twitter.images) {
1024
+ const meta = document.createElement("meta");
1025
+ meta.setAttribute("name", "twitter:image");
1026
+ meta.setAttribute("content", image);
1027
+ document.head.appendChild(meta);
1028
+ }
1029
+ }
1030
+ }
1031
+ }
926
1032
  function ClientRouter({ children, manifest, initialRoute }) {
927
1033
  const [navigationState, setNavigationState] = useState(() => ({
928
1034
  currentRoute: normalizePath(initialRoute),
@@ -1083,6 +1189,15 @@ function ClientRouter({ children, manifest, initialRoute }) {
1083
1189
  cleanupAbortedNavigation(targetPath, navigationId);
1084
1190
  return;
1085
1191
  }
1192
+ try {
1193
+ const metadataHeader = response.headers.get("x-rari-metadata");
1194
+ if (metadataHeader) {
1195
+ const decodedMetadata = decodeURIComponent(metadataHeader);
1196
+ updateDocumentMetadata(JSON.parse(decodedMetadata));
1197
+ }
1198
+ } catch (metadataError) {
1199
+ console.warn("[ClientRouter] Failed to extract/apply metadata:", metadataError);
1200
+ }
1086
1201
  const rscWireFormat = await response.text();
1087
1202
  window.dispatchEvent(new CustomEvent("rari:navigate", { detail: {
1088
1203
  from: fromRoute,
@@ -1443,7 +1558,6 @@ async function extractMetadata(componentPath, params, searchParams) {
1443
1558
  /* @vite-ignore */
1444
1559
  componentPath
1445
1560
  );
1446
- if (module.metadata && typeof module.metadata === "object") return module.metadata;
1447
1561
  if (typeof module.generateMetadata === "function") {
1448
1562
  const metadata = await module.generateMetadata({
1449
1563
  params,
@@ -1451,6 +1565,7 @@ async function extractMetadata(componentPath, params, searchParams) {
1451
1565
  });
1452
1566
  if (metadata && typeof metadata === "object") return metadata;
1453
1567
  }
1568
+ if (module.metadata && typeof module.metadata === "object") return module.metadata;
1454
1569
  return {};
1455
1570
  } catch (error) {
1456
1571
  console.error(`Failed to extract metadata from ${componentPath}:`, error);
@@ -0,0 +1,3 @@
1
+ import { n as createServerBuildPlugin, r as scanDirectory, t as ServerComponentBuilder } from "./server-build-ChAPR3tl.mjs";
2
+
3
+ export { ServerComponentBuilder, scanDirectory };
@@ -52,7 +52,8 @@ var ServerComponentBuilder = class {
52
52
  outDir: options.outDir || path.join(projectRoot, "dist"),
53
53
  serverDir: options.serverDir || "server",
54
54
  manifestPath: options.manifestPath || "server-manifest.json",
55
- minify: options.minify ?? process.env.NODE_ENV === "production"
55
+ minify: options.minify ?? process.env.NODE_ENV === "production",
56
+ alias: options.alias || {}
56
57
  };
57
58
  }
58
59
  isServerComponent(filePath) {
@@ -263,6 +264,38 @@ const ${importName} = (props) => {
263
264
  metafile: false,
264
265
  write: false,
265
266
  plugins: [
267
+ {
268
+ name: "resolve-aliases",
269
+ setup: (build$1) => {
270
+ const aliases = this.options.alias || {};
271
+ for (const [alias, replacement] of Object.entries(aliases)) {
272
+ const escapedAlias = alias.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
273
+ const filter = /* @__PURE__ */ new RegExp(`^${escapedAlias}(/|$)`);
274
+ build$1.onResolve({ filter }, (args) => {
275
+ const relativePath = args.path.slice(alias.length);
276
+ const newPath = path.join(replacement, relativePath);
277
+ const resolvedPath = path.isAbsolute(newPath) ? newPath : path.resolve(args.resolveDir, newPath);
278
+ for (const ext$1 of [
279
+ "",
280
+ ".ts",
281
+ ".tsx",
282
+ ".js",
283
+ ".jsx"
284
+ ]) {
285
+ const pathWithExt = resolvedPath + ext$1;
286
+ if (fs.existsSync(pathWithExt) && fs.statSync(pathWithExt).isFile()) {
287
+ if (this.isClientComponent(pathWithExt)) return {
288
+ path: args.path,
289
+ external: true
290
+ };
291
+ return { path: pathWithExt };
292
+ }
293
+ }
294
+ return { path: resolvedPath };
295
+ });
296
+ }
297
+ }
298
+ },
266
299
  {
267
300
  name: "replace-react-imports",
268
301
  setup(build$1) {
@@ -451,6 +484,32 @@ const ${importName} = (props) => {
451
484
  metafile: false,
452
485
  write: false,
453
486
  plugins: [
487
+ {
488
+ name: "resolve-aliases",
489
+ setup: (build$1) => {
490
+ const aliases = this.options.alias || {};
491
+ for (const [alias, replacement] of Object.entries(aliases)) {
492
+ const escapedAlias = alias.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
493
+ const filter = /* @__PURE__ */ new RegExp(`^${escapedAlias}(/|$)`);
494
+ build$1.onResolve({ filter }, (args) => {
495
+ const relativePath = args.path.slice(alias.length);
496
+ const newPath = path.join(replacement, relativePath);
497
+ const resolvedPath = path.isAbsolute(newPath) ? newPath : path.resolve(args.resolveDir, newPath);
498
+ for (const ext$1 of [
499
+ "",
500
+ ".ts",
501
+ ".tsx",
502
+ ".js",
503
+ ".jsx"
504
+ ]) {
505
+ const pathWithExt = resolvedPath + ext$1;
506
+ if (fs.existsSync(pathWithExt) && fs.statSync(pathWithExt).isFile()) return { path: pathWithExt };
507
+ }
508
+ return { path: resolvedPath };
509
+ });
510
+ }
511
+ }
512
+ },
454
513
  {
455
514
  name: "replace-react-imports",
456
515
  setup(build$1) {
@@ -667,7 +726,7 @@ if (!globalThis["${componentId}"]) {
667
726
  }
668
727
  transformClientImports(code, inputPath) {
669
728
  let transformedCode = code;
670
- const importRegex = /import\s+(\w+)(?:\s*,\s*\{[^}]*\})?\s+from\s+['"]([./][^'"]+)['"];?\s*$/gm;
729
+ const importRegex = /import\s+(\w+)(?:\s*,\s*\{[^}]*\})?\s+from\s+['"]([^'"]+)['"];?\s*$/gm;
671
730
  let match;
672
731
  const replacements = [];
673
732
  let hasClientComponents = false;
@@ -727,7 +786,14 @@ function registerClientReference(clientReference, id, exportName) {
727
786
  return transformedCode;
728
787
  }
729
788
  resolveImportPath(importPath, importerPath) {
730
- const resolvedPath = path.resolve(path.dirname(importerPath), importPath);
789
+ let resolvedPath = importPath;
790
+ const aliases = this.options.alias || {};
791
+ for (const [alias, replacement] of Object.entries(aliases)) if (importPath.startsWith(`${alias}/`) || importPath === alias) {
792
+ const relativePath = importPath.slice(alias.length);
793
+ resolvedPath = path.join(replacement, relativePath);
794
+ break;
795
+ }
796
+ if (!path.isAbsolute(resolvedPath)) resolvedPath = path.resolve(path.dirname(importerPath), resolvedPath);
731
797
  const extensions = [
732
798
  ".tsx",
733
799
  ".jsx",
@@ -907,7 +973,20 @@ function createServerBuildPlugin(options = {}) {
907
973
  configResolved(config) {
908
974
  projectRoot = config.root;
909
975
  isDev = config.command === "serve";
910
- builder = new ServerComponentBuilder(projectRoot, options);
976
+ const alias = {};
977
+ if (config.resolve?.alias) {
978
+ const aliasConfig = config.resolve.alias;
979
+ if (Array.isArray(aliasConfig)) aliasConfig.forEach((entry) => {
980
+ if (typeof entry.find === "string" && typeof entry.replacement === "string") alias[entry.find] = entry.replacement;
981
+ });
982
+ else if (typeof aliasConfig === "object") Object.entries(aliasConfig).forEach(([key, value]) => {
983
+ if (typeof value === "string") alias[key] = value;
984
+ });
985
+ }
986
+ builder = new ServerComponentBuilder(projectRoot, {
987
+ ...options,
988
+ alias
989
+ });
911
990
  },
912
991
  buildStart() {
913
992
  if (!builder) return;
@@ -71,6 +71,7 @@ interface ServerBuildOptions {
71
71
  serverDir?: string;
72
72
  manifestPath?: string;
73
73
  minify?: boolean;
74
+ alias?: Record<string, string>;
74
75
  }
75
76
  //#endregion
76
77
  //#region src/vite/index.d.ts
@@ -1,5 +1,5 @@
1
1
  import { t as __require } from "./chunk-DFPPfDFE.mjs";
2
- import { n as createServerBuildPlugin } from "./server-build-MmIJHCpL.mjs";
2
+ import { n as createServerBuildPlugin } from "./server-build-ChAPR3tl.mjs";
3
3
  import fs, { promises, stat, unwatchFile, watch, watchFile } from "node:fs";
4
4
  import * as sp from "node:path";
5
5
  import path, { join, relative, resolve, sep } from "node:path";
@@ -2326,6 +2326,7 @@ function rari(options = {}) {
2326
2326
  let rustServerProcess = null;
2327
2327
  const serverImportedClientComponents = /* @__PURE__ */ new Set();
2328
2328
  let hmrCoordinator = null;
2329
+ const resolvedAlias = {};
2329
2330
  function isServerComponent(filePath) {
2330
2331
  if (filePath.includes("node_modules")) return false;
2331
2332
  if (filePath.includes("/rari/dist/") || filePath.includes("\\rari\\dist\\")) return false;
@@ -2509,7 +2510,12 @@ if (import.meta.hot) {
2509
2510
  const existingDedupe = Array.isArray(config.resolve.dedupe) ? config.resolve.dedupe : [];
2510
2511
  const toAdd = ["react", "react-dom"];
2511
2512
  config.resolve.dedupe = Array.from(new Set([...existingDedupe || [], ...toAdd]));
2512
- const existingAlias = Array.isArray(config.resolve.alias) ? config.resolve.alias : [];
2513
+ let existingAlias = [];
2514
+ if (Array.isArray(config.resolve.alias)) existingAlias = config.resolve.alias;
2515
+ else if (config.resolve.alias && typeof config.resolve.alias === "object") existingAlias = Object.entries(config.resolve.alias).map(([key, value]) => ({
2516
+ find: key,
2517
+ replacement: value
2518
+ }));
2513
2519
  const aliasFinds = new Set(existingAlias.map((a) => String(a.find)));
2514
2520
  try {
2515
2521
  const reactPath = __require.resolve("react");
@@ -2563,7 +2569,7 @@ if (import.meta.hot) {
2563
2569
  "client"
2564
2570
  ]) {
2565
2571
  const env = config.environments[envName];
2566
- if (env && env.build) env.build.rollupOptions = env.build.rollupOptions || {};
2572
+ if (env && env.build) env.build.rolldownOptions = env.build.rolldownOptions || {};
2567
2573
  }
2568
2574
  config.server = config.server || {};
2569
2575
  config.server.proxy = config.server.proxy || {};
@@ -2589,16 +2595,34 @@ if (import.meta.hot) {
2589
2595
  };
2590
2596
  if (command === "build") {
2591
2597
  config.build = config.build || {};
2592
- config.build.rollupOptions = config.build.rollupOptions || {};
2593
- if (!config.build.rollupOptions.input) config.build.rollupOptions.input = { main: "./index.html" };
2598
+ config.build.rolldownOptions = config.build.rolldownOptions || {};
2599
+ if (!config.build.rolldownOptions.input) config.build.rolldownOptions.input = { main: "./index.html" };
2594
2600
  }
2595
2601
  if (config.environments && config.environments.client) {
2596
2602
  if (!config.environments.client.build) config.environments.client.build = {};
2597
- if (!config.environments.client.build.rollupOptions) config.environments.client.build.rollupOptions = {};
2598
- if (!config.environments.client.build.rollupOptions.input) config.environments.client.build.rollupOptions.input = {};
2603
+ if (!config.environments.client.build.rolldownOptions) config.environments.client.build.rolldownOptions = {};
2604
+ if (!config.environments.client.build.rolldownOptions.input) config.environments.client.build.rolldownOptions.input = {};
2599
2605
  }
2600
2606
  return config;
2601
2607
  },
2608
+ configResolved(config) {
2609
+ const excludeAliases = new Set([
2610
+ "react",
2611
+ "react-dom",
2612
+ "react/jsx-runtime",
2613
+ "react/jsx-dev-runtime",
2614
+ "react-dom/client"
2615
+ ]);
2616
+ if (config.resolve?.alias) {
2617
+ const aliasConfig = config.resolve.alias;
2618
+ if (Array.isArray(aliasConfig)) aliasConfig.forEach((entry) => {
2619
+ if (typeof entry.find === "string" && typeof entry.replacement === "string" && !excludeAliases.has(entry.find)) resolvedAlias[entry.find] = entry.replacement;
2620
+ });
2621
+ else if (typeof aliasConfig === "object") Object.entries(aliasConfig).forEach(([key, value]) => {
2622
+ if (typeof value === "string" && !excludeAliases.has(key)) resolvedAlias[key] = value;
2623
+ });
2624
+ }
2625
+ },
2602
2626
  transform(code, id) {
2603
2627
  if (!/\.(?:tsx?|jsx?)$/.test(id)) return null;
2604
2628
  const environment = this.environment;
@@ -2716,11 +2740,12 @@ const ${componentName$1} = registerClientReference(
2716
2740
  let serverComponentBuilder = null;
2717
2741
  const discoverAndRegisterComponents = async () => {
2718
2742
  try {
2719
- const { ServerComponentBuilder, scanDirectory } = await import("./server-build-BqMz9o5w.mjs");
2743
+ const { ServerComponentBuilder, scanDirectory } = await import("./server-build-Br9CwaA7.mjs");
2720
2744
  const builder = new ServerComponentBuilder(projectRoot, {
2721
2745
  outDir: "dist",
2722
2746
  serverDir: "server",
2723
- manifestPath: "server-manifest.json"
2747
+ manifestPath: "server-manifest.json",
2748
+ alias: resolvedAlias
2724
2749
  });
2725
2750
  serverComponentBuilder = builder;
2726
2751
  if (!hmrCoordinator && serverComponentBuilder) {
@@ -2877,11 +2902,12 @@ const ${componentName$1} = registerClientReference(
2877
2902
  const handleServerComponentHMR = async (filePath) => {
2878
2903
  try {
2879
2904
  if (!isServerComponent(filePath)) return;
2880
- const { ServerComponentBuilder } = await import("./server-build-BqMz9o5w.mjs");
2905
+ const { ServerComponentBuilder } = await import("./server-build-Br9CwaA7.mjs");
2881
2906
  const builder = new ServerComponentBuilder(projectRoot, {
2882
2907
  outDir: "dist",
2883
2908
  serverDir: "server",
2884
- manifestPath: "server-manifest.json"
2909
+ manifestPath: "server-manifest.json",
2910
+ alias: resolvedAlias
2885
2911
  });
2886
2912
  builder.addServerComponent(filePath);
2887
2913
  const components = await builder.getTransformedComponentsForDevelopment();
package/dist/vite.d.mts CHANGED
@@ -1,3 +1,3 @@
1
1
  import { $ as RouteSegment, B as AppRouteManifest, C as extractStaticParams, G as GenerateStaticParams, H as ErrorEntry, J as LoadingEntry, K as LayoutEntry, Q as PageProps, S as extractServerPropsWithCache, U as ErrorProps, V as AppRouteMatch, W as GenerateMetadata, X as NotFoundEntry, Y as LoadingProps, Z as NotFoundProps, _ as StaticParamsResult, b as extractMetadata, et as RouteSegmentType, g as ServerPropsResult, h as MetadataResult, i as HttpRuntimeClient, l as createHttpRuntimeClient, q as LayoutProps, s as RuntimeClient, v as clearPropsCache, w as hasServerSideDataFetching, x as extractServerProps, y as clearPropsCacheForComponent, z as AppRouteEntry } from "./runtime-client-DrRcA8ca.mjs";
2
- import { a as rari, c as generateAppRouteManifest, d as headers, f as ApiRouteHandlers, h as RouteHandler, i as defineRariOptions, l as loadManifest, m as RouteContext, n as Response, o as rariRouter, p as RariResponse, r as defineRariConfig, s as AppRouteGenerator, t as Request, u as writeManifest } from "./vite-CEX_9o-t.mjs";
2
+ import { a as rari, c as generateAppRouteManifest, d as headers, f as ApiRouteHandlers, h as RouteHandler, i as defineRariOptions, l as loadManifest, m as RouteContext, n as Response, o as rariRouter, p as RariResponse, r as defineRariConfig, s as AppRouteGenerator, t as Request, u as writeManifest } from "./vite-BOlxeo_Q.mjs";
3
3
  export { ApiRouteHandlers, AppRouteEntry, AppRouteGenerator, AppRouteManifest, AppRouteMatch, ErrorEntry, ErrorProps, GenerateMetadata, GenerateStaticParams, HttpRuntimeClient, LayoutEntry, LayoutProps, LoadingEntry, LoadingProps, MetadataResult, NotFoundEntry, NotFoundProps, PageProps, RariResponse, Request, Response, RouteContext, RouteHandler, RouteSegment, RouteSegmentType, RuntimeClient, ServerPropsResult, StaticParamsResult, clearPropsCache, clearPropsCacheForComponent, createHttpRuntimeClient, defineRariConfig, defineRariOptions, extractMetadata, extractServerProps, extractServerPropsWithCache, extractStaticParams, generateAppRouteManifest, hasServerSideDataFetching, headers, loadManifest, rari, rariRouter, writeManifest };
package/dist/vite.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { a as headers, i as rariRouter, n as defineRariOptions, o as RariResponse, r as rari, t as defineRariConfig } from "./vite-7bcdKkub.mjs";
1
+ import { a as headers, i as rariRouter, n as defineRariOptions, o as RariResponse, r as rari, t as defineRariConfig } from "./vite-B_QMp3M4.mjs";
2
2
  import { i as writeManifest, n as generateAppRouteManifest, r as loadManifest, t as AppRouteGenerator } from "./app-routes-DZjfJPdB.mjs";
3
- import { c as createHttpRuntimeClient, d as clearPropsCacheForComponent, f as extractMetadata, g as hasServerSideDataFetching, h as extractStaticParams, i as HttpRuntimeClient, m as extractServerPropsWithCache, p as extractServerProps, u as clearPropsCache } from "./runtime-client-AtnJSL0q.mjs";
4
- import "./server-build-MmIJHCpL.mjs";
3
+ import { c as createHttpRuntimeClient, d as clearPropsCacheForComponent, f as extractMetadata, g as hasServerSideDataFetching, h as extractStaticParams, i as HttpRuntimeClient, m as extractServerPropsWithCache, p as extractServerProps, u as clearPropsCache } from "./runtime-client-DCkfDJpL.mjs";
4
+ import "./server-build-ChAPR3tl.mjs";
5
5
 
6
6
  export { AppRouteGenerator, HttpRuntimeClient, RariResponse, clearPropsCache, clearPropsCacheForComponent, createHttpRuntimeClient, defineRariConfig, defineRariOptions, extractMetadata, extractServerProps, extractServerPropsWithCache, extractStaticParams, generateAppRouteManifest, hasServerSideDataFetching, headers, loadManifest, rari, rariRouter, writeManifest };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "rari",
3
3
  "type": "module",
4
- "version": "0.5.15",
4
+ "version": "0.5.17",
5
5
  "description": "Runtime Accelerated Rendering Infrastructure (Rari)",
6
6
  "author": "Ryan Skinner",
7
7
  "license": "MIT",
@@ -89,11 +89,11 @@
89
89
  "picocolors": "^1.1.1"
90
90
  },
91
91
  "optionalDependencies": {
92
- "rari-darwin-arm64": "0.5.10",
93
- "rari-darwin-x64": "0.5.10",
94
- "rari-linux-arm64": "0.5.10",
95
- "rari-linux-x64": "0.5.10",
96
- "rari-win32-x64": "0.5.10"
92
+ "rari-darwin-arm64": "0.5.11",
93
+ "rari-darwin-x64": "0.5.11",
94
+ "rari-linux-arm64": "0.5.11",
95
+ "rari-linux-x64": "0.5.11",
96
+ "rari-win32-x64": "0.5.11"
97
97
  },
98
98
  "devDependencies": {
99
99
  "@types/node": "^25.0.1",
@@ -12,6 +12,193 @@ import { extractPathname, findLayoutChain, isExternalUrl, matchRouteParams, norm
12
12
  import { NavigationErrorOverlay } from './NavigationErrorOverlay'
13
13
  import { StatePreserver } from './StatePreserver'
14
14
 
15
+ interface PageMetadata {
16
+ title?: string
17
+ description?: string
18
+ keywords?: string[]
19
+ viewport?: string
20
+ canonical?: string
21
+ openGraph?: {
22
+ title?: string
23
+ description?: string
24
+ url?: string
25
+ siteName?: string
26
+ images?: string[]
27
+ type?: string
28
+ }
29
+ twitter?: {
30
+ card?: string
31
+ site?: string
32
+ creator?: string
33
+ title?: string
34
+ description?: string
35
+ images?: string[]
36
+ }
37
+ robots?: {
38
+ index?: boolean
39
+ follow?: boolean
40
+ nocache?: boolean
41
+ }
42
+ }
43
+
44
+ function updateDocumentMetadata(metadata: PageMetadata): void {
45
+ if (metadata.title) {
46
+ document.title = metadata.title
47
+ }
48
+
49
+ const updateOrCreateMetaTag = (selector: string, attributes: Record<string, string>) => {
50
+ let element = document.querySelector(selector) as HTMLMetaElement | null
51
+ if (!element) {
52
+ element = document.createElement('meta')
53
+ for (const [key, value] of Object.entries(attributes)) {
54
+ element.setAttribute(key, value)
55
+ }
56
+ document.head.appendChild(element)
57
+ }
58
+ else {
59
+ if (attributes.content) {
60
+ element.setAttribute('content', attributes.content)
61
+ }
62
+ }
63
+ }
64
+
65
+ if (metadata.description) {
66
+ updateOrCreateMetaTag('meta[name="description"]', {
67
+ name: 'description',
68
+ content: metadata.description,
69
+ })
70
+ }
71
+
72
+ if (metadata.keywords && metadata.keywords.length > 0) {
73
+ updateOrCreateMetaTag('meta[name="keywords"]', {
74
+ name: 'keywords',
75
+ content: metadata.keywords.join(', '),
76
+ })
77
+ }
78
+
79
+ if (metadata.viewport) {
80
+ updateOrCreateMetaTag('meta[name="viewport"]', {
81
+ name: 'viewport',
82
+ content: metadata.viewport,
83
+ })
84
+ }
85
+
86
+ if (metadata.canonical) {
87
+ let canonical = document.querySelector('link[rel="canonical"]') as HTMLLinkElement | null
88
+ if (!canonical) {
89
+ canonical = document.createElement('link')
90
+ canonical.setAttribute('rel', 'canonical')
91
+ document.head.appendChild(canonical)
92
+ }
93
+ canonical.setAttribute('href', metadata.canonical)
94
+ }
95
+
96
+ if (metadata.robots) {
97
+ const robotsContent: string[] = []
98
+ if (metadata.robots.index !== undefined) {
99
+ robotsContent.push(metadata.robots.index ? 'index' : 'noindex')
100
+ }
101
+ if (metadata.robots.follow !== undefined) {
102
+ robotsContent.push(metadata.robots.follow ? 'follow' : 'nofollow')
103
+ }
104
+ if (metadata.robots.nocache) {
105
+ robotsContent.push('nocache')
106
+ }
107
+ if (robotsContent.length > 0) {
108
+ updateOrCreateMetaTag('meta[name="robots"]', {
109
+ name: 'robots',
110
+ content: robotsContent.join(', '),
111
+ })
112
+ }
113
+ }
114
+
115
+ if (metadata.openGraph) {
116
+ const og = metadata.openGraph
117
+ if (og.title) {
118
+ updateOrCreateMetaTag('meta[property="og:title"]', {
119
+ property: 'og:title',
120
+ content: og.title,
121
+ })
122
+ }
123
+ if (og.description) {
124
+ updateOrCreateMetaTag('meta[property="og:description"]', {
125
+ property: 'og:description',
126
+ content: og.description,
127
+ })
128
+ }
129
+ if (og.url) {
130
+ updateOrCreateMetaTag('meta[property="og:url"]', {
131
+ property: 'og:url',
132
+ content: og.url,
133
+ })
134
+ }
135
+ if (og.siteName) {
136
+ updateOrCreateMetaTag('meta[property="og:site_name"]', {
137
+ property: 'og:site_name',
138
+ content: og.siteName,
139
+ })
140
+ }
141
+ if (og.type) {
142
+ updateOrCreateMetaTag('meta[property="og:type"]', {
143
+ property: 'og:type',
144
+ content: og.type,
145
+ })
146
+ }
147
+ if (og.images && og.images.length > 0) {
148
+ document.querySelectorAll('meta[property="og:image"]').forEach(el => el.remove())
149
+ for (const image of og.images) {
150
+ const meta = document.createElement('meta')
151
+ meta.setAttribute('property', 'og:image')
152
+ meta.setAttribute('content', image)
153
+ document.head.appendChild(meta)
154
+ }
155
+ }
156
+ }
157
+
158
+ if (metadata.twitter) {
159
+ const twitter = metadata.twitter
160
+ if (twitter.card) {
161
+ updateOrCreateMetaTag('meta[name="twitter:card"]', {
162
+ name: 'twitter:card',
163
+ content: twitter.card,
164
+ })
165
+ }
166
+ if (twitter.site) {
167
+ updateOrCreateMetaTag('meta[name="twitter:site"]', {
168
+ name: 'twitter:site',
169
+ content: twitter.site,
170
+ })
171
+ }
172
+ if (twitter.creator) {
173
+ updateOrCreateMetaTag('meta[name="twitter:creator"]', {
174
+ name: 'twitter:creator',
175
+ content: twitter.creator,
176
+ })
177
+ }
178
+ if (twitter.title) {
179
+ updateOrCreateMetaTag('meta[name="twitter:title"]', {
180
+ name: 'twitter:title',
181
+ content: twitter.title,
182
+ })
183
+ }
184
+ if (twitter.description) {
185
+ updateOrCreateMetaTag('meta[name="twitter:description"]', {
186
+ name: 'twitter:description',
187
+ content: twitter.description,
188
+ })
189
+ }
190
+ if (twitter.images && twitter.images.length > 0) {
191
+ document.querySelectorAll('meta[name="twitter:image"]').forEach(el => el.remove())
192
+ for (const image of twitter.images) {
193
+ const meta = document.createElement('meta')
194
+ meta.setAttribute('name', 'twitter:image')
195
+ meta.setAttribute('content', image)
196
+ document.head.appendChild(meta)
197
+ }
198
+ }
199
+ }
200
+ }
201
+
15
202
  export interface ClientRouterProps {
16
203
  children: React.ReactNode
17
204
  manifest: AppRouteManifest
@@ -305,6 +492,18 @@ export function ClientRouter({ children, manifest, initialRoute }: ClientRouterP
305
492
  return
306
493
  }
307
494
 
495
+ try {
496
+ const metadataHeader = response.headers.get('x-rari-metadata')
497
+ if (metadataHeader) {
498
+ const decodedMetadata = decodeURIComponent(metadataHeader)
499
+ const metadata = JSON.parse(decodedMetadata) as PageMetadata
500
+ updateDocumentMetadata(metadata)
501
+ }
502
+ }
503
+ catch (metadataError) {
504
+ console.warn('[ClientRouter] Failed to extract/apply metadata:', metadataError)
505
+ }
506
+
308
507
  const rscWireFormat = await response.text()
309
508
 
310
509
  window.dispatchEvent(new CustomEvent('rari:navigate', {
@@ -80,11 +80,13 @@ export type { NavigationErrorOverlayProps } from './NavigationErrorOverlay'
80
80
  export {
81
81
  clearPropsCache,
82
82
  clearPropsCacheForComponent,
83
+ collectMetadataFromChain,
83
84
  extractMetadata,
84
85
  extractServerProps,
85
86
  extractServerPropsWithCache,
86
87
  extractStaticParams,
87
88
  hasServerSideDataFetching,
89
+ mergeMetadata,
88
90
  } from './props-extractor'
89
91
 
90
92
  export type {
@@ -162,10 +162,6 @@ export async function extractMetadata(
162
162
  try {
163
163
  const module = await import(/* @vite-ignore */ componentPath)
164
164
 
165
- if (module.metadata && typeof module.metadata === 'object') {
166
- return module.metadata
167
- }
168
-
169
165
  if (typeof module.generateMetadata === 'function') {
170
166
  const metadata = await module.generateMetadata({ params, searchParams })
171
167
  if (metadata && typeof metadata === 'object') {
@@ -173,6 +169,10 @@ export async function extractMetadata(
173
169
  }
174
170
  }
175
171
 
172
+ if (module.metadata && typeof module.metadata === 'object') {
173
+ return module.metadata
174
+ }
175
+
176
176
  return {}
177
177
  }
178
178
  catch (error) {
@@ -181,6 +181,60 @@ export async function extractMetadata(
181
181
  }
182
182
  }
183
183
 
184
+ export function mergeMetadata(
185
+ parentMetadata: MetadataResult,
186
+ childMetadata: MetadataResult,
187
+ ): MetadataResult {
188
+ const merged: MetadataResult = { ...parentMetadata }
189
+
190
+ if (childMetadata.title !== undefined) {
191
+ if (typeof childMetadata.title === 'string') {
192
+ if (typeof parentMetadata.title === 'object' && parentMetadata.title?.template) {
193
+ merged.title = parentMetadata.title.template.replace('%s', childMetadata.title)
194
+ }
195
+ else {
196
+ merged.title = childMetadata.title
197
+ }
198
+ }
199
+ else {
200
+ merged.title = childMetadata.title
201
+ }
202
+ }
203
+
204
+ if (childMetadata.description !== undefined) {
205
+ merged.description = childMetadata.description
206
+ }
207
+ if (childMetadata.keywords !== undefined) {
208
+ merged.keywords = childMetadata.keywords
209
+ }
210
+ if (childMetadata.openGraph !== undefined) {
211
+ merged.openGraph = { ...parentMetadata.openGraph, ...childMetadata.openGraph }
212
+ }
213
+ if (childMetadata.twitter !== undefined) {
214
+ merged.twitter = { ...parentMetadata.twitter, ...childMetadata.twitter }
215
+ }
216
+ if (childMetadata.robots !== undefined) {
217
+ merged.robots = { ...parentMetadata.robots, ...childMetadata.robots }
218
+ }
219
+ if (childMetadata.icons !== undefined) {
220
+ merged.icons = { ...parentMetadata.icons, ...childMetadata.icons }
221
+ }
222
+ if (childMetadata.manifest !== undefined) {
223
+ merged.manifest = childMetadata.manifest
224
+ }
225
+ if (childMetadata.viewport !== undefined) {
226
+ merged.viewport = { ...parentMetadata.viewport, ...childMetadata.viewport }
227
+ }
228
+ if (childMetadata.verification !== undefined) {
229
+ merged.verification = { ...parentMetadata.verification, ...childMetadata.verification }
230
+ }
231
+ if (childMetadata.alternates !== undefined) {
232
+ merged.alternates = { ...parentMetadata.alternates, ...childMetadata.alternates }
233
+ }
234
+
235
+ return merged
236
+ }
237
+
184
238
  export async function extractStaticParams(
185
239
  componentPath: string,
186
240
  ): Promise<StaticParamsResult> {
@@ -260,3 +314,22 @@ export function clearPropsCacheForComponent(componentPath: string): void {
260
314
  }
261
315
  }
262
316
  }
317
+
318
+ export async function collectMetadataFromChain(
319
+ layoutPaths: string[],
320
+ pagePath: string,
321
+ params: Record<string, string>,
322
+ searchParams: Record<string, string>,
323
+ ): Promise<MetadataResult> {
324
+ let metadata: MetadataResult = {}
325
+
326
+ for (const layoutPath of layoutPaths) {
327
+ const layoutMetadata = await extractMetadata(layoutPath, params, searchParams)
328
+ metadata = mergeMetadata(metadata, layoutMetadata)
329
+ }
330
+
331
+ const pageMetadata = await extractMetadata(pagePath, params, searchParams)
332
+ metadata = mergeMetadata(metadata, pageMetadata)
333
+
334
+ return metadata
335
+ }
package/src/vite/index.ts CHANGED
@@ -103,6 +103,7 @@ export function rari(options: RariOptions = {}): Plugin[] {
103
103
  const serverImportedClientComponents = new Set<string>()
104
104
 
105
105
  let hmrCoordinator: HMRCoordinator | null = null
106
+ const resolvedAlias: Record<string, string> = {}
106
107
 
107
108
  function isServerComponent(filePath: string): boolean {
108
109
  if (filePath.includes('node_modules')) {
@@ -434,12 +435,21 @@ if (import.meta.hot) {
434
435
  new Set([...(existingDedupe || []), ...toAdd]),
435
436
  )
436
437
 
437
- const existingAlias: Array<{
438
+ let existingAlias: Array<{
438
439
  find: string | RegExp
439
440
  replacement: string
440
- }> = Array.isArray((config.resolve as any).alias)
441
- ? (config.resolve as any).alias
442
- : []
441
+ }> = []
442
+
443
+ if (Array.isArray((config.resolve as any).alias)) {
444
+ existingAlias = (config.resolve as any).alias
445
+ }
446
+ else if ((config.resolve as any).alias && typeof (config.resolve as any).alias === 'object') {
447
+ existingAlias = Object.entries((config.resolve as any).alias).map(([key, value]) => ({
448
+ find: key,
449
+ replacement: value as string,
450
+ }))
451
+ }
452
+
443
453
  const aliasFinds = new Set(existingAlias.map(a => String(a.find)))
444
454
  try {
445
455
  const reactPath = require.resolve('react')
@@ -516,7 +526,7 @@ if (import.meta.hot) {
516
526
  for (const envName of ['rsc', 'ssr', 'client']) {
517
527
  const env = config.environments[envName]
518
528
  if (env && env.build) {
519
- env.build.rollupOptions = env.build.rollupOptions || {}
529
+ env.build.rolldownOptions = env.build.rolldownOptions || {}
520
530
  }
521
531
  }
522
532
  }
@@ -552,10 +562,10 @@ if (import.meta.hot) {
552
562
 
553
563
  if (command === 'build') {
554
564
  config.build = config.build || {}
555
- config.build.rollupOptions = config.build.rollupOptions || {}
565
+ config.build.rolldownOptions = config.build.rolldownOptions || {}
556
566
 
557
- if (!config.build.rollupOptions.input) {
558
- config.build.rollupOptions.input = {
567
+ if (!config.build.rolldownOptions.input) {
568
+ config.build.rolldownOptions.input = {
559
569
  main: './index.html',
560
570
  }
561
571
  }
@@ -565,17 +575,39 @@ if (import.meta.hot) {
565
575
  if (!config.environments.client.build) {
566
576
  config.environments.client.build = {}
567
577
  }
568
- if (!config.environments.client.build.rollupOptions) {
569
- config.environments.client.build.rollupOptions = {}
578
+ if (!config.environments.client.build.rolldownOptions) {
579
+ config.environments.client.build.rolldownOptions = {}
570
580
  }
571
- if (!config.environments.client.build.rollupOptions.input) {
572
- config.environments.client.build.rollupOptions.input = {}
581
+ if (!config.environments.client.build.rolldownOptions.input) {
582
+ config.environments.client.build.rolldownOptions.input = {}
573
583
  }
574
584
  }
575
585
 
576
586
  return config
577
587
  },
578
588
 
589
+ configResolved(config) {
590
+ const excludeAliases = new Set(['react', 'react-dom', 'react/jsx-runtime', 'react/jsx-dev-runtime', 'react-dom/client'])
591
+
592
+ if (config.resolve?.alias) {
593
+ const aliasConfig = config.resolve.alias
594
+ if (Array.isArray(aliasConfig)) {
595
+ aliasConfig.forEach((entry) => {
596
+ if (typeof entry.find === 'string' && typeof entry.replacement === 'string' && !excludeAliases.has(entry.find)) {
597
+ resolvedAlias[entry.find] = entry.replacement
598
+ }
599
+ })
600
+ }
601
+ else if (typeof aliasConfig === 'object') {
602
+ Object.entries(aliasConfig).forEach(([key, value]) => {
603
+ if (typeof value === 'string' && !excludeAliases.has(key)) {
604
+ resolvedAlias[key] = value
605
+ }
606
+ })
607
+ }
608
+ }
609
+ },
610
+
579
611
  transform(code, id) {
580
612
  if (!/\.(?:tsx?|jsx?)$/.test(id)) {
581
613
  return null
@@ -819,6 +851,7 @@ const ${componentName} = registerClientReference(
819
851
  outDir: 'dist',
820
852
  serverDir: 'server',
821
853
  manifestPath: 'server-manifest.json',
854
+ alias: resolvedAlias,
822
855
  })
823
856
 
824
857
  serverComponentBuilder = builder
@@ -1093,6 +1126,7 @@ const ${componentName} = registerClientReference(
1093
1126
  outDir: 'dist',
1094
1127
  serverDir: 'server',
1095
1128
  manifestPath: 'server-manifest.json',
1129
+ alias: resolvedAlias,
1096
1130
  })
1097
1131
 
1098
1132
  builder.addServerComponent(filePath)
@@ -60,6 +60,7 @@ export interface ServerBuildOptions {
60
60
  serverDir?: string
61
61
  manifestPath?: string
62
62
  minify?: boolean
63
+ alias?: Record<string, string>
63
64
  }
64
65
 
65
66
  export interface ComponentRebuildResult {
@@ -110,6 +111,7 @@ export class ServerComponentBuilder {
110
111
  serverDir: options.serverDir || 'server',
111
112
  manifestPath: options.manifestPath || 'server-manifest.json',
112
113
  minify: options.minify ?? process.env.NODE_ENV === 'production',
114
+ alias: options.alias || {},
113
115
  }
114
116
  }
115
117
 
@@ -419,6 +421,34 @@ const ${importName} = (props) => {
419
421
  metafile: false,
420
422
  write: false,
421
423
  plugins: [
424
+ {
425
+ name: 'resolve-aliases',
426
+ setup: (build) => {
427
+ const aliases = this.options.alias || {}
428
+ for (const [alias, replacement] of Object.entries(aliases)) {
429
+ const escapedAlias = alias.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
430
+ const filter = new RegExp(`^${escapedAlias}(/|$)`)
431
+ build.onResolve({ filter }, (args) => {
432
+ const relativePath = args.path.slice(alias.length)
433
+ const newPath = path.join(replacement, relativePath)
434
+ const resolvedPath = path.isAbsolute(newPath) ? newPath : path.resolve(args.resolveDir, newPath)
435
+
436
+ const possibleExtensions = ['', '.ts', '.tsx', '.js', '.jsx']
437
+ for (const ext of possibleExtensions) {
438
+ const pathWithExt = resolvedPath + ext
439
+ if (fs.existsSync(pathWithExt) && fs.statSync(pathWithExt).isFile()) {
440
+ if (this.isClientComponent(pathWithExt)) {
441
+ return { path: args.path, external: true }
442
+ }
443
+ return { path: pathWithExt }
444
+ }
445
+ }
446
+
447
+ return { path: resolvedPath }
448
+ })
449
+ }
450
+ },
451
+ },
422
452
  {
423
453
  name: 'replace-react-imports',
424
454
  setup(build) {
@@ -671,6 +701,31 @@ const ${importName} = (props) => {
671
701
  metafile: false,
672
702
  write: false,
673
703
  plugins: [
704
+ {
705
+ name: 'resolve-aliases',
706
+ setup: (build) => {
707
+ const aliases = this.options.alias || {}
708
+ for (const [alias, replacement] of Object.entries(aliases)) {
709
+ const escapedAlias = alias.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
710
+ const filter = new RegExp(`^${escapedAlias}(/|$)`)
711
+ build.onResolve({ filter }, (args) => {
712
+ const relativePath = args.path.slice(alias.length)
713
+ const newPath = path.join(replacement, relativePath)
714
+ const resolvedPath = path.isAbsolute(newPath) ? newPath : path.resolve(args.resolveDir, newPath)
715
+
716
+ const possibleExtensions = ['', '.ts', '.tsx', '.js', '.jsx']
717
+ for (const ext of possibleExtensions) {
718
+ const pathWithExt = resolvedPath + ext
719
+ if (fs.existsSync(pathWithExt) && fs.statSync(pathWithExt).isFile()) {
720
+ return { path: pathWithExt }
721
+ }
722
+ }
723
+
724
+ return { path: resolvedPath }
725
+ })
726
+ }
727
+ },
728
+ },
674
729
  {
675
730
  name: 'replace-react-imports',
676
731
  setup(build) {
@@ -1024,7 +1079,7 @@ if (!globalThis["${componentId}"]) {
1024
1079
  let transformedCode = code
1025
1080
 
1026
1081
  const importRegex
1027
- = /import\s+(\w+)(?:\s*,\s*\{[^}]*\})?\s+from\s+['"]([./][^'"]+)['"];?\s*$/gm
1082
+ = /import\s+(\w+)(?:\s*,\s*\{[^}]*\})?\s+from\s+['"]([^'"]+)['"];?\s*$/gm
1028
1083
  let match
1029
1084
 
1030
1085
  const replacements: Array<{ original: string, replacement: string }> = []
@@ -1099,7 +1154,20 @@ function registerClientReference(clientReference, id, exportName) {
1099
1154
  }
1100
1155
 
1101
1156
  private resolveImportPath(importPath: string, importerPath: string): string {
1102
- const resolvedPath = path.resolve(path.dirname(importerPath), importPath)
1157
+ let resolvedPath = importPath
1158
+ const aliases = this.options.alias || {}
1159
+
1160
+ for (const [alias, replacement] of Object.entries(aliases)) {
1161
+ if (importPath.startsWith(`${alias}/`) || importPath === alias) {
1162
+ const relativePath = importPath.slice(alias.length)
1163
+ resolvedPath = path.join(replacement, relativePath)
1164
+ break
1165
+ }
1166
+ }
1167
+
1168
+ if (!path.isAbsolute(resolvedPath)) {
1169
+ resolvedPath = path.resolve(path.dirname(importerPath), resolvedPath)
1170
+ }
1103
1171
 
1104
1172
  const extensions = ['.tsx', '.jsx', '.ts', '.js']
1105
1173
  for (const ext of extensions) {
@@ -1412,7 +1480,27 @@ export function createServerBuildPlugin(
1412
1480
  configResolved(config) {
1413
1481
  projectRoot = config.root
1414
1482
  isDev = config.command === 'serve'
1415
- builder = new ServerComponentBuilder(projectRoot, options)
1483
+
1484
+ const alias: Record<string, string> = {}
1485
+ if (config.resolve?.alias) {
1486
+ const aliasConfig = config.resolve.alias
1487
+ if (Array.isArray(aliasConfig)) {
1488
+ aliasConfig.forEach((entry) => {
1489
+ if (typeof entry.find === 'string' && typeof entry.replacement === 'string') {
1490
+ alias[entry.find] = entry.replacement
1491
+ }
1492
+ })
1493
+ }
1494
+ else if (typeof aliasConfig === 'object') {
1495
+ Object.entries(aliasConfig).forEach(([key, value]) => {
1496
+ if (typeof value === 'string') {
1497
+ alias[key] = value
1498
+ }
1499
+ })
1500
+ }
1501
+ }
1502
+
1503
+ builder = new ServerComponentBuilder(projectRoot, { ...options, alias })
1416
1504
  },
1417
1505
 
1418
1506
  buildStart() {
@@ -1,3 +0,0 @@
1
- import { n as createServerBuildPlugin, r as scanDirectory, t as ServerComponentBuilder } from "./server-build-MmIJHCpL.mjs";
2
-
3
- export { ServerComponentBuilder, scanDirectory };