Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: first implementation for serialized config #13000

Merged
merged 6 commits into from
Jan 21, 2025
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions packages/astro/client.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,18 @@ declare module 'astro:middleware' {
export * from 'astro/virtual-modules/middleware.js';
}

declare module 'astro:manifest/server' {
type ServerConfigSerialized = import('./dist/types/public/manifest.js').ServerConfigSerialized;
const manifest: ServerConfigSerialized;
export default manifest;
}

declare module 'astro:manifest/client' {
type ClientConfigSerialized = import('./dist/types/public/manifest.js').ClientConfigSerialized;
const manifest: ClientConfigSerialized;
export default manifest;
}

declare module 'astro:components' {
export * from 'astro/components';
}
Expand Down
5 changes: 5 additions & 0 deletions packages/astro/src/core/config/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ export const ASTRO_CONFIG_DEFAULTS = {
contentIntellisense: false,
responsiveImages: false,
svg: false,
serializeManifest: false,
},
} satisfies AstroUserConfig & { server: { open: boolean } };

Expand Down Expand Up @@ -589,6 +590,10 @@ export const AstroConfigSchema = z.object({
}
return svgConfig;
}),
serializeManifest: z
.boolean()
.optional()
.default(ASTRO_CONFIG_DEFAULTS.experimental.serializeManifest),
})
.strict(
`Invalid or outdated experimental feature.\nCheck for incorrect spelling or outdated Astro version.\nSee https://docs.astro.build/en/reference/experimental-flags/ for a list of all current experiments.`,
Expand Down
2 changes: 2 additions & 0 deletions packages/astro/src/core/create-vite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { createEnvLoader } from '../env/env-loader.js';
import { astroEnv } from '../env/vite-plugin-env.js';
import { importMetaEnv } from '../env/vite-plugin-import-meta-env.js';
import astroInternationalization from '../i18n/vite-plugin-i18n.js';
import astroVirtualManifestPlugin from '../manifest/virtual-module.js';
import astroPrefetch from '../prefetch/vite-plugin-prefetch.js';
import astroDevToolbar from '../toolbar/vite-plugin-dev-toolbar.js';
import astroTransitions from '../transitions/vite-plugin-transitions.js';
Expand Down Expand Up @@ -141,6 +142,7 @@ export async function createVite(
exclude: ['astro', 'node-fetch'],
},
plugins: [
astroVirtualManifestPlugin({ settings, logger }),
configAliasVitePlugin({ settings }),
astroLoadFallbackPlugin({ fs, root: settings.config.root }),
astroVitePlugin({ settings, logger }),
Expand Down
12 changes: 12 additions & 0 deletions packages/astro/src/core/errors/errors-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1782,6 +1782,18 @@ export const ActionCalledFromServerError = {
hint: 'See the `Astro.callAction()` reference for usage examples: https://docs.astro.build/en/reference/api-reference/#callaction',
} satisfies ErrorData;

/**
* @docs
* @description
* Cannot the module without enabling the experimental feature
*/
export const CantUseManifestModule = {
name: 'CantUseManifestModule',
title: 'Cannot the module without enabling the experimental feature.',
message: (moduleName) =>
`Cannot import the module "${moduleName}" because the experimental feature is disabled. Enable \`experimental.serializeManifest\` in your \`astro.config.mjs\` `,
} satisfies ErrorData;

// Generic catch-all - Only use this in extreme cases, like if there was a cosmic ray bit flip.
export const UnknownError = { name: 'UnknownError', title: 'Unknown Error.' } satisfies ErrorData;

Expand Down
102 changes: 102 additions & 0 deletions packages/astro/src/manifest/virtual-module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import type { Plugin } from 'vite';
import { CantUseManifestModule } from '../core/errors/errors-data.js';
import { AstroError, AstroErrorData } from '../core/errors/index.js';
import type { Logger } from '../core/logger/core.js';
import type { AstroSettings } from '../types/astro.js';
import type {
AstroConfig,
ClientConfigSerialized,
ServerConfigSerialized,
} from '../types/public/index.js';

const VIRTUAL_SERVER_ID = 'astro:manifest/server';
const RESOLVED_VIRTUAL_SERVER_ID = '\0' + VIRTUAL_SERVER_ID;
const VIRTUAL_CLIENT_ID = 'astro:manifest/client';
const RESOLVED_VIRTUAL_CLIENT_ID = '\0' + VIRTUAL_CLIENT_ID;

export default function virtualModulePlugin({
settings,
logger: _logger,
}: { settings: AstroSettings; logger: Logger }): Plugin {
ematipico marked this conversation as resolved.
Show resolved Hide resolved
return {
enforce: 'pre',
name: 'astro-manifest-plugin',
resolveId(id) {
// Resolve the virtual module
if (VIRTUAL_SERVER_ID === id) {
return RESOLVED_VIRTUAL_SERVER_ID;
} else if (VIRTUAL_CLIENT_ID === id) {
return RESOLVED_VIRTUAL_CLIENT_ID;
}
},
load(id, opts) {
// client
if (id === RESOLVED_VIRTUAL_CLIENT_ID) {
if (!settings.config.experimental.serializeManifest) {
throw new AstroError({
...CantUseManifestModule,
message: CantUseManifestModule.message(VIRTUAL_CLIENT_ID),
});
}
// There's nothing wrong about using `/client` on the server
ematipico marked this conversation as resolved.
Show resolved Hide resolved
return `${serializeClientConfig(settings.config)};`;
}
// server
else if (id == RESOLVED_VIRTUAL_SERVER_ID) {
if (!settings.config.experimental.serializeManifest) {
throw new AstroError({
...CantUseManifestModule,
message: CantUseManifestModule.message(VIRTUAL_SERVER_ID),
});
}
if (!opts?.ssr) {
throw new AstroError({
...AstroErrorData.ServerOnlyModule,
message: AstroErrorData.ServerOnlyModule.message(VIRTUAL_SERVER_ID),
});
}
return `${serializeServerConfig(settings.config)};`;
}
},
};
}

function serializeClientConfig(config: AstroConfig): string {
const serClientConfig: ClientConfigSerialized = {
base: config.base,
i18n: config.i18n,
build: {
format: config.build.format,
redirects: config.build.redirects,
},
trailingSlash: config.trailingSlash,
compressHTML: config.compressHTML,
site: config.site,
legacy: config.legacy,
};

const output = [];
for (const [key, value] of Object.entries(serClientConfig)) {
output.push(`export const ${key} = ${JSON.stringify(value)};`);
}
return output.join('\n') + '\n';
}

function serializeServerConfig(config: AstroConfig): string {
const serverConfig: ServerConfigSerialized = {
build: {
client: config.build.client,
server: config.build.server,
},
cacheDir: config.cacheDir,
outDir: config.outDir,
publicDir: config.publicDir,
srcDir: config.srcDir,
root: config.root,
};
const output = [];
for (const [key, value] of Object.entries(serverConfig)) {
output.push(`export const ${key} = ${JSON.stringify(value)};`);
}
return output.join('\n') + '\n';
}
13 changes: 13 additions & 0 deletions packages/astro/src/types/public/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2059,6 +2059,19 @@ export interface ViteUserConfig extends OriginalViteUserConfig {
*/
mode: SvgRenderMode;
};

/**
* @name experimental.serializeManifest
* @type {boolean}
* @default `false`
* @version 5.x
* @description
*
* Allows to use the virtual modules `astro:manifest/server` and `astro:manifest/client`.
*
* These two virtual modules contain a serializable subset of the Astro configuration.
*/
serializeManifest?: boolean;
};
}

