astro 4.4.14 → 4.5.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 (98) hide show
  1. package/components/Code.astro +15 -12
  2. package/dist/@types/astro.d.ts +95 -18
  3. package/dist/assets/utils/getAssetsPrefix.d.ts +2 -0
  4. package/dist/assets/utils/getAssetsPrefix.js +14 -0
  5. package/dist/assets/vite-plugin-assets.js +10 -3
  6. package/dist/cli/add/index.js +76 -28
  7. package/dist/cli/install-package.js +2 -2
  8. package/dist/content/types-generator.js +56 -7
  9. package/dist/content/vite-plugin-content-assets.js +11 -3
  10. package/dist/core/app/common.js +2 -0
  11. package/dist/core/app/index.js +10 -2
  12. package/dist/core/app/types.d.ts +7 -2
  13. package/dist/core/base-pipeline.d.ts +2 -1
  14. package/dist/core/base-pipeline.js +2 -1
  15. package/dist/core/build/generate.js +1 -0
  16. package/dist/core/build/internal.d.ts +6 -0
  17. package/dist/core/build/internal.js +1 -0
  18. package/dist/core/build/plugins/index.js +6 -1
  19. package/dist/core/build/plugins/plugin-analyzer.js +10 -98
  20. package/dist/core/build/plugins/plugin-css.js +27 -1
  21. package/dist/core/build/plugins/plugin-manifest.js +5 -2
  22. package/dist/core/build/plugins/plugin-scripts.d.ts +8 -0
  23. package/dist/core/build/plugins/plugin-scripts.js +34 -0
  24. package/dist/core/compile/compile.d.ts +1 -7
  25. package/dist/core/compile/compile.js +5 -4
  26. package/dist/core/compile/style.d.ts +4 -3
  27. package/dist/core/compile/style.js +5 -4
  28. package/dist/core/compile/types.d.ts +11 -0
  29. package/dist/core/config/schema.d.ts +177 -113
  30. package/dist/core/config/schema.js +42 -9
  31. package/dist/core/config/vite-load.js +1 -0
  32. package/dist/core/constants.d.ts +1 -0
  33. package/dist/core/constants.js +3 -1
  34. package/dist/core/create-vite.js +5 -3
  35. package/dist/core/dev/dev.js +1 -1
  36. package/dist/core/errors/dev/vite.js +1 -1
  37. package/dist/core/messages.js +2 -2
  38. package/dist/core/render/params-and-props.js +2 -1
  39. package/dist/core/render/ssr-element.d.ts +8 -8
  40. package/dist/core/render/ssr-element.js +4 -2
  41. package/dist/core/render-context.js +3 -1
  42. package/dist/core/routing/astro-designed-error-pages.d.ts +2 -0
  43. package/dist/core/routing/astro-designed-error-pages.js +21 -0
  44. package/dist/runtime/client/dev-toolbar/apps/audit/index.d.ts +8 -15
  45. package/dist/runtime/client/dev-toolbar/apps/audit/index.js +130 -249
  46. package/dist/runtime/client/dev-toolbar/apps/audit/{a11y.js → rules/a11y.js} +4 -2
  47. package/dist/runtime/client/dev-toolbar/apps/audit/rules/index.d.ts +35 -0
  48. package/dist/runtime/client/dev-toolbar/apps/audit/rules/index.js +40 -0
  49. package/dist/runtime/client/dev-toolbar/apps/audit/{perf.js → rules/perf.js} +2 -2
  50. package/dist/runtime/client/dev-toolbar/apps/audit/ui/audit-list-item.d.ts +7 -0
  51. package/dist/runtime/client/dev-toolbar/apps/audit/ui/audit-list-item.js +137 -0
  52. package/dist/runtime/client/dev-toolbar/apps/audit/ui/audit-list-window.d.ts +23 -0
  53. package/dist/runtime/client/dev-toolbar/apps/audit/ui/audit-list-window.js +384 -0
  54. package/dist/runtime/client/dev-toolbar/apps/audit/ui/audit-ui.d.ts +6 -0
  55. package/dist/runtime/client/dev-toolbar/apps/audit/ui/audit-ui.js +126 -0
  56. package/dist/runtime/client/dev-toolbar/apps/utils/window.d.ts +1 -1
  57. package/dist/runtime/client/dev-toolbar/apps/utils/window.js +3 -1
  58. package/dist/runtime/client/dev-toolbar/entrypoint.js +43 -15
  59. package/dist/runtime/client/dev-toolbar/settings.d.ts +3 -1
  60. package/dist/runtime/client/dev-toolbar/settings.js +8 -2
  61. package/dist/runtime/client/dev-toolbar/toolbar.d.ts +1 -0
  62. package/dist/runtime/client/dev-toolbar/toolbar.js +10 -8
  63. package/dist/runtime/client/dev-toolbar/ui-library/badge.d.ts +14 -4
  64. package/dist/runtime/client/dev-toolbar/ui-library/badge.js +72 -33
  65. package/dist/runtime/client/dev-toolbar/ui-library/button.d.ts +14 -4
  66. package/dist/runtime/client/dev-toolbar/ui-library/button.js +100 -47
  67. package/dist/runtime/client/dev-toolbar/ui-library/card.d.ts +9 -0
  68. package/dist/runtime/client/dev-toolbar/ui-library/card.js +57 -2
  69. package/dist/runtime/client/dev-toolbar/ui-library/highlight.d.ts +9 -0
  70. package/dist/runtime/client/dev-toolbar/ui-library/highlight.js +54 -2
  71. package/dist/runtime/client/dev-toolbar/ui-library/icons.d.ts +4 -0
  72. package/dist/runtime/client/dev-toolbar/ui-library/icons.js +5 -1
  73. package/dist/runtime/client/dev-toolbar/ui-library/toggle.d.ts +9 -0
  74. package/dist/runtime/client/dev-toolbar/ui-library/toggle.js +64 -5
  75. package/dist/runtime/compiler/index.d.ts +1 -1
  76. package/dist/runtime/compiler/index.js +2 -0
  77. package/dist/runtime/server/hydration.js +3 -2
  78. package/dist/runtime/server/index.d.ts +1 -1
  79. package/dist/runtime/server/index.js +2 -0
  80. package/dist/runtime/server/render/astro/factory.d.ts +1 -1
  81. package/dist/runtime/server/render/component.js +4 -5
  82. package/dist/runtime/server/render/index.d.ts +1 -0
  83. package/dist/runtime/server/render/index.js +2 -0
  84. package/dist/runtime/server/render/script.d.ts +6 -0
  85. package/dist/runtime/server/render/script.js +15 -0
  86. package/dist/transitions/router.js +12 -3
  87. package/dist/vite-plugin-astro/index.d.ts +2 -2
  88. package/dist/vite-plugin-astro/index.js +12 -1
  89. package/dist/vite-plugin-astro/types.d.ts +21 -1
  90. package/dist/vite-plugin-astro-server/pipeline.js +6 -2
  91. package/dist/vite-plugin-astro-server/plugin.js +6 -2
  92. package/dist/vite-plugin-astro-server/response.d.ts +6 -0
  93. package/dist/vite-plugin-astro-server/response.js +13 -0
  94. package/dist/vite-plugin-astro-server/route.js +18 -2
  95. package/package.json +8 -9
  96. package/tsconfigs/base.json +3 -1
  97. /package/dist/runtime/client/dev-toolbar/apps/audit/{a11y.d.ts → rules/a11y.d.ts} +0 -0
  98. /package/dist/runtime/client/dev-toolbar/apps/audit/{perf.d.ts → rules/perf.d.ts} +0 -0
