diff --git a/.changeset/old-actors-learn.md b/.changeset/old-actors-learn.md
new file mode 100644
index 000000000000..0691a7a5b890
--- /dev/null
+++ b/.changeset/old-actors-learn.md
@@ -0,0 +1,10 @@
+---
+'create-astro': minor
+---
+
+Reworks the experience of creating a new Astro project using the `create astro` CLI command.
+
+- Updates the list of templates to include Starlight and combines the "minimal" and "basics" templates into a new, refreshed "Basics" template to serve as the single, minimal Astro project starter.
+- Removes the TypeScript question. Astro is TypeScript-only, so this question was often misleading. The "Strict" preset is now the default, but it can still be changed manually in `tsconfig.json`.
+- `astro check` is no longer automatically added to the build script.
+- Added a new `--add` flag to install additional integrations after creating a project. For example, `pnpm create astro --add react` will create a new Astro project and install the React integration.
diff --git a/examples/basics/README.md b/examples/basics/README.md
index 1db3fb3991a8..ff19a3e7ece8 100644
--- a/examples/basics/README.md
+++ b/examples/basics/README.md
@@ -21,8 +21,6 @@ Inside of your Astro project, you'll see the following folders and files:
├── public/
│ └── favicon.svg
├── src/
-│ ├── components/
-│ │ └── Card.astro
│ ├── layouts/
│ │ └── Layout.astro
│ └── pages/
@@ -30,11 +28,7 @@ Inside of your Astro project, you'll see the following folders and files:
└── package.json
```
-Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name.
-
-There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components.
-
-Any static assets, like images, can be placed in the `public/` directory.
+To learn more about the folder structure of an Astro project, refer to [our guide on project structure](https://docs.astro.build/en/basics/project-structure/).
## 🧞 Commands
diff --git a/examples/basics/astro.config.mjs b/examples/basics/astro.config.mjs
index 882e6515a67e..e762ba5cf616 100644
--- a/examples/basics/astro.config.mjs
+++ b/examples/basics/astro.config.mjs
@@ -1,3 +1,4 @@
+// @ts-check
import { defineConfig } from 'astro/config';
// https://astro.build/config
diff --git a/examples/basics/src/components/Card.astro b/examples/basics/src/components/Card.astro
deleted file mode 100644
index bd6d5971ebf3..000000000000
--- a/examples/basics/src/components/Card.astro
+++ /dev/null
@@ -1,61 +0,0 @@
----
-interface Props {
- title: string;
- body: string;
- href: string;
-}
-
-const { href, title, body } = Astro.props;
----
-
-
-
-
- {title}
- →
-
-
- {body}
-
-
-
-
diff --git a/examples/basics/src/layouts/Layout.astro b/examples/basics/src/layouts/Layout.astro
index 181097125d82..a25b9e69d5e5 100644
--- a/examples/basics/src/layouts/Layout.astro
+++ b/examples/basics/src/layouts/Layout.astro
@@ -1,50 +1,13 @@
----
-interface Props {
- title: string;
-}
-
-const { title } = Astro.props;
----
-
-
- {title}
+ Astro Basics
-
diff --git a/examples/basics/src/pages/index.astro b/examples/basics/src/pages/index.astro
index fb6262872d0e..a2bf4ee37b63 100644
--- a/examples/basics/src/pages/index.astro
+++ b/examples/basics/src/pages/index.astro
@@ -1,123 +1,8 @@
---
+import { Welcome } from 'astro:components';
import Layout from '../layouts/Layout.astro';
-import Card from '../components/Card.astro';
---
-
-
-
-
-
-
-
-
-
-
-
- Welcome to Astro
-
- To get started, open the directory src/pages
in your project.
- Code Challenge: Tweak the "Welcome to Astro" message above.
-
-
-
+
+
-
-
diff --git a/examples/basics/tsconfig.json b/examples/basics/tsconfig.json
index f11a46c8e5fb..8bf91d3bb997 100644
--- a/examples/basics/tsconfig.json
+++ b/examples/basics/tsconfig.json
@@ -1,5 +1,5 @@
{
- "extends": "astro/tsconfigs/base",
+ "extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"]
}
diff --git a/examples/blog/astro.config.mjs b/examples/blog/astro.config.mjs
index 3b2f75c840d3..d45f3951e1b2 100644
--- a/examples/blog/astro.config.mjs
+++ b/examples/blog/astro.config.mjs
@@ -1,6 +1,6 @@
+// @ts-check
import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';
-
import sitemap from '@astrojs/sitemap';
// https://astro.build/config
diff --git a/examples/blog/tsconfig.json b/examples/blog/tsconfig.json
index 676d1945a177..0dc098dd7eaa 100644
--- a/examples/blog/tsconfig.json
+++ b/examples/blog/tsconfig.json
@@ -1,5 +1,5 @@
{
- "extends": "astro/tsconfigs/base",
+ "extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"],
"compilerOptions": {
diff --git a/examples/component/tsconfig.json b/examples/component/tsconfig.json
index e2bdd98c6fd7..f85ec795bf88 100644
--- a/examples/component/tsconfig.json
+++ b/examples/component/tsconfig.json
@@ -1,5 +1,5 @@
{
- "extends": "astro/tsconfigs/base",
+ "extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"],
"compilerOptions": {
diff --git a/examples/container-with-vitest/tsconfig.json b/examples/container-with-vitest/tsconfig.json
index f11a46c8e5fb..8bf91d3bb997 100644
--- a/examples/container-with-vitest/tsconfig.json
+++ b/examples/container-with-vitest/tsconfig.json
@@ -1,5 +1,5 @@
{
- "extends": "astro/tsconfigs/base",
+ "extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"]
}
diff --git a/examples/framework-alpine/astro.config.mjs b/examples/framework-alpine/astro.config.mjs
index 60bfc7d45d92..5fddf771766c 100644
--- a/examples/framework-alpine/astro.config.mjs
+++ b/examples/framework-alpine/astro.config.mjs
@@ -1,3 +1,4 @@
+// @ts-check
import { defineConfig } from 'astro/config';
import alpine from '@astrojs/alpinejs';
diff --git a/examples/framework-alpine/tsconfig.json b/examples/framework-alpine/tsconfig.json
index f11a46c8e5fb..8bf91d3bb997 100644
--- a/examples/framework-alpine/tsconfig.json
+++ b/examples/framework-alpine/tsconfig.json
@@ -1,5 +1,5 @@
{
- "extends": "astro/tsconfigs/base",
+ "extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"]
}
diff --git a/examples/framework-multiple/astro.config.mjs b/examples/framework-multiple/astro.config.mjs
index 36f75aec2610..7609d3fc6f5c 100644
--- a/examples/framework-multiple/astro.config.mjs
+++ b/examples/framework-multiple/astro.config.mjs
@@ -1,3 +1,4 @@
+// @ts-check
import { defineConfig } from 'astro/config';
import preact from '@astrojs/preact';
import react from '@astrojs/react';
diff --git a/examples/framework-multiple/tsconfig.json b/examples/framework-multiple/tsconfig.json
index 1d2def77194d..a19c58a62c30 100644
--- a/examples/framework-multiple/tsconfig.json
+++ b/examples/framework-multiple/tsconfig.json
@@ -1,5 +1,5 @@
{
- "extends": "astro/tsconfigs/base",
+ "extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"],
"compilerOptions": {
diff --git a/examples/framework-preact/astro.config.mjs b/examples/framework-preact/astro.config.mjs
index b1c8d1150ee7..1d726f9fe133 100644
--- a/examples/framework-preact/astro.config.mjs
+++ b/examples/framework-preact/astro.config.mjs
@@ -1,3 +1,4 @@
+// @ts-check
import { defineConfig } from 'astro/config';
import preact from '@astrojs/preact';
diff --git a/examples/framework-preact/tsconfig.json b/examples/framework-preact/tsconfig.json
index 50ad34429bdb..c8983c2ef0a2 100644
--- a/examples/framework-preact/tsconfig.json
+++ b/examples/framework-preact/tsconfig.json
@@ -1,5 +1,5 @@
{
- "extends": "astro/tsconfigs/base",
+ "extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"],
"compilerOptions": {
diff --git a/examples/framework-react/astro.config.mjs b/examples/framework-react/astro.config.mjs
index 4b5a68ec00b8..36ed34a5e0d0 100644
--- a/examples/framework-react/astro.config.mjs
+++ b/examples/framework-react/astro.config.mjs
@@ -1,3 +1,4 @@
+// @ts-check
import { defineConfig } from 'astro/config';
import react from '@astrojs/react';
diff --git a/examples/framework-react/tsconfig.json b/examples/framework-react/tsconfig.json
index 866156f0784c..92a18df9052f 100644
--- a/examples/framework-react/tsconfig.json
+++ b/examples/framework-react/tsconfig.json
@@ -1,5 +1,5 @@
{
- "extends": "astro/tsconfigs/base",
+ "extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"],
"compilerOptions": {
diff --git a/examples/framework-solid/astro.config.mjs b/examples/framework-solid/astro.config.mjs
index 623fb8ea5e31..8bdaa267967d 100644
--- a/examples/framework-solid/astro.config.mjs
+++ b/examples/framework-solid/astro.config.mjs
@@ -1,3 +1,4 @@
+// @ts-check
import { defineConfig } from 'astro/config';
import solid from '@astrojs/solid-js';
diff --git a/examples/framework-solid/tsconfig.json b/examples/framework-solid/tsconfig.json
index 7db18fbb3c12..76e1efdbaed8 100644
--- a/examples/framework-solid/tsconfig.json
+++ b/examples/framework-solid/tsconfig.json
@@ -1,5 +1,5 @@
{
- "extends": "astro/tsconfigs/base",
+ "extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"],
"compilerOptions": {
diff --git a/examples/framework-svelte/astro.config.mjs b/examples/framework-svelte/astro.config.mjs
index 194e4591765f..5eeedb56ec6e 100644
--- a/examples/framework-svelte/astro.config.mjs
+++ b/examples/framework-svelte/astro.config.mjs
@@ -1,3 +1,4 @@
+// @ts-check
import { defineConfig } from 'astro/config';
import svelte from '@astrojs/svelte';
diff --git a/examples/framework-svelte/tsconfig.json b/examples/framework-svelte/tsconfig.json
index f11a46c8e5fb..8bf91d3bb997 100644
--- a/examples/framework-svelte/tsconfig.json
+++ b/examples/framework-svelte/tsconfig.json
@@ -1,5 +1,5 @@
{
- "extends": "astro/tsconfigs/base",
+ "extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"]
}
diff --git a/examples/framework-vue/astro.config.mjs b/examples/framework-vue/astro.config.mjs
index f30130a95318..5afe92269a73 100644
--- a/examples/framework-vue/astro.config.mjs
+++ b/examples/framework-vue/astro.config.mjs
@@ -1,3 +1,4 @@
+// @ts-check
import { defineConfig } from 'astro/config';
import vue from '@astrojs/vue';
diff --git a/examples/framework-vue/tsconfig.json b/examples/framework-vue/tsconfig.json
index 1d2def77194d..a19c58a62c30 100644
--- a/examples/framework-vue/tsconfig.json
+++ b/examples/framework-vue/tsconfig.json
@@ -1,5 +1,5 @@
{
- "extends": "astro/tsconfigs/base",
+ "extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"],
"compilerOptions": {
diff --git a/examples/hackernews/astro.config.mjs b/examples/hackernews/astro.config.mjs
index 68ba7fac5876..bf6f1a022825 100644
--- a/examples/hackernews/astro.config.mjs
+++ b/examples/hackernews/astro.config.mjs
@@ -1,3 +1,4 @@
+// @ts-check
import { defineConfig } from 'astro/config';
import node from '@astrojs/node';
diff --git a/examples/hackernews/tsconfig.json b/examples/hackernews/tsconfig.json
index f11a46c8e5fb..8bf91d3bb997 100644
--- a/examples/hackernews/tsconfig.json
+++ b/examples/hackernews/tsconfig.json
@@ -1,5 +1,5 @@
{
- "extends": "astro/tsconfigs/base",
+ "extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"]
}
diff --git a/examples/integration/tsconfig.json b/examples/integration/tsconfig.json
index d78f81ec4e8e..bcbf8b50906a 100644
--- a/examples/integration/tsconfig.json
+++ b/examples/integration/tsconfig.json
@@ -1,3 +1,3 @@
{
- "extends": "astro/tsconfigs/base"
+ "extends": "astro/tsconfigs/strict"
}
diff --git a/examples/minimal/astro.config.mjs b/examples/minimal/astro.config.mjs
index 882e6515a67e..e762ba5cf616 100644
--- a/examples/minimal/astro.config.mjs
+++ b/examples/minimal/astro.config.mjs
@@ -1,3 +1,4 @@
+// @ts-check
import { defineConfig } from 'astro/config';
// https://astro.build/config
diff --git a/examples/minimal/tsconfig.json b/examples/minimal/tsconfig.json
index f11a46c8e5fb..8bf91d3bb997 100644
--- a/examples/minimal/tsconfig.json
+++ b/examples/minimal/tsconfig.json
@@ -1,5 +1,5 @@
{
- "extends": "astro/tsconfigs/base",
+ "extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"]
}
diff --git a/examples/portfolio/astro.config.mjs b/examples/portfolio/astro.config.mjs
index 882e6515a67e..e762ba5cf616 100644
--- a/examples/portfolio/astro.config.mjs
+++ b/examples/portfolio/astro.config.mjs
@@ -1,3 +1,4 @@
+// @ts-check
import { defineConfig } from 'astro/config';
// https://astro.build/config
diff --git a/examples/portfolio/tsconfig.json b/examples/portfolio/tsconfig.json
index f11a46c8e5fb..8bf91d3bb997 100644
--- a/examples/portfolio/tsconfig.json
+++ b/examples/portfolio/tsconfig.json
@@ -1,5 +1,5 @@
{
- "extends": "astro/tsconfigs/base",
+ "extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"]
}
diff --git a/examples/server-islands/tsconfig.json b/examples/server-islands/tsconfig.json
new file mode 100644
index 000000000000..8bf91d3bb997
--- /dev/null
+++ b/examples/server-islands/tsconfig.json
@@ -0,0 +1,5 @@
+{
+ "extends": "astro/tsconfigs/strict",
+ "include": [".astro/types.d.ts", "**/*"],
+ "exclude": ["dist"]
+}
diff --git a/examples/ssr/astro.config.mjs b/examples/ssr/astro.config.mjs
index b79949397d94..78d88cb1aa06 100644
--- a/examples/ssr/astro.config.mjs
+++ b/examples/ssr/astro.config.mjs
@@ -1,3 +1,4 @@
+// @ts-check
import { defineConfig } from 'astro/config';
import svelte from '@astrojs/svelte';
import node from '@astrojs/node';
diff --git a/examples/ssr/tsconfig.json b/examples/ssr/tsconfig.json
index f11a46c8e5fb..8bf91d3bb997 100644
--- a/examples/ssr/tsconfig.json
+++ b/examples/ssr/tsconfig.json
@@ -1,5 +1,5 @@
{
- "extends": "astro/tsconfigs/base",
+ "extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"]
}
diff --git a/examples/starlog/astro.config.mjs b/examples/starlog/astro.config.mjs
index b093ec0e02bc..759bb082c3fd 100644
--- a/examples/starlog/astro.config.mjs
+++ b/examples/starlog/astro.config.mjs
@@ -1,3 +1,4 @@
+// @ts-check
import { defineConfig } from 'astro/config';
// https://astro.build/config
diff --git a/examples/toolbar-app/tsconfig.json b/examples/toolbar-app/tsconfig.json
index b3e754ea04d9..281fb7f925fa 100644
--- a/examples/toolbar-app/tsconfig.json
+++ b/examples/toolbar-app/tsconfig.json
@@ -1,5 +1,5 @@
{
- "extends": "astro/tsconfigs/base",
+ "extends": "astro/tsconfigs/strict",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
diff --git a/examples/with-markdoc/astro.config.mjs b/examples/with-markdoc/astro.config.mjs
index 29d846359bb2..517f5a62e872 100644
--- a/examples/with-markdoc/astro.config.mjs
+++ b/examples/with-markdoc/astro.config.mjs
@@ -1,3 +1,4 @@
+// @ts-check
import { defineConfig } from 'astro/config';
import markdoc from '@astrojs/markdoc';
diff --git a/examples/with-markdoc/tsconfig.json b/examples/with-markdoc/tsconfig.json
index 676d1945a177..0dc098dd7eaa 100644
--- a/examples/with-markdoc/tsconfig.json
+++ b/examples/with-markdoc/tsconfig.json
@@ -1,5 +1,5 @@
{
- "extends": "astro/tsconfigs/base",
+ "extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"],
"compilerOptions": {
diff --git a/examples/with-mdx/astro.config.mjs b/examples/with-mdx/astro.config.mjs
index d797941ec2cb..93aeffbc5417 100644
--- a/examples/with-mdx/astro.config.mjs
+++ b/examples/with-mdx/astro.config.mjs
@@ -1,3 +1,4 @@
+// @ts-check
import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';
import preact from '@astrojs/preact';
diff --git a/examples/with-mdx/tsconfig.json b/examples/with-mdx/tsconfig.json
index f11a46c8e5fb..8bf91d3bb997 100644
--- a/examples/with-mdx/tsconfig.json
+++ b/examples/with-mdx/tsconfig.json
@@ -1,5 +1,5 @@
{
- "extends": "astro/tsconfigs/base",
+ "extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"]
}
diff --git a/examples/with-nanostores/astro.config.mjs b/examples/with-nanostores/astro.config.mjs
index 3e161041b59d..9f7dbd219cf5 100644
--- a/examples/with-nanostores/astro.config.mjs
+++ b/examples/with-nanostores/astro.config.mjs
@@ -1,3 +1,4 @@
+// @ts-check
import { defineConfig } from 'astro/config';
import preact from '@astrojs/preact';
diff --git a/examples/with-nanostores/tsconfig.json b/examples/with-nanostores/tsconfig.json
index 50ad34429bdb..c8983c2ef0a2 100644
--- a/examples/with-nanostores/tsconfig.json
+++ b/examples/with-nanostores/tsconfig.json
@@ -1,5 +1,5 @@
{
- "extends": "astro/tsconfigs/base",
+ "extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"],
"compilerOptions": {
diff --git a/examples/with-tailwindcss/astro.config.mjs b/examples/with-tailwindcss/astro.config.mjs
index 4ad396807723..7c7ad346f1ae 100644
--- a/examples/with-tailwindcss/astro.config.mjs
+++ b/examples/with-tailwindcss/astro.config.mjs
@@ -1,3 +1,4 @@
+// @ts-check
import { defineConfig } from 'astro/config';
import tailwind from '@astrojs/tailwind';
diff --git a/examples/with-tailwindcss/tsconfig.json b/examples/with-tailwindcss/tsconfig.json
index f11a46c8e5fb..8bf91d3bb997 100644
--- a/examples/with-tailwindcss/tsconfig.json
+++ b/examples/with-tailwindcss/tsconfig.json
@@ -1,5 +1,5 @@
{
- "extends": "astro/tsconfigs/base",
+ "extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"]
}
diff --git a/examples/with-vitest/astro.config.ts b/examples/with-vitest/astro.config.ts
index 882e6515a67e..e762ba5cf616 100644
--- a/examples/with-vitest/astro.config.ts
+++ b/examples/with-vitest/astro.config.ts
@@ -1,3 +1,4 @@
+// @ts-check
import { defineConfig } from 'astro/config';
// https://astro.build/config
diff --git a/examples/with-vitest/tsconfig.json b/examples/with-vitest/tsconfig.json
index f11a46c8e5fb..8bf91d3bb997 100644
--- a/examples/with-vitest/tsconfig.json
+++ b/examples/with-vitest/tsconfig.json
@@ -1,5 +1,5 @@
{
- "extends": "astro/tsconfigs/base",
+ "extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"]
}
diff --git a/packages/astro/components/Welcome.astro b/packages/astro/components/Welcome.astro
new file mode 100644
index 000000000000..2f91eb5ddd27
--- /dev/null
+++ b/packages/astro/components/Welcome.astro
@@ -0,0 +1,172 @@
+---
+interface Props {
+ title?: string;
+}
+
+const cards = [
+ {
+ href: 'https://docs.astro.build/',
+ title: 'Documentation',
+ body: 'Learn how Astro works and explore the official API docs.',
+ },
+ {
+ href: 'https://astro.build/integrations/',
+ title: 'Integrations',
+ body: 'Supercharge your project with new frameworks and libraries.',
+ },
+ {
+ href: 'https://astro.build/themes/',
+ title: 'Themes',
+ body: 'Explore a galaxy of community-built starter themes.',
+ },
+ {
+ href: 'https://astro.build/chat/',
+ title: 'Community',
+ body: 'Come say hi to our amazing Discord community. ❤️',
+ },
+];
+
+const { title = 'Welcome to Astro' } = Astro.props;
+---
+
+
+
+
+
+
+
+
+
+
+
+ {title}
+
+ To get started, open the directory src/pages
in your project.
+ Code Challenge: Tweak the "Welcome to Astro" message above.
+
+
+
+
+
diff --git a/packages/astro/components/index.ts b/packages/astro/components/index.ts
index e5ac0251d0f1..fb553b489f3c 100644
--- a/packages/astro/components/index.ts
+++ b/packages/astro/components/index.ts
@@ -1,6 +1,8 @@
// The `ts-ignore` comments here are necessary because we're importing this file inside the `astro:components`
-// virtual module's types, which means that `tsc` will try to resolve these imports. Don't mind the editor errors.
+// virtual module's types, which means that `tsc` will try to resolve these imports.
// @ts-ignore
-export { default as Code } from './Code.astro';
+export { default as Code } from "./Code.astro";
// @ts-ignore
-export { default as Debug } from './Debug.astro';
+export { default as Debug } from "./Debug.astro";
+// @ts-ignore
+export { default as Welcome } from "./Welcome.astro";
diff --git a/packages/astro/test/fixtures/legacy-data-collections/astro.config.mjs b/packages/astro/test/fixtures/legacy-data-collections/astro.config.mjs
index c342649f77fb..3f4722ff1bb4 100644
--- a/packages/astro/test/fixtures/legacy-data-collections/astro.config.mjs
+++ b/packages/astro/test/fixtures/legacy-data-collections/astro.config.mjs
@@ -1,3 +1,4 @@
+// @ts-check
import { defineConfig } from 'astro/config';
// https://astro.build/config
diff --git a/packages/create-astro/README.md b/packages/create-astro/README.md
index bfdfb13e3967..260922b0acd4 100644
--- a/packages/create-astro/README.md
+++ b/packages/create-astro/README.md
@@ -45,19 +45,19 @@ npm create astro@latest my-astro-project -- --template cassidoo/shopify-react-as
May be provided in place of prompts
-| Name | Description |
-| :--------------------------- | :----------------------------------------------------- |
-| `--help` (`-h`) | Display available flags. |
-| `--template ` | Specify your template. |
-| `--install` / `--no-install` | Install dependencies (or not). |
-| `--git` / `--no-git` | Initialize git repo (or not). |
-| `--yes` (`-y`) | Skip all prompts by accepting defaults. |
-| `--no` (`-n`) | Skip all prompts by declining defaults. |
-| `--dry-run` | Walk through steps without executing. |
-| `--skip-houston` | Skip Houston animation. |
-| `--ref` | Specify an Astro branch (default: latest). |
-| `--fancy` | Enable full Unicode support for Windows. |
-| `--typescript ` | TypeScript option: `strict` / `strictest` / `relaxed`. |
+| Name | Description |
+| :--------------------------- | :----------------------------------------- |
+| `--help` (`-h`) | Display available flags. |
+| `--template ` | Specify your template. |
+| `--install` / `--no-install` | Install dependencies (or not). |
+| `--add ` | Add integrations. |
+| `--git` / `--no-git` | Initialize git repo (or not). |
+| `--yes` (`-y`) | Skip all prompts by accepting defaults. |
+| `--no` (`-n`) | Skip all prompts by declining defaults. |
+| `--dry-run` | Walk through steps without executing. |
+| `--skip-houston` | Skip Houston animation. |
+| `--ref` | Specify an Astro branch (default: latest). |
+| `--fancy` | Enable full Unicode support for Windows. |
[examples]: https://github.com/withastro/astro/tree/main/examples
[typescript]: https://github.com/withastro/astro/tree/main/packages/astro/tsconfigs
diff --git a/packages/create-astro/src/actions/context.ts b/packages/create-astro/src/actions/context.ts
index 83a13eda7c94..59f85f88a10e 100644
--- a/packages/create-astro/src/actions/context.ts
+++ b/packages/create-astro/src/actions/context.ts
@@ -15,6 +15,7 @@ export interface Context {
version: Promise;
skipHouston: boolean;
fancy?: boolean;
+ add?: string[];
dryRun?: boolean;
yes?: boolean;
projectName?: string;
@@ -43,11 +44,11 @@ export async function getContext(argv: string[]): Promise {
'--no-install': Boolean,
'--git': Boolean,
'--no-git': Boolean,
- '--typescript': String,
'--skip-houston': Boolean,
'--dry-run': Boolean,
'--help': Boolean,
'--fancy': Boolean,
+ '--add': [String],
'-y': '--yes',
'-n': '--no',
@@ -67,11 +68,11 @@ export async function getContext(argv: string[]): Promise {
'--no-install': noInstall,
'--git': git,
'--no-git': noGit,
- '--typescript': typescript,
'--fancy': fancy,
'--skip-houston': skipHouston,
'--dry-run': dryRun,
'--ref': ref,
+ '--add': add,
} = flags;
let projectName = cwd;
@@ -79,12 +80,11 @@ export async function getContext(argv: string[]): Promise {
yes = false;
if (install == undefined) install = false;
if (git == undefined) git = false;
- if (typescript == undefined) typescript = 'strict';
}
skipHouston =
((os.platform() === 'win32' && !fancy) || skipHouston) ??
- [yes, no, install, git, typescript].some((v) => v !== undefined);
+ [yes, no, install, git].some((v) => v !== undefined);
const { messages, hats, ties } = getSeasonalData({ fancy });
@@ -96,6 +96,7 @@ export async function getContext(argv: string[]): Promise {
version: getVersion(packageManager, 'astro', process.env.ASTRO_VERSION),
skipHouston,
fancy,
+ add,
dryRun,
projectName,
template,
@@ -106,7 +107,6 @@ export async function getContext(argv: string[]): Promise {
yes,
install: install ?? (noInstall ? false : undefined),
git: git ?? (noGit ? false : undefined),
- typescript,
cwd,
exit(code) {
process.exit(code);
diff --git a/packages/create-astro/src/actions/dependencies.ts b/packages/create-astro/src/actions/dependencies.ts
index 6a9b6fccb556..72dc9f353688 100644
--- a/packages/create-astro/src/actions/dependencies.ts
+++ b/packages/create-astro/src/actions/dependencies.ts
@@ -6,7 +6,10 @@ import { shell } from '../shell.js';
import type { Context } from './context.js';
export async function dependencies(
- ctx: Pick,
+ ctx: Pick<
+ Context,
+ 'install' | 'yes' | 'prompt' | 'packageManager' | 'cwd' | 'dryRun' | 'tasks' | 'add'
+ >,
) {
let deps = ctx.install ?? ctx.yes;
if (deps === undefined) {
@@ -21,8 +24,10 @@ export async function dependencies(
ctx.install = deps;
}
+ ctx.add = ctx.add?.reduce((acc, item) => acc.concat(item.split(',')), []);
+
if (ctx.dryRun) {
- await info('--dry-run', `Skipping dependency installation`);
+ await info('--dry-run', `Skipping dependency installation${ ctx.add ? ` and adding ${ctx.add.join(', ')}` : '' }`);
} else if (deps) {
ctx.tasks.push({
pending: 'Dependencies',
@@ -39,6 +44,27 @@ export async function dependencies(
},
while: () => install({ packageManager: ctx.packageManager, cwd: ctx.cwd }),
});
+
+ let add = ctx.add;
+
+ if (add) {
+ ctx.tasks.push({
+ pending: 'Integrations',
+ start: `Adding integrations with astro add`,
+ end: 'Integrations added',
+ onError: (e) => {
+ error('error', e);
+ error(
+ 'error',
+ `Failed to add integrations, please run ${color.bold(
+ `astro add ${add.join(' ')}`,
+ )} to install them manually after setup.`,
+ );
+ },
+ while: () =>
+ astroAdd({ integrations: add, packageManager: ctx.packageManager, cwd: ctx.cwd }),
+ });
+ }
} else {
await info(
ctx.yes === false ? 'deps [skip]' : 'No problem!',
@@ -47,6 +73,19 @@ export async function dependencies(
}
}
+async function astroAdd({
+ integrations,
+ packageManager,
+ cwd,
+}: { integrations: string[]; packageManager: string; cwd: string }) {
+ if (packageManager === 'yarn') await ensureYarnLock({ cwd });
+ return shell(
+ packageManager === 'npm' ? 'npx' : `${packageManager} dlx`,
+ ['astro add', integrations.join(' '), '-y'],
+ { cwd, timeout: 90_000, stdio: 'ignore' },
+ );
+}
+
async function install({ packageManager, cwd }: { packageManager: string; cwd: string }) {
if (packageManager === 'yarn') await ensureYarnLock({ cwd });
return shell(packageManager, ['install'], { cwd, timeout: 90_000, stdio: 'ignore' });
diff --git a/packages/create-astro/src/actions/help.ts b/packages/create-astro/src/actions/help.ts
index 097dfa7010a8..1d5c7f6098c0 100644
--- a/packages/create-astro/src/actions/help.ts
+++ b/packages/create-astro/src/actions/help.ts
@@ -10,6 +10,7 @@ export function help() {
['--help (-h)', 'See all available flags.'],
['--template ', 'Specify your template.'],
['--install / --no-install', 'Install dependencies (or not).'],
+ ['--add ', 'Add integrations.'],
['--git / --no-git', 'Initialize git repo (or not).'],
['--yes (-y)', 'Skip all prompts by accepting defaults.'],
['--no (-n)', 'Skip all prompts by declining defaults.'],
@@ -17,7 +18,6 @@ export function help() {
['--skip-houston', 'Skip Houston animation.'],
['--ref', 'Choose astro branch (default: latest).'],
['--fancy', 'Enable full Unicode support for Windows.'],
- ['--typescript ', 'TypeScript option: strict | strictest | relaxed.'],
],
},
});
diff --git a/packages/create-astro/src/actions/template.ts b/packages/create-astro/src/actions/template.ts
index a5d217e0ea3f..512e1f921cab 100644
--- a/packages/create-astro/src/actions/template.ts
+++ b/packages/create-astro/src/actions/template.ts
@@ -21,9 +21,9 @@ export async function template(
message: 'How would you like to start your new project?',
initial: 'basics',
choices: [
- { value: 'basics', label: 'Include sample files', hint: '(recommended)' },
+ { value: 'basics', label: 'A basic, minimal starter', hint: '(recommended)' },
{ value: 'blog', label: 'Use blog template' },
- { value: 'minimal', label: 'Empty' },
+ { value: 'starlight', label: 'Use docs (Starlight) template' },
],
});
ctx.template = tmpl;
diff --git a/packages/create-astro/src/actions/typescript.ts b/packages/create-astro/src/actions/typescript.ts
deleted file mode 100644
index 6fb6c7104af5..000000000000
--- a/packages/create-astro/src/actions/typescript.ts
+++ /dev/null
@@ -1,166 +0,0 @@
-import { readFile, rm, writeFile } from 'node:fs/promises';
-import path from 'node:path';
-import { color } from '@astrojs/cli-kit';
-import stripJsonComments from 'strip-json-comments';
-import { error, getVersion, info, title, typescriptByDefault } from '../messages.js';
-import type { Context } from './context.js';
-
-type PickedTypeScriptContext = Pick<
- Context,
- | 'typescript'
- | 'yes'
- | 'prompt'
- | 'dryRun'
- | 'cwd'
- | 'exit'
- | 'packageManager'
- | 'install'
- | 'tasks'
->;
-
-export async function typescript(ctx: PickedTypeScriptContext) {
- let ts = ctx.typescript ?? (typeof ctx.yes !== 'undefined' ? 'strict' : undefined);
- if (ts === undefined) {
- const { useTs } = await ctx.prompt({
- name: 'useTs',
- type: 'confirm',
- label: title('ts'),
- message: `Do you plan to write TypeScript?`,
- initial: true,
- });
- if (!useTs) {
- await typescriptByDefault();
- return;
- }
-
- ({ ts } = await ctx.prompt({
- name: 'ts',
- type: 'select',
- label: title('use'),
- message: `How strict should TypeScript be?`,
- initial: 'strict',
- choices: [
- { value: 'strict', label: 'Strict', hint: `(recommended)` },
- { value: 'strictest', label: 'Strictest' },
- { value: 'base', label: 'Relaxed' },
- ],
- }));
- } else {
- if (!['strict', 'strictest', 'relaxed', 'default', 'base'].includes(ts)) {
- if (!ctx.dryRun) {
- await rm(ctx.cwd, { recursive: true, force: true });
- }
- error(
- 'Error',
- `Unknown TypeScript option ${color.reset(ts)}${color.dim(
- '! Expected strict | strictest | relaxed',
- )}`,
- );
- ctx.exit(1);
- }
- await info('ts', `Using ${color.reset(ts)}${color.dim(' TypeScript configuration')}`);
- }
-
- if (ctx.dryRun) {
- await info('--dry-run', `Skipping TypeScript setup`);
- } else if (ts && ts !== 'unsure') {
- if (ts === 'relaxed' || ts === 'default') {
- ts = 'base';
- }
- ctx.tasks.push({
- pending: 'TypeScript',
- start: 'TypeScript customizing...',
- end: 'TypeScript customized',
- while: () =>
- setupTypeScript(ts!, ctx).catch((e) => {
- error('error', e);
- process.exit(1);
- }),
- });
- } else {
- }
-}
-
-const FILES_TO_UPDATE = {
- 'package.json': async (
- file: string,
- options: { value: string; ctx: PickedTypeScriptContext },
- ) => {
- try {
- // inject additional command to build script
- const data = await readFile(file, { encoding: 'utf-8' });
- const indent = /(^\s+)/m.exec(data)?.[1] ?? '\t';
- const parsedPackageJson = JSON.parse(data);
-
- const buildScript = parsedPackageJson.scripts?.build;
-
- // in case of any other template already have astro checks defined, we don't want to override it
- if (typeof buildScript === 'string' && !buildScript.includes('astro check')) {
- // Mutate the existing object to avoid changing user-defined script order
- parsedPackageJson.scripts.build = `astro check && ${buildScript}`;
- }
-
- const [astroCheckVersion, typescriptVersion] = await Promise.all([
- getVersion(options.ctx.packageManager, '@astrojs/check', process.env.ASTRO_CHECK_VERSION),
- getVersion(options.ctx.packageManager, 'typescript', process.env.TYPESCRIPT_VERSION),
- ]);
- parsedPackageJson.dependencies ??= {};
- parsedPackageJson.dependencies['@astrojs/check'] = `^${astroCheckVersion}`;
- parsedPackageJson.dependencies.typescript = `^${typescriptVersion}`;
-
- await writeFile(file, JSON.stringify(parsedPackageJson, null, indent) + '\n', 'utf-8');
- } catch (err) {
- // if there's no package.json (which is very unlikely), then do nothing
- if (err && (err as any).code === 'ENOENT') return;
- if (err instanceof Error) throw new Error(err.message);
- }
- },
- 'tsconfig.json': async (file: string, options: { value: string }) => {
- try {
- const data = await readFile(file, { encoding: 'utf-8' });
- const templateTSConfig = JSON.parse(stripJsonComments(data));
- if (templateTSConfig && typeof templateTSConfig === 'object') {
- const result = Object.assign(templateTSConfig, {
- extends: `astro/tsconfigs/${options.value}`,
- });
-
- await writeFile(file, JSON.stringify(result, null, 2) + '\n');
- } else {
- throw new Error(
- "There was an error applying the requested TypeScript settings. This could be because the template's tsconfig.json is malformed",
- );
- }
- } catch (err) {
- if (err && (err as any).code === 'ENOENT') {
- // If the template doesn't have a tsconfig.json, let's add one instead
- await writeFile(
- file,
- JSON.stringify({ extends: `astro/tsconfigs/${options.value}` }, null, 2) + '\n',
- );
- }
- }
- },
- 'astro.config.mjs': async (file: string, options: { value: string }) => {
- if (!(options.value === 'strict' || options.value === 'strictest')) {
- return;
- }
-
- try {
- let data = await readFile(file, { encoding: 'utf-8' });
- data = `// @ts-check\n${data}`;
- await writeFile(file, data, { encoding: 'utf-8' });
- } catch (err) {
- // if there's no astro.config.mjs (which is very unlikely), then do nothing
- if (err && (err as any).code === 'ENOENT') return;
- if (err instanceof Error) throw new Error(err.message);
- }
- },
-};
-
-export async function setupTypeScript(value: string, ctx: PickedTypeScriptContext) {
- await Promise.all(
- Object.entries(FILES_TO_UPDATE).map(async ([file, update]) =>
- update(path.resolve(path.join(ctx.cwd, file)), { value, ctx }),
- ),
- );
-}
diff --git a/packages/create-astro/src/index.ts b/packages/create-astro/src/index.ts
index fdd0aa32c633..60816f75d510 100644
--- a/packages/create-astro/src/index.ts
+++ b/packages/create-astro/src/index.ts
@@ -8,7 +8,6 @@ import { intro } from './actions/intro.js';
import { next } from './actions/next-steps.js';
import { projectName } from './actions/project-name.js';
import { template } from './actions/template.js';
-import { setupTypeScript, typescript } from './actions/typescript.js';
import { verify } from './actions/verify.js';
import { setStdout } from './messages.js';
@@ -36,7 +35,6 @@ export async function main() {
intro,
projectName,
template,
- typescript,
dependencies,
// Steps which write to files need to go above git
@@ -61,16 +59,4 @@ export async function main() {
process.exit(0);
}
-export {
- dependencies,
- getContext,
- git,
- intro,
- next,
- projectName,
- setStdout,
- setupTypeScript,
- template,
- typescript,
- verify,
-};
+export { dependencies, getContext, git, intro, next, projectName, setStdout, template, verify };
diff --git a/packages/create-astro/test/context.test.js b/packages/create-astro/test/context.test.js
index 48d2d4297643..b4e67a8c69bb 100644
--- a/packages/create-astro/test/context.test.js
+++ b/packages/create-astro/test/context.test.js
@@ -51,6 +51,11 @@ describe('context', () => {
assert.deepEqual(ctx.install, true);
});
+ it('add', async () => {
+ const ctx = await getContext(['--add', 'node']);
+ assert.deepEqual(ctx.add, ['node']);
+ });
+
it('no install', async () => {
const ctx = await getContext(['--no-install']);
assert.deepEqual(ctx.install, false);
@@ -65,9 +70,4 @@ describe('context', () => {
const ctx = await getContext(['--no-git']);
assert.deepEqual(ctx.git, false);
});
-
- it('typescript', async () => {
- const ctx = await getContext(['--typescript', 'strict']);
- assert.deepEqual(ctx.typescript, 'strict');
- });
});
diff --git a/packages/create-astro/test/integrations.test.js b/packages/create-astro/test/integrations.test.js
new file mode 100644
index 000000000000..8e27a3cfa963
--- /dev/null
+++ b/packages/create-astro/test/integrations.test.js
@@ -0,0 +1,60 @@
+import assert from 'node:assert/strict';
+import { describe, it } from 'node:test';
+import { dependencies } from '../dist/index.js';
+import { setup } from './utils.js';
+describe('integrations', () => {
+ const fixture = setup();
+
+ it('--add node', async () => {
+ const context = {
+ cwd: '',
+ yes: true,
+ packageManager: 'npm',
+ dryRun: true,
+ add: ['node'],
+ };
+
+ await dependencies(context);
+
+ assert.ok(fixture.hasMessage('--dry-run Skipping dependency installation and adding node'));
+ });
+
+ it('--add node --add react', async () => {
+ const context = {
+ cwd: '',
+ yes: true,
+ packageManager: 'npm',
+ dryRun: true,
+ add: ['node', 'react'],
+ };
+
+ await dependencies(context);
+
+ assert.ok(fixture.hasMessage('--dry-run Skipping dependency installation and adding node, react'));
+ });
+
+ it('--add node,react', async () => {
+ const context = {
+ cwd: '',
+ yes: true,
+ packageManager: 'npm',
+ dryRun: true,
+ add: ['node,react']
+ };
+
+ await dependencies(context);
+
+ assert.ok(fixture.hasMessage('--dry-run Skipping dependency installation and adding node, react'));
+ });
+
+ it('-y', async () => {
+ const context = {
+ cwd: '',
+ yes: true,
+ packageManager: 'npm',
+ dryRun: true,
+ };
+ await dependencies(context);
+ assert.ok(fixture.hasMessage('--dry-run Skipping dependency installation'));
+ });
+});
diff --git a/packages/create-astro/test/typescript.test.js b/packages/create-astro/test/typescript.test.js
deleted file mode 100644
index 0cd6a858cc58..000000000000
--- a/packages/create-astro/test/typescript.test.js
+++ /dev/null
@@ -1,155 +0,0 @@
-import assert from 'node:assert/strict';
-import fs from 'node:fs';
-import { after, beforeEach, describe, it } from 'node:test';
-import { fileURLToPath } from 'node:url';
-
-import { setupTypeScript, typescript } from '../dist/index.js';
-import { resetFixtures, setup } from './utils.js';
-
-describe('typescript', async () => {
- const fixture = setup();
-
- it('none', async () => {
- const context = { cwd: '', dryRun: true, prompt: () => ({ ts: 'strict', useTs: true }) };
- await typescript(context);
-
- assert.ok(fixture.hasMessage('Skipping TypeScript setup'));
- });
-
- it('use false', async () => {
- const context = { cwd: '', dryRun: true, prompt: () => ({ ts: 'strict', useTs: false }) };
- await typescript(context);
-
- assert.ok(fixture.hasMessage('No worries'));
- });
-
- it('strict', async () => {
- const context = {
- typescript: 'strict',
- cwd: '',
- dryRun: true,
- prompt: () => ({ ts: 'strict' }),
- };
- await typescript(context);
- assert.ok(fixture.hasMessage('Using strict TypeScript configuration'));
- assert.ok(fixture.hasMessage('Skipping TypeScript setup'));
- });
-
- it('default', async () => {
- const context = {
- typescript: 'default',
- cwd: '',
- dryRun: true,
- prompt: () => ({ ts: 'strict' }),
- };
- await typescript(context);
- assert.ok(fixture.hasMessage('Using default TypeScript configuration'));
- assert.ok(fixture.hasMessage('Skipping TypeScript setup'));
- });
-
- it('relaxed', async () => {
- const context = {
- typescript: 'relaxed',
- cwd: '',
- dryRun: true,
- prompt: () => ({ ts: 'strict' }),
- };
- await typescript(context);
- assert.ok(fixture.hasMessage('Using relaxed TypeScript configuration'));
- assert.ok(fixture.hasMessage('Skipping TypeScript setup'));
- });
-
- it('other', async () => {
- const context = {
- typescript: 'other',
- cwd: '',
- dryRun: true,
- prompt: () => ({ ts: 'strict' }),
- exit(code) {
- throw code;
- },
- };
- let err = null;
- try {
- await typescript(context);
- } catch (e) {
- err = e;
- }
- assert.equal(err, 1);
- });
-});
-
-describe('typescript: setup tsconfig', async () => {
- beforeEach(() => resetFixtures());
- after(() => resetFixtures());
-
- it('none', async () => {
- const root = new URL('./fixtures/empty/', import.meta.url);
- const tsconfig = new URL('./tsconfig.json', root);
-
- await setupTypeScript('strict', { cwd: fileURLToPath(root) });
- assert.deepEqual(JSON.parse(fs.readFileSync(tsconfig, { encoding: 'utf-8' })), {
- extends: 'astro/tsconfigs/strict',
- });
- assert(
- fs.readFileSync(tsconfig, { encoding: 'utf-8' }).endsWith('\n'),
- 'The file does not end with a newline',
- );
- });
-
- it('exists', async () => {
- const root = new URL('./fixtures/not-empty/', import.meta.url);
- const tsconfig = new URL('./tsconfig.json', root);
- await setupTypeScript('strict', { cwd: fileURLToPath(root) });
- assert.deepEqual(JSON.parse(fs.readFileSync(tsconfig, { encoding: 'utf-8' })), {
- extends: 'astro/tsconfigs/strict',
- });
- assert(
- fs.readFileSync(tsconfig, { encoding: 'utf-8' }).endsWith('\n'),
- 'The file does not end with a newline',
- );
- });
-});
-
-describe('typescript: setup package', async () => {
- beforeEach(() => resetFixtures());
- after(() => resetFixtures());
-
- it('none', async () => {
- const root = new URL('./fixtures/empty/', import.meta.url);
- const packageJson = new URL('./package.json', root);
-
- await setupTypeScript('strictest', { cwd: fileURLToPath(root), install: false });
- assert.ok(!fs.existsSync(packageJson));
- });
-
- it('none', async () => {
- const root = new URL('./fixtures/not-empty/', import.meta.url);
- const packageJson = new URL('./package.json', root);
- assert.equal(
- JSON.parse(fs.readFileSync(packageJson, { encoding: 'utf-8' })).scripts.build,
- 'astro build',
- );
-
- await setupTypeScript('strictest', { cwd: fileURLToPath(root), install: false });
- assert(
- fs.readFileSync(packageJson, { encoding: 'utf-8' }).endsWith('\n'),
- 'The file does not end with a newline',
- );
- const { scripts, dependencies } = JSON.parse(
- fs.readFileSync(packageJson, { encoding: 'utf-8' }),
- );
-
- assert.deepEqual(
- Object.keys(scripts),
- ['dev', 'build', 'preview'],
- 'does not override existing scripts',
- );
-
- for (const value of Object.values(dependencies)) {
- assert.doesNotMatch(value, /undefined$/, 'does not include undefined values');
- }
-
- assert.equal(scripts.build, 'astro check && astro build', 'prepends astro check command');
- });
-});