dtwo 3.0.0-rc.14 → 3.1.0-0

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.
Files changed (61) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +6 -2
  3. package/bin/dtwo.mjs +1 -1
  4. package/config.d.ts +1 -1
  5. package/dist/app/compat/idle-callback.d.ts +2 -0
  6. package/dist/app/compat/idle-callback.mjs +13 -0
  7. package/dist/app/components/dtwo-island.d.ts +33 -0
  8. package/dist/app/components/dtwo-island.mjs +62 -0
  9. package/dist/app/components/dtwo-link.d.ts +3 -3
  10. package/dist/app/components/dtwo-link.mjs +26 -28
  11. package/dist/app/components/dtwo-loading-indicator.d.ts +3 -3
  12. package/dist/app/components/dtwo-loading-indicator.mjs +8 -7
  13. package/dist/app/components/dtwo-root.kdu +10 -2
  14. package/dist/app/components/island-renderer.d.ts +20 -0
  15. package/dist/app/components/island-renderer.mjs +26 -0
  16. package/dist/app/components/layout.d.ts +1 -1
  17. package/dist/app/components/layout.mjs +12 -3
  18. package/dist/app/components/utils.mjs +1 -0
  19. package/dist/app/composables/asyncData.d.ts +5 -2
  20. package/dist/app/composables/asyncData.mjs +15 -2
  21. package/dist/app/composables/component.d.ts +1 -1
  22. package/dist/app/composables/cookie.d.ts +5 -4
  23. package/dist/app/composables/cookie.mjs +8 -2
  24. package/dist/app/composables/error.d.ts +1 -1
  25. package/dist/app/composables/fetch.d.ts +6 -6
  26. package/dist/app/composables/fetch.mjs +2 -1
  27. package/dist/app/composables/index.d.ts +2 -1
  28. package/dist/app/composables/index.mjs +2 -1
  29. package/dist/app/composables/ready.d.ts +1 -0
  30. package/dist/app/composables/ready.mjs +12 -0
  31. package/dist/app/composables/router.d.ts +1 -1
  32. package/dist/app/composables/router.mjs +5 -0
  33. package/dist/app/composables/ssr.d.ts +1 -1
  34. package/dist/app/config.mjs +1 -0
  35. package/dist/app/dtwo.d.ts +5 -4
  36. package/dist/app/plugins/cross-origin-prefetch.client.mjs +19 -14
  37. package/dist/app/plugins/router.mjs +13 -5
  38. package/dist/app/types/augments.d.ts +1 -1
  39. package/dist/components/runtime/server-component.d.ts +3 -0
  40. package/dist/components/runtime/server-component.mjs +87 -0
  41. package/dist/core/runtime/hole/renderer.d.ts +19 -0
  42. package/dist/core/runtime/hole/renderer.mjs +71 -9
  43. package/dist/head/runtime/components.d.ts +14 -14
  44. package/dist/head/runtime/components.mjs +12 -1
  45. package/dist/head/runtime/composables.d.ts +17 -0
  46. package/dist/head/runtime/composables.mjs +9 -0
  47. package/dist/head/runtime/lib/kduse-head.plugin.mjs +2 -1
  48. package/dist/index.mjs +298 -79
  49. package/dist/pages/runtime/composables.d.ts +1 -1
  50. package/dist/pages/runtime/page.d.ts +5 -1
  51. package/dist/pages/runtime/page.mjs +6 -3
  52. package/dist/pages/runtime/plugins/prefetch.client.mjs +36 -0
  53. package/dist/pages/runtime/{router.d.ts → plugins/router.d.ts} +1 -1
  54. package/dist/pages/runtime/{router.mjs → plugins/router.mjs} +11 -8
  55. package/dist/pages/runtime/utils.d.ts +1 -1
  56. package/dist/pages/runtime/utils.mjs +1 -1
  57. package/dist/pages/runtime/validate.mjs +4 -4
  58. package/package.json +51 -51
  59. package/types.d.ts +3 -0
  60. package/dist/head/runtime/lib/kdu-meta.plugin.mjs +0 -31
  61. /package/dist/{head/runtime/lib/kdu-meta.plugin.d.ts → pages/runtime/plugins/prefetch.client.d.ts} +0 -0
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { dirname, resolve, basename, extname, relative, normalize, isAbsolute, join } from 'pathe';
2
2
  import { createHooks, createDebugger } from 'hookable';
3
- import { useDtwo, resolveFiles, defineDtwoModule, addPlugin, addTemplate, addComponent, updateTemplates, addWitePlugin, addWebpackPlugin, findPath, isIgnored, resolveAlias, addPluginTemplate, logger, resolvePath, dtwoCtx, tryResolveModule, installModule, loadDtwoConfig, normalizeTemplate, compileTemplate, normalizePlugin, templateUtils, importModule } from '@dtwo/kit';
3
+ import { useDtwo, resolveFiles, defineDtwoModule, addPlugin, addTemplate, addComponent, updateTemplates, addWitePlugin, addWebpackPlugin, findPath, isIgnored, resolveAlias, addPluginTemplate, logger, resolvePath, createResolver, dtwoCtx, tryResolveModule, installModule, loadDtwoConfig, normalizeTemplate, compileTemplate, normalizePlugin, templateUtils, importModule } from '@dtwo/kit';
4
4
  import escapeRE from 'escape-string-regexp';
5
5
  import fse from 'fs-extra';
6
6
  import { encodePath, parseURL, stringifyQuery, parseQuery, joinURL, withTrailingSlash, withoutLeadingSlash } from 'ufo';
@@ -15,18 +15,21 @@ import MagicString from 'magic-string';
15
15
  import { globby } from 'globby';
16
16
  import { hyphenate } from '@kdujs/shared';
17
17
  import { parse, walk as walk$1, ELEMENT_NODE } from 'ultrahtml';
18
- import { defineKdimportPreset, createKdimport, toImports, scanDirExports } from 'kdimport';
18
+ import { defineKdimportPreset, createKdimport, scanDirExports } from 'kdimport';
19
19
  import { createRequire } from 'node:module';
20
20
  import { createTransformer } from 'unctx/transform';
21
21
  import { stripLiteral } from 'strip-literal';
22
22
  import { createHole, scanHandlers, writeTypes, build as build$1, prepare, copyPublicAssets, prerender, createDevServer } from 'holepack';
