[astro add] Support adapters and third party packages (#3854)
* feat: support adapters and third part integrations by keywords
* refactor: add keywords to all official integrations
* docs: add adapter ex to astro add help
* nit: clarify astro add usage
* nit: highlight link
* fix: use process.exit(1) on error
* chore: changeset
* nit: bold integration name
* fix: log install instructions for adapters instead
* nit: change to logAdapterConfigInstructions
* Revert "fix: log install instructions for adapters instead"
This reverts commit 1a459f152b
.
* feat: add hardcoded adapter export map
* refactor: inline adapter config log
This commit is contained in:
parent
6258cd1c3a
commit
b012ee55b1
20 changed files with 222 additions and 38 deletions
23
.changeset/lucky-bottles-wait.md
Normal file
23
.changeset/lucky-bottles-wait.md
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
---
|
||||||
|
'astro': patch
|
||||||
|
'@astrojs/cloudflare': patch
|
||||||
|
'@astrojs/deno': patch
|
||||||
|
'@astrojs/image': patch
|
||||||
|
'@astrojs/lit': patch
|
||||||
|
'@astrojs/mdx': patch
|
||||||
|
'@astrojs/netlify': patch
|
||||||
|
'@astrojs/node': patch
|
||||||
|
'@astrojs/partytown': patch
|
||||||
|
'@astrojs/preact': patch
|
||||||
|
'@astrojs/prefetch': patch
|
||||||
|
'@astrojs/react': patch
|
||||||
|
'@astrojs/sitemap': patch
|
||||||
|
'@astrojs/solid-js': patch
|
||||||
|
'@astrojs/svelte': patch
|
||||||
|
'@astrojs/tailwind': patch
|
||||||
|
'@astrojs/turbolinks': patch
|
||||||
|
'@astrojs/vercel': patch
|
||||||
|
'@astrojs/vue': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
[astro add] Support adapters and third party packages
|
|
@ -3,7 +3,7 @@ import boxen from 'boxen';
|
||||||
import { diffWords } from 'diff';
|
import { diffWords } from 'diff';
|
||||||
import { execa } from 'execa';
|
import { execa } from 'execa';
|
||||||
import { existsSync, promises as fs } from 'fs';
|
import { existsSync, promises as fs } from 'fs';
|
||||||
import { bold, cyan, dim, green, magenta } from 'kleur/colors';
|
import { bold, cyan, dim, green, magenta, yellow } from 'kleur/colors';
|
||||||
import ora from 'ora';
|
import ora from 'ora';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import preferredPM from 'preferred-pm';
|
import preferredPM from 'preferred-pm';
|
||||||
|
@ -32,6 +32,7 @@ export interface IntegrationInfo {
|
||||||
id: string;
|
id: string;
|
||||||
packageName: string;
|
packageName: string;
|
||||||
dependencies: [name: string, version: string][];
|
dependencies: [name: string, version: string][];
|
||||||
|
type: 'integration' | 'adapter';
|
||||||
}
|
}
|
||||||
const ALIASES = new Map([
|
const ALIASES = new Map([
|
||||||
['solid', 'solid-js'],
|
['solid', 'solid-js'],
|
||||||
|
@ -47,11 +48,19 @@ module.exports = {
|
||||||
plugins: [],
|
plugins: [],
|
||||||
}\n`;
|
}\n`;
|
||||||
|
|
||||||
|
const OFFICIAL_ADAPTER_TO_IMPORT_MAP: Record<string, string> = {
|
||||||
|
'netlify': '@astrojs/netlify/functions',
|
||||||
|
'vercel': '@astrojs/vercel/serverless',
|
||||||
|
'cloudflare': '@astrojs/cloudflare',
|
||||||
|
'node': '@astrojs/node',
|
||||||
|
'deno': '@astrojs/deno',
|
||||||
|
}
|
||||||
|
|
||||||
export default async function add(names: string[], { cwd, flags, logging, telemetry }: AddOptions) {
|
export default async function add(names: string[], { cwd, flags, logging, telemetry }: AddOptions) {
|
||||||
if (flags.help || names.length === 0) {
|
if (flags.help || names.length === 0) {
|
||||||
printHelp({
|
printHelp({
|
||||||
commandName: 'astro add',
|
commandName: 'astro add',
|
||||||
usage: '[...integrations]',
|
usage: '[...integrations] [...adapters]',
|
||||||
tables: {
|
tables: {
|
||||||
Flags: [
|
Flags: [
|
||||||
['--yes', 'Accept all prompts.'],
|
['--yes', 'Accept all prompts.'],
|
||||||
|
@ -70,6 +79,11 @@ export default async function add(names: string[], { cwd, flags, logging, teleme
|
||||||
['partytown', 'astro add partytown'],
|
['partytown', 'astro add partytown'],
|
||||||
['sitemap', 'astro add sitemap'],
|
['sitemap', 'astro add sitemap'],
|
||||||
],
|
],
|
||||||
|
'Example: Add an Adapter': [
|
||||||
|
['netlify', 'astro add netlify'],
|
||||||
|
['vercel', 'astro add vercel'],
|
||||||
|
['deno', 'astro add deno'],
|
||||||
|
],
|
||||||
},
|
},
|
||||||
description: `Check out the full integration catalog: ${cyan(
|
description: `Check out the full integration catalog: ${cyan(
|
||||||
'https://astro.build/integrations'
|
'https://astro.build/integrations'
|
||||||
|
@ -120,7 +134,20 @@ export default async function add(names: string[], { cwd, flags, logging, teleme
|
||||||
debug('add', 'Astro config ensured `defineConfig`');
|
debug('add', 'Astro config ensured `defineConfig`');
|
||||||
|
|
||||||
for (const integration of integrations) {
|
for (const integration of integrations) {
|
||||||
await addIntegration(ast, integration);
|
if (isAdapter(integration)) {
|
||||||
|
const officialExportName = OFFICIAL_ADAPTER_TO_IMPORT_MAP[integration.id];
|
||||||
|
if (officialExportName) {
|
||||||
|
await setAdapter(ast, integration, officialExportName);
|
||||||
|
} else {
|
||||||
|
info(
|
||||||
|
logging,
|
||||||
|
null,
|
||||||
|
`\n ${magenta(`Check our deployment docs for ${bold(integration.packageName)} to update your "adapter" config.`)}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await addIntegration(ast, integration);
|
||||||
|
}
|
||||||
debug('add', `Astro config added integration ${integration.id}`);
|
debug('add', `Astro config added integration ${integration.id}`);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -133,7 +160,13 @@ export default async function add(names: string[], { cwd, flags, logging, teleme
|
||||||
|
|
||||||
if (ast) {
|
if (ast) {
|
||||||
try {
|
try {
|
||||||
configResult = await updateAstroConfig({ configURL, ast, flags, logging });
|
configResult = await updateAstroConfig({
|
||||||
|
configURL,
|
||||||
|
ast,
|
||||||
|
flags,
|
||||||
|
logging,
|
||||||
|
logAdapterInstructions: integrations.some(isAdapter),
|
||||||
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
debug('add', 'Error updating astro config', err);
|
debug('add', 'Error updating astro config', err);
|
||||||
throw createPrettyError(err as Error);
|
throw createPrettyError(err as Error);
|
||||||
|
@ -231,6 +264,10 @@ export default async function add(names: string[], { cwd, flags, logging, teleme
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isAdapter(integration: IntegrationInfo): integration is IntegrationInfo & { type: 'adapter' } {
|
||||||
|
return integration.type === 'adapter';
|
||||||
|
}
|
||||||
|
|
||||||
async function parseAstroConfig(configURL: URL): Promise<t.File> {
|
async function parseAstroConfig(configURL: URL): Promise<t.File> {
|
||||||
const source = await fs.readFile(fileURLToPath(configURL), { encoding: 'utf-8' });
|
const source = await fs.readFile(fileURLToPath(configURL), { encoding: 'utf-8' });
|
||||||
const result = parse(source);
|
const result = parse(source);
|
||||||
|
@ -314,6 +351,50 @@ async function addIntegration(ast: t.File, integration: IntegrationInfo) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function setAdapter(ast: t.File, adapter: IntegrationInfo, exportName: string) {
|
||||||
|
const adapterId = t.identifier(toIdent(adapter.id));
|
||||||
|
|
||||||
|
ensureImport(
|
||||||
|
ast,
|
||||||
|
t.importDeclaration(
|
||||||
|
[t.importDefaultSpecifier(adapterId)],
|
||||||
|
t.stringLiteral(exportName)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
visit(ast, {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||||||
|
ExportDefaultDeclaration(path) {
|
||||||
|
if (!t.isCallExpression(path.node.declaration)) return;
|
||||||
|
|
||||||
|
const configObject = path.node.declaration.arguments[0];
|
||||||
|
if (!t.isObjectExpression(configObject)) return;
|
||||||
|
|
||||||
|
let adapterProp = configObject.properties.find((prop) => {
|
||||||
|
if (prop.type !== 'ObjectProperty') return false;
|
||||||
|
if (prop.key.type === 'Identifier') {
|
||||||
|
if (prop.key.name === 'adapter') return true;
|
||||||
|
}
|
||||||
|
if (prop.key.type === 'StringLiteral') {
|
||||||
|
if (prop.key.value === 'adapter') return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}) as t.ObjectProperty | undefined;
|
||||||
|
|
||||||
|
const adapterCall = t.callExpression(adapterId, []);
|
||||||
|
|
||||||
|
if (!adapterProp) {
|
||||||
|
configObject.properties.push(
|
||||||
|
t.objectProperty(t.identifier('adapter'), adapterCall)
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
adapterProp.value = adapterCall;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const enum UpdateResult {
|
const enum UpdateResult {
|
||||||
none,
|
none,
|
||||||
updated,
|
updated,
|
||||||
|
@ -326,11 +407,13 @@ async function updateAstroConfig({
|
||||||
ast,
|
ast,
|
||||||
flags,
|
flags,
|
||||||
logging,
|
logging,
|
||||||
|
logAdapterInstructions,
|
||||||
}: {
|
}: {
|
||||||
configURL: URL;
|
configURL: URL;
|
||||||
ast: t.File;
|
ast: t.File;
|
||||||
flags: yargs.Arguments;
|
flags: yargs.Arguments;
|
||||||
logging: LogOptions;
|
logging: LogOptions;
|
||||||
|
logAdapterInstructions: boolean;
|
||||||
}): Promise<UpdateResult> {
|
}): Promise<UpdateResult> {
|
||||||
const input = await fs.readFile(fileURLToPath(configURL), { encoding: 'utf-8' });
|
const input = await fs.readFile(fileURLToPath(configURL), { encoding: 'utf-8' });
|
||||||
let output = await generate(ast);
|
let output = await generate(ast);
|
||||||
|
@ -378,6 +461,14 @@ async function updateAstroConfig({
|
||||||
`\n ${magenta('Astro will make the following changes to your config file:')}\n${message}`
|
`\n ${magenta('Astro will make the following changes to your config file:')}\n${message}`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (logAdapterInstructions) {
|
||||||
|
info(
|
||||||
|
logging,
|
||||||
|
null,
|
||||||
|
magenta(` For complete deployment options, visit\n ${bold('https://docs.astro.build/en/guides/deploy/')}\n`)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (await askToContinue({ flags })) {
|
if (await askToContinue({ flags })) {
|
||||||
await fs.writeFile(fileURLToPath(configURL), output, { encoding: 'utf-8' });
|
await fs.writeFile(fileURLToPath(configURL), output, { encoding: 'utf-8' });
|
||||||
debug('add', `Updated astro config`);
|
debug('add', `Updated astro config`);
|
||||||
|
@ -479,46 +570,98 @@ async function tryToInstallIntegrations({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function fetchPackageJson(scope: string | undefined, name: string, tag: string): Promise<object | Error> {
|
||||||
|
const packageName = `${scope ? `@${scope}/` : ''}${name}`;
|
||||||
|
const res = await fetch(`https://registry.npmjs.org/${packageName}/${tag}`)
|
||||||
|
if (res.status === 404) {
|
||||||
|
return new Error();
|
||||||
|
} else {
|
||||||
|
return await res.json();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function validateIntegrations(integrations: string[]): Promise<IntegrationInfo[]> {
|
export async function validateIntegrations(integrations: string[]): Promise<IntegrationInfo[]> {
|
||||||
const spinner = ora('Resolving integrations...').start();
|
const spinner = ora('Resolving packages...').start();
|
||||||
const integrationEntries = await Promise.all(
|
try {
|
||||||
integrations.map(async (integration): Promise<IntegrationInfo> => {
|
const integrationEntries = await Promise.all(
|
||||||
const parsed = parseIntegrationName(integration);
|
integrations.map(async (integration): Promise<IntegrationInfo> => {
|
||||||
if (!parsed) {
|
const parsed = parseIntegrationName(integration);
|
||||||
spinner.fail();
|
if (!parsed) {
|
||||||
throw new Error(`${integration} does not appear to be a valid package name!`);
|
throw new Error(`${bold(integration)} does not appear to be a valid package name!`);
|
||||||
}
|
|
||||||
|
|
||||||
let { scope = '', name, tag } = parsed;
|
|
||||||
// Allow third-party integrations starting with `astro-` namespace
|
|
||||||
if (!name.startsWith('astro-')) {
|
|
||||||
scope = `astrojs`;
|
|
||||||
}
|
|
||||||
const packageName = `${scope ? `@${scope}/` : ''}${name}`;
|
|
||||||
|
|
||||||
const result = await fetch(`https://registry.npmjs.org/${packageName}/${tag}`).then((res) => {
|
|
||||||
if (res.status === 404) {
|
|
||||||
spinner.fail();
|
|
||||||
throw new Error(`Unable to fetch ${packageName}. Does this package exist?`);
|
|
||||||
}
|
}
|
||||||
return res.json();
|
|
||||||
});
|
|
||||||
|
|
||||||
let dependencies: IntegrationInfo['dependencies'] = [
|
let { scope, name, tag } = parsed;
|
||||||
[result['name'], `^${result['version']}`],
|
let pkgJson = null;
|
||||||
];
|
let pkgType: 'first-party' | 'third-party' = 'first-party';
|
||||||
|
|
||||||
if (result['peerDependencies']) {
|
if (!scope) {
|
||||||
for (const peer in result['peerDependencies']) {
|
const firstPartyPkgCheck = await fetchPackageJson('astrojs', name, tag);
|
||||||
dependencies.push([peer, result['peerDependencies'][peer]]);
|
if (firstPartyPkgCheck instanceof Error) {
|
||||||
|
spinner.warn(yellow(`${bold(integration)} is not an official Astro package. Use at your own risk!`));
|
||||||
|
const response = await prompts({
|
||||||
|
type: 'confirm',
|
||||||
|
name: 'askToContinue',
|
||||||
|
message: 'Continue?',
|
||||||
|
initial: true,
|
||||||
|
});
|
||||||
|
if (!response.askToContinue) {
|
||||||
|
throw new Error(`No problem! Find our official integrations at ${cyan('https://astro.build/integrations')}`);
|
||||||
|
}
|
||||||
|
spinner.start('Resolving with third party packages...');
|
||||||
|
pkgType = 'third-party';
|
||||||
|
} else {
|
||||||
|
pkgJson = firstPartyPkgCheck as any;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pkgType === 'third-party') {
|
||||||
|
const thirdPartyPkgCheck = await fetchPackageJson(scope, name, tag);
|
||||||
|
if (thirdPartyPkgCheck instanceof Error) {
|
||||||
|
throw new Error(
|
||||||
|
`Unable to fetch ${bold(integration)}. Does the package exist?`,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
pkgJson = thirdPartyPkgCheck as any;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return { id: integration, packageName, dependencies };
|
const resolvedScope = pkgType === 'first-party' ? 'astrojs' : scope;
|
||||||
})
|
const packageName = `${resolvedScope ? `@${resolvedScope}/` : ''}${name}`;
|
||||||
);
|
|
||||||
spinner.succeed();
|
let dependencies: IntegrationInfo['dependencies'] = [
|
||||||
return integrationEntries;
|
[pkgJson['name'], `^${pkgJson['version']}`],
|
||||||
|
];
|
||||||
|
|
||||||
|
if (pkgJson['peerDependencies']) {
|
||||||
|
for (const peer in pkgJson['peerDependencies']) {
|
||||||
|
dependencies.push([peer, pkgJson['peerDependencies'][peer]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let integrationType: IntegrationInfo['type'];
|
||||||
|
const keywords = Array.isArray(pkgJson['keywords']) ? pkgJson['keywords'] : [];
|
||||||
|
if (keywords.includes('astro-integration')) {
|
||||||
|
integrationType = 'integration';
|
||||||
|
} else if (keywords.includes('astro-adapter')) {
|
||||||
|
integrationType = 'adapter';
|
||||||
|
} else {
|
||||||
|
throw new Error(
|
||||||
|
`${bold(packageName)} doesn't appear to be an integration or an adapter. Find our official integrations at ${cyan('https://astro.build/integrations')}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { id: integration, packageName, dependencies, type: integrationType };
|
||||||
|
})
|
||||||
|
);
|
||||||
|
spinner.succeed();
|
||||||
|
return integrationEntries;
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof Error) {
|
||||||
|
spinner.fail(e.message);
|
||||||
|
process.exit(1);
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseIntegrationName(spec: string) {
|
function parseIntegrationName(spec: string) {
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
"url": "https://github.com/withastro/astro.git",
|
"url": "https://github.com/withastro/astro.git",
|
||||||
"directory": "packages/integrations/cloudflare"
|
"directory": "packages/integrations/cloudflare"
|
||||||
},
|
},
|
||||||
|
"keywords": ["astro-adapter"],
|
||||||
"bugs": "https://github.com/withastro/astro/issues",
|
"bugs": "https://github.com/withastro/astro/issues",
|
||||||
"homepage": "https://astro.build",
|
"homepage": "https://astro.build",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
"url": "https://github.com/withastro/astro.git",
|
"url": "https://github.com/withastro/astro.git",
|
||||||
"directory": "packages/integrations/deno"
|
"directory": "packages/integrations/deno"
|
||||||
},
|
},
|
||||||
|
"keywords": ["astro-adapter"],
|
||||||
"bugs": "https://github.com/withastro/astro/issues",
|
"bugs": "https://github.com/withastro/astro/issues",
|
||||||
"homepage": "https://astro.build",
|
"homepage": "https://astro.build",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
"directory": "packages/integrations/image"
|
"directory": "packages/integrations/image"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
"astro-integration",
|
||||||
"astro-component",
|
"astro-component",
|
||||||
"withastro",
|
"withastro",
|
||||||
"image"
|
"image"
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
"directory": "packages/integrations/lit"
|
"directory": "packages/integrations/lit"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
"astro-integration",
|
||||||
"astro-component",
|
"astro-component",
|
||||||
"renderer",
|
"renderer",
|
||||||
"lit"
|
"lit"
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
"directory": "packages/integrations/mdx"
|
"directory": "packages/integrations/mdx"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
"astro-integration",
|
||||||
"astro-component",
|
"astro-component",
|
||||||
"renderer",
|
"renderer",
|
||||||
"mdx"
|
"mdx"
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
"url": "https://github.com/withastro/astro.git",
|
"url": "https://github.com/withastro/astro.git",
|
||||||
"directory": "packages/integrations/netlify"
|
"directory": "packages/integrations/netlify"
|
||||||
},
|
},
|
||||||
|
"keywords": ["astro-adapter"],
|
||||||
"bugs": "https://github.com/withastro/astro/issues",
|
"bugs": "https://github.com/withastro/astro/issues",
|
||||||
"homepage": "https://astro.build",
|
"homepage": "https://astro.build",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
"url": "https://github.com/withastro/astro.git",
|
"url": "https://github.com/withastro/astro.git",
|
||||||
"directory": "packages/integrations/node"
|
"directory": "packages/integrations/node"
|
||||||
},
|
},
|
||||||
|
"keywords": ["astro-adapter"],
|
||||||
"bugs": "https://github.com/withastro/astro/issues",
|
"bugs": "https://github.com/withastro/astro/issues",
|
||||||
"homepage": "https://astro.build",
|
"homepage": "https://astro.build",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
"directory": "packages/integrations/partytown"
|
"directory": "packages/integrations/partytown"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
"astro-integration",
|
||||||
"astro-component",
|
"astro-component",
|
||||||
"analytics",
|
"analytics",
|
||||||
"performance"
|
"performance"
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
"directory": "packages/integrations/preact"
|
"directory": "packages/integrations/preact"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
"astro-integration",
|
||||||
"astro-component",
|
"astro-component",
|
||||||
"renderer",
|
"renderer",
|
||||||
"preact"
|
"preact"
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
"url": "https://github.com/withastro/astro.git",
|
"url": "https://github.com/withastro/astro.git",
|
||||||
"directory": "packages/astro-prefetch"
|
"directory": "packages/astro-prefetch"
|
||||||
},
|
},
|
||||||
|
"keywords": ["astro-integration"],
|
||||||
"bugs": "https://github.com/withastro/astro/issues",
|
"bugs": "https://github.com/withastro/astro/issues",
|
||||||
"homepage": "https://astro.build",
|
"homepage": "https://astro.build",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
"directory": "packages/integrations/react"
|
"directory": "packages/integrations/react"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
"astro-integration",
|
||||||
"astro-component",
|
"astro-component",
|
||||||
"renderer",
|
"renderer",
|
||||||
"react"
|
"react"
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
"directory": "packages/integrations/sitemap"
|
"directory": "packages/integrations/sitemap"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
"astro-integration",
|
||||||
"astro-component",
|
"astro-component",
|
||||||
"seo",
|
"seo",
|
||||||
"sitemap"
|
"sitemap"
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
"directory": "packages/integrations/solid"
|
"directory": "packages/integrations/solid"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
"astro-integration",
|
||||||
"astro-component",
|
"astro-component",
|
||||||
"renderer",
|
"renderer",
|
||||||
"solid"
|
"solid"
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
"directory": "packages/integrations/svelte"
|
"directory": "packages/integrations/svelte"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
"astro-integration",
|
||||||
"astro-component",
|
"astro-component",
|
||||||
"renderer",
|
"renderer",
|
||||||
"svelte"
|
"svelte"
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
"directory": "packages/integrations/tailwind"
|
"directory": "packages/integrations/tailwind"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
"astro-integration",
|
||||||
"astro-component"
|
"astro-component"
|
||||||
],
|
],
|
||||||
"bugs": "https://github.com/withastro/astro/issues",
|
"bugs": "https://github.com/withastro/astro/issues",
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
"directory": "packages/integrations/turbolinks"
|
"directory": "packages/integrations/turbolinks"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
"astro-integration",
|
||||||
"astro-component",
|
"astro-component",
|
||||||
"performance"
|
"performance"
|
||||||
],
|
],
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
"url": "https://github.com/withastro/astro.git",
|
"url": "https://github.com/withastro/astro.git",
|
||||||
"directory": "packages/integrations/vercel"
|
"directory": "packages/integrations/vercel"
|
||||||
},
|
},
|
||||||
|
"keywords": ["astro-adapter"],
|
||||||
"bugs": "https://github.com/withastro/astro/issues",
|
"bugs": "https://github.com/withastro/astro/issues",
|
||||||
"homepage": "https://astro.build",
|
"homepage": "https://astro.build",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
"directory": "packages/integrations/vue"
|
"directory": "packages/integrations/vue"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
"astro-integration",
|
||||||
"astro-component",
|
"astro-component",
|
||||||
"renderer",
|
"renderer",
|
||||||
"vue"
|
"vue"
|
||||||
|
|
Loading…
Add table
Reference in a new issue