astro 1.4.7 → 1.5.1

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 (71) hide show
  1. package/astro-jsx.d.ts +8 -6
  2. package/components/Code.astro +1 -1
  3. package/config.d.ts +1 -1
  4. package/dist/@types/astro.d.ts +200 -19
  5. package/dist/cli/index.js +35 -36
  6. package/dist/config/index.js +2 -7
  7. package/dist/core/add/index.js +141 -24
  8. package/dist/core/app/index.js +45 -43
  9. package/dist/core/build/generate.js +14 -12
  10. package/dist/core/build/index.js +3 -3
  11. package/dist/core/config/config.d.ts +1 -1
  12. package/dist/core/config/config.js +6 -2
  13. package/dist/core/config/index.d.ts +1 -1
  14. package/dist/core/config/index.js +2 -1
  15. package/dist/core/config/schema.d.ts +139 -1
  16. package/dist/core/config/schema.js +36 -3
  17. package/dist/core/config/settings.d.ts +1 -7
  18. package/dist/core/config/settings.js +7 -4
  19. package/dist/core/config/tsconfig.d.ts +10 -1
  20. package/dist/core/config/tsconfig.js +72 -7
  21. package/dist/core/constants.d.ts +1 -0
  22. package/dist/core/constants.js +4 -0
  23. package/dist/core/cookies/cookies.d.ts +1 -1
  24. package/dist/core/dev/index.js +7 -2
  25. package/dist/core/endpoint/dev/index.d.ts +2 -1
  26. package/dist/core/endpoint/dev/index.js +13 -6
  27. package/dist/core/endpoint/index.d.ts +4 -3
  28. package/dist/core/endpoint/index.js +57 -9
  29. package/dist/core/messages.js +2 -2
  30. package/dist/core/preview/index.d.ts +2 -11
  31. package/dist/core/preview/index.js +31 -125
  32. package/dist/core/preview/static-preview-server.d.ts +17 -0
  33. package/dist/core/preview/static-preview-server.js +127 -0
  34. package/dist/core/render/context.d.ts +20 -0
  35. package/dist/core/render/context.js +15 -0
  36. package/dist/core/render/core.d.ts +4 -24
  37. package/dist/core/render/core.js +26 -47
  38. package/dist/core/render/dev/environment.d.ts +9 -0
  39. package/dist/core/render/dev/environment.js +30 -0
  40. package/dist/core/render/dev/index.d.ts +22 -5
  41. package/dist/core/render/dev/index.js +38 -69
  42. package/dist/core/render/dev/resolve.d.ts +2 -0
  43. package/dist/core/render/dev/resolve.js +14 -0
  44. package/dist/core/render/environment.d.ts +29 -0
  45. package/dist/core/render/environment.js +21 -0
  46. package/dist/core/render/index.d.ts +6 -0
  47. package/dist/core/render/index.js +13 -0
  48. package/dist/core/render/renderer.d.ts +9 -0
  49. package/dist/core/render/renderer.js +23 -0
  50. package/dist/core/render/result.js +3 -3
  51. package/dist/core/routing/manifest/create.js +14 -5
  52. package/dist/core/routing/manifest/generator.js +8 -3
  53. package/dist/core/util.d.ts +3 -14
  54. package/dist/core/util.js +4 -2
  55. package/dist/events/index.js +1 -1
  56. package/dist/integrations/index.d.ts +3 -2
  57. package/dist/integrations/index.js +39 -2
  58. package/dist/jsx/component.d.ts +1 -0
  59. package/dist/jsx/component.js +10 -0
  60. package/dist/jsx/index.d.ts +2 -0
  61. package/dist/jsx/index.js +6 -0
  62. package/dist/jsx-runtime/index.js +1 -1
  63. package/dist/runtime/server/astro-global.js +1 -1
  64. package/dist/runtime/server/index.d.ts +1 -0
  65. package/dist/runtime/server/index.js +2 -0
  66. package/dist/vite-plugin-astro-server/index.js +35 -60
  67. package/dist/vite-plugin-jsx/index.js +9 -5
  68. package/dist/vite-plugin-jsx/tag.d.ts +3 -2
  69. package/dist/vite-plugin-jsx/tag.js +10 -4
  70. package/env.d.ts +1 -1
  71. package/package.json +8 -3
