summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.changeset/fluffy-jars-live.md7
-rw-r--r--.changeset/slimy-queens-hang.md7
-rw-r--r--.changeset/unlucky-bobcats-sit.md5
-rw-r--r--packages/astro/src/core/build/plugins/plugin-manifest.ts4
-rw-r--r--packages/astro/src/core/logger/core.ts1
-rw-r--r--packages/astro/src/integrations/features-validation.ts148
-rw-r--r--packages/astro/src/integrations/hooks.ts16
-rw-r--r--packages/astro/src/types/public/integrations.ts45
-rw-r--r--packages/astro/test/units/integrations/api.test.js58
9 files changed, 127 insertions, 164 deletions
diff --git a/.changeset/fluffy-jars-live.md b/.changeset/fluffy-jars-live.md
new file mode 100644
index 000000000..59549a4a2
--- /dev/null
+++ b/.changeset/fluffy-jars-live.md
@@ -0,0 +1,7 @@
+---
+'astro': major
+---
+
+Removes the `assets` property on `supportedAstroFeatures` for adapters, as it did not reflect reality properly in many cases.
+
+Now, relating to assets, only a single `sharpImageService` property is available, determining if the adapter is compatible with the built-in sharp image service.
diff --git a/.changeset/slimy-queens-hang.md b/.changeset/slimy-queens-hang.md
new file mode 100644
index 000000000..936ed2731
--- /dev/null
+++ b/.changeset/slimy-queens-hang.md
@@ -0,0 +1,7 @@
+---
+'astro': minor
+---
+
+The value of the different properties on `supportedAstroFeatures` for adapters can now be objects, with a `support` and `message` properties. The content of the `message` property will be shown in the Astro CLI when the adapter is not compatible with the feature, allowing one to give a better informational message to the user.
+
+This is notably useful with the new `limited` value, to explain to the user why support is limited.
diff --git a/.changeset/unlucky-bobcats-sit.md b/.changeset/unlucky-bobcats-sit.md
new file mode 100644
index 000000000..e815c8acd
--- /dev/null
+++ b/.changeset/unlucky-bobcats-sit.md
@@ -0,0 +1,5 @@
+---
+'astro': minor
+---
+
+Adds a new `limited` value for the different properties of `supportedAstroFeatures` for adapters, which indicates that the adapter is compatible with the feature, but with some limitations. This is useful for adapters that support a feature, but not in all cases or with all options.
diff --git a/packages/astro/src/core/build/plugins/plugin-manifest.ts b/packages/astro/src/core/build/plugins/plugin-manifest.ts
index 79bd3b44d..df3c8c811 100644
--- a/packages/astro/src/core/build/plugins/plugin-manifest.ts
+++ b/packages/astro/src/core/build/plugins/plugin-manifest.ts
@@ -5,6 +5,7 @@ import type { Plugin as VitePlugin } from 'vite';
import { getAssetsPrefix } from '../../../assets/utils/getAssetsPrefix.js';
import { normalizeTheLocale } from '../../../i18n/index.js';
import { toFallbackType, toRoutingStrategy } from '../../../i18n/utils.js';
+import { unwrapSupportKind } from '../../../integrations/features-validation.js';
import { runHookBuildSsr } from '../../../integrations/hooks.js';
import { BEFORE_HYDRATION_SCRIPT_ID, PAGE_SCRIPT_ID } from '../../../vite-plugin-scripts/index.js';
import type {
@@ -273,6 +274,7 @@ function buildManifest(
serverIslandNameMap: Array.from(settings.serverIslandNameMap),
key: encodedKey,
envGetSecretEnabled:
- (settings.adapter?.supportedAstroFeatures.envGetSecret ?? 'unsupported') !== 'unsupported',
+ (unwrapSupportKind(settings.adapter?.supportedAstroFeatures.envGetSecret) ??
+ 'unsupported') !== 'unsupported',
};
}
diff --git a/packages/astro/src/core/logger/core.ts b/packages/astro/src/core/logger/core.ts
index 51ebd9325..05566b258 100644
--- a/packages/astro/src/core/logger/core.ts
+++ b/packages/astro/src/core/logger/core.ts
@@ -33,6 +33,7 @@ export type LoggerLabel =
| 'assets'
| 'env'
| 'update'
+ | 'adapter'
// SKIP_FORMAT: A special label that tells the logger not to apply any formatting.
// Useful for messages that are already formatted, like the server start message.
| 'SKIP_FORMAT';
diff --git a/packages/astro/src/integrations/features-validation.ts b/packages/astro/src/integrations/features-validation.ts
index 77db47e0a..9383c76b2 100644
--- a/packages/astro/src/integrations/features-validation.ts
+++ b/packages/astro/src/integrations/features-validation.ts
@@ -1,22 +1,18 @@
import type { Logger } from '../core/logger/core.js';
import type { AstroSettings } from '../types/astro.js';
-import type { AstroConfig } from '../types/public/config.js';
import type {
+ AdapterSupport,
AdapterSupportsKind,
AstroAdapterFeatureMap,
- AstroAdapterFeatures,
- AstroAssetsFeature,
} from '../types/public/integrations.js';
-const STABLE = 'stable';
-const DEPRECATED = 'deprecated';
-const UNSUPPORTED = 'unsupported';
-const EXPERIMENTAL = 'experimental';
-
-const UNSUPPORTED_ASSETS_FEATURE: AstroAssetsFeature = {
- supportKind: UNSUPPORTED,
- isSharpCompatible: false,
-};
+export const AdapterFeatureStability = {
+ STABLE: 'stable',
+ DEPRECATED: 'deprecated',
+ UNSUPPORTED: 'unsupported',
+ EXPERIMENTAL: 'experimental',
+ LIMITED: 'limited',
+} as const;
type ValidationResult = {
[Property in keyof AstroAdapterFeatureMap]: boolean;
@@ -33,16 +29,15 @@ export function validateSupportedFeatures(
adapterName: string,
featureMap: AstroAdapterFeatureMap,
settings: AstroSettings,
- adapterFeatures: AstroAdapterFeatures | undefined,
logger: Logger,
): ValidationResult {
const {
- assets = UNSUPPORTED_ASSETS_FEATURE,
- serverOutput = UNSUPPORTED,
- staticOutput = UNSUPPORTED,
- hybridOutput = UNSUPPORTED,
- i18nDomains = UNSUPPORTED,
- envGetSecret = UNSUPPORTED,
+ serverOutput = AdapterFeatureStability.UNSUPPORTED,
+ staticOutput = AdapterFeatureStability.UNSUPPORTED,
+ hybridOutput = AdapterFeatureStability.UNSUPPORTED,
+ i18nDomains = AdapterFeatureStability.UNSUPPORTED,
+ envGetSecret = AdapterFeatureStability.UNSUPPORTED,
+ sharpImageService = AdapterFeatureStability.UNSUPPORTED,
} = featureMap;
const validationResult: ValidationResult = {};
@@ -67,9 +62,8 @@ export function validateSupportedFeatures(
adapterName,
logger,
'serverOutput',
- () => settings.config?.output === 'server',
+ () => settings.config?.output === 'server' || settings.buildOutput === 'server',
);
- validationResult.assets = validateAssetsFeature(assets, adapterName, settings.config, logger);
if (settings.config.i18n?.domains) {
validationResult.i18nDomains = validateSupportKind(
@@ -91,71 +85,93 @@ export function validateSupportedFeatures(
() => Object.keys(settings.config?.env?.schema ?? {}).length !== 0,
);
+ validationResult.sharpImageService = validateSupportKind(
+ sharpImageService,
+ adapterName,
+ logger,
+ 'sharp',
+ () => settings.config?.image?.service?.entrypoint === 'astro/assets/services/sharp',
+ );
+
return validationResult;
}
+export function unwrapSupportKind(supportKind?: AdapterSupport): AdapterSupportsKind | undefined {
+ if (!supportKind) {
+ return undefined;
+ }
+
+ return typeof supportKind === 'object' ? supportKind.support : supportKind;
+}
+
+export function getSupportMessage(supportKind: AdapterSupport): string | undefined {
+ return typeof supportKind === 'object' ? supportKind.message : undefined;
+}
+
function validateSupportKind(
- supportKind: AdapterSupportsKind,
+ supportKind: AdapterSupport,
adapterName: string,
logger: Logger,
featureName: string,
hasCorrectConfig: () => boolean,
): boolean {
- if (supportKind === STABLE) {
- return true;
- } else if (supportKind === DEPRECATED) {
- featureIsDeprecated(adapterName, logger, featureName);
- } else if (supportKind === EXPERIMENTAL) {
- featureIsExperimental(adapterName, logger, featureName);
- }
+ const supportValue = unwrapSupportKind(supportKind);
+ const message = getSupportMessage(supportKind);
- if (hasCorrectConfig() && supportKind === UNSUPPORTED) {
- featureIsUnsupported(adapterName, logger, featureName);
+ if (!supportValue) {
return false;
- } else {
- return true;
}
-}
-function featureIsUnsupported(adapterName: string, logger: Logger, featureName: string) {
- logger.error(
- 'config',
- `The adapter ${adapterName} doesn't currently support the feature "${featureName}".`,
- );
-}
+ if (supportValue === AdapterFeatureStability.STABLE) {
+ return true;
+ } else if (hasCorrectConfig()) {
+ // If the user has the relevant configuration, but the adapter doesn't support it, warn the user
+ logFeatureSupport(adapterName, logger, featureName, supportValue, message);
+ }
-function featureIsExperimental(adapterName: string, logger: Logger, featureName: string) {
- logger.warn(
- 'config',
- `The adapter ${adapterName} provides experimental support for "${featureName}". You may experience issues or breaking changes until this feature is fully supported by the adapter.`,
- );
+ return false;
}
-function featureIsDeprecated(adapterName: string, logger: Logger, featureName: string) {
- logger.warn(
- 'config',
- `The adapter ${adapterName} has deprecated its support for "${featureName}", and future compatibility is not guaranteed. The adapter may completely remove support for this feature without warning.`,
- );
-}
-
-const SHARP_SERVICE = 'astro/assets/services/sharp';
-
-function validateAssetsFeature(
- assets: AstroAssetsFeature,
+function logFeatureSupport(
adapterName: string,
- config: AstroConfig,
logger: Logger,
-): boolean {
- const { supportKind = UNSUPPORTED, isSharpCompatible = false } = assets;
- if (config?.image?.service?.entrypoint === SHARP_SERVICE && !isSharpCompatible) {
- logger.warn(
- null,
- `The currently selected adapter \`${adapterName}\` is not compatible with the image service "Sharp".`,
- );
- return false;
+ featureName: string,
+ supportKind: AdapterSupport,
+ adapterMessage?: string,
+) {
+ switch (supportKind) {
+ case AdapterFeatureStability.STABLE:
+ break;
+ case AdapterFeatureStability.DEPRECATED:
+ logger.warn(
+ 'config',
+ `The adapter ${adapterName} has deprecated its support for "${featureName}", and future compatibility is not guaranteed. The adapter may completely remove support for this feature without warning.`,
+ );
+ break;
+ case AdapterFeatureStability.EXPERIMENTAL:
+ logger.warn(
+ 'config',
+ `The adapter ${adapterName} provides experimental support for "${featureName}". You may experience issues or breaking changes until this feature is fully supported by the adapter.`,
+ );
+ break;
+ case AdapterFeatureStability.LIMITED:
+ logger.warn(
+ 'config',
+ `The adapter ${adapterName} has limited support for "${featureName}". Certain features may not work as expected.`,
+ );
+ break;
+ case AdapterFeatureStability.UNSUPPORTED:
+ logger.error(
+ 'config',
+ `The adapter ${adapterName} does not currently support the feature "${featureName}". Your project may not build correctly.`,
+ );
+ break;
}
- return validateSupportKind(supportKind, adapterName, logger, 'assets', () => true);
+ // If the adapter specified a custom message, log it after the default message
+ if (adapterMessage) {
+ logger.warn('adapter', adapterMessage);
+ }
}
export function getAdapterStaticRecommendation(adapterName: string): string | undefined {
diff --git a/packages/astro/src/integrations/hooks.ts b/packages/astro/src/integrations/hooks.ts
index 18544ae80..5ac21c435 100644
--- a/packages/astro/src/integrations/hooks.ts
+++ b/packages/astro/src/integrations/hooks.ts
@@ -323,26 +323,12 @@ export async function runHookConfigDone({
`The adapter ${adapter.name} doesn't provide a feature map. It is required in Astro 4.0.`,
);
} else {
- const validationResult = validateSupportedFeatures(
+ validateSupportedFeatures(
adapter.name,
adapter.supportedAstroFeatures,
settings,
- // SAFETY: we checked before if it's not present, and we throw an error
- adapter.adapterFeatures,
logger,
);
- for (const [featureName, supported] of Object.entries(validationResult)) {
- // If `supported` / `validationResult[featureName]` only allows boolean,
- // in theory 'assets' false, doesn't mean that the feature is not supported, but rather that the chosen image service is unsupported
- // in this case we should not show an error, that the featrue is not supported
- // if we would refactor the validation to support more than boolean, we could still be able to differentiate between the two cases
- if (!supported && featureName !== 'assets') {
- logger.error(
- null,
- `The adapter ${adapter.name} doesn't support the feature ${featureName}. Your project won't be built. You should not use it.`,
- );
- }
- }
}
settings.adapter = adapter;
},
diff --git a/packages/astro/src/types/public/integrations.ts b/packages/astro/src/types/public/integrations.ts
index 1980c0ab1..49557c23a 100644
--- a/packages/astro/src/types/public/integrations.ts
+++ b/packages/astro/src/types/public/integrations.ts
@@ -3,6 +3,7 @@ import type { ViteDevServer, InlineConfig as ViteInlineConfig } from 'vite';
import type { SerializedSSRManifest } from '../../core/app/types.js';
import type { PageBuildData } from '../../core/build/types.js';
import type { AstroIntegrationLogger } from '../../core/logger/core.js';
+import type { AdapterFeatureStability } from '../../integrations/features-validation.js';
import type { getToolbarServerCommunicationHelpers } from '../../integrations/hooks.js';
import type { DeepPartial } from '../../type-utils.js';
import type { AstroConfig } from './config.js';
@@ -60,7 +61,15 @@ export interface AstroRenderer {
serverEntrypoint: string;
}
-export type AdapterSupportsKind = 'unsupported' | 'stable' | 'experimental' | 'deprecated';
+export type AdapterSupportsKind =
+ (typeof AdapterFeatureStability)[keyof typeof AdapterFeatureStability];
+
+export type AdapterSupportWithMessage = {
+ support: Exclude<AdapterSupportsKind, 'stable'>;
+ message: string;
+};
+
+export type AdapterSupport = AdapterSupportsKind | AdapterSupportWithMessage;
export interface AstroAdapterFeatures {
/**
@@ -92,45 +101,33 @@ export type AstroAdapterFeatureMap = {
/**
* The adapter is able serve static pages
*/
- staticOutput?: AdapterSupportsKind;
+ staticOutput?: AdapterSupport;
+
/**
* The adapter is able to serve pages that are static or rendered via server
*/
- hybridOutput?: AdapterSupportsKind;
+ hybridOutput?: AdapterSupport;
+
/**
* The adapter is able to serve SSR pages
*/
- serverOutput?: AdapterSupportsKind;
- /**
- * The adapter can emit static assets
- */
- assets?: AstroAssetsFeature;
+ serverOutput?: AdapterSupport;
/**
- * List of features that orbit around the i18n routing
+ * The adapter is able to support i18n domains
*/
- i18nDomains?: AdapterSupportsKind;
+ i18nDomains?: AdapterSupport;
/**
* The adapter is able to support `getSecret` exported from `astro:env/server`
*/
- envGetSecret?: AdapterSupportsKind;
-};
+ envGetSecret?: AdapterSupport;
-export interface AstroAssetsFeature {
- supportKind?: AdapterSupportsKind;
/**
- * Whether if this adapter deploys files in an environment that is compatible with the library `sharp`
+ * The adapter supports image transformation using the built-in Sharp image service
*/
- isSharpCompatible?: boolean;
-}
-
-export interface AstroInternationalizationFeature {
- /**
- * The adapter should be able to create the proper redirects
- */
- domains?: AdapterSupportsKind;
-}
+ sharpImageService?: AdapterSupport;
+};
/**
* IDs for different stages of JS script injection:
diff --git a/packages/astro/test/units/integrations/api.test.js b/packages/astro/test/units/integrations/api.test.js
index 4aef593be..0a0233215 100644
--- a/packages/astro/test/units/integrations/api.test.js
+++ b/packages/astro/test/units/integrations/api.test.js
@@ -153,7 +153,6 @@ describe('Astro feature map', function () {
buildOutput: 'server',
config: { output: 'static' },
},
- {},
defaultLogger,
);
assert.equal(result['hybridOutput'], false);
@@ -167,7 +166,6 @@ describe('Astro feature map', function () {
buildOutput: 'server',
config: { output: 'static' },
},
- {},
defaultLogger,
);
assert.equal(result['hybridOutput'], false);
@@ -181,7 +179,6 @@ describe('Astro feature map', function () {
{
config: { output: 'static' },
},
- {},
defaultLogger,
);
assert.equal(result['staticOutput'], true);
@@ -195,7 +192,6 @@ describe('Astro feature map', function () {
buildOutput: 'static',
config: { output: 'static' },
},
- {},
defaultLogger,
);
assert.equal(result['staticOutput'], false);
@@ -209,7 +205,6 @@ describe('Astro feature map', function () {
{
config: { output: 'static' },
},
- {},
defaultLogger,
);
assert.equal(result['hybridOutput'], true);
@@ -225,7 +220,6 @@ describe('Astro feature map', function () {
buildOutput: 'server',
config: { output: 'static' },
},
- {},
defaultLogger,
);
assert.equal(result['hybridOutput'], false);
@@ -239,7 +233,6 @@ describe('Astro feature map', function () {
{
config: { output: 'server' },
},
- {},
defaultLogger,
);
assert.equal(result['serverOutput'], true);
@@ -254,62 +247,11 @@ describe('Astro feature map', function () {
{
config: { output: 'server' },
},
- {},
defaultLogger,
);
assert.equal(result['serverOutput'], false);
});
});
-
- describe('assets', function () {
- it('should be supported when it is sharp compatible', () => {
- let result = validateSupportedFeatures(
- 'test',
- {
- assets: {
- supportKind: 'stable',
- isSharpCompatible: true,
- },
- },
- {
- config: {
- image: {
- service: {
- entrypoint: 'astro/assets/services/sharp',
- },
- },
- },
- },
- {},
- defaultLogger,
- );
- assert.equal(result['assets'], true);
- });
-
- it("should not be valid if the config is correct, but the it's unsupported", () => {
- let result = validateSupportedFeatures(
- 'test',
- {
- assets: {
- supportKind: 'unsupported',
- isNodeCompatible: false,
- },
- },
- {
- config: {
- image: {
- service: {
- entrypoint: 'astro/assets/services/sharp',
- },
- },
- },
- },
- {},
- defaultLogger,
- );
- assert.equal(result['assets'], false);
- });
- });
});
describe('normalizeInjectedTypeFilename', () => {