@marko/run 0.2.6 → 0.2.8

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.
@@ -87,14 +87,15 @@ import path2 from "path";
87
87
  import crypto from "crypto";
88
88
  import fs3 from "fs";
89
89
  import glob from "glob";
90
+ import { fileURLToPath } from "url";
91
+ import browserslist from "browserslist";
92
+ import { resolveToEsbuildTarget } from "esbuild-plugin-browserslist";
90
93
  import { mergeConfig } from "vite";
91
94
  import markoVitePlugin, { FileStore } from "@marko/vite";
92
95
 
93
96
  // src/vite/constants.ts
94
97
  var markoRunFilePrefix = "__marko-run__";
95
98
  var virtualFilePrefix = "virtual:marko-run";
96
- var virtualRoutesPrefix = `${virtualFilePrefix}/routes`;
97
- var virtualRuntimePrefix = `${virtualFilePrefix}/internal`;
98
99
  var httpVerbs = ["get", "post", "put", "delete"];
99
100
  var serverEntryQuery = "?marko-server-entry";
100
101
  var RoutableFileTypes = {
@@ -109,7 +110,7 @@ var RoutableFileTypes = {
109
110
 
110
111
  // src/vite/routes/vdir.ts
111
112
  var _dirs, _pathlessDirs;
112
- var _VDir = class {
113
+ var _VDir = class _VDir {
113
114
  constructor(parent, segment, source) {
114
115
  __privateAdd(this, _dirs, void 0);
115
116
  __privateAdd(this, _pathlessDirs, void 0);
@@ -246,9 +247,9 @@ var _VDir = class {
246
247
  return dirs;
247
248
  }
248
249
  };
249
- var VDir = _VDir;
250
250
  _dirs = new WeakMap();
251
251
  _pathlessDirs = new WeakMap();
252
+ var VDir = _VDir;
252
253
 
253
254
  // src/vite/routes/parse.ts
254
255
  function parseFlatRoute(pattern) {
@@ -769,23 +770,35 @@ function renderRouteTemplate(route) {
769
770
  if (!route.page) {
770
771
  throw new Error(`Route ${route.key} has no page to render`);
771
772
  }
773
+ return renderEntryTemplate(
774
+ route.entryName,
775
+ [...route.layouts, route.page].map((file) => `./${file.importPath}`)
776
+ );
777
+ }
778
+ function renderEntryTemplate(name, files) {
779
+ if (!name) {
780
+ throw new Error(`Invalid argument - 'name' cannot be empty`);
781
+ }
782
+ if (!files.length) {
783
+ throw new Error(`Invalid argument - 'files' cannot be empty`);
784
+ }
772
785
  const writer = createStringWriter();
773
- writer.writeLines(`// ${virtualFilePrefix}/${route.entryName}.marko`);
786
+ writer.writeLines(`// ${virtualFilePrefix}/${name}.marko`);
774
787
  writer.branch("imports");
775
788
  writer.writeLines("");
776
- writeRouteTemplateTag(writer, [...route.layouts, route.page]);
789
+ writeEntryTemplateTag(writer, files);
777
790
  return writer.end();
778
791
  }
779
- function writeRouteTemplateTag(writer, [file, ...rest], index = 1) {
792
+ function writeEntryTemplateTag(writer, [file, ...rest], index = 1) {
780
793
  if (file) {
781
794
  const isLast = !rest.length;
782
795
  const tag = isLast ? "page" : `layout${index}`;
783
- writer.branch("imports").writeLines(`import ${tag} from './${file.importPath}';`);
796
+ writer.branch("imports").writeLines(`import ${tag} from '${file}';`);
784
797
  if (isLast) {
785
- writer.writeLines(`<${tag} ...input />`);
798
+ writer.writeLines(`<${tag} ...input/>`);
786
799
  } else {
787
800
  writer.writeBlockStart(`<${tag} ...input>`);
788
- writeRouteTemplateTag(writer, rest, index + 1);
801
+ writeEntryTemplateTag(writer, rest, index + 1);
789
802
  writer.writeBlockEnd(`</>`);
790
803
  }
791
804
  }
@@ -817,7 +830,9 @@ function renderRouteEntry(route) {
817
830
  }
818
831
  if (runtimeImports.length) {
819
832
  imports.writeLines(
820
- `import { ${runtimeImports.join(", ")} } from '${virtualRuntimePrefix}';`
833
+ `import { ${runtimeImports.join(
834
+ ", "
835
+ )} } from '${virtualFilePrefix}/runtime/internal';`
821
836
  );
822
837
  }
823
838
  if (middleware.length) {
@@ -931,6 +946,45 @@ function writeRouteEntryHandler(writer, route, verb) {
931
946
  continuations.join();
932
947
  writer.writeBlockEnd("}");
933
948
  }
949
+ function renderErrorRouter(error, options = {
950
+ trailingSlashes: "RedirectWithout"
951
+ }) {
952
+ const writer = createStringWriter();
953
+ writer.write(`
954
+ // @marko/run/router
955
+ import { createContext } from '${virtualFilePrefix}/runtime/internal';
956
+ import errorPage from '${virtualFilePrefix}/${markoRunFilePrefix}error.marko${serverEntryQuery}';
957
+
958
+ const error = new Error(\`${error.message}\`);
959
+ error.name = '${error.name}';`);
960
+ if (error.stack) {
961
+ writer.write(`
962
+ error.stack = \`${error.stack}\`;`);
963
+ }
964
+ writer.write(`
965
+
966
+ globalThis.__marko_run__ = { match, fetch, invoke };
967
+
968
+ export function match() {
969
+ return { handler: errorPage, params: {}, meta: {}, path: '/*' }; // /$$
970
+ }
971
+
972
+ export async function invoke(route, request, platform, url) {
973
+ const [context, buildInput] = createContext(route, request, platform, url);
974
+ if (context.request.headers.get('Accept')?.includes('text/html')) {
975
+ return new Response(errorPage.stream(buildInput({ error })), {
976
+ status: 500,
977
+ headers: { "content-type": "text/html;charset=UTF-8" },
978
+ });
979
+ }
980
+ return new Response(error, {
981
+ status: 500,
982
+ });
983
+ }
984
+ `);
985
+ renderFetch(writer, options);
986
+ return writer.end();
987
+ }
934
988
  function renderRouter(routes, options = {
935
989
  trailingSlashes: "RedirectWithout"
936
990
  }) {
@@ -938,7 +992,7 @@ function renderRouter(routes, options = {
938
992
  writer.writeLines(`// @marko/run/router`);
939
993
  const imports = writer.branch("imports");
940
994
  imports.writeLines(
941
- `import { NotHandled, NotMatched, createContext } from 'virtual:marko-run/internal';`
995
+ `import { NotHandled, NotMatched, createContext } from '${virtualFilePrefix}/runtime/internal';`
942
996
  );
943
997
  for (const route of routes.list) {
944
998
  const verbs = getVerbs(route);
@@ -974,24 +1028,24 @@ globalThis.__marko_run__ = { match, fetch, invoke };
974
1028
  }
975
1029
  }
976
1030
  writer.writeBlockEnd("}").writeLines("return null;").writeBlockEnd("}");
977
- writer.write(`
978
- export async function invoke(route, request, platform, url) {
979
- const [context, buildInput] = createContext(route, request, platform, url);
980
- try {
981
- if (route) {
982
- try {
983
- const response = await route.handler(context, buildInput);
984
- if (response) return response;
985
- } catch (error) {
986
- if (error === NotHandled) {
987
- return;
988
- } else if (error !== NotMatched) {
989
- throw error;
990
- }
991
- }
992
- `);
1031
+ writer.writeLines("").writeBlockStart(
1032
+ "export async function invoke(route, request, platform, url) {"
1033
+ ).writeLines(
1034
+ "const [context, buildInput] = createContext(route, request, platform, url);"
1035
+ );
1036
+ const hasErrorPage = Boolean(routes.special[RoutableFileTypes.Error]);
1037
+ if (hasErrorPage) {
1038
+ writer.writeBlockStart("try {");
1039
+ }
1040
+ writer.writeBlockStart("if (route) {").writeBlockStart("try {").writeLines(
1041
+ "const response = await route.handler(context, buildInput);",
1042
+ "if (response) return response;"
1043
+ ).indent--;
1044
+ writer.writeBlockStart("} catch (error) {").writeLines(
1045
+ "if (error === NotHandled) return;",
1046
+ "if (error !== NotMatched) throw error;"
1047
+ ).writeBlockEnd("}").writeBlockEnd("}");
993
1048
  if (routes.special[RoutableFileTypes.NotFound]) {
994
- writer.indent = 2;
995
1049
  imports.writeLines(
996
1050
  `
997
1051
  const page404ResponseInit = {
@@ -999,33 +1053,31 @@ const page404ResponseInit = {
999
1053
  headers: { "content-type": "text/html;charset=UTF-8" },
1000
1054
  };`
1001
1055
  );
1002
- writer.write(
1003
- ` } else {
1004
- }
1056
+ writer.write(`
1005
1057
  if (context.request.headers.get('Accept')?.includes('text/html')) {
1006
1058
  return new Response(page404.stream(buildInput()), page404ResponseInit);
1007
1059
  }
1008
- `
1009
- );
1010
- } else {
1011
- writer.indent = 3;
1012
- writer.writeBlockEnd("}");
1060
+ `);
1013
1061
  }
1014
1062
  writer.indent--;
1015
- writer.writeBlockStart(`} catch (error) {`);
1016
- if (routes.special[RoutableFileTypes.Error]) {
1063
+ if (hasErrorPage) {
1017
1064
  imports.writeLines(`
1018
1065
  const page500ResponseInit = {
1019
1066
  status: 500,
1020
1067
  headers: { "content-type": "text/html;charset=UTF-8" },
1021
1068
  };`);
1022
- writer.writeBlockStart(
1069
+ writer.writeBlockStart(`} catch (error) {`).writeBlockStart(
1023
1070
  `if (context.request.headers.get('Accept')?.includes('text/html')) {`
1024
1071
  ).writeLines(
1025
1072
  `return new Response(page500.stream(buildInput({ error })), page500ResponseInit);`
1026
- ).writeBlockEnd("}");
1073
+ ).writeBlockEnd("}").writeLines("throw error;").writeBlockEnd("}");
1027
1074
  }
1028
- writer.writeLines(`throw error;`).writeBlockEnd("}").writeBlockEnd("}").write(`
1075
+ writer.writeBlockEnd("}");
1076
+ renderFetch(writer, options);
1077
+ return writer.end();
1078
+ }
1079
+ function renderFetch(writer, options) {
1080
+ writer.write(`
1029
1081
  export async function fetch(request, platform) {
1030
1082
  try {
1031
1083
  const url = new URL(request.url);
@@ -1063,15 +1115,22 @@ export async function fetch(request, platform) {
1063
1115
  const route = match(request.method, pathname);
1064
1116
  return await invoke(route, request, platform, url);
1065
1117
  } catch (error) {
1066
- const body = import.meta.env.DEV
1067
- ? error.stack || error.message || "Internal Server Error"
1068
- : null;
1069
- return new Response(body, {
1118
+ if (import.meta.env.DEV) {
1119
+ let body;
1120
+ if (error.cause) {
1121
+ body = error.cause.stack || error.cause.message || error.cause;
1122
+ } else {
1123
+ body = error.stack || error.message || "Internal Server Error";
1124
+ }
1125
+ return new Response(body, {
1126
+ status: 500
1127
+ });
1128
+ }
1129
+ return new Response(null, {
1070
1130
  status: 500
1071
1131
  });
1072
1132
  }
1073
1133
  }`);
1074
- return writer.end();
1075
1134
  }
1076
1135
  function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
1077
1136
  const { route, dynamic, catchAll } = trie;
@@ -1193,7 +1252,12 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
1193
1252
  }
1194
1253
  if (catchAll) {
1195
1254
  writer.writeLines(
1196
- `return ${renderMatch(verb, catchAll.route, catchAll.path, String(offset))}; // ${catchAll.path.path}`
1255
+ `return ${renderMatch(
1256
+ verb,
1257
+ catchAll.route,
1258
+ catchAll.path,
1259
+ String(offset)
1260
+ )}; // ${catchAll.path.path}`
1197
1261
  );
1198
1262
  } else if (level === 0) {
1199
1263
  writer.writeLines("return null;");
@@ -1235,7 +1299,9 @@ function renderMiddleware(middleware) {
1235
1299
  `// ${virtualFilePrefix}/${markoRunFilePrefix}middleware.js`
1236
1300
  );
1237
1301
  const imports = writer.branch("imports");
1238
- imports.writeLines(`import { normalize } from 'virtual:marko-run/internal';`);
1302
+ imports.writeLines(
1303
+ `import { normalize } from '${virtualFilePrefix}/runtime/internal';`
1304
+ );
1239
1305
  writer.writeLines("");
1240
1306
  for (const { id, importPath } of middleware) {
1241
1307
  const importName = `middleware${id}`;
@@ -1553,7 +1619,9 @@ function logRoutesTable(routes, bundle, options) {
1553
1619
  entryType.push(kleur.yellow("page"));
1554
1620
  size = prettySize(computeRouteSize(getRouteChunkName(route), bundle));
1555
1621
  }
1556
- const row = [kleur.bold(HttpVerbColors[verb](verb.toUpperCase()))];
1622
+ const row = [
1623
+ kleur.bold(HttpVerbColors[verb](verb.toUpperCase()))
1624
+ ];
1557
1625
  if (verbs.length === 1 || firstRow) {
1558
1626
  row.push({ rowSpan: verbs.length, content: prettyPath(path4.path) });
1559
1627
  firstRow = false;
@@ -1591,10 +1659,7 @@ function byteSize(source) {
1591
1659
  }
1592
1660
  function computeChunkSize(chunk, bundle, seen = /* @__PURE__ */ new Set()) {
1593
1661
  if (chunk.type === "asset") {
1594
- return [
1595
- byteSize(chunk.source),
1596
- gzipSize(chunk.source)
1597
- ];
1662
+ return [byteSize(chunk.source), gzipSize(chunk.source)];
1598
1663
  }
1599
1664
  const size = [byteSize(chunk.code), gzipSize(chunk.code)];
1600
1665
  for (const id of chunk.imports) {
@@ -1627,7 +1692,6 @@ function prettyPath(path4) {
1627
1692
  }
1628
1693
 
1629
1694
  // src/vite/plugin.ts
1630
- import { fileURLToPath } from "url";
1631
1695
  var __dirname = path2.dirname(fileURLToPath(import.meta.url));
1632
1696
  var PLUGIN_NAME_PREFIX = "marko-run-vite";
1633
1697
  var POSIX_SEP = "/";
@@ -1660,14 +1724,14 @@ function markoRun(opts = {}) {
1660
1724
  routesBuild: 0,
1661
1725
  routesRender: 0
1662
1726
  };
1663
- async function writeTypesFile() {
1664
- if (tsConfigExists ?? (tsConfigExists = await globFileExists(
1727
+ async function writeTypesFile(routes2) {
1728
+ if (routes2 && (tsConfigExists ?? (tsConfigExists = await globFileExists(
1665
1729
  root,
1666
1730
  "{.tsconfig*,tsconfig*.json}"
1667
- ))) {
1731
+ )))) {
1668
1732
  const filepath = path2.join(typesDir, "routes.d.ts");
1669
1733
  const data = await renderRouteTypeInfo(
1670
- routes,
1734
+ routes2,
1671
1735
  normalizePath(path2.relative(typesDir, resolvedRoutesDir)),
1672
1736
  adapter
1673
1737
  );
@@ -1677,65 +1741,93 @@ function markoRun(opts = {}) {
1677
1741
  }
1678
1742
  }
1679
1743
  }
1680
- async function setVirtualFiles(render = false) {
1681
- for (const route of routes.list) {
1682
- if (render && route.handler) {
1683
- route.handler.verbs = await extractVerbs(route.handler.filePath);
1684
- if (!route.handler.verbs.length) {
1685
- console.warn(
1686
- `Did not find any valid exports in middleware entry file:'${route.handler.filePath}' - expected to find any of 'GET', 'POST', 'PUT' or 'DELETE'`
1744
+ const buildVirtualFiles = single(async (render) => {
1745
+ var _a;
1746
+ const routerOptions = {
1747
+ trailingSlashes: opts.trailingSlashes || "RedirectWithout"
1748
+ };
1749
+ try {
1750
+ if (isStale) {
1751
+ virtualFiles.clear();
1752
+ isRendered = false;
1753
+ const buildStartTime = performance.now();
1754
+ routes = await buildRoutes(
1755
+ createFSWalker(resolvedRoutesDir),
1756
+ routesDir
1757
+ );
1758
+ times.routesBuild = performance.now() - buildStartTime;
1759
+ if (!routes.list.length) {
1760
+ throw new Error("No routes generated");
1761
+ }
1762
+ }
1763
+ const renderStartTime = performance.now();
1764
+ for (const route of routes.list) {
1765
+ if (render && route.handler) {
1766
+ route.handler.verbs = await extractVerbs(route.handler.filePath);
1767
+ if (!route.handler.verbs.length) {
1768
+ throw new Error(
1769
+ `Did not find any valid exports in middleware entry file:'${route.handler.filePath}' - expected to find any of 'GET', 'POST', 'PUT' or 'DELETE'`
1770
+ );
1771
+ }
1772
+ }
1773
+ if (route.page) {
1774
+ virtualFiles.set(
1775
+ path2.posix.join(root, `${route.entryName}.marko`),
1776
+ render ? renderRouteTemplate(route) : ""
1687
1777
  );
1688
1778
  }
1779
+ virtualFiles.set(
1780
+ path2.posix.join(root, `${route.entryName}.js`),
1781
+ render ? renderRouteEntry(route) : ""
1782
+ );
1689
1783
  }
1690
- if (route.page) {
1784
+ for (const route of Object.values(routes.special)) {
1691
1785
  virtualFiles.set(
1692
1786
  path2.posix.join(root, `${route.entryName}.marko`),
1693
1787
  render ? renderRouteTemplate(route) : ""
1694
1788
  );
1695
1789
  }
1790
+ if (routes.middleware.length) {
1791
+ virtualFiles.set(
1792
+ path2.posix.join(root, `${markoRunFilePrefix}middleware.js`),
1793
+ render ? renderMiddleware(routes.middleware) : ""
1794
+ );
1795
+ }
1696
1796
  virtualFiles.set(
1697
- path2.posix.join(root, `${route.entryName}.js`),
1698
- render ? renderRouteEntry(route) : ""
1797
+ "@marko/run/router",
1798
+ render ? renderRouter(routes, routerOptions) : ""
1699
1799
  );
1700
- }
1701
- for (const route of Object.values(routes.special)) {
1800
+ times.routesRender = performance.now() - renderStartTime;
1801
+ if (render) {
1802
+ await writeTypesFile(routes);
1803
+ if (!isBuild) {
1804
+ await ((_a = opts == null ? void 0 : opts.emitRoutes) == null ? void 0 : _a.call(opts, routes.list));
1805
+ }
1806
+ isRendered = true;
1807
+ }
1808
+ } catch (err) {
1809
+ if (isBuild) {
1810
+ throw err;
1811
+ }
1812
+ console.error(err);
1702
1813
  virtualFiles.set(
1703
- path2.posix.join(root, `${route.entryName}.marko`),
1704
- render ? renderRouteTemplate(route) : ""
1814
+ path2.posix.join(root, `${markoRunFilePrefix}error.marko`),
1815
+ renderEntryTemplate(`${markoRunFilePrefix}error`, ["<dev-error-page>"])
1705
1816
  );
1817
+ virtualFiles.set(
1818
+ "@marko/run/router",
1819
+ renderErrorRouter(err, routerOptions)
1820
+ );
1821
+ isRendered = true;
1706
1822
  }
1707
- virtualFiles.set(
1708
- "@marko/run/router",
1709
- render ? renderRouter(routes, {
1710
- trailingSlashes: opts.trailingSlashes || "RedirectWithout"
1711
- }) : ""
1712
- );
1713
- virtualFiles.set(
1714
- path2.posix.join(root, `${markoRunFilePrefix}middleware.js`),
1715
- render ? renderMiddleware(routes.middleware) : ""
1716
- );
1717
- }
1718
- const buildVirtualFiles = single(async () => {
1719
- const startTime = performance.now();
1720
- routes = await buildRoutes(createFSWalker(resolvedRoutesDir), routesDir);
1721
- times.routesBuild = performance.now() - startTime;
1722
- await setVirtualFiles(false);
1723
1823
  isStale = false;
1724
- isRendered = false;
1725
- });
1726
- const renderVirtualFiles = single(async () => {
1727
- const startTime = performance.now();
1728
- await setVirtualFiles(true);
1729
- await writeTypesFile();
1730
- times.routesRender = performance.now() - startTime;
1731
- isRendered = true;
1732
1824
  });
1733
1825
  return [
1734
1826
  {
1735
1827
  name: `${PLUGIN_NAME_PREFIX}:pre`,
1736
1828
  enforce: "pre",
1737
1829
  async config(config2, env) {
1738
- var _a, _b, _c, _d, _e, _f;
1830
+ var _a, _b, _c, _d, _e, _f, _g, _h;
1739
1831
  const externalPluginOptions = getExternalPluginOptions(config2);
1740
1832
  if (externalPluginOptions) {
1741
1833
  opts = mergeConfig(opts, externalPluginOptions);
@@ -1761,6 +1853,11 @@ function markoRun(opts = {}) {
1761
1853
  }
1762
1854
  compiler ?? (compiler = await import(opts.compiler || "@marko/compiler"));
1763
1855
  compiler.taglib.register("@marko/run", {
1856
+ "<dev-error-page>": {
1857
+ template: normalizePath(
1858
+ path2.resolve(__dirname, "../components/dev-error-page.marko")
1859
+ )
1860
+ },
1764
1861
  "<*>": {
1765
1862
  transform: path2.resolve(
1766
1863
  __dirname,
@@ -1825,11 +1922,26 @@ function markoRun(opts = {}) {
1825
1922
  noExternal: /@marko\/run/
1826
1923
  },
1827
1924
  build: {
1925
+ target: isBuild && !((_g = config2.build) == null ? void 0 : _g.target) ? resolveToEsbuildTarget(
1926
+ browserslist(void 0, {
1927
+ path: root
1928
+ }),
1929
+ { printUnknownTargets: false }
1930
+ ) : void 0,
1828
1931
  emptyOutDir: isSSRBuild,
1932
+ // Avoid server & client deleting files from each other.
1829
1933
  rollupOptions: {
1830
1934
  output: rollupOutputOptions
1831
1935
  }
1832
1936
  },
1937
+ optimizeDeps: {
1938
+ entries: !((_h = config2.optimizeDeps) == null ? void 0 : _h.entries) ? [
1939
+ "src/pages/**/*+{page,layout}.marko",
1940
+ "!**/__snapshots__/**",
1941
+ `!**/__tests__/**`,
1942
+ `!**/coverage/**`
1943
+ ] : void 0
1944
+ },
1833
1945
  resolve: isBuild ? {
1834
1946
  browserField: isSSRBuild ? false : void 0,
1835
1947
  conditions: [
@@ -1914,40 +2026,35 @@ function markoRun(opts = {}) {
1914
2026
  },
1915
2027
  async resolveId(importee, importer) {
1916
2028
  let resolved;
1917
- if (importee.startsWith(virtualRuntimePrefix)) {
1918
- return this.resolve(
1919
- path2.resolve(__dirname, "../runtime/internal"),
1920
- importer,
1921
- { skipSelf: true }
1922
- );
1923
- } else if (importee.startsWith(virtualFilePrefix)) {
1924
- importee = path2.resolve(
1925
- root,
1926
- importee.slice(virtualFilePrefix.length + 1)
1927
- );
2029
+ let virtualFilePath;
2030
+ if (importee.startsWith(virtualFilePrefix)) {
2031
+ virtualFilePath = importee.slice(virtualFilePrefix.length + 1);
2032
+ importee = path2.resolve(root, virtualFilePath);
1928
2033
  } else if (!isBuild && importer && (importer === devEntryFile || normalizePath(importer) === devEntryFilePosix) && importee.startsWith(`/${markoRunFilePrefix}`)) {
1929
2034
  importee = path2.resolve(root, "." + importee);
1930
2035
  }
1931
2036
  importee = normalizePath(importee);
1932
2037
  if (isStale) {
1933
- await buildVirtualFiles();
2038
+ await buildVirtualFiles(false);
1934
2039
  }
1935
2040
  if (virtualFiles.has(importee)) {
1936
2041
  resolved = importee;
2042
+ } else if (virtualFilePath) {
2043
+ const filePath = path2.resolve(__dirname, "..", virtualFilePath);
2044
+ const resolution = await this.resolve(filePath, importer, {
2045
+ skipSelf: true
2046
+ });
2047
+ return resolution;
1937
2048
  }
1938
2049
  return resolved || null;
1939
2050
  },
1940
2051
  async load(id) {
1941
- var _a;
1942
2052
  if (id.endsWith(serverEntryQuery)) {
1943
2053
  id = id.slice(0, -serverEntryQuery.length);
1944
2054
  }
1945
2055
  if (virtualFiles.has(id)) {
1946
- if (!isRendered) {
1947
- await renderVirtualFiles();
1948
- if (!isBuild) {
1949
- await ((_a = opts == null ? void 0 : opts.emitRoutes) == null ? void 0 : _a.call(opts, routes.list));
1950
- }
2056
+ if (isStale || !isRendered) {
2057
+ await buildVirtualFiles(true);
1951
2058
  }
1952
2059
  return virtualFiles.get(id);
1953
2060
  }
@@ -1990,12 +2097,12 @@ function markoRun(opts = {}) {
1990
2097
  }
1991
2098
  await store.set(routeDataFilename, JSON.stringify(routeData));
1992
2099
  await ((_a = opts == null ? void 0 : opts.emitRoutes) == null ? void 0 : _a.call(opts, routes.list));
1993
- } else if (isBuild) {
2100
+ } else {
1994
2101
  logRoutesTable(routes, bundle, options);
1995
2102
  }
1996
2103
  },
1997
2104
  async closeBundle() {
1998
- if (isBuild && !isSSRBuild && (adapter == null ? void 0 : adapter.buildEnd)) {
2105
+ if (isBuild && !isSSRBuild && (adapter == null ? void 0 : adapter.buildEnd) && routes) {
1999
2106
  await adapter.buildEnd(
2000
2107
  resolvedConfig,
2001
2108
  routes.list,
@@ -2128,7 +2235,7 @@ var __dirname2 = path3.dirname(fileURLToPath2(import.meta.url));
2128
2235
  var defaultPort = Number(process.env.PORT || 3e3);
2129
2236
  var defaultConfigFileBases = ["serve.config", "vite.config"];
2130
2237
  var defaultConfigFileExts = [".js", ".cjs", ".mjs", ".ts", ".mts"];
2131
- async function preview(entry, cwd, configFile, port, outDir, envFile, args = []) {
2238
+ async function preview(sourceEntry, entry, cwd, configFile, port, outDir, envFile, args = []) {
2132
2239
  const resolvedConfig = await resolveConfig(
2133
2240
  { root: cwd, configFile, logLevel: "silent", build: { outDir } },
2134
2241
  "serve"
@@ -2152,7 +2259,8 @@ async function preview(entry, cwd, configFile, port, outDir, envFile, args = [])
2152
2259
  dir,
2153
2260
  args,
2154
2261
  port: availablePort,
2155
- envFile
2262
+ envFile,
2263
+ sourceEntry
2156
2264
  };
2157
2265
  return await adapter.startPreview(entryFile, options);
2158
2266
  }
@@ -2171,6 +2279,7 @@ async function dev(entry, cwd, configFile, port, envFile, args = []) {
2171
2279
  if (!adapter) {
2172
2280
  throw new Error(
2173
2281
  "No adapter specified for 'dev' command without custom target"
2282
+ // Would the user know what a target is if presented with this error?
2174
2283
  );
2175
2284
  } else if (!adapter.startDev) {
2176
2285
  throw new Error(
@@ -2239,6 +2348,7 @@ async function build(entry, cwd, configFile, outDir, envFile) {
2239
2348
  rollupOptions: {
2240
2349
  output: {
2241
2350
  entryFileNames: "index.mjs"
2351
+ // Would rather build with `.js` extension but that will fail in zero-config projects where node runs in cjs mode
2242
2352
  }
2243
2353
  }
2244
2354
  }
@@ -2302,6 +2412,7 @@ prog.command("preview [entry]").describe("Start a production-like server for alr
2302
2412
  const config2 = await getViteConfig(cwd, opts.config);
2303
2413
  await build(entry, cwd, config2, opts.output, opts.env);
2304
2414
  await preview(
2415
+ entry,
2305
2416
  opts.file,
2306
2417
  cwd,
2307
2418
  config2,
@@ -0,0 +1,14 @@
1
+ export interface Input {
2
+ error: Error
3
+ }
4
+
5
+ <!doctype html>
6
+ <html lang="en">
7
+ <head>
8
+ <meta charset="UTF-8">
9
+ <title>${input.error.message}</title>
10
+ </head>
11
+ <body>
12
+ <pre>${input.error.stack || (input.error.name + ': ' + input.error.message)}</pre>
13
+ </body>
14
+ </html>
@@ -1,7 +1,9 @@
1
+ import { InlineConfig } from "vite";
1
2
  import { NotHandled, NotMatched } from "./namespace";
2
3
  import type { GetPaths, PostPaths, GetablePath, GetableHref, PostablePath, PostableHref, Platform, HandlerTypeFn, RuntimeModule, AnyRoute, AnyContext, AnyHandler } from "./types";
3
4
  declare global {
4
5
  var __marko_run__: RuntimeModule;
6
+ var __marko_run_vite_config__: InlineConfig | undefined;
5
7
  namespace MarkoRun {
6
8
  export const route: HandlerTypeFn;
7
9
  export { GetPaths, PostPaths, GetablePath, GetableHref, PostablePath, PostableHref, Platform, NotHandled, NotMatched, AnyRoute as Route, AnyContext as Context, AnyHandler as Handler, };
@@ -1,6 +1,8 @@
1
1
  import type { Adapter, Route, BuiltRoutes, RoutableFile, RouterOptions } from "../types";
2
2
  export declare function renderRouteTemplate(route: Route): string;
3
+ export declare function renderEntryTemplate(name: string, files: string[]): string;
3
4
  export declare function renderRouteEntry(route: Route): string;
5
+ export declare function renderErrorRouter(error: Error, options?: RouterOptions): string;
4
6
  export declare function renderRouter(routes: BuiltRoutes, options?: RouterOptions): string;
5
7
  export declare function renderMiddleware(middleware: RoutableFile[]): string;
6
8
  export declare function renderRouteTypeInfo(routes: BuiltRoutes, pathPrefix?: string, adapter?: Adapter | null): Promise<string>;
@@ -1,8 +1,6 @@
1
1
  type ValuesOf<T> = T[keyof T];
2
2
  export declare const markoRunFilePrefix = "__marko-run__";
3
3
  export declare const virtualFilePrefix = "virtual:marko-run";
4
- export declare const virtualRoutesPrefix: string;
5
- export declare const virtualRuntimePrefix: string;
6
4
  export declare const httpVerbs: readonly ["get", "post", "put", "delete"];
7
5
  export declare const serverEntryQuery = "?marko-server-entry";
8
6
  export declare const browserEntryQuery = "?marko-browser-entry";