@@ -2,13 +2,18 @@ import boxen from "boxen";
2
2
  import { diffWords } from "diff";
3
3
  import { execa } from "execa";
4
4
  import { existsSync, promises as fs } from "fs";
5
- import { bold, cyan, dim, green, magenta, yellow } from "kleur/colors";
5
+ import { bold, cyan, dim, green, magenta, red, yellow } from "kleur/colors";
6
6
  import ora from "ora";
7
7
  import path from "path";
8
8
  import preferredPM from "preferred-pm";
9
9
  import prompts from "prompts";
10
10
  import { fileURLToPath, pathToFileURL } from "url";
11
- import { resolveConfigPath } from "../config/index.js";
11
+ import { loadTSConfig, resolveConfigPath } from "../config/index.js";
12
+ import {
13
+ defaultTSConfig,
14
+ presets,
15
+ updateTSConfigForFramework
16
+ } from "../config/tsconfig.js";
12
17
  import { debug, info } from "../logger/core.js";
13
18
  import * as msg from "../messages.js";
14
19
  import { printHelp } from "../messages.js";
@@ -212,7 +217,7 @@ async function add(names, { cwd, flags, logging, telemetry }) {
212
217
  switch (configResult) {
213
218
  case UpdateResult.cancelled: {
214
219
  info(logging, null, msg.cancelled(`Your configuration has ${bold("NOT")} been updated.`));
215
- return;
220
+ break;
216
221
  }
217
222
  case UpdateResult.none: {
218
223
  const pkgURL = new URL("./package.json", configURL);
@@ -224,11 +229,11 @@ async function add(names, { cwd, flags, logging, telemetry }) {
224
229
  );
225
230
  if (missingDeps.length === 0) {
226
231
  info(logging, null, msg.success(`Configuration up-to-date.`));
227
- return;
232
+ break;
228
233
  }
229
234
  }
230
235
  info(logging, null, msg.success(`Configuration up-to-date.`));
231
- return;
236
+ break;
232
237
  }
233
238
  default: {
234
239
  const list = integrations.map((integration) => ` - ${integration.packageName}`).join("\n");
@@ -242,6 +247,27 @@ ${list}`
242
247
  );
243
248
  }
244
249
  }
250
+ const updateTSConfigResult = await updateTSConfig(cwd, logging, integrations, flags);
251
+ switch (updateTSConfigResult) {
252
+ case UpdateResult.none: {
253
+ break;
254
+ }
255
+ case UpdateResult.cancelled: {
256
+ info(
257
+ logging,
258
+ null,
259
+ msg.cancelled(`Your TypeScript configuration has ${bold("NOT")} been updated.`)
260
+ );
261
+ break;
262
+ }
263
+ case UpdateResult.failure: {
264
+ throw new Error(
265
+ `Unknown error parsing tsconfig.json or jsconfig.json. Could not update TypeScript settings.`
266
+ );
267
+ }
268
+ default:
269
+ info(logging, null, msg.success(`Successfully updated TypeScript settings`));
270
+ }
245
271
  }
246
272
  function isAdapter(integration) {
247
273
  return integration.type === "adapter";
@@ -392,27 +418,12 @@ ${defaultExport}`);
392
418
  if (input === output) {
393
419
  return 0 /* none */;
394
420
  }
395
- let changes = [];
396
- for (const change of diffWords(input, output)) {
397
- let lines = change.value.trim().split("\n").slice(0, change.count);
398
- if (lines.length === 0)
399
- continue;
400
- if (change.added) {
401
- if (!change.value.trim())
402
- continue;
403
- changes.push(change.value);
404
- }
405
- }
406
- if (changes.length === 0) {
421
+ const diff = getDiffContent(input, output);
422
+ if (!diff) {
407
423
  return 0 /* none */;
408
424
  }
409
- let diffed = output;
410
- for (let newContent of changes) {
411
- const coloredOutput = newContent.split("\n").map((ln) => ln ? green(ln) : "").join("\n");
412
- diffed = diffed.replace(newContent, coloredOutput);
413
- }
414
425
  const message = `
415
- ${boxen(diffed, {
426
+ ${boxen(diff, {
416
427
  margin: 0.5,
417
428
  padding: 0.5,
418
429
  borderStyle: "round",
@@ -464,7 +475,7 @@ async function getInstallIntegrationsCommand({
464
475
  case "yarn":
465
476
  return { pm: "yarn", command: "add", flags: [], dependencies };
466
477
  case "pnpm":
467
- return { pm: "pnpm", command: "install", flags: [], dependencies };
478
+ return { pm: "pnpm", command: "add", flags: [], dependencies };
468
479
  default:
469
480
  return null;
470
481
  }
@@ -616,6 +627,90 @@ async function validateIntegrations(integrations) {
616
627
  }
617
628
  }
618
629
  }
630
+ async function updateTSConfig(cwd = process.cwd(), logging, integrationsInfo, flags) {
631
+ var _a, _b;
632
+ const integrations = integrationsInfo.map(
633
+ (integration) => integration.id
634
+ );
635
+ const firstIntegrationWithTSSettings = integrations.find(
636
+ (integration) => presets.has(integration)
637
+ );
638
+ if (!firstIntegrationWithTSSettings) {
639
+ return 0 /* none */;
640
+ }
641
+ const inputConfig = loadTSConfig(cwd, false);
642
+ const configFileName = inputConfig.exists ? inputConfig.path.split("/").pop() : "tsconfig.json";
643
+ if (inputConfig.reason === "invalid-config") {
644
+ return 3 /* failure */;
645
+ }
646
+ if (inputConfig.reason === "not-found") {
647
+ debug("add", "Couldn't find tsconfig.json or jsconfig.json, generating one");
648
+ }
649
+ const outputConfig = updateTSConfigForFramework(
650
+ inputConfig.exists ? inputConfig.config : defaultTSConfig,
651
+ firstIntegrationWithTSSettings
652
+ );
653
+ const input = inputConfig.exists ? JSON.stringify(inputConfig.config, null, 2) : "";
654
+ const output = JSON.stringify(outputConfig, null, 2);
655
+ const diff = getDiffContent(input, output);
656
+ if (!diff) {
657
+ return 0 /* none */;
658
+ }
659
+ const message = `
660
+ ${boxen(diff, {
661
+ margin: 0.5,
662
+ padding: 0.5,
663
+ borderStyle: "round",
664
+ title: configFileName
665
+ })}
666
+ `;
667
+ info(
668
+ logging,
669
+ null,
670
+ `
671
+ ${magenta(`Astro will make the following changes to your ${configFileName}:`)}
672
+ ${message}`
673
+ );
674
+ const conflictingIntegrations = [...Object.keys(presets).filter((config) => config !== "vue")];
675
+ const hasConflictingIntegrations = integrations.filter((integration) => presets.has(integration)).length > 1 && integrations.filter((integration) => conflictingIntegrations.includes(integration)).length > 0;
676
+ if (hasConflictingIntegrations) {
677
+ info(
678
+ logging,
679
+ null,
680
+ red(
681
+ ` ${bold(
682
+ "Caution:"
683
+ )} Selected UI frameworks require conflicting tsconfig.json settings, as such only settings for ${bold(
684
+ firstIntegrationWithTSSettings
685
+ )} were used.
686
+ More information: https://docs.astro.build/en/guides/typescript/#errors-typing-multiple-jsx-frameworks-at-the-same-time
687
+ `
688
+ )
689
+ );
690
+ }
691
+ if (integrations.includes("vue") && hasConflictingIntegrations && (((_a = outputConfig.compilerOptions) == null ? void 0 : _a.jsx) !== "preserve" && ((_b = outputConfig.compilerOptions) == null ? void 0 : _b.jsxImportSource) !== void 0 || integrations.includes("react"))) {
692
+ info(
693
+ logging,
694
+ null,
695
+ red(
696
+ ` ${bold(
697
+ "Caution:"
698
+ )} Using Vue together with a JSX framework can lead to type checking issues inside Vue files.
699
+ More information: https://docs.astro.build/en/guides/typescript/#vue-components-are-mistakenly-typed-by-the-typesreact-package-when-installed
700
+ `
701
+ )
702
+ );
703
+ }
704
+ if (await askToContinue({ flags })) {
705
+ await fs.writeFile((inputConfig == null ? void 0 : inputConfig.path) ?? path.join(cwd, "tsconfig.json"), output, {
706
+ encoding: "utf-8"
707
+ });
708
+ debug("add", `Updated ${configFileName} file`);
709
+ return 1 /* updated */;
710
+ } else {
711
+ return 2 /* cancelled */;
712
+ }
713
+ }
619
714
  function parseIntegrationName(spec) {
620
715
  const result = parseNpmName(spec);
621
716
  if (!result)
@@ -643,6 +738,28 @@ async function askToContinue({ flags }) {
643
738
  });
644
739
  return Boolean(response.askToContinue);
645
740
  }
741
+ function getDiffContent(input, output) {
742
+ let changes = [];
743
+ for (const change of diffWords(input, output)) {
744
+ let lines = change.value.trim().split("\n").slice(0, change.count);
745
+ if (lines.length === 0)
746
+ continue;
747
+ if (change.added) {
748
+ if (!change.value.trim())
749
+ continue;
750
+ changes.push(change.value);
751
+ }
752
+ }
753
+ if (changes.length === 0) {
754
+ return null;
755
+ }
756
+ let diffed = output;
757
+ for (let newContent of changes) {
758
+ const coloredOutput = newContent.split("\n").map((ln) => ln ? green(ln) : "").join("\n");
759
+ diffed = diffed.replace(newContent, coloredOutput);
760
+ }
761
+ return diffed;
762
+ }
646
763
  export {
647
764
  add as default,
648
765
  validateIntegrations
@@ -20,14 +20,18 @@ var __privateMethod = (obj, member, method) => {
20
20
  __accessCheck(obj, member, "access private method");
21
21
  return method;
22
22
  };
23
- var _manifest, _manifestData, _routeDataToRouteInfo, _routeCache, _encoder, _logging, _streaming, _renderPage, renderPage_fn, _callEndpoint, callEndpoint_fn;
23
+ var _env, _manifest, _manifestData, _routeDataToRouteInfo, _encoder, _logging, _renderPage, renderPage_fn, _callEndpoint, callEndpoint_fn;
24
24
  import mime from "mime";
25
- import { getSetCookiesFromResponse } from "../cookies/index.js";
25
+ import { attachToResponse, getSetCookiesFromResponse } from "../cookies/index.js";
26
26
  import { call as callEndpoint } from "../endpoint/index.js";
27
27
  import { consoleLogDestination } from "../logger/console.js";
28
28
  import { error } from "../logger/core.js";
29
29
  import { joinPaths, prependForwardSlash } from "../path.js";
30
- import { render } from "../render/core.js";
30
+ import {
31
+ createEnvironment,
32
+ createRenderContext,
33
+ renderPage
34
+ } from "../render/index.js";
31
35
  import { RouteCache } from "../render/route-cache.js";
32
36
  import {
33
37
  createLinkStylesheetElementSet,
@@ -41,23 +45,46 @@ class App {
41
45
  constructor(manifest, streaming = true) {
42
46
  __privateAdd(this, _renderPage);
43
47
  __privateAdd(this, _callEndpoint);
48
+ __privateAdd(this, _env, void 0);
44
49
  __privateAdd(this, _manifest, void 0);
45
50
  __privateAdd(this, _manifestData, void 0);
46
51
  __privateAdd(this, _routeDataToRouteInfo, void 0);
47
- __privateAdd(this, _routeCache, void 0);
48
52
  __privateAdd(this, _encoder, new TextEncoder());
49
53
  __privateAdd(this, _logging, {
50
54
  dest: consoleLogDestination,
51
55
  level: "info"
52
56
  });
53
- __privateAdd(this, _streaming, void 0);
54
57
  __privateSet(this, _manifest, manifest);
55
58
  __privateSet(this, _manifestData, {
56
59
  routes: manifest.routes.map((route) => route.routeData)
57
60
  });
58
61
  __privateSet(this, _routeDataToRouteInfo, new Map(manifest.routes.map((route) => [route.routeData, route])));
59
- __privateSet(this, _routeCache, new RouteCache(__privateGet(this, _logging)));
60
- __privateSet(this, _streaming, streaming);
62
+ __privateSet(this, _env, createEnvironment({
63
+ adapterName: manifest.adapterName,
64
+ logging: __privateGet(this, _logging),
65
+ markdown: manifest.markdown,
66
+ mode: "production",
67
+ renderers: manifest.renderers,
68
+ async resolve(specifier) {
69
+ if (!(specifier in manifest.entryModules)) {
70
+ throw new Error(`Unable to resolve [${specifier}]`);
71
+ }
72
+ const bundlePath = manifest.entryModules[specifier];
73
+ switch (true) {
74
+ case bundlePath.startsWith("data:"):
75
+ case bundlePath.length === 0: {
76
+ return bundlePath;
77
+ }
78
+ default: {
79
+ return prependForwardSlash(joinPaths(manifest.base, bundlePath));
80
+ }
81
+ }
82
+ },
83
+ routeCache: new RouteCache(__privateGet(this, _logging)),
84
+ site: __privateGet(this, _manifest).site,
85
+ ssr: true,
86
+ streaming
87
+ }));
61
88
  }
62
89
  match(request, { matchNotFound = false } = {}) {
63
90
  const url = new URL(request.url);
@@ -116,13 +143,12 @@ class App {
116
143
  return getSetCookiesFromResponse(response);
117
144
  }
118
145
  }
146
+ _env = new WeakMap();
119
147
  _manifest = new WeakMap();
120
148
  _manifestData = new WeakMap();
121
149
  _routeDataToRouteInfo = new WeakMap();
122
- _routeCache = new WeakMap();
123
150
  _encoder = new WeakMap();
124
151
  _logging = new WeakMap();
125
- _streaming = new WeakMap();
126
152
  _renderPage = new WeakSet();
127
153
  renderPage_fn = async function(request, routeData, mod, status = 200) {
128
154
  const url = new URL(request.url);
@@ -144,40 +170,16 @@ renderPage_fn = async function(request, routeData, mod, status = 200) {
144
170
  }
145
171
  }
146
172
  try {
147
- const response = await render({
148
- adapterName: manifest.adapterName,
149
- links,
150
- logging: __privateGet(this, _logging),
151
- markdown: manifest.markdown,
152
- mod,
153
- mode: "production",
173
+ const ctx = createRenderContext({
174
+ request,
154
175
  origin: url.origin,
155
176
  pathname: url.pathname,
156
177
  scripts,
157
- renderers,
158
- async resolve(specifier) {
159
- if (!(specifier in manifest.entryModules)) {
160
- throw new Error(`Unable to resolve [${specifier}]`);
161
- }
162
- const bundlePath = manifest.entryModules[specifier];
163
- switch (true) {
164
- case bundlePath.startsWith("data:"):
165
- case bundlePath.length === 0: {
166
- return bundlePath;
167
- }
168
- default: {
169
- return prependForwardSlash(joinPaths(manifest.base, bundlePath));
170
- }
171
- }
172
- },
178
+ links,
173
179
  route: routeData,
174
- routeCache: __privateGet(this, _routeCache),
175
- site: __privateGet(this, _manifest).site,
176
- ssr: true,
177
- request,
178
- streaming: __privateGet(this, _streaming),
179
180
  status
180
181
  });
182
+ const response = await renderPage(mod, ctx, __privateGet(this, _env));
181
183
  return response;
182
184
  } catch (err) {
183
185
  error(__privateGet(this, _logging), "ssr", err.stack || err.message || String(err));
@@ -191,16 +193,14 @@ _callEndpoint = new WeakSet();
191
193
  callEndpoint_fn = async function(request, routeData, mod, status = 200) {
192
194
  const url = new URL(request.url);
193
195
  const handler = mod;
194
- const result = await callEndpoint(handler, {
195
- logging: __privateGet(this, _logging),
196
+ const ctx = createRenderContext({
197
+ request,
196
198
  origin: url.origin,
197
199
  pathname: url.pathname,
198
- request,
199
200
  route: routeData,
200
- routeCache: __privateGet(this, _routeCache),
201
- ssr: true,
202
201
  status
203
202
  });
203
+ const result = await callEndpoint(handler, __privateGet(this, _env), ctx);
204
204
  if (result.type === "response") {
205
205
  if (result.response.headers.get("X-Astro-Response") === "Not-Found") {
206
206
  const fourOhFourRequest = new Request(new URL("/404", request.url));
@@ -221,10 +221,12 @@ callEndpoint_fn = async function(request, routeData, mod, status = 200) {
221
221
  }
222
222
  const bytes = __privateGet(this, _encoder).encode(body);
223
223
  headers.set("Content-Length", bytes.byteLength.toString());
224
- return new Response(bytes, {
224
+ const response = new Response(bytes, {
225
225
  status: 200,
226
226
  headers
227
227
  });
228
+ attachToResponse(response, result.cookies);
229
+ return response;
228
230
  }
229
231
  };
230
232
  export {
@@ -13,7 +13,7 @@ import { runHookBuildGenerated } from "../../integrations/index.js";
13
13
  import { BEFORE_HYDRATION_SCRIPT_ID, PAGE_SCRIPT_ID } from "../../vite-plugin-scripts/index.js";
14
14
  import { call as callEndpoint } from "../endpoint/index.js";
15
15
  import { debug, info } from "../logger/core.js";
16
- import { render } from "../render/core.js";
16
+ import { createEnvironment, createRenderContext, renderPage } from "../render/index.js";
17
17
  import { callGetStaticPaths } from "../render/route-cache.js";
18
18
  import { createLinkStylesheetElementSet, createModuleScriptsSet } from "../render/ssr-element.js";
19
19
  import { createRequest } from "../request.js";
@@ -234,19 +234,14 @@ async function generatePath(pathname, opts, gopts) {
234
234
  opts.settings.config.build.format,
235
235
  pageData.route.type
236
236
  );
237
- const options = {
237
+ const env = createEnvironment({
238
238
  adapterName: void 0,
239
- links,
240
239
  logging,
241
240
  markdown: {
242
241
  ...settings.config.markdown,
243
242
  isAstroFlavoredMd: settings.config.legacy.astroFlavoredMarkdown
244
243
  },
245
- mod,
246
244
  mode: opts.mode,
247
- origin,
248
- pathname,
249
- scripts,
250
245
  renderers,
251
246
  async resolve(specifier) {
252
247
  const hashedFilePath = internals.entrySpecifierToBundleMap.get(specifier);
@@ -258,24 +253,31 @@ async function generatePath(pathname, opts, gopts) {
258
253
  }
259
254
  return prependForwardSlash(npath.posix.join(settings.config.base, hashedFilePath));
260
255
  },
261
- request: createRequest({ url, headers: new Headers(), logging, ssr }),
262
- route: pageData.route,
263
256
  routeCache,
264
257
  site: settings.config.site ? new URL(settings.config.base, settings.config.site).toString() : settings.config.site,
265
258
  ssr,
266
259
  streaming: true
267
- };
260
+ });
261
+ const ctx = createRenderContext({
262
+ origin,
263
+ pathname,
264
+ request: createRequest({ url, headers: new Headers(), logging, ssr }),
265
+ scripts,
266
+ links,
267
+ route: pageData.route
268
+ });
268
269
  let body;
269
270
  let encoding;
270
271
  if (pageData.route.type === "endpoint") {
271
- const result = await callEndpoint(mod, options);
272
+ const endpointHandler = mod;
273
+ const result = await callEndpoint(endpointHandler, env, ctx);
272
274
  if (result.type === "response") {
273
275
  throw new Error(`Returning a Response from an endpoint is not supported in SSG mode.`);
274
276
  }
275
277
  body = result.body;
276
278
  encoding = result.encoding;
277
279
  } else {
278
- const response = await render(options);
280
+ const response = await renderPage(mod, ctx, env);
279
281
  if (response.status !== 200 || !response.body) {
280
282
  return;
281
283
  }
@@ -59,9 +59,9 @@ class AstroBuilder {
59
59
  }
60
60
  async build({ viteConfig }) {
61
61
  const buildConfig = {
62
- client: new URL("./client/", this.settings.config.outDir),
63
- server: new URL("./server/", this.settings.config.outDir),
64
- serverEntry: "entry.mjs"
62
+ client: this.settings.config.build.client,
63
+ server: this.settings.config.build.server,
64
+ serverEntry: this.settings.config.build.serverEntry
65
65
  };
66
66
  await runHookBuildStart({ config: this.settings.config, buildConfig, logging: this.logging });
67
67
  this.validateConfig();
@@ -14,7 +14,7 @@ interface LoadConfigOptions {
14
14
  validate?: boolean;
15
15
  logging: LogOptions;
16
16
  /** Invalidate when reloading a previously loaded config */
17
- isConfigReload?: boolean;
17
+ isRestart?: boolean;
18
18
  }
19
19
  /**
20
20
  * Resolve the file URL of the user's `astro.config.js|cjs|mjs|ts` file
@@ -6,7 +6,7 @@ import path from "path";
6
6
  import { fileURLToPath, pathToFileURL } from "url";
7
7
  import * as vite from "vite";
8
8
  import { mergeConfig as mergeViteConfig } from "vite";
9
- import { arraify, isObject } from "../util.js";
9
+ import { arraify, isObject, isURL } from "../util.js";
10
10
  import { createRelativeSchema } from "./schema.js";
11
11
  load.use([loadTypeScript]);
12
12
  const LEGACY_ASTRO_CONFIG_KEYS = /* @__PURE__ */ new Set([
@@ -150,7 +150,7 @@ async function tryLoadConfig(configOptions, flags, root) {
150
150
  });
151
151
  if (!configPath)
152
152
  return void 0;
153
- if (configOptions.isConfigReload) {
153
+ if (configOptions.isRestart) {
154
154
  const tempConfigPath = path.join(
155
155
  root,
156
156
  `.temp.${Date.now()}.config${path.extname(configPath)}`
@@ -237,6 +237,10 @@ function mergeConfigRecursively(defaults, overrides, rootPath) {
237
237
  merged[key] = [...arraify(existing ?? []), ...arraify(value ?? [])];
238
238
  continue;
239
239
  }
240
+ if (isURL(existing) && isURL(value)) {
241
+ merged[key] = value;
242
+ continue;
243
+ }
240
244
  if (isObject(existing) && isObject(value)) {
241
245
  merged[key] = mergeConfigRecursively(existing, value, rootPath ? `${rootPath}.${key}` : key);
242
246
  continue;
@@ -1,4 +1,4 @@
1
1
  export { openConfig, resolveConfigPath, resolveFlags, resolveRoot, validateConfig, } from './config.js';
2
2
  export type { AstroConfigSchema } from './schema';
3
3
  export { createSettings } from './settings.js';
4
- export { loadTSConfig } from './tsconfig.js';
4
+ export { loadTSConfig, updateTSConfigForFramework } from './tsconfig.js';
@@ -6,7 +6,7 @@ import {
6
6
  validateConfig
7
7
  } from "./config.js";
8
8
  import { createSettings } from "./settings.js";
9
- import { loadTSConfig } from "./tsconfig.js";
9
+ import { loadTSConfig, updateTSConfigForFramework } from "./tsconfig.js";
10
10
  export {
11
11
  createSettings,
12
12
  loadTSConfig,
@@ -14,5 +14,6 @@ export {
14
14
  resolveConfigPath,
15
15
  resolveFlags,
16
16
  resolveRoot,
17
+ updateTSConfigForFramework,
17
18
  validateConfig
18
19
  };