23
- import defu from 'defu';
23
+ import defu, { defu as defu$1 } from 'defu';
24
24
  import { dynamicEventHandler } from 'h3';
25
25
  import { createHeadCore } from 'kdhead';
26
26
  import { renderSSRHead } from '@kdhead/ssr';
27
+ import { rm, mkdir, writeFile } from 'node:fs/promises';
27
28
  import chokidar from 'chokidar';
28
29
  import { debounce } from 'perfect-debounce';
29
- import { generateTypes, resolveSchema } from 'untyped';
30
+ import { resolveSchema, generateMarkdown, generateTypes } from 'untyped';
31
+ import untypedPlugin from 'untyped/babel-plugin';
32
+ import jiti from 'jiti';
30
33
  import { hash } from 'ohash';
31
34
 
32
35
  let _distDir = dirname(fileURLToPath(import.meta.url));
@@ -192,26 +195,30 @@ function prepareRoutes(routes, parent) {
192
195
  return routes;
193
196
  }
194
197
  function normalizeRoutes(routes, metaImports = /* @__PURE__ */ new Set()) {
198
+ const dtwo = useDtwo();
195
199
  return {
196
200
  imports: metaImports,
197
- routes: genArrayFromRaw(routes.map((route) => {
198
- const file = normalize(route.file);
199
- const metaImportName = genSafeVariableName(file) + "Meta";
201
+ routes: genArrayFromRaw(routes.map((page) => {
202
+ const file = normalize(page.file);
203
+ const metaImportName = genSafeVariableName(relative(dtwo.options.rootDir, file)) + "Meta";
200
204
  metaImports.add(genImport(`${file}?macro=true`, [{ name: "default", as: metaImportName }]));
201
205
  let aliasCode = `${metaImportName}?.alias || []`;
202
- if (Array.isArray(route.alias) && route.alias.length) {
203
- aliasCode = `${JSON.stringify(route.alias)}.concat(${aliasCode})`;
204
- }
205
- return {
206
- ...Object.fromEntries(Object.entries(route).map(([key, value]) => [key, JSON.stringify(value)])),
207
- name: `${metaImportName}?.name ?? ${route.name ? JSON.stringify(route.name) : "undefined"}`,
208
- path: `${metaImportName}?.path ?? ${JSON.stringify(route.path)}`,
209
- children: route.children ? normalizeRoutes(route.children, metaImports).routes : [],
210
- meta: route.meta ? `{...(${metaImportName} || {}), ...${JSON.stringify(route.meta)}}` : metaImportName,
206
+ if (Array.isArray(page.alias) && page.alias.length) {
207
+ aliasCode = `${JSON.stringify(page.alias)}.concat(${aliasCode})`;
208
+ }
209
+ const route = {
210
+ ...Object.fromEntries(Object.entries(page).map(([key, value]) => [key, JSON.stringify(value)])),
211
+ file: void 0,
212
+ name: `${metaImportName}?.name ?? ${page.name ? JSON.stringify(page.name) : "undefined"}`,
213
+ path: `${metaImportName}?.path ?? ${JSON.stringify(page.path)}`,
214
+ children: page.children ? normalizeRoutes(page.children, metaImports).routes : [],
215
+ meta: page.meta ? `{...(${metaImportName} || {}), ...${JSON.stringify(page.meta)}}` : metaImportName,
211
216
  alias: aliasCode,
212
- redirect: route.redirect ? JSON.stringify(route.redirect) : `${metaImportName}?.redirect || undefined`,
217
+ redirect: page.redirect ? JSON.stringify(page.redirect) : `${metaImportName}?.redirect || undefined`,
213
218
  component: genDynamicImport(file, { interopDefault: true })
214
219
  };
220
+ delete route.file;
221
+ return route;
215
222
  }))
216
223
  };
217
224
  }
@@ -227,7 +234,7 @@ if (import.meta.hot) {
227
234
  Object.assign(__dtwo_page_meta, mod)
228
235
  })
229
236
  }
230
- // Webpack
237
+ // webpack
231
238
  if (import.meta.webpackHot) {
232
239
  import.meta.webpackHot.accept((err) => {
233
240
  if (err) { window.location = window.location.href }
@@ -500,7 +507,8 @@ const pagesModule = defineDtwoModule({
500
507
  };
501
508
  addWitePlugin(PageMetaPlugin.wite(pageMetaOptions));
502
509
  addWebpackPlugin(PageMetaPlugin.webpack(pageMetaOptions));
503
- addPlugin(resolve(runtimeDir, "router"));
510
+ addPlugin(resolve(runtimeDir, "plugins/prefetch.client"));
511
+ addPlugin(resolve(runtimeDir, "plugins/router"));
504
512
  const getSources = (pages) => pages.flatMap(
505
513
  (p) => [relative(dtwo.options.srcDir, p.file), ...getSources(p.children || [])]
506
514
  );
@@ -543,6 +551,7 @@ const pagesModule = defineDtwoModule({
543
551
  `const configRouterOptions = ${configRouterOptions}`,
544
552
  "export default {",
545
553
  "...configRouterOptions,",
554
+ // We need to reverse spreading order to respect layers priority
546
555
  ...routerOptionsFiles.map((_, index) => `...routerOptions${index},`).reverse(),
547
556
  "}"
548
557
  ].join("\n");
@@ -605,6 +614,7 @@ const metaModule = defineDtwoModule({
605
614
  name: componentName,
606
615
  filePath: componentsPath,
607
616
  export: componentName,
617
+ // kebab case version of these tags is not valid
608
618
  kebabName: componentName
609
619
  });
610
620
  }
@@ -643,11 +653,12 @@ export default defineDtwoPlugin(dtwoApp => {
643
653
  }
644
654
  };
645
655
  const componentsTemplate = {
656
+ // components.[server|client].mjs'
646
657
  getContents({ options }) {
647
658
  const imports = /* @__PURE__ */ new Set();
648
659
  imports.add("import { defineAsyncComponent } from 'kdu'");
649
660
  let num = 0;
650
- const components = options.getComponents(options.mode).flatMap((c) => {
661
+ const components = options.getComponents(options.mode).filter((c) => !c.island).flatMap((c) => {
651
662
  const exp = c.export === "default" ? "c.default || c" : `c['${c.export}']`;
652
663
  const comment = createImportMagicComments(c);
653
664
  const isClient = c.mode === "client";
@@ -667,15 +678,32 @@ const componentsTemplate = {
667
678
  return [
668
679
  ...imports,
669
680
  ...components,
670
- `export const componentNames = ${JSON.stringify(options.getComponents().map((c) => c.pascalName))}`
681
+ `export const componentNames = ${JSON.stringify(options.getComponents().filter((c) => !c.island).map((c) => c.pascalName))}`
671
682
  ].join("\n");
672
683
  }
673
684
  };
685
+ const componentsIslandsTemplate = {
686
+ // components.islands.mjs'
687
+ getContents({ options }) {
688
+ const components = options.getComponents();
689
+ const islands = components.filter(
690
+ (component) => component.island || // .server components without a corresponding .client component will need to be rendered as an island
691
+ component.mode === "server" && !components.some((c) => c.pascalName === component.pascalName && c.mode === "client")
692
+ );
693
+ return islands.map(
694
+ (c) => {
695
+ const exp = c.export === "default" ? "c.default || c" : `c['${c.export}']`;
696
+ const comment = createImportMagicComments(c);
697
+ return `export const ${c.pascalName} = defineAsyncComponent(${genDynamicImport(c.filePath, { comment })}.then(c => ${exp}))`;
698
+ }
699
+ ).join("\n");
700
+ }
701
+ };
674
702
  const componentsTypeTemplate = {
675
703
  filename: "components.d.ts",
676
704
  getContents: ({ options, dtwo }) => {
677
705
  const buildDir = dtwo.options.buildDir;
678
- const componentTypes = options.getComponents().map((c) => [
706
+ const componentTypes = options.getComponents().filter((c) => !c.island).map((c) => [
679
707
  c.pascalName,
680
708
  `typeof ${genDynamicImport(isAbsolute(c.filePath) ? relative(buildDir, c.filePath).replace(/(?<=\w)\.(?!kdu)\w+$/g, "") : c.filePath.replace(/(?<=\w)\.(?!kdu)\w+$/g, ""), { wrapper: false })}['${c.export}']`
681
709
  ]);
@@ -716,9 +744,10 @@ async function scanComponents(dirs, srcDir) {
716
744
  dir.pathPrefix !== false ? splitByCase(relative(dir.path, dirname(filePath))) : []
717
745
  );
718
746
  let fileName = basename(filePath, extname(filePath));
719
- const global = /\.(global)$/.test(fileName) || dir.global;
720
- const mode = fileName.match(/(?<=\.)(client|server)(\.global)?$/)?.[1] || "all";
721
- fileName = fileName.replace(/(\.(client|server))?(\.global)?$/, "");
747
+ const island = /\.(island)(\.global)?$/.test(fileName) || dir.island;
748
+ const global = /\.(global)(\.island)?$/.test(fileName) || dir.global;
749
+ const mode = island ? "server" : fileName.match(/(?<=\.)(client|server)(\.global|\.island)*$/)?.[1] || "all";
750
+ fileName = fileName.replace(/(\.(client|server))?(\.global|\.island)*$/, "");
722
751
  if (fileName.toLowerCase() === "index") {
723
752
  fileName = dir.pathPrefix === false ? basename(dirname(filePath)) : "";
724
753
  }
@@ -744,10 +773,13 @@ async function scanComponents(dirs, srcDir) {
744
773
  const shortPath = relative(srcDir, filePath);
745
774
  const chunkName = "components/" + kebabName + suffix;
746
775
  let component = {
776
+ // inheritable from directory configuration
747
777
  mode,
748
778
  global,
779
+ island,
749
780
  prefetch: Boolean(dir.prefetch),
750
781
  preload: Boolean(dir.preload),
782
+ // specific to the file
751
783
  filePath,
752
784
  pascalName,
753
785
  kebabName,
@@ -787,6 +819,7 @@ function isKduTemplate(id) {
787
819
  const loaderPlugin = createUnplugin((options) => {
788
820
  const exclude = options.transform?.exclude || [];
789
821
  const include = options.transform?.include || [];
822
+ const serverComponentRuntime = resolve(distDir, "components/runtime/server-component");
790
823
  return {
791
824
  name: "dtwo:components-loader",
792
825
  enforce: "post",
@@ -810,6 +843,15 @@ const loaderPlugin = createUnplugin((options) => {
810
843
  if (component) {
811
844
  let identifier = map.get(component) || `__dtwo_component_${num++}`;
812
845
  map.set(component, identifier);
846
+ const isServerOnly = component.mode === "server" && !components.some((c) => c.pascalName === component.pascalName && c.mode === "client");
847
+ if (isServerOnly) {
848
+ imports.add(genImport(serverComponentRuntime, [{ name: "createServerComponent" }]));
849
+ imports.add(`const ${identifier} = createServerComponent(${JSON.stringify(name)})`);
850
+ if (!options.experimentalComponentIslands) {
851
+ console.warn(`Standalone server components (\`${name}\`) are not yet supported without enabling \`experimental.componentIslands\`.`);
852
+ }
853
+ return identifier;
854
+ }
813
855
  const isClientOnly = component.mode === "client";
814
856
  if (isClientOnly) {
815
857
  imports.add(genImport("#app/components/client-only", [{ name: "createClientOnly" }]));
@@ -845,10 +887,13 @@ const loaderPlugin = createUnplugin((options) => {
845
887
  function findComponent(components, name, mode) {
846
888
  const id = pascalCase(name).replace(/["']/g, "");
847
889
  const component = components.find((component2) => id === component2.pascalName && ["all", mode, void 0].includes(component2.mode));
848
- if (!component && components.some((component2) => id === component2.pascalName)) {
849
- return components.find((component2) => component2.pascalName === "ServerPlaceholder");
890
+ if (component) {
891
+ return component;
892
+ }
893
+ if (mode === "server" && !component) {
894
+ return components.find((c) => c.pascalName === "ServerPlaceholder");
850
895
  }
851
- return component;
896
+ return components.find((component2) => id === component2.pascalName);
852
897
  }
853
898
 
854
899
  const PLACEHOLDER_RE = /^(k-slot|#)(fallback|placeholder)/;
@@ -912,7 +957,7 @@ const isDirectory = (p) => {
912
957
  function compareDirByPathLength({ path: pathA }, { path: pathB }) {
913
958
  return pathB.split(/[\\/]/).filter(Boolean).length - pathA.split(/[\\/]/).filter(Boolean).length;
914
959
  }
915
- const DEFAULT_COMPONENTS_DIRS_RE = /\/components$|\/components\/global$/;
960
+ const DEFAULT_COMPONENTS_DIRS_RE = /\/components(\/global|\/islands)?$/;
916
961
  const componentsModule = defineDtwoModule({
917
962
  meta: {
918
963
  name: "components",
@@ -935,6 +980,7 @@ const componentsModule = defineDtwoModule({
935
980
  }
936
981
  if (dir === true || dir === void 0) {
937
982
  return [
983
+ { path: resolve(cwd, "components/islands"), island: true },
938
984
  { path: resolve(cwd, "components/global"), global: true },
939
985
  { path: resolve(cwd, "components") }
940
986
  ];
@@ -968,13 +1014,16 @@ const componentsModule = defineDtwoModule({
968
1014
  return {
969
1015
  global: componentOptions.global,
970
1016
  ...dirOptions,
1017
+ // TODO
971
1018
  enabled: true,
972
1019
  path: dirPath,
973
1020
  extensions,
974
1021
  pattern: dirOptions.pattern || `**/*.{${extensions.join(",")},}`,
975
1022
  ignore: [
976
1023
  "**/*{M,.m,-m}ixin.{js,ts,jsx,tsx}",
1024
+ // ignore mixins
977
1025
  "**/*.d.ts",
1026
+ // .d.ts files
978
1027
  ...dirOptions.ignore || []
979
1028
  ],
980
1029
  transpile: transpile === "auto" ? dirPath.includes("node_modules") : transpile
@@ -990,6 +1039,11 @@ const componentsModule = defineDtwoModule({
990
1039
  addPluginTemplate({ ...componentsPluginTemplate, options: { getComponents } });
991
1040
  addTemplate({ ...componentsTemplate, filename: "components.server.mjs", options: { getComponents, mode: "server" } });
992
1041
  addTemplate({ ...componentsTemplate, filename: "components.client.mjs", options: { getComponents, mode: "client" } });
1042
+ if (dtwo.options.experimental.componentIslands) {
1043
+ addTemplate({ ...componentsIslandsTemplate, filename: "components.islands.mjs", options: { getComponents } });
1044
+ } else {
1045
+ addTemplate({ filename: "components.islands.mjs", getContents: () => "export default {}" });
1046
+ }
993
1047
  dtwo.hook("wite:extendConfig", (config, { isClient }) => {
994
1048
  const mode = isClient ? "client" : "server";
995
1049
  config.resolve.alias["#components"] = resolve(dtwo.options.buildDir, `components.${mode}.mjs`);
@@ -1049,7 +1103,8 @@ const componentsModule = defineDtwoModule({
1049
1103
  config.plugins.push(loaderPlugin.wite({
1050
1104
  sourcemap: dtwo.options.sourcemap[mode],
1051
1105
  getComponents,
1052
- mode
1106
+ mode,
1107
+ experimentalComponentIslands: dtwo.options.experimental.componentIslands
1053
1108
  }));
1054
1109
  if (dtwo.options.experimental.treeshakeClientOnly && isServer) {
1055
1110
  config.plugins.push(TreeShakeTemplatePlugin.wite({
@@ -1065,7 +1120,8 @@ const componentsModule = defineDtwoModule({
1065
1120
  config.plugins.push(loaderPlugin.webpack({
1066
1121
  sourcemap: dtwo.options.sourcemap[mode],
1067
1122
  getComponents,
1068
- mode
1123
+ mode,
1124
+ experimentalComponentIslands: dtwo.options.experimental.componentIslands
1069
1125
  }));
1070
1126
  if (dtwo.options.experimental.treeshakeClientOnly && mode === "server") {
1071
1127
  config.plugins.push(TreeShakeTemplatePlugin.webpack({
@@ -1116,12 +1172,16 @@ const TransformPlugin = createUnplugin(({ ctx, options, sourcemap }) => {
1116
1172
  });
1117
1173
 
1118
1174
  const commonPresets = [
1175
+ // #head
1119
1176
  defineKdimportPreset({
1120
1177
  from: "#head",
1121
1178
  imports: [
1122
- "useHead"
1179
+ "useHead",
1180
+ "useSeoMeta",
1181
+ "useServerSeoMeta"
1123
1182
  ]
1124
1183
  }),
1184
+ // kdu-demi (mocked)
1125
1185
  defineKdimportPreset({
1126
1186
  from: "kdu-demi",
1127
1187
  imports: [
@@ -1135,6 +1195,7 @@ const appPreset = defineKdimportPreset({
1135
1195
  imports: [
1136
1196
  "useAsyncData",
1137
1197
  "useLazyAsyncData",
1198
+ "useDtwoData",
1138
1199
  "refreshDtwoData",
1139
1200
  "clearDtwoData",
1140
1201
  "defineDtwoComponent",
@@ -1149,14 +1210,13 @@ const appPreset = defineKdimportPreset({
1149
1210
  "useRequestEvent",
1150
1211
  "setResponseStatus",
1151
1212
  "setPageLayout",
1213
+ "onDtwoReady",
1152
1214
  "useRouter",
1153
1215
  "useRoute",
1154
- "useActiveRoute",
1155
1216
  "defineDtwoRouteMiddleware",
1156
1217
  "navigateTo",
1157
1218
  "abortNavigation",
1158
1219
  "addRouteMiddleware",
1159
- "throwError",
1160
1220
  "showError",
1161
1221
  "clearError",
1162
1222
  "isDtwoError",
@@ -1184,12 +1244,14 @@ const routerPreset = defineKdimportPreset({
1184
1244
  const kduPreset = defineKdimportPreset({
1185
1245
  from: "kdu",
1186
1246
  imports: [
1247
+ // <script setup>
1187
1248
  "withCtx",
1188
1249
  "withDirectives",
1189
1250
  "withKeys",
1190
1251
  "withMemo",
1191
1252
  "withModifiers",
1192
1253
  "withScopeId",
1254
+ // Lifecycle
1193
1255
  "onActivated",
1194
1256
  "onBeforeMount",
1195
1257
  "onBeforeUnmount",
@@ -1202,6 +1264,7 @@ const kduPreset = defineKdimportPreset({
1202
1264
  "onServerPrefetch",
1203
1265
  "onUnmounted",
1204
1266
  "onUpdated",
1267
+ // Reactivity
1205
1268
  "computed",
1206
1269
  "customRef",
1207
1270
  "isProxy",
@@ -1224,10 +1287,12 @@ const kduPreset = defineKdimportPreset({
1224
1287
  "watch",
1225
1288
  "watchEffect",
1226
1289
  "isShallow",
1290
+ // effect
1227
1291
  "effect",
1228
1292
  "effectScope",
1229
1293
  "getCurrentScope",
1230
1294
  "onScopeDispose",
1295
+ // Component
1231
1296
  "defineComponent",
1232
1297
  "defineAsyncComponent",
1233
1298
  "resolveComponent",
@@ -1264,19 +1329,21 @@ const importsModule = defineDtwoModule({
1264
1329
  transform: {
1265
1330
  include: [],
1266
1331
  exclude: void 0
1267
- }
1332
+ },
1333
+ virtualImports: ["#imports"]
1268
1334
  },
1269
1335
  async setup(options, dtwo) {
1270
1336
  const presets = JSON.parse(JSON.stringify(options.presets));
1271
1337
  await dtwo.callHook("imports:sources", presets);
1272
1338
  const ctx = createKdimport({
1273
- presets,
1274
- imports: options.imports,
1275
- virtualImports: ["#imports"],
1339
+ ...options,
1276
1340
  addons: {
1277
- kduTemplate: options.autoImport
1278
- }
1341
+ kduTemplate: options.autoImport,
1342
+ ...options.addons
1343
+ },
1344
+ presets
1279
1345
  });
1346
+ await dtwo.callHook("imports:context", ctx);
1280
1347
  let composablesDirs = [];
1281
1348
  for (const layer of dtwo.options._layers) {
1282
1349
  composablesDirs.push(resolve(layer.config.srcDir, "composables"));
@@ -1295,28 +1362,17 @@ const importsModule = defineDtwoModule({
1295
1362
  getContents: async () => await ctx.toExports() + '\nif (process.dev) { console.warn("[dtwo] `#imports` should be transformed with real imports. There seems to be something wrong with the imports plugin.") }'
1296
1363
  });
1297
1364
  dtwo.options.alias["#imports"] = join(dtwo.options.buildDir, "imports");
1298
- if (dtwo.options.dev && options.global) {
1299
- addPluginTemplate({
1300
- filename: "imports.mjs",
1301
- getContents: async () => {
1302
- const imports = await ctx.getImports();
1303
- const importStatement = toImports(imports);
1304
- const globalThisSet = imports.map((i) => `globalThis.${i.as} = ${i.as};`).join("\n");
1305
- return `${importStatement}
1306
-
1307
- ${globalThisSet}
1308
-
1309
- export default () => {};`;
1310
- }
1311
- });
1312
- } else {
1313
- addWitePlugin(TransformPlugin.wite({ ctx, options, sourcemap: dtwo.options.sourcemap.server || dtwo.options.sourcemap.client }));
1314
- addWebpackPlugin(TransformPlugin.webpack({ ctx, options, sourcemap: dtwo.options.sourcemap.server || dtwo.options.sourcemap.client }));
1315
- }
1365
+ addWitePlugin(TransformPlugin.wite({ ctx, options, sourcemap: dtwo.options.sourcemap.server || dtwo.options.sourcemap.client }));
1366
+ addWebpackPlugin(TransformPlugin.webpack({ ctx, options, sourcemap: dtwo.options.sourcemap.server || dtwo.options.sourcemap.client }));
1367
+ const priorities = dtwo.options._layers.map((layer, i) => [layer.config.srcDir, -i]).sort(([a], [b]) => b.length - a.length);
1316
1368
  const regenerateImports = async () => {
1317
1369
  ctx.clearDynamicImports();
1318
1370
  await ctx.modifyDynamicImports(async (imports) => {
1319
- imports.push(...await scanDirExports(composablesDirs));
1371
+ const composableImports = await scanDirExports(composablesDirs);
1372
+ for (const i of composableImports) {
1373
+ i.priority = i.priority || priorities.find(([dir]) => i.from.startsWith(dir))?.[1];
1374
+ }
1375
+ imports.push(...composableImports);
1320
1376
  await dtwo.callHook("imports:extend", imports);
1321
1377
  });
1322
1378
  };
@@ -1370,7 +1426,7 @@ function addDeclarationTemplates(ctx, options) {
1370
1426
  });
1371
1427
  }
1372
1428
 
1373
- const version = "3.0.0-rc.14";
1429
+ const version = "3.1.0-0";
1374
1430
 
1375
1431
  const _require = createRequire(import.meta.url);
1376
1432
  const kduAppPatterns = (dtwo) => [
@@ -1430,7 +1486,7 @@ const UnctxTransformPlugin = (dtwo) => {
1430
1486
  app = _app;
1431
1487
  });
1432
1488
  return createUnplugin((options = {}) => ({
1433
- name: "unctx:transfrom",
1489
+ name: "unctx:transform",
1434
1490
  enforce: "post",
1435
1491
  transformInclude(id) {
1436
1492
  id = normalize(id).replace(/\?.*$/, "");
@@ -1451,7 +1507,7 @@ const UnctxTransformPlugin = (dtwo) => {
1451
1507
  const TreeShakePlugin = createUnplugin((options) => {
1452
1508
  const COMPOSABLE_RE = new RegExp(`($\\s+)(${options.treeShake.join("|")})(?=\\()`, "gm");
1453
1509
  return {
1454
- name: "dtwo:server-treeshake:transfrom",
1510
+ name: "dtwo:server-treeshake:transform",
1455
1511
  enforce: "post",
1456
1512
  transformInclude(id) {
1457
1513
  const { pathname, search } = parseURL(decodeURIComponent(pathToFileURL(id).href));
@@ -1483,9 +1539,9 @@ const TreeShakePlugin = createUnplugin((options) => {
1483
1539
  });
1484
1540
 
1485
1541
  const DevOnlyPlugin = createUnplugin((options) => {
1486
- const DEVONLY_COMP_RE = /<dev-?only>(:?[\s\S]*)<\/dev-?only>/gmi;
1542
+ const DEVONLY_COMP_RE = /<(dev-only|DevOnly)>[\s\S]*?<\/(dev-only|DevOnly)>/g;
1487
1543
  return {
1488
- name: "dtwo:server-devonly:transfrom",
1544
+ name: "dtwo:server-devonly:transform",
1489
1545
  enforce: "pre",
1490
1546
  transformInclude(id) {
1491
1547
  const { pathname, search } = parseURL(decodeURIComponent(pathToFileURL(id).href));
@@ -1540,6 +1596,20 @@ async function initHole(dtwo) {
1540
1596
  srcDir: dtwo.options.serverDir,
1541
1597
  dev: dtwo.options.dev,
1542
1598
  buildDir: dtwo.options.buildDir,
1599
+ imports: {
1600
+ imports: [
1601
+ {
1602
+ as: "__buildAssetsURL",
1603
+ name: "buildAssetsURL",
1604
+ from: resolve(distDir, "core/runtime/hole/paths")
1605
+ },
1606
+ {
1607
+ as: "__publicAssetsURL",
1608
+ name: "publicAssetsURL",
1609
+ from: resolve(distDir, "core/runtime/hole/paths")
1610
+ }
1611
+ ]
1612
+ },
1543
1613
  esbuild: {
1544
1614
  options: {
1545
1615
  exclude: [
@@ -1591,6 +1661,7 @@ async function initHole(dtwo) {
1591
1661
  "@dtwo/",
1592
1662
  dtwo.options.buildDir
1593
1663
  ],
1664
+ ...dtwo.options.build.transpile.filter((i) => typeof i === "string"),
1594
1665
  "dtwo/dist",
1595
1666
  "dtwo3/dist",
1596
1667
  distDir
@@ -1602,13 +1673,16 @@ async function initHole(dtwo) {
1602
1673
  "kdu/server-renderer": "kdu/server-renderer",
1603
1674
  kdu: await resolvePath(`kdu/dist/kdu.cjs${dtwo.options.dev ? "" : ".prod"}.js`)
1604
1675
  },
1676
+ // Kdu 3 mocks
1605
1677
  "estree-walker": "unenv/runtime/mock/proxy",
1606
1678
  "@babel/parser": "unenv/runtime/mock/proxy",
1607
1679
  "@kdujs/compiler-core": "unenv/runtime/mock/proxy",
1608
1680
  "@kdujs/compiler-dom": "unenv/runtime/mock/proxy",
1609
1681
  "@kdujs/compiler-ssr": "unenv/runtime/mock/proxy",
1610
1682
  "@kdujs/devtools-api": "kdu-devtools-stub",
1683
+ // Paths
1611
1684
  "#paths": resolve(distDir, "core/runtime/hole/paths"),
1685
+ // Dtwo aliases
1612
1686
  ...dtwo.options.alias
1613
1687
  },
1614
1688
  replace: {
@@ -1617,10 +1691,12 @@ async function initHole(dtwo) {
1617
1691
  "process.env.DTWO_NO_SCRIPTS": !!dtwo.options.experimental.noScripts && !dtwo.options.dev,
1618
1692
  "process.env.DTWO_INLINE_STYLES": !!dtwo.options.experimental.inlineSSRStyles,
1619
1693
  "process.env.DTWO_PAYLOAD_EXTRACTION": !!dtwo.options.experimental.payloadExtraction,
1694
+ "process.env.DTWO_COMPONENT_ISLANDS": !!dtwo.options.experimental.componentIslands,
1620
1695
  "process.dev": dtwo.options.dev,
1621
1696
  __KDU_PROD_DEVTOOLS__: false
1622
1697
  },
1623
1698
  rollupConfig: {
1699
+ output: {},
1624
1700
  plugins: []
1625
1701
  }
1626
1702
  });
@@ -1634,6 +1710,8 @@ async function initHole(dtwo) {
1634
1710
  if (!dtwo.options.experimental.inlineSSRStyles) {
1635
1711
  holeConfig.virtual["#build/dist/server/styles.mjs"] = "export default {}";
1636
1712
  }
1713
+ holeConfig.rollupConfig.plugins = await holeConfig.rollupConfig.plugins || [];
1714
+ holeConfig.rollupConfig.plugins = Array.isArray(holeConfig.rollupConfig.plugins) ? holeConfig.rollupConfig.plugins : [holeConfig.rollupConfig.plugins];
1637
1715
  holeConfig.rollupConfig.plugins.push(
1638
1716
  ImportProtectionPlugin.rollup({
1639
1717
  rootDir: dtwo.options.rootDir,
@@ -1676,7 +1754,9 @@ async function initHole(dtwo) {
1676
1754
  await copyPublicAssets(hole);
1677
1755
  await prerender(hole);
1678
1756
  if (!dtwo.options._generate) {
1757
+ logger.restoreAll();
1679
1758
  await build$1(hole);
1759
+ logger.wrapAll();
1680
1760
  } else {
1681
1761
  const distDir2 = resolve(dtwo.options.rootDir, "dist");
1682
1762
  if (!existsSync(distDir2)) {
@@ -1705,6 +1785,126 @@ async function initHole(dtwo) {
1705
1785
  }
1706
1786
  }
1707
1787
 
1788
+ const schemaModule = defineDtwoModule({
1789
+ meta: {
1790
+ name: "dtwo-config-schema"
1791
+ },
1792
+ async setup(_, dtwo) {
1793
+ if (!dtwo.options.experimental.configSchema) {
1794
+ return;
1795
+ }
1796
+ const resolver = createResolver(import.meta.url);
1797
+ const _resolveSchema = jiti(dirname(import.meta.url), {
1798
+ esmResolve: true,
1799
+ interopDefault: true,
1800
+ cache: false,
1801
+ requireCache: false,
1802
+ transformOptions: {
1803
+ babel: {
1804
+ plugins: [untypedPlugin]
1805
+ }
1806
+ }
1807
+ });
1808
+ dtwo.hook("prepare:types", (ctx) => {
1809
+ ctx.references.push({ path: "dtwo-config-schema" });
1810
+ ctx.references.push({ path: "schema/dtwo.schema.d.ts" });
1811
+ });
1812
+ let schema;
1813
+ dtwo.hook("modules:done", async () => {
1814
+ schema = await resolveSchema$1();
1815
+ });
1816
+ dtwo.hooks.hook("build:done", async () => {
1817
+ await dtwo.hooks.callHook("schema:beforeWrite", schema);
1818
+ await writeSchema(schema);
1819
+ await dtwo.hooks.callHook("schema:written");
1820
+ });
1821
+ if (dtwo.options.dev) {
1822
+ const filesToWatch = await Promise.all(dtwo.options._layers.map(
1823
+ (layer) => resolver.resolve(layer.config.rootDir, "dtwo.schema.*")
1824
+ ));
1825
+ const watcher = chokidar.watch(filesToWatch, {
1826
+ ...dtwo.options.watchers.chokidar,
1827
+ ignoreInitial: true
1828
+ });
1829
+ const onChange = debounce(async () => {
1830
+ schema = await resolveSchema$1();
1831
+ await dtwo.hooks.callHook("schema:beforeWrite", schema);
1832
+ await writeSchema(schema);
1833
+ await dtwo.hooks.callHook("schema:written");
1834
+ });
1835
+ watcher.on("all", onChange);
1836
+ dtwo.hook("close", () => watcher.close());
1837
+ }
1838
+ async function resolveSchema$1() {
1839
+ globalThis.defineDtwoSchema = (val) => val;
1840
+ const schemaDefs = [dtwo.options.$schema];
1841
+ for (const layer of dtwo.options._layers) {
1842
+ const filePath = await resolver.resolvePath(resolve(layer.config.rootDir, "dtwo.schema"));
1843
+ if (filePath && existsSync(filePath)) {
1844
+ let loadedConfig;
1845
+ try {
1846
+ loadedConfig = _resolveSchema(filePath);
1847
+ } catch (err) {
1848
+ console.warn(
1849
+ "[dtwo-config-schema] Unable to load schema from",
1850
+ filePath,
1851
+ err
1852
+ );
1853
+ continue;
1854
+ }
1855
+ schemaDefs.push(loadedConfig);
1856
+ }
1857
+ }
1858
+ await dtwo.hooks.callHook("schema:extend", schemaDefs);
1859
+ const schemas = await Promise.all(
1860
+ schemaDefs.map((schemaDef) => resolveSchema(schemaDef))
1861
+ );
1862
+ const schema2 = defu$1(...schemas);
1863
+ await dtwo.hooks.callHook("schema:resolved", schema2);
1864
+ return schema2;
1865
+ }
1866
+ async function writeSchema(schema2) {
1867
+ const isEmptySchema = !schema2.properties || Object.keys(schema2.properties).length === 0;
1868
+ if (isEmptySchema) {
1869
+ await rm(resolve(dtwo.options.buildDir, "schema"), { recursive: true }).catch(() => {
1870
+ });
1871
+ return;
1872
+ }
1873
+ await mkdir(resolve(dtwo.options.buildDir, "schema"), { recursive: true });
1874
+ await writeFile(
1875
+ resolve(dtwo.options.buildDir, "schema/dtwo.schema.json"),
1876
+ JSON.stringify(schema2, null, 2),
1877
+ "utf8"
1878
+ );
1879
+ const markdown = "# Dtwo Custom Config Schema" + generateMarkdown(schema2);
1880
+ await writeFile(
1881
+ resolve(dtwo.options.buildDir, "schema/dtwo.schema.md"),
1882
+ markdown,
1883
+ "utf8"
1884
+ );
1885
+ const _types = generateTypes(schema2, {
1886
+ addExport: true,
1887
+ interfaceName: "DtwoCustomSchema",
1888
+ partial: true
1889
+ });
1890
+ const types = _types + `
1891
+ export type CustomAppConfig = Exclude<DtwoCustomSchema['appConfig'], undefined>
1892
+
1893
+ declare module '@dtwo/schema' {
1894
+ interface DtwoConfig extends DtwoCustomSchema {}
1895
+ interface DtwoOptions extends DtwoCustomSchema {}
1896
+ interface AppConfigInput extends CustomAppConfig {}
1897
+ interface AppConfig extends CustomAppConfig {}
1898
+ }`;
1899
+ const typesPath = resolve(
1900
+ dtwo.options.buildDir,
1901
+ "schema/dtwo.schema.d.ts"
1902
+ );
1903
+ await writeFile(typesPath, types, "utf8");
1904
+ }
1905
+ }
1906
+ });
1907
+
1708
1908
  function createDtwo(options) {
1709
1909
  const hooks = createHooks();
1710
1910
  const dtwo = {
@@ -1741,6 +1941,7 @@ async function initDtwo(dtwo) {
1741
1941
  });
1742
1942
  const config = {
1743
1943
  rootDir: dtwo.options.rootDir,
1944
+ // Exclude top-level resolutions by plugins
1744
1945
  exclude: [join(dtwo.options.rootDir, "index.html")],
1745
1946
  patterns: kduAppPatterns(dtwo)
1746
1947
  };
@@ -1808,6 +2009,12 @@ async function initDtwo(dtwo) {
1808
2009
  name: "DtwoLoadingIndicator",
1809
2010
  filePath: resolve(dtwo.options.appDir, "components/dtwo-loading-indicator")
1810
2011
  });
2012
+ if (dtwo.options.experimental.componentIslands) {
2013
+ addComponent({
2014
+ name: "DtwoIsland",
2015
+ filePath: resolve(dtwo.options.appDir, "components/dtwo-island")
2016
+ });
2017
+ }
1811
2018
  if (!dtwo.options.dev && dtwo.options.experimental.payloadExtraction) {
1812
2019
  addPlugin(resolve(dtwo.options.appDir, "plugins/payload.client"));
1813
2020
  }
@@ -1843,6 +2050,7 @@ async function loadDtwo(opts) {
1843
2050
  include: options._layers.filter((i) => i.cwd && i.cwd.includes("node_modules")).map((i) => new RegExp(`(^|\\/)${escapeRE(i.cwd.split("node_modules/").pop())}(\\/|$)(?!node_modules\\/)`))
1844
2051
  }
1845
2052
  }]);
2053
+ options._modules.push(schemaModule);
1846
2054
  options.modulesDir.push(resolve(options.workspaceDir, "node_modules"));
1847
2055
  options.modulesDir.push(resolve(pkgDir, "node_modules"));
1848
2056
  options.build.transpile.push("@dtwo/ui-templates");
@@ -1959,13 +2167,16 @@ const schemaTemplate = {
1959
2167
  importName: m.entryPath || m.meta?.name
1960
2168
  })).filter((m) => m.configKey && m.name && !adHocModules.includes(m.name));
1961
2169
  const relativeRoot = relative(resolve(dtwo.options.buildDir, "types"), dtwo.options.rootDir);
2170
+ const getImportName = (name) => (name.startsWith(".") ? "./" + join(relativeRoot, name) : name).replace(/\.\w+$/, "");
2171
+ const modules = moduleInfo.map((meta) => [genString(meta.configKey), getImportName(meta.importName)]);
1962
2172
  return [
1963
2173
  "import { DtwoModule } from '@dtwo/schema'",
1964
2174
  "declare module '@dtwo/schema' {",
1965
2175
  " interface DtwoConfig {",
1966
- ...moduleInfo.filter(Boolean).map(
1967
- (meta) => ` [${genString(meta.configKey)}]?: typeof ${genDynamicImport(meta.importName.startsWith(".") ? "./" + join(relativeRoot, meta.importName) : meta.importName, { wrapper: false })}.default extends DtwoModule<infer O> ? Partial<O> : Record<string, any>`
2176
+ ...modules.map(
2177
+ ([configKey, importName]) => ` [${configKey}]?: typeof ${genDynamicImport(importName, { wrapper: false })}.default extends DtwoModule<infer O> ? Partial<O> : Record<string, any>`
1968
2178
  ),
2179
+ modules.length > 0 ? ` modules?: (DtwoModule | string | [DtwoModule | string, Record<string, any>] | ${modules.map(([configKey, importName]) => `[${genString(importName)}, DtwoConfig[${configKey}]]`).join(" | ")})[],` : "",
1969
2180
  " }",
1970
2181
  generateTypes(
1971
2182
  await resolveSchema(Object.fromEntries(Object.entries(dtwo.options.runtimeConfig).filter(([key]) => key !== "public"))),
@@ -2066,6 +2277,7 @@ const publicPathTemplate = {
2066
2277
  " const publicBase = appConfig.cdnURL || appConfig.baseURL",
2067
2278
  " return path.length ? joinURL(publicBase, ...path) : publicBase",
2068
2279
  "}",
2280
+ // On server these are registered directly in packages/dtwo/src/core/runtime/hole/renderer.ts
2069
2281
  "if (process.client) {",
2070
2282
  " globalThis.__buildAssetsURL = buildAssetsURL",
2071
2283
  " globalThis.__publicAssetsURL = publicAssetsURL",
@@ -2082,9 +2294,11 @@ const dtwoConfigTemplate = {
2082
2294
  function _resolveId(id) {
2083
2295
  return resolvePath$1(id, {
2084
2296
  url: [
2297
+ // @ts-ignore
2085
2298
  global.__DTWO_PREPATHS__,
2086
2299
  import.meta.url,
2087
2300
  process.cwd(),
2301
+ // @ts-ignore
2088
2302
  global.__DTWO_PATHS__
2089
2303
  ]
2090
2304
  });
@@ -2092,22 +2306,22 @@ function _resolveId(id) {
2092
2306
 
2093
2307
  const defaultTemplates = {
2094
2308
  __proto__: null,
2095
- kduShim: kduShim,
2096
2309
  appComponentTemplate: appComponentTemplate,
2097
- rootComponentTemplate: rootComponentTemplate,
2098
- errorComponentTemplate: errorComponentTemplate,
2099
- cssTemplate: cssTemplate,
2310
+ appConfigDeclarationTemplate: appConfigDeclarationTemplate,
2311
+ appConfigTemplate: appConfigTemplate,
2312
+ clientConfigTemplate: clientConfigTemplate,
2100
2313
  clientPluginTemplate: clientPluginTemplate,
2101
- serverPluginTemplate: serverPluginTemplate,
2102
- pluginsDeclaration: pluginsDeclaration,
2103
- schemaTemplate: schemaTemplate,
2314
+ cssTemplate: cssTemplate,
2315
+ dtwoConfigTemplate: dtwoConfigTemplate,
2316
+ errorComponentTemplate: errorComponentTemplate,
2317
+ kduShim: kduShim,
2104
2318
  layoutTemplate: layoutTemplate,
2105
2319
  middlewareTemplate: middlewareTemplate,
2106
- clientConfigTemplate: clientConfigTemplate,
2107
- appConfigDeclarationTemplate: appConfigDeclarationTemplate,
2108
- appConfigTemplate: appConfigTemplate,
2320
+ pluginsDeclaration: pluginsDeclaration,
2109
2321
  publicPathTemplate: publicPathTemplate,
2110
- dtwoConfigTemplate: dtwoConfigTemplate
2322
+ rootComponentTemplate: rootComponentTemplate,
2323
+ schemaTemplate: schemaTemplate,
2324
+ serverPluginTemplate: serverPluginTemplate
2111
2325
  };
2112
2326
 
2113
2327
  function createApp(dtwo, options = {}) {
@@ -2143,7 +2357,10 @@ async function generateApp(dtwo, app, options = {}) {
2143
2357
  async function resolveApp(dtwo, app) {
2144
2358
  if (!app.mainComponent) {
2145
2359
  app.mainComponent = await findPath(
2146
- dtwo.options._layers.flatMap((layer) => [`${layer.config.srcDir}/App`, `${layer.config.srcDir}/app`])
2360
+ dtwo.options._layers.flatMap((layer) => [
2361
+ join(layer.config.srcDir, "App"),
2362
+ join(layer.config.srcDir, "app")
2363
+ ])
2147
2364
  );
2148
2365
  }
2149
2366
  if (!app.mainComponent) {
@@ -2153,7 +2370,9 @@ async function resolveApp(dtwo, app) {
2153
2370
  app.rootComponent = await findPath(["~/app.root", resolve(dtwo.options.appDir, "components/dtwo-root.kdu")]);
2154
2371
  }
2155
2372
  if (!app.errorComponent) {
2156
- app.errorComponent = await findPath(["~/error"]) || resolve(dtwo.options.appDir, "components/dtwo-error-page.kdu");
2373
+ app.errorComponent = await findPath(
2374
+ dtwo.options._layers.map((layer) => join(layer.config.srcDir, "error"))
2375
+ ) ?? resolve(dtwo.options.appDir, "components/dtwo-error-page.kdu");
2157
2376
  }
2158
2377
  app.layouts = {};
2159
2378
  for (const config of dtwo.options._layers.map((layer) => layer.config)) {