@@ -3,6 +3,8 @@ import { fileURLToPath, pathToFileURL } from "node:url";
3
3
  import glob from "fast-glob";
4
4
  import { bold, cyan } from "kleur/colors";
5
5
  import { normalizePath } from "vite";
6
+ import { z } from "zod";
7
+ import { zodToJsonSchema } from "zod-to-json-schema";
6
8
  import { AstroError } from "../core/errors/errors.js";
7
9
  import { AstroErrorData } from "../core/errors/index.js";
8
10
  import { isRelativePath } from "../core/path.js";
@@ -72,7 +74,10 @@ async function createContentTypesGenerator({
72
74
  return { shouldGenerateTypes: false };
73
75
  switch (event.name) {
74
76
  case "addDir":
75
- collectionEntryMap[JSON.stringify(collection2)] = { type: "unknown", entries: {} };
77
+ collectionEntryMap[JSON.stringify(collection2)] = {
78
+ type: "unknown",
79
+ entries: {}
80
+ };
76
81
  logger.debug("content", `${cyan(collection2)} collection added`);
77
82
  break;
78
83
  case "unlinkDir":
@@ -150,7 +155,11 @@ async function createContentTypesGenerator({
150
155
  const contentEntryType = contentEntryConfigByExt.get(path.extname(event.entry.pathname));
151
156
  if (!contentEntryType)
152
157
  return { shouldGenerateTypes: false };
153
- const { id, slug: generatedSlug } = getContentEntryIdAndSlug({ entry, contentDir, collection });
158
+ const { id, slug: generatedSlug } = getContentEntryIdAndSlug({
159
+ entry,
160
+ contentDir,
161
+ collection
162
+ });
154
163
  const collectionKey = JSON.stringify(collection);
155
164
  if (!(collectionKey in collectionEntryMap)) {
156
165
  collectionEntryMap[collectionKey] = { type: "content", entries: {} };
@@ -181,7 +190,10 @@ async function createContentTypesGenerator({
181
190
  if (!(entryKey in collectionEntryMap[collectionKey].entries)) {
182
191
  collectionEntryMap[collectionKey] = {
183
192
  type: "content",
184
- entries: { ...collectionInfo.entries, [entryKey]: { slug: addedSlug } }
193
+ entries: {
194
+ ...collectionInfo.entries,
195
+ [entryKey]: { slug: addedSlug }
196
+ }
185
197
  };
186
198
  }
187
199
  return { shouldGenerateTypes: true };
@@ -244,7 +256,9 @@ async function createContentTypesGenerator({
244
256
  typeTemplateContent,
245
257
  contentConfig: observable.status === "loaded" ? observable.config : void 0,
246
258
  contentEntryTypes: settings.contentEntryTypes,
247
- viteServer
259
+ viteServer,
260
+ logger,
261
+ settings
248
262
  });
249
263
  invalidateVirtualMod(viteServer);
250
264
  }
@@ -269,12 +283,21 @@ async function writeContentFiles({
269
283
  typeTemplateContent,
270
284
  contentEntryTypes,
271
285
  contentConfig,
272
- viteServer
286
+ viteServer,
287
+ logger,
288
+ settings
273
289
  }) {
274
290
  let contentTypesStr = "";
275
291
  let dataTypesStr = "";
292
+ const collectionSchemasDir = new URL("./collections/", contentPaths.cacheDir);
293
+ if (settings.config.experimental.contentCollectionJsonSchema && !fs.existsSync(collectionSchemasDir)) {
294
+ fs.mkdirSync(collectionSchemasDir, { recursive: true });
295
+ }
276
296
  for (const [collection, config] of Object.entries(contentConfig?.collections ?? {})) {
277
- collectionEntryMap[JSON.stringify(collection)] ??= { type: config.type, entries: {} };
297
+ collectionEntryMap[JSON.stringify(collection)] ??= {
298
+ type: config.type,
299
+ entries: {}
300
+ };
278
301
  }
279
302
  for (const collectionKey of Object.keys(collectionEntryMap).sort()) {
280
303
  const collectionConfig = contentConfig?.collections[JSON.parse(collectionKey)];
@@ -292,7 +315,6 @@ async function writeContentFiles({
292
315
  hint: collection.type === "data" ? "Try adding `type: 'data'` to your collection config." : void 0,
293
316
  location: {
294
317
  file: ""
295
- /** required for error overlay `hot` messages */
296
318
  }
297
319
  })
298
320
  });
@@ -337,6 +359,33 @@ async function writeContentFiles({
337
359
  data: ${dataType}
338
360
  };
339
361
  `;
362
+ if (settings.config.experimental.contentCollectionJsonSchema && collectionConfig?.schema) {
363
+ let zodSchemaForJson = collectionConfig.schema;
364
+ if (zodSchemaForJson instanceof z.ZodObject) {
365
+ zodSchemaForJson = zodSchemaForJson.extend({
366
+ $schema: z.string().optional()
367
+ });
368
+ }
369
+ try {
370
+ await fs.promises.writeFile(
371
+ new URL(`./${collectionKey.replace(/"/g, "")}.schema.json`, collectionSchemasDir),
372
+ JSON.stringify(
373
+ zodToJsonSchema(zodSchemaForJson, {
374
+ name: collectionKey.replace(/"/g, ""),
375
+ markdownDescription: true,
376
+ errorMessages: true
377
+ }),
378
+ null,
379
+ 2
380
+ )
381
+ );
382
+ } catch (err) {
383
+ logger.warn(
384
+ "content",
385
+ `An error was encountered while creating the JSON schema. Proceeding without it. Error: ${err}`
386
+ );
387
+ }
388
+ }
340
389
  }
341
390
  dataTypesStr += `};
342
391
  `;
@@ -1,5 +1,6 @@
1
1
  import { extname } from "node:path";
2
2
  import { pathToFileURL } from "node:url";
3
+ import { getAssetsPrefix } from "../assets/utils/getAssetsPrefix.js";
3
4
  import { moduleIsTopLevelPage, walkParentInfos } from "../core/build/graph.js";
4
5
  import { getPageDataByViteID } from "../core/build/internal.js";
5
6
  import { createViteLoader } from "../core/module-loader/vite.js";
@@ -54,7 +55,11 @@ function astroContentAssetPropagationPlugin({
54
55
  urls,
55
56
  crawledFiles: styleCrawledFiles
56
57
  } = await getStylesForURL(pathToFileURL(basePath), devModuleLoader);
57
- const { scripts: hoistedScripts, crawledFiles: scriptCrawledFiles } = await getScriptsForURL(pathToFileURL(basePath), settings.config.root, devModuleLoader);
58
+ const { scripts: hoistedScripts, crawledFiles: scriptCrawledFiles } = settings.config.experimental.directRenderScript ? { scripts: /* @__PURE__ */ new Set(), crawledFiles: /* @__PURE__ */ new Set() } : await getScriptsForURL(
59
+ pathToFileURL(basePath),
60
+ settings.config.root,
61
+ devModuleLoader
62
+ );
58
63
  for (const file of styleCrawledFiles) {
59
64
  if (!file.includes("node_modules")) {
60
65
  this.addWatchFile(file);
@@ -108,8 +113,11 @@ function astroConfigBuildPlugin(options, internals) {
108
113
  "build:post": ({ ssrOutputs, clientOutputs, mutate }) => {
109
114
  const outputs = ssrOutputs.flatMap((o) => o.output);
110
115
  const prependBase = (src) => {
111
- if (options.settings.config.build.assetsPrefix) {
112
- return joinPaths(options.settings.config.build.assetsPrefix, src);
116
+ const { assetsPrefix } = options.settings.config.build;
117
+ if (assetsPrefix) {
118
+ const fileExtension = extname(src);
119
+ const pf = getAssetsPrefix(fileExtension, assetsPrefix);
120
+ return joinPaths(pf, src);
113
121
  } else {
114
122
  return prependForwardSlash(joinPaths(options.settings.config.base, src));
115
123
  }
@@ -11,6 +11,7 @@ function deserializeManifest(serializedManifest) {
11
11
  }
12
12
  const assets = new Set(serializedManifest.assets);
13
13
  const componentMetadata = new Map(serializedManifest.componentMetadata);
14
+ const inlinedScripts = new Map(serializedManifest.inlinedScripts);
14
15
  const clientDirectives = new Map(serializedManifest.clientDirectives);
15
16
  return {
16
17
  // in case user middleware exists, this no-op middleware will be reassigned (see plugin-ssr.ts)
@@ -20,6 +21,7 @@ function deserializeManifest(serializedManifest) {
20
21
  ...serializedManifest,
21
22
  assets,
22
23
  componentMetadata,
24
+ inlinedScripts,
23
25
  clientDirectives,
24
26
  routes
25
27
  };
@@ -1,5 +1,6 @@
1
1
  import { normalizeTheLocale } from "../../i18n/index.js";
2
2
  import {
3
+ DEFAULT_404_COMPONENT,
3
4
  REROUTABLE_STATUS_CODES,
4
5
  REROUTE_DIRECTIVE_HEADER,
5
6
  clientAddressSymbol,
@@ -20,6 +21,7 @@ import {
20
21
  import { RedirectSinglePageBuiltModule } from "../redirects/index.js";
21
22
  import { RenderContext } from "../render-context.js";
22
23
  import { createAssetLink } from "../render/ssr-element.js";
24
+ import { ensure404Route } from "../routing/astro-designed-error-pages.js";
23
25
  import { matchRoute } from "../routing/match.js";
24
26
  import { AppPipeline } from "./pipeline.js";
25
27
  import { deserializeManifest } from "./common.js";
@@ -36,9 +38,9 @@ class App {
36
38
  #renderOptionsDeprecationWarningShown = false;
37
39
  constructor(manifest, streaming = true) {
38
40
  this.#manifest = manifest;
39
- this.#manifestData = {
41
+ this.#manifestData = ensure404Route({
40
42
  routes: manifest.routes.map((route) => route.routeData)
41
- };
43
+ });
42
44
  this.#baseWithoutTrailingSlash = removeTrailingForwardSlash(this.#manifest.base);
43
45
  this.#pipeline = this.#createPipeline(streaming);
44
46
  this.#adapterLogger = new AstroIntegrationLogger(
@@ -348,6 +350,12 @@ class App {
348
350
  return 200;
349
351
  }
350
352
  async #getModuleForRoute(route) {
353
+ if (route.component === DEFAULT_404_COMPONENT) {
354
+ return {
355
+ page: async () => ({ default: () => new Response(null, { status: 404 }) }),
356
+ renderers: []
357
+ };
358
+ }
351
359
  if (route.type === "redirect") {
352
360
  return RedirectSinglePageBuiltModule;
353
361
  } else {
@@ -26,6 +26,9 @@ export type SerializedRouteInfo = Omit<RouteInfo, 'routeData'> & {
26
26
  routeData: SerializedRouteData;
27
27
  };
28
28
  export type ImportComponentInstance = () => Promise<SinglePageBuiltModule>;
29
+ export type AssetsPrefix = string | ({
30
+ fallback: string;
31
+ } & Record<string, string>) | undefined;
29
32
  export type SSRManifest = {
30
33
  adapterName: string;
31
34
  routes: RouteInfo[];
@@ -34,13 +37,14 @@ export type SSRManifest = {
34
37
  trailingSlash: 'always' | 'never' | 'ignore';
35
38
  buildFormat: 'file' | 'directory' | 'preserve';
36
39
  compressHTML: boolean;
37
- assetsPrefix?: string;
40
+ assetsPrefix?: AssetsPrefix;
38
41
  renderers: SSRLoadedRenderer[];
39
42
  /**
40
43
  * Map of directive name (e.g. `load`) to the directive script code
41
44
  */
42
45
  clientDirectives: Map<string, string>;
43
46
  entryModules: Record<string, string>;
47
+ inlinedScripts: Map<string, string>;
44
48
  assets: Set<string>;
45
49
  componentMetadata: SSRResult['componentMetadata'];
46
50
  pageModule?: SinglePageBuiltModule;
@@ -55,9 +59,10 @@ export type SSRManifestI18n = {
55
59
  defaultLocale: string;
56
60
  domainLookupTable: Record<string, string>;
57
61
  };
58
- export type SerializedSSRManifest = Omit<SSRManifest, 'middleware' | 'routes' | 'assets' | 'componentMetadata' | 'clientDirectives'> & {
62
+ export type SerializedSSRManifest = Omit<SSRManifest, 'middleware' | 'routes' | 'assets' | 'componentMetadata' | 'inlinedScripts' | 'clientDirectives'> & {
59
63
  routes: SerializedRouteInfo[];
60
64
  assets: string[];
61
65
  componentMetadata: [string, SSRComponentMetadata][];
66
+ inlinedScripts: [string, string][];
62
67
  clientDirectives: [string, string][];
63
68
  };
@@ -26,6 +26,7 @@ export declare abstract class Pipeline {
26
26
  */
27
27
  readonly adapterName: string;
28
28
  readonly clientDirectives: Map<string, string>;
29
+ readonly inlinedScripts: Map<string, string>;
29
30
  readonly compressHTML: boolean;
30
31
  readonly i18n: import("./app/types.js").SSRManifestI18n | undefined;
31
32
  readonly middleware: MiddlewareHandler;
@@ -47,7 +48,7 @@ export declare abstract class Pipeline {
47
48
  /**
48
49
  * Used to provide better error messages for `Astro.clientAddress`
49
50
  */
50
- adapterName?: string, clientDirectives?: Map<string, string>, compressHTML?: boolean, i18n?: import("./app/types.js").SSRManifestI18n | undefined, middleware?: MiddlewareHandler, routeCache?: RouteCache,
51
+ adapterName?: string, clientDirectives?: Map<string, string>, inlinedScripts?: Map<string, string>, compressHTML?: boolean, i18n?: import("./app/types.js").SSRManifestI18n | undefined, middleware?: MiddlewareHandler, routeCache?: RouteCache,
51
52
  /**
52
53
  * Used for `Astro.site`.
53
54
  */
@@ -1,7 +1,7 @@
1
1
  import { createI18nMiddleware } from "../i18n/middleware.js";
2
2
  import { RouteCache } from "./render/route-cache.js";
3
3
  class Pipeline {
4
- constructor(logger, manifest, mode, renderers, resolve, serverLike, streaming, adapterName = manifest.adapterName, clientDirectives = manifest.clientDirectives, compressHTML = manifest.compressHTML, i18n = manifest.i18n, middleware = manifest.middleware, routeCache = new RouteCache(logger, mode), site = manifest.site ? new URL(manifest.site) : void 0) {
4
+ constructor(logger, manifest, mode, renderers, resolve, serverLike, streaming, adapterName = manifest.adapterName, clientDirectives = manifest.clientDirectives, inlinedScripts = manifest.inlinedScripts, compressHTML = manifest.compressHTML, i18n = manifest.i18n, middleware = manifest.middleware, routeCache = new RouteCache(logger, mode), site = manifest.site ? new URL(manifest.site) : void 0) {
5
5
  this.logger = logger;
6
6
  this.manifest = manifest;
7
7
  this.mode = mode;
@@ -11,6 +11,7 @@ class Pipeline {
11
11
  this.streaming = streaming;
12
12
  this.adapterName = adapterName;
13
13
  this.clientDirectives = clientDirectives;
14
+ this.inlinedScripts = inlinedScripts;
14
15
  this.compressHTML = compressHTML;
15
16
  this.i18n = i18n;
16
17
  this.middleware = middleware;
@@ -421,6 +421,7 @@ function createBuildManifest(settings, internals, renderers, middleware) {
421
421
  trailingSlash: settings.config.trailingSlash,
422
422
  assets: /* @__PURE__ */ new Set(),
423
423
  entryModules: Object.fromEntries(internals.entrySpecifierToBundleMap.entries()),
424
+ inlinedScripts: internals.inlinedScripts,
424
425
  routes: [],
425
426
  adapterName: "",
426
427
  clientDirectives: settings.clientDirectives,
@@ -13,6 +13,12 @@ export interface BuildInternals {
13
13
  cssModuleToChunkIdMap: Map<string, string>;
14
14
  hoistedScriptIdToHoistedMap: Map<string, Set<string>>;
15
15
  hoistedScriptIdToPagesMap: Map<string, Set<string>>;
16
+ /**
17
+ * Used by the `directRenderScript` option. If script is inlined, its id and
18
+ * inlined code is mapped here. The resolved id is an URL like "/_astro/something.js"
19
+ * but will no longer exist as the content is now inlined in this map.
20
+ */
21
+ inlinedScripts: Map<string, string>;
16
22
  entrySpecifierToBundleMap: Map<string, string>;
17
23
  /**
18
24
  * A map to get a specific page's bundled output file.
@@ -14,6 +14,7 @@ function createBuildInternals() {
14
14
  cssModuleToChunkIdMap: /* @__PURE__ */ new Map(),
15
15
  hoistedScriptIdToHoistedMap,
16
16
  hoistedScriptIdToPagesMap,
17
+ inlinedScripts: /* @__PURE__ */ new Map(),
17
18
  entrySpecifierToBundleMap: /* @__PURE__ */ new Map(),
18
19
  pageToBundleMap: /* @__PURE__ */ new Map(),
19
20
  pagesByComponent: /* @__PURE__ */ new Map(),
@@ -12,6 +12,7 @@ import { pluginMiddleware } from "./plugin-middleware.js";
12
12
  import { pluginPages } from "./plugin-pages.js";
13
13
  import { pluginPrerender } from "./plugin-prerender.js";
14
14
  import { pluginRenderers } from "./plugin-renderers.js";
15
+ import { pluginScripts } from "./plugin-scripts.js";
15
16
  import { pluginSSR, pluginSSRSplit } from "./plugin-ssr.js";
16
17
  function registerAllPlugins({ internals, options, register }) {
17
18
  register(pluginComponentEntry(internals));
@@ -26,7 +27,11 @@ function registerAllPlugins({ internals, options, register }) {
26
27
  register(astroHeadBuildPlugin(internals));
27
28
  register(pluginPrerender(options, internals));
28
29
  register(astroConfigBuildPlugin(options, internals));
29
- register(pluginHoistedScripts(options, internals));
30
+ if (options.settings.config.experimental.directRenderScript) {
31
+ register(pluginScripts(internals));
32
+ } else {
33
+ register(pluginHoistedScripts(options, internals));
34
+ }
30
35
  register(pluginSSR(options, internals));
31
36
  register(pluginSSRSplit(options, internals));
32
37
  register(pluginChunks());
@@ -9,82 +9,6 @@ function isPropagatedAsset(id) {
9
9
  return false;
10
10
  }
11
11
  }
12
- async function doesParentImportChild(parentInfo, childInfo, childExportNames) {
13
- if (!childInfo || !parentInfo.ast || !childExportNames)
14
- return "no";
15
- if (childExportNames === "dynamic" || parentInfo.dynamicallyImportedIds?.includes(childInfo.id)) {
16
- return "dynamic";
17
- }
18
- const imports = [];
19
- const exports = [];
20
- for (const node of parentInfo.ast.body) {
21
- if (node.type === "ImportDeclaration") {
22
- imports.push(node);
23
- } else if (node.type === "ExportDefaultDeclaration" || node.type === "ExportNamedDeclaration") {
24
- exports.push(node);
25
- }
26
- }
27
- const importNames = [];
28
- const exportNames = [];
29
- for (const node of imports) {
30
- const resolved = await this.resolve(node.source.value, parentInfo.id);
31
- if (!resolved || resolved.id !== childInfo.id)
32
- continue;
33
- for (const specifier of node.specifiers) {
34
- if (specifier.type === "ImportNamespaceSpecifier")
35
- continue;
36
- const name = specifier.type === "ImportDefaultSpecifier" ? "default" : specifier.imported.name;
37
- if (childExportNames.includes(name)) {
38
- importNames.push(specifier.local.name);
39
- }
40
- }
41
- }
42
- for (const node of exports) {
43
- if (node.type === "ExportDefaultDeclaration") {
44
- if (node.declaration.type === "Identifier" && importNames.includes(node.declaration.name)) {
45
- exportNames.push("default");
46
- }
47
- } else {
48
- if (node.source) {
49
- const resolved = await this.resolve(node.source.value, parentInfo.id);
50
- if (!resolved || resolved.id !== childInfo.id)
51
- continue;
52
- for (const specifier of node.specifiers) {
53
- if (childExportNames.includes(specifier.local.name)) {
54
- importNames.push(specifier.local.name);
55
- exportNames.push(specifier.exported.name);
56
- }
57
- }
58
- }
59
- if (node.declaration) {
60
- if (node.declaration.type !== "VariableDeclaration")
61
- continue;
62
- for (const declarator of node.declaration.declarations) {
63
- if (declarator.init?.type !== "Identifier")
64
- continue;
65
- if (declarator.id.type !== "Identifier")
66
- continue;
67
- if (importNames.includes(declarator.init.name)) {
68
- exportNames.push(declarator.id.name);
69
- }
70
- }
71
- }
72
- for (const specifier of node.specifiers) {
73
- if (importNames.includes(specifier.local.name)) {
74
- exportNames.push(specifier.exported.name);
75
- }
76
- }
77
- }
78
- }
79
- if (!importNames.length)
80
- return "no";
81
- if (parentInfo.id.endsWith(".astro")) {
82
- exportNames.push("default");
83
- } else if (parentInfo.id.endsWith(".mdx")) {
84
- exportNames.push("Content");
85
- }
86
- return exportNames;
87
- }
88
12
  function vitePluginAnalyzer(options, internals) {
89
13
  function hoistedScriptScanner() {
90
14
  const uniqueHoistedIds = /* @__PURE__ */ new Map();
@@ -97,29 +21,9 @@ function vitePluginAnalyzer(options, internals) {
97
21
  hoistedScripts.add(hid);
98
22
  }
99
23
  if (hoistedScripts.size) {
100
- const depthsToChildren = /* @__PURE__ */ new Map();
101
- const depthsToExportNames = /* @__PURE__ */ new Map();
102
- depthsToExportNames.set(0, ["default"]);
103
- for (const [parentInfo, depth] of walkParentInfos(from, this, function until(importer) {
24
+ for (const [parentInfo] of walkParentInfos(from, this, function until(importer) {
104
25
  return isPropagatedAsset(importer);
105
26
  })) {
106
- if (options.settings.config.experimental.optimizeHoistedScript) {
107
- depthsToChildren.set(depth, parentInfo);
108
- if (depth > 0) {
109
- const childInfo = depthsToChildren.get(depth - 1);
110
- const childExportNames = depthsToExportNames.get(depth - 1);
111
- const doesImport = await doesParentImportChild.call(
112
- this,
113
- parentInfo,
114
- childInfo,
115
- childExportNames
116
- );
117
- if (doesImport === "no") {
118
- continue;
119
- }
120
- depthsToExportNames.set(depth, doesImport);
121
- }
122
- }
123
27
  if (isPropagatedAsset(parentInfo.id)) {
124
28
  for (const [nestedParentInfo] of walkParentInfos(from, this)) {
125
29
  if (moduleIsTopLevelPage(nestedParentInfo)) {
@@ -188,7 +92,9 @@ function vitePluginAnalyzer(options, internals) {
188
92
  return {
189
93
  name: "@astro/rollup-plugin-astro-analyzer",
190
94
  async generateBundle() {
191
- const hoistScanner = hoistedScriptScanner();
95
+ const hoistScanner = options.settings.config.experimental.directRenderScript ? { scan: async () => {
96
+ }, finalize: () => {
97
+ } } : hoistedScriptScanner();
192
98
  const ids = this.getModuleIds();
193
99
  for (const id of ids) {
194
100
  const info = this.getModuleInfo(id);
@@ -232,6 +138,12 @@ function vitePluginAnalyzer(options, internals) {
232
138
  trackClientOnlyPageDatas(internals, newPageData, clientOnlys);
233
139
  }
234
140
  }
141
+ if (options.settings.config.experimental.directRenderScript && astro.scripts.length) {
142
+ for (let i = 0; i < astro.scripts.length; i++) {
143
+ const hid = `${id.replace("/@fs", "")}?astro&type=script&index=${i}&lang.ts`;
144
+ internals.discoveredScripts.add(hid);
145
+ }
146
+ }
235
147
  }
236
148
  hoistScanner.finalize();
237
149
  }
@@ -125,6 +125,22 @@ function rollupPluginAstroBuildCSS(options) {
125
125
  }
126
126
  }
127
127
  };
128
+ const cssScopeToPlugin = {
129
+ name: "astro:rollup-plugin-css-scope-to",
130
+ renderChunk(_, chunk, __, meta) {
131
+ for (const id in chunk.modules) {
132
+ const modMeta = this.getModuleInfo(id)?.meta;
133
+ const cssScopeTo = modMeta?.astroCss?.cssScopeTo;
134
+ if (cssScopeTo && !isCssScopeToRendered(cssScopeTo, Object.values(meta.chunks))) {
135
+ delete chunk.modules[id];
136
+ const moduleIdsIndex = chunk.moduleIds.indexOf(id);
137
+ if (moduleIdsIndex > -1) {
138
+ chunk.moduleIds.splice(moduleIdsIndex, 1);
139
+ }
140
+ }
141
+ }
142
+ }
143
+ };
128
144
  const singleCssPlugin = {
129
145
  name: "astro:rollup-plugin-single-css",
130
146
  enforce: "post",
@@ -197,7 +213,7 @@ function rollupPluginAstroBuildCSS(options) {
197
213
  });
198
214
  }
199
215
  };
200
- return [cssBuildPlugin, singleCssPlugin, inlineStylesheetsPlugin];
216
+ return [cssBuildPlugin, cssScopeToPlugin, singleCssPlugin, inlineStylesheetsPlugin];
201
217
  }
202
218
  function* getParentClientOnlys(id, ctx, internals) {
203
219
  for (const [info] of walkParentInfos(id, ctx)) {
@@ -222,6 +238,16 @@ function appendCSSToPage(pageData, meta, pagesToCss, depth, order) {
222
238
  }
223
239
  }
224
240
  }
241
+ function isCssScopeToRendered(cssScopeTo, chunks) {
242
+ for (const moduleId in cssScopeTo) {
243
+ const exports = cssScopeTo[moduleId];
244
+ const renderedModule = chunks.find((c) => c.moduleIds.includes(moduleId))?.modules[moduleId];
245
+ if (renderedModule?.renderedExports.some((e) => exports.includes(e))) {
246
+ return true;
247
+ }
248
+ }
249
+ return false;
250
+ }
225
251
  export {
226
252
  pluginCSS
227
253
  };
@@ -1,11 +1,12 @@
1
1
  import { fileURLToPath } from "node:url";
2
2
  import glob from "fast-glob";
3
3
  import {} from "vite";
4
+ import { getAssetsPrefix } from "../../../assets/utils/getAssetsPrefix.js";
4
5
  import { normalizeTheLocale } from "../../../i18n/index.js";
5
6
  import { toRoutingStrategy } from "../../../i18n/utils.js";
6
7
  import { runHookBuildSsr } from "../../../integrations/index.js";
7
8
  import { BEFORE_HYDRATION_SCRIPT_ID, PAGE_SCRIPT_ID } from "../../../vite-plugin-scripts/index.js";
8
- import { joinPaths, prependForwardSlash } from "../../path.js";
9
+ import { fileExtension, joinPaths, prependForwardSlash } from "../../path.js";
9
10
  import { serializeRouteData } from "../../routing/index.js";
10
11
  import { addRollupInput } from "../add-rollup-input.js";
11
12
  import { getOutFile, getOutFolder } from "../common.js";
@@ -120,7 +121,8 @@ function buildManifest(opts, internals, staticFiles) {
120
121
  }
121
122
  const prefixAssetPath = (pth) => {
122
123
  if (settings.config.build.assetsPrefix) {
123
- return joinPaths(settings.config.build.assetsPrefix, pth);
124
+ const pf = getAssetsPrefix(fileExtension(pth), settings.config.build.assetsPrefix);
125
+ return joinPaths(pf, pth);
124
126
  } else {
125
127
  return prependForwardSlash(joinPaths(settings.config.base, pth));
126
128
  }
@@ -208,6 +210,7 @@ function buildManifest(opts, internals, staticFiles) {
208
210
  renderers: [],
209
211
  clientDirectives: Array.from(settings.clientDirectives),
210
212
  entryModules,
213
+ inlinedScripts: Array.from(internals.inlinedScripts),
211
214
  assets: staticFiles.map(prefixAssetPath),
212
215
  i18n: i18nManifest,
213
216
  buildFormat: settings.config.build.format
@@ -0,0 +1,8 @@
1
+ import type { Plugin as VitePlugin } from 'vite';
2
+ import type { BuildInternals } from '../internal.js';
3
+ import type { AstroBuildPlugin } from '../plugin.js';
4
+ /**
5
+ * Used by the `experimental.directRenderScript` option to inline scripts directly into the HTML.
6
+ */
7
+ export declare function vitePluginScripts(internals: BuildInternals): VitePlugin;
8
+ export declare function pluginScripts(internals: BuildInternals): AstroBuildPlugin;
@@ -0,0 +1,34 @@
1
+ import { shouldInlineAsset } from "./util.js";
2
+ function vitePluginScripts(internals) {
3
+ let assetInlineLimit;
4
+ return {
5
+ name: "@astro/plugin-scripts",
6
+ configResolved(config) {
7
+ assetInlineLimit = config.build.assetsInlineLimit;
8
+ },
9
+ async generateBundle(_options, bundle) {
10
+ for (const [id, output] of Object.entries(bundle)) {
11
+ if (output.type === "chunk" && output.facadeModuleId && internals.discoveredScripts.has(output.facadeModuleId) && output.imports.length === 0 && output.dynamicImports.length === 0 && shouldInlineAsset(output.code, output.fileName, assetInlineLimit)) {
12
+ internals.inlinedScripts.set(output.facadeModuleId, output.code.trim());
13
+ delete bundle[id];
14
+ }
15
+ }
16
+ }
17
+ };
18
+ }
19
+ function pluginScripts(internals) {
20
+ return {
21
+ targets: ["client"],
22
+ hooks: {
23
+ "build:before": () => {
24
+ return {
25
+ vitePlugin: vitePluginScripts(internals)
26
+ };
27
+ }
28
+ }
29
+ };
30
+ }
31
+ export {
32
+ pluginScripts,
33
+ vitePluginScripts
34
+ };
@@ -2,6 +2,7 @@ import type { TransformResult } from '@astrojs/compiler';
2
2
  import type { ResolvedConfig } from 'vite';
3
3
  import type { AstroConfig } from '../../@types/astro.js';
4
4
  import type { AstroPreferences } from '../../preferences/index.js';
5
+ import type { CompileCssResult } from './types.js';
5
6
  export interface CompileProps {
6
7
  astroConfig: AstroConfig;
7
8
  viteConfig: ResolvedConfig;
@@ -9,13 +10,6 @@ export interface CompileProps {
9
10
  filename: string;
10
11
  source: string;
11
12
  }
12
- export interface CompileCssResult {
13
- code: string;
14
- /**
15
- * The dependencies of the transformed CSS (Normalized paths)
16
- */
17
- dependencies?: string[];
18
- }
19
13
  export interface CompileResult extends Omit<TransformResult, 'css'> {
20
14
  css: CompileCssResult[];
21
15
  }
@@ -12,7 +12,7 @@ async function compile({
12
12
  filename,
13
13
  source
14
14
  }) {
15
- const cssDeps = [];
15
+ const cssPartialCompileResults = [];
16
16
  const cssTransformErrors = [];
17
17
  let transformResult;
18
18
  try {
@@ -29,10 +29,11 @@ async function compile({
29
29
  resultScopedSlot: true,
30
30
  transitionsAnimationURL: "astro/components/viewtransitions.css",
31
31
  annotateSourceFile: viteConfig.command === "serve" && astroConfig.devToolbar && astroConfig.devToolbar.enabled && await preferences.get("devToolbar.enabled"),
32
+ renderScript: astroConfig.experimental.directRenderScript,
32
33
  preprocessStyle: createStylePreprocessor({
33
34
  filename,
34
35
  viteConfig,
35
- cssDeps,
36
+ cssPartialCompileResults,
36
37
  cssTransformErrors
37
38
  }),
38
39
  async resolvePath(specifier) {
@@ -53,8 +54,8 @@ async function compile({
53
54
  return {
54
55
  ...transformResult,
55
56
  css: transformResult.css.map((code, i) => ({
56
- code,
57
- dependencies: cssDeps[i]
57
+ ...cssPartialCompileResults[i],
58
+ code
58
59
  }))
59
60
  };
60
61
  }