Expand Down
1 change: 1 addition & 0 deletions packages/astro/src/types/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export type * from './context.js';
export type * from './preview.js';
export type * from './content.js';
export type * from './common.js';
export type * from './manifest.js';

export type { AstroIntegrationLogger } from '../../core/logger/core.js';
export type { ToolbarServerHelpers } from '../../runtime/client/dev-toolbar/helpers.js';
Expand Down
19 changes: 19 additions & 0 deletions packages/astro/src/types/public/manifest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { AstroConfig } from './config.js';

export type SerializedClientBuild = Pick<AstroConfig['build'], 'format' | 'redirects'>;
ematipico marked this conversation as resolved.
Show resolved Hide resolved

export type SerializedServerBuild = Pick<AstroConfig['build'], 'client' | 'server'>;

export type ClientConfigSerialized = Pick<
AstroConfig,
'base' | 'i18n' | 'trailingSlash' | 'compressHTML' | 'site' | 'legacy'
> & {
build: SerializedClientBuild;
};

export type ServerConfigSerialized = Pick<
AstroConfig,
'cacheDir' | 'outDir' | 'publicDir' | 'srcDir' | 'root'
> & {
build: SerializedServerBuild;
};
13 changes: 13 additions & 0 deletions packages/astro/test/fixtures/astro-manifest/astro.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { defineConfig } from "astro/config";

// https://astro.build/config
export default defineConfig({
site: "https://astro.build/",
experimental: {
serializeManifest: true,
},
i18n: {
locales: ["en", "fr"],
defaultLocale: "en",
}
});
8 changes: 8 additions & 0 deletions packages/astro/test/fixtures/astro-manifest/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "@test/astro-manifest",
"version": "0.0.0",
"private": true,
"dependencies": {
"astro": "workspace:*"
}
}
20 changes: 20 additions & 0 deletions packages/astro/test/fixtures/astro-manifest/src/pages/client.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
---

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Document</title>
</head>
<body>
<h1>Hello, World!</h1>
<p>Welcome to this Astro page.</p>
<script>
import { outDir } from "astro:manifest/server"

console.log(outDir)
</script>
</body>
</html>
19 changes: 19 additions & 0 deletions packages/astro/test/fixtures/astro-manifest/src/pages/index.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@

---
import { base, i18n, trailingSlash, compressHTML, site, legacy, build } from "astro:manifest/client";

const config = JSON.stringify({ base, i18n, build, trailingSlash, compressHTML, site, legacy });
---
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Document</title>
</head>
<body>
<h1>Hello, World!</h1>
<p>Welcome to this Astro page.</p>
<p id="config">{config}</p>
</body>
</html>
21 changes: 21 additions & 0 deletions packages/astro/test/fixtures/astro-manifest/src/pages/server.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
import { root, outDir, srcDir, build, cacheDir } from "astro:manifest/server";
---
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Document</title>
</head>
<body>
<h1>Hello, World!</h1>
<p>Welcome to this Astro page.</p>
<p id="out-dir">{outDir}</p>
<p id="src-dir">{srcDir}</p>
<p id="root">{root}</p>
<p id="cache-dir">{cacheDir}</p>
<p id="build-client">{build.client}</p>
<p id="build-server">{build.server}</p>
</body>
</html>
Loading
Loading