diff --git a/.changeset/breezy-llamas-behave.md b/.changeset/breezy-llamas-behave.md new file mode 100644 index 000000000..ca0cc3e54 --- /dev/null +++ b/.changeset/breezy-llamas-behave.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fix certain characters showing incorrectly in `astro check` diff --git a/.changeset/brown-drinks-leave.md b/.changeset/brown-drinks-leave.md new file mode 100644 index 000000000..261342ab6 --- /dev/null +++ b/.changeset/brown-drinks-leave.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +public assets should always take priority over page routes in SSR deployments diff --git a/.changeset/chatty-bikes-sin.md b/.changeset/chatty-bikes-sin.md new file mode 100644 index 000000000..99d999bda --- /dev/null +++ b/.changeset/chatty-bikes-sin.md @@ -0,0 +1,5 @@ +--- +'@astrojs/image': patch +--- + +Updates the component to pass the `alt` attribute down to the element diff --git a/.changeset/chilled-cherries-decide.md b/.changeset/chilled-cherries-decide.md new file mode 100644 index 000000000..d04ab1d38 --- /dev/null +++ b/.changeset/chilled-cherries-decide.md @@ -0,0 +1,5 @@ +--- +"@astrojs/sitemap": patch +--- + +Update README to reflect `@astrojs/sitemap@0.2.0` changes diff --git a/.changeset/cold-bears-sneeze.md b/.changeset/cold-bears-sneeze.md new file mode 100644 index 000000000..483d87cd3 --- /dev/null +++ b/.changeset/cold-bears-sneeze.md @@ -0,0 +1,5 @@ +--- +'@astrojs/markdown-remark': minor +--- + +fixed generated slugs in markdown that ends with a dash diff --git a/.changeset/cold-eyes-run.md b/.changeset/cold-eyes-run.md new file mode 100644 index 000000000..8775c1919 --- /dev/null +++ b/.changeset/cold-eyes-run.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Add export keyword to astro config file stub created by add cli command diff --git a/.changeset/dull-eagles-beg.md b/.changeset/dull-eagles-beg.md new file mode 100644 index 000000000..b36a15b1a --- /dev/null +++ b/.changeset/dull-eagles-beg.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Use a base middleware for better base path handling in dev. diff --git a/.changeset/flat-shoes-camp.md b/.changeset/flat-shoes-camp.md new file mode 100644 index 000000000..a8f1a9c4e --- /dev/null +++ b/.changeset/flat-shoes-camp.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +[#3859](https://github.com/withastro/astro/pull/3859) Overhaul Astro error handling, using Vite's built-in error overlay when possible diff --git a/.changeset/gentle-mails-mate.md b/.changeset/gentle-mails-mate.md new file mode 100644 index 000000000..eb3d561f2 --- /dev/null +++ b/.changeset/gentle-mails-mate.md @@ -0,0 +1,5 @@ +--- +"@astrojs/image": patch +--- + +Handle EXIF orientation flag diff --git a/.changeset/happy-parrots-stare.md b/.changeset/happy-parrots-stare.md new file mode 100644 index 000000000..54d117320 --- /dev/null +++ b/.changeset/happy-parrots-stare.md @@ -0,0 +1,8 @@ +--- +'astro': minor +'@astrojs/cloudflare': minor +'@astrojs/netlify': minor +'@astrojs/vercel': minor +--- + +Support for 404 and 500 pages in SSR diff --git a/.changeset/lemon-tools-rescue.md b/.changeset/lemon-tools-rescue.md new file mode 100644 index 000000000..2d8044b61 --- /dev/null +++ b/.changeset/lemon-tools-rescue.md @@ -0,0 +1,5 @@ +--- +'create-astro': patch +--- + +Fixes support for using templates from any GitHub repository diff --git a/.changeset/loud-apes-flash.md b/.changeset/loud-apes-flash.md new file mode 100644 index 000000000..598f26d05 --- /dev/null +++ b/.changeset/loud-apes-flash.md @@ -0,0 +1,5 @@ +--- +'astro': minor +--- + +Removes warnings for integrations/ssr diff --git a/.changeset/lovely-lions-attend.md b/.changeset/lovely-lions-attend.md new file mode 100644 index 000000000..e81a2b6dc --- /dev/null +++ b/.changeset/lovely-lions-attend.md @@ -0,0 +1,5 @@ +--- +'@astrojs/svelte': patch +--- + +Fix optional props not being recognized properly in the editor diff --git a/.changeset/mighty-poets-prove.md b/.changeset/mighty-poets-prove.md new file mode 100644 index 000000000..9bd49e5b6 --- /dev/null +++ b/.changeset/mighty-poets-prove.md @@ -0,0 +1,6 @@ +--- +'astro': patch +'@astrojs/lit': patch +--- + +Fixes Lit compat with Vite 3.0.1 diff --git a/.changeset/moody-crabs-occur.md b/.changeset/moody-crabs-occur.md new file mode 100644 index 000000000..050e9ec0d --- /dev/null +++ b/.changeset/moody-crabs-occur.md @@ -0,0 +1,6 @@ +--- +'astro': patch +'@astrojs/markdown-remark': patch +--- + +Avoid parsing JSX, components, and Astro islands when using "plain" md mode. This brings `markdown.mode: 'md'` in-line with our docs description. diff --git a/.changeset/moody-teachers-knock.md b/.changeset/moody-teachers-knock.md new file mode 100644 index 000000000..71746ae4a --- /dev/null +++ b/.changeset/moody-teachers-knock.md @@ -0,0 +1,9 @@ +--- +"@astrojs/image": patch +"@astrojs/partytown": patch +"@astrojs/prefetch": patch +"@astrojs/sitemap": patch +"@astrojs/tailwind": patch +--- + +[READMEs] removed "experimental" from astro add instructions diff --git a/.changeset/new-coats-cheer.md b/.changeset/new-coats-cheer.md new file mode 100644 index 000000000..12b4c0797 --- /dev/null +++ b/.changeset/new-coats-cheer.md @@ -0,0 +1,5 @@ +--- +'@astrojs/mdx': minor +--- + +Add remarkPlugins and rehypePlugins to config, with the same default plugins as our standard Markdown parser diff --git a/.changeset/old-walls-draw.md b/.changeset/old-walls-draw.md new file mode 100644 index 000000000..cda5405b3 --- /dev/null +++ b/.changeset/old-walls-draw.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Added missing `media` attributes from the JSX definitions for the `meta` element diff --git a/.changeset/olive-dryers-sell.md b/.changeset/olive-dryers-sell.md new file mode 100644 index 000000000..15f3b531e --- /dev/null +++ b/.changeset/olive-dryers-sell.md @@ -0,0 +1,18 @@ +--- +'astro': minor +'@astrojs/cloudflare': minor +'@astrojs/deno': minor +'@astrojs/netlify': minor +'@astrojs/vercel': minor +'@astrojs/node': minor +--- + +Adds support for Astro.clientAddress + +The new `Astro.clientAddress` property allows you to get the IP address of the requested user. + +```astro +
Your address { Astro.clientAddress }
+``` + +This property is only available when building for SSR, and only if the adapter you are using supports providing the IP address. If you attempt to access the property in a SSG app it will throw an error. diff --git a/.changeset/perfect-islands-teach.md b/.changeset/perfect-islands-teach.md new file mode 100644 index 000000000..7d83eb44d --- /dev/null +++ b/.changeset/perfect-islands-teach.md @@ -0,0 +1,5 @@ +--- +'@astrojs/image': patch +--- + +Fixing TypeScript definition exports for image components diff --git a/.changeset/popular-taxis-prove.md b/.changeset/popular-taxis-prove.md new file mode 100644 index 000000000..101dfd7dd --- /dev/null +++ b/.changeset/popular-taxis-prove.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Overhaul HMR handling for more stable live reload behavior diff --git a/.changeset/real-camels-roll.md b/.changeset/real-camels-roll.md new file mode 100644 index 000000000..61cf8186d --- /dev/null +++ b/.changeset/real-camels-roll.md @@ -0,0 +1,5 @@ +--- +'@astrojs/mdx': minor +--- + +Support Prism and Shiki syntax highlighting based on project config diff --git a/.changeset/rotten-candles-count.md b/.changeset/rotten-candles-count.md new file mode 100644 index 000000000..04bd7b77e --- /dev/null +++ b/.changeset/rotten-candles-count.md @@ -0,0 +1,5 @@ +--- +'@astrojs/vercel': minor +--- + +Removed requirement for `ENABLE_VC_BUILD=1`, since Build Output v3 is now stable. [Learn more](https://vercel.com/blog/build-output-api). diff --git a/.changeset/shiny-pumpkins-return.md b/.changeset/shiny-pumpkins-return.md new file mode 100644 index 000000000..6482832a5 --- /dev/null +++ b/.changeset/shiny-pumpkins-return.md @@ -0,0 +1,5 @@ +--- +'@astrojs/mdx': patch +--- + +Include page url in MDX glob result diff --git a/.changeset/silent-clocks-pump.md b/.changeset/silent-clocks-pump.md new file mode 100644 index 000000000..197d357f5 --- /dev/null +++ b/.changeset/silent-clocks-pump.md @@ -0,0 +1,6 @@ +--- +'@astrojs/mdx': minor +'astro': patch +--- + +Support YAML frontmatter in MDX files diff --git a/.changeset/sixty-drinks-search.md b/.changeset/sixty-drinks-search.md new file mode 100644 index 000000000..3565b2fcf --- /dev/null +++ b/.changeset/sixty-drinks-search.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fix `define:vars` bugs with both `style` and `script` diff --git a/.changeset/smooth-seahorses-hear.md b/.changeset/smooth-seahorses-hear.md new file mode 100644 index 000000000..0c203dc10 --- /dev/null +++ b/.changeset/smooth-seahorses-hear.md @@ -0,0 +1,6 @@ +--- +'astro': patch +'@astrojs/node': patch +--- + +Fixes Node adapter to accept a request body diff --git a/.changeset/spotty-apricots-deny.md b/.changeset/spotty-apricots-deny.md new file mode 100644 index 000000000..36d62d973 --- /dev/null +++ b/.changeset/spotty-apricots-deny.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Allow defining aliases with tsconfig diff --git a/.changeset/strong-stingrays-compete.md b/.changeset/strong-stingrays-compete.md new file mode 100644 index 000000000..f01d4cc8c --- /dev/null +++ b/.changeset/strong-stingrays-compete.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Add support for `.html` components and pages diff --git a/.changeset/thirty-beans-poke.md b/.changeset/thirty-beans-poke.md new file mode 100644 index 000000000..2b1ae5c98 --- /dev/null +++ b/.changeset/thirty-beans-poke.md @@ -0,0 +1,8 @@ +--- +'astro': minor +'@astrojs/image': minor +'@astrojs/svelte': minor +'@astrojs/vue': minor +--- + +Bump to Vite 3! diff --git a/.changeset/tiny-glasses-play.md b/.changeset/tiny-glasses-play.md new file mode 100644 index 000000000..1515d63ee --- /dev/null +++ b/.changeset/tiny-glasses-play.md @@ -0,0 +1,6 @@ +--- +'@astrojs/image': minor +--- + +- Fixes two bugs that were blocking SSR support when deployed to a hosting service +- The built-in `sharp` service now automatically rotates images based on EXIF data diff --git a/.changeset/two-hounds-sort.md b/.changeset/two-hounds-sort.md new file mode 100644 index 000000000..b6be5ea04 --- /dev/null +++ b/.changeset/two-hounds-sort.md @@ -0,0 +1,20 @@ +--- +'astro': minor +'@astrojs/markdown-component': minor +'@astrojs/markdown-remark': minor +--- + +The use of components and JSX expressions in Markdown are no longer supported by default. + +For long term support, migrate to the `@astrojs/mdx` integration for MDX support (including `.mdx` pages!). + +Not ready to migrate to MDX? Add the legacy flag to your Astro config to re-enable the previous Markdown support. + +```js +// https://astro.build/config +export default defineConfig({ + legacy: { + astroFlavoredMarkdown: true, + } +}); +``` diff --git a/.changeset/unlucky-panthers-yawn.md b/.changeset/unlucky-panthers-yawn.md new file mode 100644 index 000000000..b8e325b15 --- /dev/null +++ b/.changeset/unlucky-panthers-yawn.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Deprecate Astro.canonicalURL, in favor of Astro.url instead. diff --git a/.changeset/wet-wombats-prove.md b/.changeset/wet-wombats-prove.md new file mode 100644 index 000000000..da0b01934 --- /dev/null +++ b/.changeset/wet-wombats-prove.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Improve warning logs on astro.config change diff --git a/.changeset/wild-socks-drive.md b/.changeset/wild-socks-drive.md new file mode 100644 index 000000000..c69216ca3 --- /dev/null +++ b/.changeset/wild-socks-drive.md @@ -0,0 +1,22 @@ +--- +'astro': minor +'@astrojs/markdown-component': minor +--- + +Move the Markdown component to its own package + +This change moves the Markdown component into its own package where it will be maintained separately. All that needs to change from a user's perspective is the import statement: + +```astro +--- +import { Markdown } from 'astro/components'; +--- +``` + +Becomes: + +```astro +--- +import Markdown from '@astrojs/markdown-component'; +--- +``` diff --git a/.changeset/yellow-drinks-judge.md b/.changeset/yellow-drinks-judge.md new file mode 100644 index 000000000..fdd65d6b9 --- /dev/null +++ b/.changeset/yellow-drinks-judge.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Add Astro.url helper for getting the request URL diff --git a/.eslintignore b/.eslintignore index c2d3e8400..28768c1b9 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,8 +1,9 @@ -**/*.js -**/*.ts -!packages/astro/**/*.js -!packages/astro/**/*.ts -packages/astro/test/**/*.js +**/*.d.ts +packages/**/dist/**/* +packages/**/fixtures/**/* +packages/webapi/**/* packages/astro/vendor/vite/**/* +examples/**/* +scripts/**/* .github .changeset diff --git a/.eslintrc.cjs b/.eslintrc.cjs index d2d00d081..28ddba1e6 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -1,7 +1,7 @@ module.exports = { parser: '@typescript-eslint/parser', extends: ['plugin:@typescript-eslint/recommended', 'prettier'], - plugins: ['@typescript-eslint', 'prettier'], + plugins: ['@typescript-eslint', 'prettier', 'no-only-tests'], rules: { '@typescript-eslint/ban-ts-comment': 'off', '@typescript-eslint/camelcase': 'off', @@ -17,5 +17,6 @@ module.exports = { 'prefer-const': 'off', 'no-shadow': 'off', '@typescript-eslint/no-shadow': ['error'], + 'no-only-tests/no-only-tests': 'error', }, }; diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 495a5ff2e..7cc4d8db7 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -1,4 +1,6 @@ # Switch to tabs (Use Accessible Indentation #2253) 6ddd7678ffb6598ae6e263706813cb5e94535f02 # prettier config update -1335797903a57716e9a02b0ffd8ca636b3883c62 \ No newline at end of file +1335797903a57716e9a02b0ffd8ca636b3883c62 +# Manually format .astro files in example projects (#3862) +59e8c71786fd1c154904b3fefa7d26d88f4d92d2 diff --git a/.github/ISSUE_TEMPLATE/---01-bug-report.yml b/.github/ISSUE_TEMPLATE/---01-bug-report.yml index 05d9fe549..99594a832 100644 --- a/.github/ISSUE_TEMPLATE/---01-bug-report.yml +++ b/.github/ISSUE_TEMPLATE/---01-bug-report.yml @@ -11,7 +11,7 @@ body: Thank you for taking the time to file a bug report! Please fill out this form as completely as possible. ✅ I am using the **latest version of Astro** and all plugins. - ✅ I am using a version of Node that supports ESM (`v14.15.0+`, or `v16.0.0+`) + ✅ I am using a version of Node that supports ESM (`v14.18.0+`, or `v16.12.0+`) - type: input id: astro-version attributes: diff --git a/.github/extract-artifacts.sh b/.github/extract-artifacts.sh deleted file mode 100755 index 03f0d19a1..000000000 --- a/.github/extract-artifacts.sh +++ /dev/null @@ -1,11 +0,0 @@ -cd artifacts -mkdir -p ../tmp/packages -mv * ../tmp/packages -cd ../tmp -tar -cvzpf artifacts.tar.gz * -mv artifacts.tar.gz ../artifacts.tar.gz -cd .. -tar -xvzpf artifacts.tar.gz -rm -rf artifacts -rm -rf tmp -rm -f artifacts.tar.gz diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 16791b110..db76aefbd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,6 +7,7 @@ on: pull_request: paths-ignore: - '.vscode/**' + - '**/*.md' # Automatically cancel in-progress actions on the same branch concurrency: @@ -17,8 +18,13 @@ defaults: run: shell: bash +env: + TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} + TURBO_TEAM: ${{ secrets.TURBO_TEAM }} + FORCE_COLOR: true + ASTRO_TELEMETRY_DISABLED: true + jobs: - # Lint can run in parallel with Build. lint: name: Lint runs-on: ubuntu-latest @@ -54,9 +60,6 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: eslint: true - eslint_args: --ignore-pattern test --ignore-pattern vendor - eslint_dir: packages/astro - eslint_extensions: ts prettier: false auto_fix: true git_name: github-actions[bot] @@ -68,13 +71,17 @@ jobs: # Checks that the formatter runs successfully on all files # In the future, we may have this fail PRs on unformatted code - name: Format Check - run: yarn format --list + run: pnpm run format --list - # Build installs all devDependencies and runs our full build pipeline. - # We upload all `dist/` artifacts to GitHub, which can be shared by all dependent jobs. + # Build primes out build caches for Turbo build: - name: Build Packages - runs-on: ubuntu-latest + name: 'Build: ${{ matrix.os }}' + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest] + node_version: [14] + fail-fast: true steps: - name: Checkout uses: actions/checkout@v3 @@ -82,47 +89,32 @@ jobs: - name: Setup PNPM uses: pnpm/action-setup@v2.2.1 - - name: Setup Node + - name: Setup node@${{ matrix.node_version }} uses: actions/setup-node@v3 with: - node-version: 16 + node-version: ${{ matrix.node_version }} cache: 'pnpm' - name: Install dependencies run: pnpm install - + - name: Build Packages run: pnpm run build - - name: Upload Package Artifacts - uses: actions/upload-artifact@v3 - with: - name: artifacts - path: | - packages/*/dist/** - packages/*/*/dist/** - packages/webapi/mod.js - packages/webapi/mod.js.map - if-no-files-found: error - - # Test depends on Build's output, which allows us to skip any build process! test: name: 'Test: ${{ matrix.os }} (node@${{ matrix.node_version }})' runs-on: ${{ matrix.os }} - env: - ASTRO_TELEMETRY_DISABLED: true + needs: build strategy: matrix: os: [ubuntu-latest] node_version: [14, 16] include: - os: windows-latest - node_version: 16 + node_version: 14 - os: macos-latest - node_version: 16 + node_version: 14 fail-fast: false - needs: - - build steps: - name: Checkout uses: actions/checkout@v3 @@ -141,35 +133,25 @@ jobs: with: deno-version: v1.19.3 - - name: Download Build Artifacts - uses: actions/download-artifact@v3 - - - name: Extract Artifacts - run: ./.github/extract-artifacts.sh - - name: Install dependencies run: pnpm install + - name: Build Packages + run: pnpm run build + - name: Test run: pnpm run test e2e: - name: 'E2E: ${{ matrix.os }} (node@${{ matrix.node_version }})' + name: 'Test (E2E): ${{ matrix.os }} (node@${{ matrix.node_version }})' runs-on: ${{ matrix.os }} - env: - ASTRO_TELEMETRY_DISABLED: true + timeout-minutes: 20 + needs: build strategy: matrix: - os: [ubuntu-latest] - node_version: [14, 16] - include: - - os: windows-latest - node_version: 16 - - os: macos-latest - node_version: 16 + os: [ubuntu-latest, windows-latest] + node_version: [14] fail-fast: false - needs: - - build steps: - name: Checkout uses: actions/checkout@v3 @@ -183,73 +165,58 @@ jobs: node-version: ${{ matrix.node_version }} cache: 'pnpm' - - name: Download Build Artifacts - uses: actions/download-artifact@v3 - - - name: Extract Artifacts - run: ./.github/extract-artifacts.sh - - name: Install dependencies run: pnpm install + - name: Build Packages + run: pnpm run build + - name: Test run: pnpm run test:e2e smoke: - name: 'Test (Smoke) ${{ matrix.os }}' + name: 'Test (Smoke): ${{ matrix.os }} (node@${{ matrix.node_version }})' runs-on: ${{ matrix.os }} + needs: build strategy: matrix: - os: [windows-latest, ubuntu-latest] - needs: - - build + os: [ubuntu-latest] + node_version: [14] steps: - name: Checkout uses: actions/checkout@v3 - with: - submodules: 'recursive' - - - name: Update submodules - run: git submodule update --remote - name: Setup PNPM uses: pnpm/action-setup@v2.2.1 - - name: Setup Node + - name: Setup node@${{ matrix.node_version }} uses: actions/setup-node@v3 with: - node-version: 14 + node-version: ${{ matrix.node_version }} cache: 'pnpm' - - name: Download Build Artifacts - uses: actions/download-artifact@v3 - - - name: Extract Artifacts - run: ./.github/extract-artifacts.sh + - name: Checkout docs + uses: actions/checkout@v3 + with: + repository: withastro/docs + path: smoke/docs - name: Install dependencies run: pnpm install --no-frozen-lockfile + - name: Build Packages + run: pnpm run build + - name: Test run: pnpm run test:smoke - - name: Memory Leak Test - run: | - node ./scripts/memory/mk.js - node --expose-gc ./scripts/memory/index.js --ci - - - # Changelog can only run _after_ build. - # We download all `dist/` artifacts from GitHub to skip the build process. changelog: name: Changelog PR or Release if: ${{ (github.ref_name == 'main' || github.head_ref == 'next') && github.repository_owner == 'withastro' }} - needs: [build] runs-on: ubuntu-latest + needs: build steps: - uses: actions/checkout@v3 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Setup PNPM uses: pnpm/action-setup@v2.2.1 @@ -260,15 +227,12 @@ jobs: node-version: 16 cache: 'pnpm' - - name: Download Build Artifacts - uses: actions/download-artifact@v3 - - - name: Extract Artifacts - run: ./.github/extract-artifacts.sh - - name: Install dependencies run: pnpm install + - name: Build Packages + run: pnpm run build + - name: Create Release Pull Request or Publish id: changesets uses: changesets/action@v1 @@ -279,7 +243,9 @@ jobs: commit: '[ci] release' title: '[ci] release' env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # Needs access to push to main + GITHUB_TOKEN: ${{ secrets.FREDKBOT_GITHUB_TOKEN }} + # Needs access to publish to npm NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Generate Notification diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 4431c1675..0645326f6 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -8,11 +8,15 @@ on: jobs: format: runs-on: ubuntu-latest + env: + NODE_OPTIONS: "--max_old_space_size=4096" steps: - name: Check out code using Git uses: actions/checkout@v3 with: ref: ${{ github.head_ref }} + # Needs access to push to main + token: ${{ secrets.FREDKBOT_GITHUB_TOKEN }} - name: Setup PNPM uses: pnpm/action-setup@v2.2.1 - name: Setup Node @@ -29,3 +33,5 @@ jobs: with: commit_message: '[ci] format' branch: ${{ github.head_ref }} + commit_user_name: fredkbot + commit_user_email: fred+astrobot@astro.build diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 251f5517e..528abb6cd 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -29,12 +29,16 @@ jobs: - name: Collect stats run: node scripts/stats/index.js env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # Needs access to collect stats from the GitHub API + GITHUB_TOKEN: ${{ secrets.FREDKBOT_GITHUB_TOKEN }} + - name: Commit changes uses: stefanzweifel/git-auto-commit-action@v4 with: commit_message: '[ci] collect stats' branch: ${{ github.head_ref }} + # Needs access to push to main + token: ${{ secrets.FREDKBOT_GITHUB_TOKEN }} lockfile: if: github.repository_owner == 'withastro' @@ -53,15 +57,19 @@ jobs: node-version: 16 cache: 'pnpm' - - name: Upgrade recursive - run: pnpm upgrade --recursive + - name: Delete the existing pnpm-lock.yaml file + run: rm pnpm-lock.yaml + + - name: Create a fresh pnpm lockfile (no install) + run: pnpm install --lockfile-only - name: Create Pull Request id: createpr uses: peter-evans/create-pull-request@v3 with: branch: ci/lockfile - token: ${{ secrets.NIGHTLY_PERSONAL_GITHUB_TOKEN }} + # Access token is needed to trigger CI on this PR + token: ${{ secrets.FREDKBOT_GITHUB_TOKEN }} commit-message: '[ci] update lockfile' title: '[ci] update lockfile' body: > diff --git a/.github/workflows/scripts.yml b/.github/workflows/scripts.yml index 40a29ee61..60cf929c7 100644 --- a/.github/workflows/scripts.yml +++ b/.github/workflows/scripts.yml @@ -4,6 +4,8 @@ on: pull_request: branches: - 'main' + paths: + - 'packages/astro/src/runtime/client/**/*' # Automatically cancel in-progress actions on the same branch concurrency: diff --git a/.gitignore b/.gitignore index 8967dc4b0..a6fb80905 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ package-lock.json # do not commit .env files or any files that end with `.env` *.env +packages/astro/src/**/*.prebuilt.ts !packages/astro/vendor/vite/dist packages/integrations/**/.netlify/ diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 28a12af2d..000000000 --- a/.gitmodules +++ /dev/null @@ -1,8 +0,0 @@ -[submodule "smoke/docs"] - path = smoke/docs - url = git@github.com:withastro/docs.git - branch = main -[submodule "smoke/astro.build"] - path = smoke/astro.build - url = git@github.com:withastro/astro.build.git - branch = main diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index 63266fdec..000000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,76 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, sex characteristics, gender identity and expression, -level of experience, education, socio-economic status, nationality, personal -appearance, race, religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment -include: - -- Using welcoming and inclusive language -- Being respectful of differing viewpoints and experiences -- Gracefully accepting constructive criticism -- Focusing on what is best for the community -- Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -- The use of sexualized language or imagery and unwelcome sexual attention or - advances -- Trolling, insulting/derogatory comments, and personal or political attacks -- Public or private harassment -- Publishing others' private information, such as a physical or electronic - address, without explicit permission -- Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. - -## Enforcement - -All complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. - -See [GOVERNANCE.md](GOVERNANCE.md#Moderation) for instructions on reporting a Code of Conduct violation and a full description of the review process. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html - -[homepage]: https://www.contributor-covenant.org - -For answers to common questions about this code of conduct, see -https://www.contributor-covenant.org/faq diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b325fc8d1..3d99e1fa5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,8 +10,8 @@ We welcome contributions of any size and skill level. As an open source project, ### Prerequisite ```shell -node: "^14.15.0 || >=16.0.0" -pnpm: "^7.0.0" +node: "^14.18.0 || >=16.12.0" +pnpm: "^7.5.0" # otherwise, your build will fail ``` @@ -31,6 +31,13 @@ In [#2254](https://github.com/withastro/astro/pull/2254) a `.git-blame-ignore-re git config --local blame.ignoreRevsFile .git-blame-ignore-revs ``` +To automatically handle merge conflicts in `pnpm-lock.yaml`, you should run the following commands locally. + +```shell +pnpm add -g @pnpm/merge-driver +pnpx npm-merge-driver install --driver-name pnpm-merge-driver --driver "pnpm-merge-driver %A %O %B %P" --files pnpm-lock.yaml +``` + ### Development ```shell @@ -144,7 +151,7 @@ Understanding in which environment code runs, and at which stage in the process, ## Releasing Astro -_Note: Only [core maintainers (L3+)](https://github.com/withastro/astro/blob/main/GOVERNANCE.md#level-3-l3---core-maintainer) can release new versions of Astro._ +_Note: Only [core maintainers (L3+)](https://github.com/withastro/.github/blob/main/GOVERNANCE.md#level-3-l3---core-maintainer) can release new versions of Astro._ The repo is set up with automatic releases, using the changeset GitHub action & bot. @@ -154,21 +161,28 @@ To release a new version of Astro, find the `Version Packages` PR, read it over, Our release tool `changeset` has a feature for releasing "snapshot" releases from a PR or custom branch. These are npm package publishes that live temporarily, so that you can give users a way to test a PR before merging. This can be a great way to get early user feedback while still in the PR review process. +To run `changeset version` locally, you'll need to create a GitHub [personal access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) and set it as a `GITHUB_TOKEN` environment variable. + To release a snapshot, run the following locally: ```shell -# Note: XXX should be a keyword to identify this release. Ex: `--snapshot routing` & `--tag next--routing` +# Notes: +# - YYY should be a keyword to identify this release. Ex: `--snapshot routing` & `--tag next--routing` +# - Use npm/npx instead of pnpm, since npm handles registry login, authentication and publishing. +# - Adding GITHUB_TOKEN in the command adds that token to your bash history. Set a short expiration! -# 1: -pnpm exec changeset version --snapshot XXX -# 2: (Manual) review the diff, and make sure that you're not releasing more than you need to. +# 1: Tag the new release versions +GITHUB_TOKEN=XXX npx changeset version --snapshot YYY +# 2: Review the diff, and make sure that you're not releasing more than you need to. git checkout -- examples/ -# 3: -pnpm run release --tag next--XXX -# 4: (Manual) review the publish, and if you're happy then you can throw out all local changes +# 3: Release +npm run release --tag next--YYY +# 4: If you're satisfied, you can now throw out all local changes git reset --hard ``` +By default, every package with a changeset will be released. If you only want to target a smaller subset of packages for release, you can consider clearing out the `.changesets` directory to replace all existing changesets with a single changeset of only the packages that you want to release. Just be sure not to commit or push this to `main`, since it will destroy existing changesets that you will still want to eventually release. + Full documentation: https://github.com/atlassian/changesets/blob/main/docs/snapshot-releases.md ### Releasing `astro@next` (aka "prerelease mode") diff --git a/FUNDING.md b/FUNDING.md deleted file mode 100644 index 8a29c9011..000000000 --- a/FUNDING.md +++ /dev/null @@ -1,40 +0,0 @@ -# Astro Project Funding - -_Last Updated: 02-09-2022_ - -## Raising Funds - -Astro is an MIT licensed open source project and completely free to use. However, the amount of effort needed to maintain and develop new features for Astro is not sustainable without proper financial backing. We need your help to achieve this. - -Learn more about sponsorship on our [Open Collective.](https://opencollective.com/astrodotbuild). - -### Why Open Collective? - -- **Full Transparency.** Everyone gets to see where money is coming from and where it's going. -- **Individual and Corporate Sponsors.** Open Collective makes it easy for both individuals and companies to sponsor open source projects. -- **Potential Tax Benefits.** Because funds are paid to the Open Source Collective, a 501(c)(6) organization in the U.S., there may be tax benefits for some donors (please check with your accountant). -- **Automatic Invoicing.** For corporate sponsors, Open Collective automatically generates and sends invoices for tracking purposes. -- **Open Participation.** Anyone can request reimbursement for funds spent helping the Astro project and Astro can pay out to anyone. - -_List borrowed from [ESLint: "Funding ESLint's Future."](https://eslint.org/blog/2019/02/funding-eslint-future)_ - -## Distributing Funds - -100% of money raised is invested back into the community. Every dollar spent **must** support and/or improve Astro in some way. - -See all past expenses on our [Open Collective.](https://opencollective.com/astrodotbuild) - -Below is a (non-exhaustive) list of how we plan to distribute raised funds: - -- **Swag!** Creating stickers, t-shirts, etc. for sponsors and community members. -- **Improve documentation.** -- **Improve translations.** -- **Improve website.** -- **User research.** -- **Sponsoring conferences.** -- **Sponsoring community members to represent Astro at meetups, conferences, etc.** -- **Dedicated support for GitHub, Discord, Stack Overflow, etc.** - -## Eligibility - -**Employees of The Astro Technology Company are not eligible to receive funds from Open Collective.** These funds exist solely to serve the larger Astro community. diff --git a/FUNDING.yml b/FUNDING.yml deleted file mode 100644 index 7ace19ae2..000000000 --- a/FUNDING.yml +++ /dev/null @@ -1,12 +0,0 @@ -# These are supported funding model platforms - -github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] -patreon: # Replace with a single Patreon username -open_collective: astrodotbuild -ko_fi: # Replace with a single Ko-fi username -tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel -community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry -liberapay: # Replace with a single Liberapay username -issuehunt: # Replace with a single IssueHunt username -otechie: # Replace with a single Otechie username -custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/GOVERNANCE.md b/GOVERNANCE.md deleted file mode 100644 index 975e5267e..000000000 --- a/GOVERNANCE.md +++ /dev/null @@ -1,463 +0,0 @@ -# Governance - -This document outlines the governance model for Astro. This includes detailed descriptions of different roles, nomination processes, code review processes, and Code of Conduct enforcement. - -👉 **All community members must follow the [Code of Conduct (CoC)](CODE_OF_CONDUCT.md).** -Consequences for CoC violations are detailed in [Moderation](#moderation). - -👉 **Want to trigger a vote, nomination, or perform some other action?** -Scroll down to [Playbook](#governance-playbook). - -## Get Involved - -**Anything that supports the Astro community is a valuable contribution!** - -All types of contribution are meaningful. This can include code changes, type fixes, Discord activity, and even posting about Astro to your personal blog. No contribution is too small! - -Anyone can become an Astro contributor (yes, even you!). Engineering ability is not required. Our goal is to recognize all contributors to the project regardless of skill, experience or background. - -## Contributor Levels - -We recognize different levels of contribution as four different **Contributor Levels.** Because each level comes with a new set of privileges and responsibilities, you may also see these levels referred to as **Contributor Roles**. - -Contributor levels are available to **all members** of the Astro community, regardless of coding skill or experience. - -Two important things that we look for in a contributor are: - -- **Being here** - Everyone's time is valuable, and the fact that you're here and contributing to Astro is amazing! Thank you for being a part of this project with us. -- **Being a positive member of our community** - Go above and beyond our [Code of Conduct](CODE_OF_CONDUCT.md) and commit to healthy communication across pull requests, issue discussions, Discord conversations, and any interactions outside of our community (ex: no Twitter bullies allowed :) - -All Contributor roles are granted for as long as the individual wishes to engage with the project. - -Contributors can voluntarily leave the project at any time. See [Retiring a Role](#retiring-a-role-alumni) below for more information. - -In extreme cases -- such as a Code of Conduct violation -- a role may be revoked by a project Steward at their discretion. - -Each new Contributor level unlocks new privileges and responsibilities both on Discord and on GitHub. Below is a summary of each level. - -### Level 1 - Contributor - -Have you done something (big or small) to contribute to the health, success, or growth of Astro? **Congratulations, you're officially recognized as a contributor to the project!** - -#### Examples of recognized contributions - -- **GitHub:** Submitting a merged pull request. -- **GitHub:** Filing a detailed bug report or RFC. -- **GitHub:** Updating documentation or fixing a typo. -- Helping people on GitHub, Discord, etc. -- Answering questions on Stack Overflow, Twitter, etc. -- Blogging, Vlogging, Podcasting, and Livestreaming about Astro. -- This list is incomplete! Similar contributions are also recognized. - -#### Privileges - -- New role on [Discord](https://astro.build/chat): `@contributor` -- New name color on Discord: **light blue**. -- Invitations to contributor-only events, sticker drops, and the occasional swag drop. - -#### Responsibilities - -This role does not require any extra responsibilities nor time commitment. We hope you stick around and keep participating in our community! - -If you're interested in reaching the next level and becoming a **Maintainer**, you can explore some of those responsibilities in the [next section](#level-2-l2---maintainer). - -#### Nomination Process - -You may self-nominate by sending the message `!contribute` in any Discord channel. If you do this, please share a second message with a link or description of your contribution so that people can recognize you for the contribution. - -You may also be granted this role automatically if you are active and helpful on Discord. - -### Level 2 (L2) - Maintainer - -The **Maintainer** role is available to contributors who want to join the team and take part in the long-term maintenance and growth of Astro. - -The Maintainer role is critical to the long-term health of Astro. Maintainers act as the first line of defense when it comes to new issues, pull requests and Discord activity. Maintainers are most likely the first people that a user will interact with on Discord or GitHub. - -**Maintainers are not required to write code!** Some Maintainers spend most of their time inside of Discord, maintaining a healthy community there. Others work on technical documentation, support, or design. - -**A Maintainer has moderation privileges!** All maintainers are trusted with the ability to help moderate our Discord and GitHub communities for things like spam. There is also a special (optional, opt-in) `@mods` role open to maintainers who are also interested in helping out when a community member reaches out for moderation help. - -#### Recognized Contributions - -There is no strict minimum number of contributions needed to reach this level, as long as you can show **sustained** involvement over some amount of time (at least a few months). - -- **GitHub:** Submitting multiple non-trivial pull requests and RFCs -- **GitHub:** Reviewing multiple non-trivial pull requests and RFCs -- **Discord:** Supporting users in Discord, especially in the #support channel -- **Discord:** Active participation in RFC calls and other events -- **GitHub + Discord:** Triaging and confirming user issues -- This list is incomplete! Similar contributions are also recognized. - -#### Privileges - -- All privileges of the [Contributor role](#level-1---contributor), plus... -- Invitation to the `@maintainer` role on [Discord](https://astro.build/chat) -- Invitation to the private `#maintainers` channel on Discord. -- Invitation to the `withastro` organization on GitHub. -- Invitation to the `@maintainers` team on GitHub. -- New name color on Discord: **blue**. -- Ability to moderate Discord to remove spam, harmful speech, etc. -- Ability to join the `@mods` role on Discord (optional, opt-in). -- Ability to push branches directly to the `withastro` GitHub organization (personal forks no longer needed). -- Ability to review GitHub PRs. -- Ability to merge _some_ GitHub PRs. -- Ability to vote on _some_ initiatives (see [Voting](#voting) below). - -#### Responsibilities - -- Participate in the project as a team player. -- Bring a friendly, welcoming voice to the Astro community. -- Be active on Discord, especially in the #support channel. -- Triage new issues. -- Review pull requests. -- Merge some, non-trivial community pull requests. -- Merge your own pull requests (once reviewed and approved). - -#### Nomination - -- To be nominated, a nominee is expected to already be performing some of the responsibilities of a Maintainer. -- You can be nominated by any existing Maintainer (L2 or above). -- Once nominated, there will be a vote by existing Maintainers. -- See [vote rules & requirements](#voting) for info on how the vote works. - -### Level 3 (L3) - Core - -The **Core** role is available to community members who have a larger-than-usual impact on the Astro project and community. They are seen as leaders in the project and are listened to by the wider Astro community, often before they have even reached this level. A Core member is recognized for contributing a significant amount of time and energy to the project through issues, pull requests, bug fixes, implementing advanced enhancements/features, and/or actively posting on Discord. - -Not every contributor will reach this level, and that's okay! L2 Maintainers still have significant responsibility and privileges within our community. - -#### Privileges - -- All privileges of the [Maintainer role](#level-2---maintainer), plus... -- `@core` role on [Discord](https://astro.build/chat) -- New name color on Discord: **yellow**. -- Invitation to the private `#core` channel on Discord. -- Invitation to the `core` team on GitHub. -- Ability to vote on most initiatives (see [Voting](#voting) below). - -#### Responsibilities - -- All of the responsibilities of L2, including... -- Ownership over specific part(s) of the project. -- Ownership over the long-term health and success of Astro. -- Leadership as a role-model to other maintainers and community members. - -#### Nomination - -- To be nominated, a nominee is expected to already be performing some of the responsibilities of a Core member. -- You can be nominated by any existing Core member (L3 or above). -- Once nominated, there will be a vote by existing Core members. -- See [vote rules & requirements](#voting) for info on how the vote works. - -#### Special Membership Type: Core Residency - -**Core Residency** is a special type of Core membership that is limited in the following way(s): - -- No voting abilities. -- No nomination abilities. -- Can be revoked at any time by the project Steward. - -Because of these limitations, this type of Core membership is useful for anyone who has been brought in to work on or contribute to the Astro project without rising through our normal contributor levels. For example: an Astro designer or developer advocate hired by The Astro Technology Company to assist the community could be nominated for a Core Residency role without having a previously earned contributor level. - -A Core Residency nomination must still be approved through the normal Core nomination and voting process. During the nomination, the Project Steward will state that the nomination is for the Core Residency designation. The project Steward is the only one who can officially make this designation during the nomination process. - -A Core Residency member can become a full Core member (with all limitations removed) through the normal Core nomination and voting procedure. - -If a Core Residency member has their membership revoked, the project Steward may choose to impose a waiting period of some number of days, during which the member can not be re-nominated to become a full Core member. - -### Level 4 - Project Steward - -The **Steward** is an additional role bestowed to 1 (or more) Core member of the project. - -The role of Steward is mainly an administrative one. Stewards control and maintain sensitive project assets, assist in resolving conflicts, and act as tiebreakers in the event of disagreements. - -In extremely rare cases, a Steward can act unilaterally when they believe it is in the project's best interest and can prove that the issue cannot be resolved through normal governance procedure. The steward must publicly state their reason for unilateral action before taking it. - -The project Steward is currently: **@FredKSchott** - -#### Responsibilities - -- Access to the [@astrodotbuild Twitter account](https://twitter.com/astrodotbuild) -- Administration privileges on the [astro GitHub org](https://github.com/snowpackjs) -- Administration privileges on the [astro Discord server](https://astro.build/chat) -- Publish access to the [`astro` npm package](https://www.npmjs.com/package/astro) -- Domain registrar and DNS access to `astro.build` and all other domains -- Administration access to the `astro.build` Vercel account -- Ability to initiate a [vote](GOVERNANCE.md#voting) -- Ability to veto [votes](GOVERNANCE.md#voting) and resolve voting deadlocks -- Define project direction and planning -- Ability to decide on moderation decisions -- Access to the `*@astro.build` email address - -#### Nomination - -- Stewards cannot be self-nominated. -- Only Core members are eligible. -- New Stewards will be added based on a unanimous vote by the existing Steward(s). -- In the event that someone is unreachable then the decision will be deferred. - -## Other Roles - -### Project Teams - -Besides our contributor levels described above, there are additional roles and teams available that community members are welcome to join. Roles are a great way to organize around different projects and initiatives in our community. For example: - -- `@team-docs` runs the `#docs` channel and organizes the growth and development of Astro documentation. -- `@i18n-gang` runs the `#docs-i18n` channel and organizes translations in several languages. -- `@support-squad` runs the `#support-threads` channel and helps anyone who needs help using Astro. - -Many of these team roles can be browsed and joined automatically by visiting the `#manage-roles` channel in our Discord. Getting involved with a team is a great way to start contributing to Astro! - -### Moderator - -**Moderator** is a special role available to Maintainers (L2 and above). While all maintainers are granted permissions to moderate for bad behavior across our community, a Moderator actively takes on this the responsibility. For example, a community member may ping moderators (via the `@mods` role) to resolve spam posts or Code of Conduct violations. - -Trivial tasks (like removing spam) can be acted on unilaterally by a Moderator. Other non-trivial tasks (like assisting with or resolving a Code of Conduct violation) should involve the entire Moderator team (and in some cases, the project Steward). - -#### Privileges - -- `@mods` role on [Discord](https://astro.build/chat) -- Invitation to the private `#moderators` channel on Discord -- Invitation to the `staff` team on GitHub. - -#### Nomination - -Any Maintainer (L2 and above) can self-nominate by messaging the project Steward (`@steward`) on Discord. - -### Technical Steering Committee (TSC) - -The **TSC** is a special role available to Core members (L3 and above). TSC members are responsible for the growth and maintenance of the Astro codebase. - -TSC members are guardians over the Astro codebase. Their duty is to ensure code quality, correctness and security. - -A TSC member guides the direction of the project and ensures a healthy future for the Astro codebase. TSC members are ultimately responsible for technical decision making when it comes to any changes to the Astro codebase. - -A TSC member has significant sway in software design decisions. For this reason, coding experience is critical for this role. TSC membership is one of the only roles that requires a significant contribution history of code to the Astro project on GitHub. - -#### Privileges - -- `@tsc` role on [Discord](https://astro.build/chat) -- Invitation to the private `#tsc` channel on Discord -- Invitation to the `tsc` team on GitHub. -- Ability to merge all GitHub PRs. -- Ability to vote on RFCs and technical initiatives (see [Voting](#voting) below). - -#### Responsibilities - -- Participating in RFC discussions and technical meetings. -- Assisting with design and implementation of non-trivial GitHub PRs. -- Reviewing and merging larger, non-trivial PRs. -- Maintaining and improving overall codebase architecture. -- Tracking and ensuring progress of open pull requests. -- Mentoring and guiding other community contributors. - -#### Nomination - -- To be nominated, a nominee is expected to already be active in technical discussions and performing some of the responsibilities of a TSC member. -- You can be nominated by any existing Core member (L3 or above). Note: This includes all existing TSC members as well. -- Once nominated, there will be a vote by existing Core members. -- See [vote rules & requirements](#voting) for info on how this vote works. - -### Staff - -**Staff** is a special designation for employees of [The Astro Technology Company](https://astro.build/company). - -#### Privileges - -- `@staff` role on [Discord](https://astro.build/chat) -- New name color on Discord: **yellow**. -- Invitation to some private channels on Discord, at the discretion of the project Steward. -- Invitation to the `staff` team on GitHub. - -Staff membership does not grant any additional abilities when it comes to voting and project governance. A Staff member is still eligible for other roles in the community and may still vote as defined by their other roles. For example, a Staff member who is also a part of `@core` will be able to vote as any other `@core` member would. - -### Alumni - -**Alumni** is a special designation for Maintainers (L2 and above) who have stepped away from the project and no longer contribute regularly. See [Retiring a Role](#retiring-a-role-alumni) below for more information. - -#### Privileges - -- `@alumni` role on [Discord](https://astro.build/chat) -- New name color on Discord: **light blue**. -- Invitation to the private `#alumni` channel on Discord. - -## Retiring a Role (Alumni) - -Contributor roles are granted for as long as the person wishes to engage with the project. However, over time an active community member may choose to step away from the Astro project to work on other things. Moving on from a project is a natural and well-understood part of any open source community, and we celebrate it! - -**Alumni** is a special designation and role for any person who was once an active maintainer (L2 or above) but is now no longer actively involved. By retiring and joining Alumni you trade-in your current set of roles, privileges, and responsibilities for a new, special Alumni role (which comes with its own set of Privileges, as described above). - -As a Maintainer (L2 or above) you can retire your role at any time by pinging the project Steward and requesting Alumni status. You can initiate this action yourself if you know ahead-of-time that you need to step away from the project. Or, if you have gone several months without interacting with the Astro community, the project Steward may actively reach out to you to discuss retiring as a way to make room for new contributors. - -As an Alumni member, you are still a part of the Astro community and can continue to be a part of our Discord, GitHub, and anywhere else. You may also request to have your old roles reinstated at any time through the normal nomination & voting process for that role. - -Rejoining the project as a contributor (L1 or above) will automatically remove you from the Alumni role. - -# Governance Playbook - -## Voting - -Certain project decisions (like governance changes and membership nominations) require a vote. Below are the changes that require a vote, and the rules that govern that vote. - -The project Steward may initiate a vote for any unlisted project decision. [General Rules](#general-rules) will apply, along with any addition rules provided at the steward's discretion. If this unlisted project decision is expected to be repeated in the future, voting rules should be agreed on and then added to this document. - -### General Voting Rules - -- Members may abstain from any vote. -- Members who do not vote within 3 days will automatically abstain. -- Stewards may reduce the 3 day automatic abstain for urgent decisions. -- Stewards reserve the right to veto approval with a publicly disclosed reason. - -## Voting: Maintainer (L2) Nomination - -This process kicks off once a valid nomination has been made. See ["Maintainer - Nomination Process"](#nomination-process) above for more details on nomination. - -**Who can vote:** All Maintainers (L2 and above). - -1. A vote thread should be created in Discord #maintainers channel (the private channel for all maintainers). -2. A vote thread can be created by any Maintainer, Core member, or the Steward. -3. Once a vote thread is created, existing Maintainers can discuss the nomination in private. -4. The normal 3 day voting & discussion window begins with the thread creation. -5. Voting can be done in the thread (visible to other voters) or in a private DM to the project Steward. -6. Once the vote is complete, the thread is deleted. -7. The vote must receive an overwhelming majority (70%+) to pass. -8. **If the vote passes:** the nominee will be made a Maintainer and all privileges will be made available to them. -9. **If the vote fails:** the project Steward is responsible for informing the nominee with constructive, actionable feedback. (Note: this is not required if the nomination was made in the `#core` channel, or if the nominee was otherwise not made aware of their nomination). - -#### Draft message to send to accepted maintainer, informing them of the decision: - -``` -Hey ${NAME}! - -**I have some exciting news — you've been given the role of L2 Contributor (aka Maintainer/Moderator) in the Astro community!** - -Some background: I nominated you for the role in the (private) #maintainers channel, and the consensus was overwhelmingly positive. Some quotes from the nomination thread that sum up the impact you've already had on the project so far: - -- ... -- ... -- ... - -Thank you for ${1 SENTENCE DESCRIPTION OF CONTRIBUTIONS}. Your impact has definitely been felt and we would be thrilled to have your help building a healthy future for Astro! There is no required time commitment: you can continue to contribute as often or as little as you'd like. This is mainly a chance to recognize your contributions and give you more privileges in Discord and GitHub. - -Please let me know if you’re interested in accepting this invitation. If so, we’ll start getting your roles up to date. And if you have any questions, feel free to let me know. - -Best, -${MY_NAME} - -*PS: As a reminder, our Governance document describes the following privileges and responsibilities for the **L2 - Maintainer** role: https://github.com/withastro/astro/blob/main/GOVERNANCE.md* -``` - -## Voting: Core Member (L3) Nomination - -This process kicks off once a valid nomination has been made. See ["Core Member - Nomination Process"](#nomination-process) above for more details on nomination. - -**Who can vote:** All Core members (L3 and above). - -1. A vote thread should be created in Discord `#core` channel (the private channel for Core members). -2. A vote thread can be created by any Core member, or the Steward. -3. Once a vote thread is created, existing Core members can discuss the nomination in private. -4. The normal 3 day voting & discussion window begins with the thread creation. -5. Voting can be done in the thread (visible to other voters) or in a private DM to the project Steward. -6. Once the vote is complete, the thread is deleted. -7. The vote must receive an overwhelming majority (70%+) to pass. -8. **If the vote passes:** the nominee will be made a Core Member and all privileges will be made available to them. -9. **If the vote fails:** the project Steward is responsible for informing the nominee with constructive, actionable feedback. (Note: this is not required if the nomination was made in the #core channel, or if the nominee was otherwise not made aware of their nomination). - -#### Draft message to send to accepted maintainer, informing them of the decision: - -``` -Hey $NAME! - -I have some exciting news—you’ve been nominated and accepted as a member of the Astro Core team! The Core team held a vote and overwhelmingly agree that you would be a great addition to the team. Congratulations! Thanks for all of your significant contributions to Astro to date and your continued dedication to this project and our community. We would be thrilled to have your help ensuring a healthy future for Astro! - -Please let me know if you’re interested in accepting this invitation. If so, we’ll start getting your roles and permissions up to date. - -As a reminder, our Governance document describes the following privileges and responsibilities for a **Core Member**: - -#### Privileges - -$COPY_AND_PASTE_FROM_ABOVE - -#### Responsibilities - -$COPY_AND_PASTE_FROM_ABOVE -``` - -## Voting: Governance Change - -A vote is initiated once a pull request to the GOVERNANCE.md file is submitted by a Core Member. - -If the pull request submitter is not a Core Member, the PR can be closed by any Maintainer without a vote. However, any Core Member may request a vote on that PR, in which case a vote is initiated. - -**Who can vote:** Core members (L3 and above). All Maintainers are encouraged to discuss and voice their opinion in the pull request discussion. Core members should take the opinions of Maintainers into consideration when voting. - -1. The pull request discussion thread is used to discuss the governance change. -2. The normal 3 day voting & discussion window begins with either the PR creation or the removal of `WIP:` from the PR title if the PR was created as a draft. -3. Voting can be done in the pull request via a review of either **Approve (For)** or **Change Requested (Against)**. -4. The vote must receive a simple majority (50%+) to pass. -5. **If the vote passes:** the PR is merged and the changes take effect immediately. -6. **If the vote fails:** the PR is closed and no change occurs. - -## Voting: RFC Proposals - -Astro features are discussed using a model called [Consensus-seeking decision-making](https://en.wikipedia.org/wiki/Consensus-seeking_decision-making). This model attempts to achieve consensus on all significant changes to Astro, but has a fallback voting procedure in place if consensus appears unattainable. - -**Who can vote:** All [TSC](#technical-steering-committee-tsc) members. - -1. Anyone can submit an RFC to suggest changes to Astro. -2. A trivial change can be discussed and approved entirely within the RFC GitHub issue, as long as there are no objections from Core or TSC members. This is not considered a formal vote. -3. A non-trivial, significant change should be discussed within the RFC and approved during an RFC meeting call. In some cases, an RFC may be approved outside of an RFC meeting using Pull Request reviews as a proxy for votes. -4. During an RFC meeting, the person leading the call will attempt to achieve consensus on the RFC proposal. -5. **If consensus is reached:** the RFC is approved. -6. **If consensus is not reached:** The RFC author and TSC members must make all reasonable attempts to resolve issues and reach consensus in GitHub or a follow-up RFC meeting. The process of reaching consensus can take time, and should not be rushed as long as all participants are making a reasonable effort to respond. -7. **If consensus still cannot be reached:** The project Steward may invoke [rough consensus](https://en.wikipedia.org/wiki/Rough_consensus) to resolve an RFC that has not achieved absolute consensus, as described below (borrowed from the [IETF](https://datatracker.ietf.org/doc/html/rfc2418)): - -> Working groups make decisions through a "rough consensus" process. Astro consensus does not require that all participants agree although this is, of course, preferred. In general, the dominant view of the TSC shall prevail. (However, "dominance" is not to be determined on the basis of volume or persistence, but rather a more general sense of agreement). Consensus can be determined by a show of hands, humming, or any other means on which the TSC agrees (by rough consensus, of course). Note that 51% of the TSC does not qualify as "rough consensus" and 99% is better than rough. It is up to the project Steward to determine if rough consensus has been reached. - -## Moderation - -Outlined below is the process for Code of Conduct violation reviews. - -### Reporting - -Anyone may report a violation. Violations can be reported in the following ways: - -- In private, via email to one or more stewards. -- In private, via direct message to a project steward on Discord. -- In public, via a GitHub comment (mentioning `@snowpackjs/maintainers`). -- In public, via the project Discord server (mentioning `staff`). - -### Who gets involved? - -Each report will be assigned reviewers. These will initially be all project [stewards](#stewards). - -In the event of any conflict of interest - ie. stewards who are personally connected to a situation, they must immediately recuse themselves. - -At request of the reporter and if deemed appropriate by the reviewers, another neutral third-party may be involved in the review and decision process. - -### Review - -If a report doesn’t contain enough information, the reviewers will strive to obtain all relevant data before acting. - -The reviewers will then review the incident and determine, to the best of their ability: - -- What happened. -- Whether this event constitutes a Code of Conduct violation. -- Who, if anyone, was involved in the violation. -- Whether this is an ongoing situation. - -The reviewers should aim to have a resolution agreed very rapidly; if not agreed within a week, they will inform the parties of the planned date. - -### Resolution - -Responses will be determined by the reviewers on the basis of the information gathered and of the potential consequences. It may include: - -- taking no further action -- issuing a reprimand (private or public) -- asking for an apology (private or public) -- permanent ban from the GitHub org and Discord server -- revoked contributor status - ---- - -Inspired by [ESLint](https://eslint.org/docs/6.0.0/maintainer-guide/governance), [Rome](https://github.com/rome/tools/blob/main/GOVERNANCE.md) and [Blitz](https://blitzjs.com/docs/maintainers). diff --git a/README.md b/README.md index 4abfe365e..743d48779 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,7 @@ Join us on [Discord](https://astro.build/chat) to meet other maintainers. We'll | [@astrojs/deno](packages/integrations/deno) | [![astro version](https://img.shields.io/npm/v/@astrojs/deno.svg?label=%20)](packages/integrations/deno/CHANGELOG.md) | | [@astrojs/netlify](packages/integrations/netlify) | [![astro version](https://img.shields.io/npm/v/@astrojs/netlify.svg?label=%20)](packages/integrations/netlify/CHANGELOG.md) | | [@astrojs/vercel](packages/integrations/vercel) | [![astro version](https://img.shields.io/npm/v/@astrojs/vercel.svg?label=%20)](packages/integrations/vercel/CHANGELOG.md) | +| [@astrojs/cloudflare](packages/integrations/cloudflare) | [![astro version](https://img.shields.io/npm/v/@astrojs/cloudflare.svg?label=%20)](packages/integrations/cloudflare/CHANGELOG.md) | | [@astrojs/partytown](packages/integrations/partytown) | [![astro version](https://img.shields.io/npm/v/@astrojs/partytown.svg?label=%20)](packages/integrations/partytown/CHANGELOG.md) | | [@astrojs/sitemap](packages/integrations/sitemap) | [![astro version](https://img.shields.io/npm/v/@astrojs/sitemap.svg?label=%20)](packages/integrations/sitemap/CHANGELOG.md) | | [@astrojs/tailwind](packages/integrations/tailwind) | [![astro version](https://img.shields.io/npm/v/@astrojs/tailwind.svg?label=%20)](packages/integrations/tailwind/CHANGELOG.md) | @@ -65,16 +66,16 @@ Several official projects are maintained outside of this repo: ## Links - [License (MIT)](LICENSE) -- [Code of Conduct](CODE_OF_CONDUCT.md) -- [Open Governance & Voting](GOVERNANCE.md) -- [Project Funding](FUNDING.md) +- [Code of Conduct](https://github.com/withastro/.github/blob/main/CODE_OF_CONDUCT.md) +- [Open Governance & Voting](https://github.com/withastro/.github/blob/main/GOVERNANCE.md) +- [Project Funding](https://github.com/withastro/.github/blob/main/FUNDING.md) - [Website](https://astro.build/) ## Sponsors Astro is generously supported by Netlify, Vercel, and several other amazing organizations. -[❤️ Sponsor Astro! ❤️](FUNDING.md) +[❤️ Sponsor Astro! ❤️](https://github.com/withastro/.github/blob/main/FUNDING.md) ### Platinum Sponsors diff --git a/examples/basics/package.json b/examples/basics/package.json index b046d99ce..8e24174f3 100644 --- a/examples/basics/package.json +++ b/examples/basics/package.json @@ -9,6 +9,6 @@ "preview": "astro preview" }, "devDependencies": { - "astro": "^1.0.0-beta.46" + "astro": "^1.0.0-beta.73" } } diff --git a/examples/basics/src/components/Card.astro b/examples/basics/src/components/Card.astro index 53b67a9da..4039d4f4f 100644 --- a/examples/basics/src/components/Card.astro +++ b/examples/basics/src/components/Card.astro @@ -1,26 +1,26 @@ --- export interface Props { - title: string, - body: string, - href: string, + title: string; + body: string; + href: string; } -const {href, title, body} = Astro.props; +const { href, title, body } = Astro.props; --- + diff --git a/examples/basics/src/pages/index.astro b/examples/basics/src/pages/index.astro index ea7401f11..cf05f0bb6 100644 --- a/examples/basics/src/pages/index.astro +++ b/examples/basics/src/pages/index.astro @@ -1,26 +1,43 @@ --- -import Layout from '../layouts/Layout.astro'; -import Card from '../components/Card.astro'; +import Layout from "../layouts/Layout.astro"; +import Card from "../components/Card.astro"; --- +

Welcome to Astro

- Check out the src/pages directory to get started.
+ Check out the src/pages directory to get started.
Code Challenge: Tweak the "Welcome to Astro" message above.

- Logo - - - - My Blog - - - - - - diff --git a/examples/blog/src/components/BlogPost.astro b/examples/blog/src/components/BlogPost.astro deleted file mode 100644 index 2dba32c3d..000000000 --- a/examples/blog/src/components/BlogPost.astro +++ /dev/null @@ -1,88 +0,0 @@ ---- -import Author from './Author.astro'; - -export interface Props { - title: string; - author: string; - publishDate: string; - heroImage: string; - alt: string; -} - -const { title, author, publishDate, heroImage, alt } = Astro.props; ---- - -
-
-
-
- {heroImage && {alt}} -

{publishDate}

-

{title}

- -
-
- -
-
-
-
- - diff --git a/examples/blog/src/components/BlogPostPreview.astro b/examples/blog/src/components/BlogPostPreview.astro index f935ff8b2..865eeeb7f 100644 --- a/examples/blog/src/components/BlogPostPreview.astro +++ b/examples/blog/src/components/BlogPostPreview.astro @@ -1,48 +1,36 @@ --- export interface Props { - post: any; + title: string; + description: string; + publishDate: string; + url: string; } -const { post } = Astro.props; +const { title, description, publishDate, url } = Astro.props as Props; ---
-

{post.frontmatter.publishDate}

-

{post.frontmatter.title}

+ +

{title}

-

{post.frontmatter.description}

- Read more +

{description}

+ Read more
+ + + + My Blog + + + + + diff --git a/examples/blog/src/components/LikeButton.tsx b/examples/blog/src/components/LikeButton.tsx new file mode 100644 index 000000000..23d8518de --- /dev/null +++ b/examples/blog/src/components/LikeButton.tsx @@ -0,0 +1,35 @@ +import { useState } from 'preact/hooks'; + +interface Props { + pageUrl: string; +} + +export default function LikeButton({ pageUrl }: Props) { + const persistedLike = localStorage.getItem(`liked-${pageUrl}`); + const [liked, setLiked] = useState(persistedLike ? JSON.parse(persistedLike) : false); + + function toggleLike() { + const toggled = !liked; + setLiked(toggled); + // preserve your likes as you navigate the site + localStorage.setItem(`liked-${pageUrl}`, JSON.stringify(toggled)); + } + + return ( + + ); +} diff --git a/examples/blog/src/components/Logo.astro b/examples/blog/src/components/Logo.astro deleted file mode 100644 index a92927536..000000000 --- a/examples/blog/src/components/Logo.astro +++ /dev/null @@ -1,86 +0,0 @@ - - - diff --git a/examples/blog/src/layouts/BlogPost.astro b/examples/blog/src/layouts/BlogPost.astro index 50e854511..b8b47bfc0 100644 --- a/examples/blog/src/layouts/BlogPost.astro +++ b/examples/blog/src/layouts/BlogPost.astro @@ -1,25 +1,102 @@ --- -import BaseHead from '../components/BaseHead.astro'; -import BlogHeader from '../components/BlogHeader.astro'; -import BlogPost from '../components/BlogPost.astro'; +import BaseHead from "../components/BaseHead.astro"; +import Header from "../components/Header.astro"; +export interface Props { + content: { + title: string; + description: string; + publishDate: string; + heroImage?: { + src: string; + alt: string; + }; + }; +} -const { content } = Astro.props; -const { title, description, publishDate, author, heroImage, permalink, alt } = content; +const { + content: { title, description, publishDate, heroImage }, +} = Astro.props as Props; --- - + - - + - -
- - - -
+
+
+
+ {heroImage && ( + {heroImage.alt} + )} +

{title}

+ +
+
+ +
+
+ + diff --git a/examples/blog/src/pages/index.astro b/examples/blog/src/pages/index.astro index 1e1264533..22c095c74 100644 --- a/examples/blog/src/pages/index.astro +++ b/examples/blog/src/pages/index.astro @@ -1,78 +1,62 @@ --- -// Component Imports -import BaseHead from '../components/BaseHead.astro'; -import BlogHeader from '../components/BlogHeader.astro'; -import BlogPostPreview from '../components/BlogPostPreview.astro'; +import BaseHead from "../components/BaseHead.astro"; +import Header from "../components/Header.astro"; +import BlogPostPreview from "../components/BlogPostPreview.astro"; -// Component Script: -// You can write any JavaScript/TypeScript that you'd like here. -// It will run during the build, but never in the browser. -// All variables are available to use in the HTML template below. -let title = 'Example Blog'; -let description = 'The perfect starter for your perfect blog.'; -let permalink = 'https://example.com/'; +let title = "Example Blog"; +let description = "The perfect starter for your perfect blog."; -// Data Fetching: List all Markdown posts in the repo. - -let allPosts = await Astro.glob('./posts/*.md'); -allPosts = allPosts.sort((a, b) => new Date(b.frontmatter.publishDate).valueOf() - new Date(a.frontmatter.publishDate).valueOf()); - -// Full Astro Component Syntax: -// https://docs.astro.build/core-concepts/astro-components/ +// Use Astro.glob to fetch all post with associated frontmatter +const unsortedPosts = await Astro.glob("./posts/*.md"); +const posts = unsortedPosts.sort(function (a, b) { + return ( + new Date(b.frontmatter.publishDate).valueOf() - new Date(a.frontmatter.publishDate).valueOf() + ); +}); --- - - - + - +
-

{title}

+

{title}

{description}

- {allPosts.map((p) => )} + {posts.map(({ url, frontmatter }) => ( + + ))}
+ + diff --git a/examples/blog/src/pages/posts/index.md b/examples/blog/src/pages/posts/index.md deleted file mode 100644 index e118d869d..000000000 --- a/examples/blog/src/pages/posts/index.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -setup: | - import Layout from '../../layouts/BlogPost.astro' - import Cool from '../../components/Author.astro' -title: Hello world! -publishDate: 12 Sep 2021 -name: Nate Moore -value: 128 -description: Just a Hello World Post! ---- - - - -This is so cool! - -Do variables work {frontmatter.value * 2}? - -```javascript -// Example JavaScript - -const x = 7; -function returnSeven() { - return x; -} - -``` diff --git a/examples/blog/src/pages/posts/interactive-content.md b/examples/blog/src/pages/posts/interactive-content.md new file mode 100644 index 000000000..68c571eb4 --- /dev/null +++ b/examples/blog/src/pages/posts/interactive-content.md @@ -0,0 +1,22 @@ +--- +layout: "../../layouts/BlogPost.astro" +title: "Hello galaxy of possibilities!" +description: "Take your blog to astronomical heights" +publishDate: "12 Sep 2021" +followMe: + username: "bholmesdev" + href: "https://twitter.com/bholmesdev" +halfTheMeaning: 21 +heroImage: + src: "/assets/blog/introducing-astro.jpg" + alt: "Space shuttle leaving curved trail in the sky" +setup: | + import LikeButton from "../../components/LikeButton" + import FollowMe from "../../components/FollowMe.astro" +--- + + + +Access all exported properties with JSX expressions. For example, let's find the meaning of life: **{frontmatter.halfTheMeaning * 2}** + +If this seems cool, consider giving my post a like with this Preact component: diff --git a/examples/blog/src/pages/posts/static-content.md b/examples/blog/src/pages/posts/static-content.md new file mode 100644 index 000000000..8925e6ba3 --- /dev/null +++ b/examples/blog/src/pages/posts/static-content.md @@ -0,0 +1,28 @@ +--- +layout: "../../layouts/BlogPost.astro" +title: "Hello static content!" +description: "Bring your markdown, we'll handle the rest" +publishDate: "11 Jul 2022" +heroImage: + src: "/assets/blog/introducing-astro.jpg" + alt: "Space shuttle leaving curved trail in the sky" +--- + +**Astro has built-in support for markdown pages!** All frontmatter data will be available [via `Astro.glob` imports](https://docs.astro.build/en/reference/api-reference/#astroglob) as well, making blog landing pages easy to build. + +**Code challenge:** Try editing the `title` frontmatter property for this post and [visiting the homepage](/) again. + +## Code block demo + +```typescript +// Oh, and get Shiki syntax highlighting out-of-the-box! +// See our docs for customization options: +// https://docs.astro.build/en/guides/markdown-content/#syntax-highlighting +function getDistance(amount: number) { + if (amount === Infinity) { + return "and beyond!"; + } else { + return "and the normal distance!"; + } +} +``` diff --git a/examples/blog/src/styles/blog.css b/examples/blog/src/styles/blog.css index 2a722d237..2f338fd6a 100644 --- a/examples/blog/src/styles/blog.css +++ b/examples/blog/src/styles/blog.css @@ -32,6 +32,8 @@ --color-red-rgb: 255, 22, 57; --color-yellow: #ffbe2d; --color-yellow-rgb: 255, 190, 45; + + --content-max-width: 70ch; } :root { @@ -77,7 +79,6 @@ body { * { box-sizing: border-box; - margin: 0; } :root { @@ -101,7 +102,7 @@ body { .wrapper { margin-left: auto; margin-right: auto; - max-width: 65em; + max-width: var(--content-max-width); padding-left: 2rem; padding-right: 2rem; width: 100%; diff --git a/examples/blog/tsconfig.json b/examples/blog/tsconfig.json index 7ac81809a..4db6ee701 100644 --- a/examples/blog/tsconfig.json +++ b/examples/blog/tsconfig.json @@ -9,7 +9,7 @@ "resolveJsonModule": true, // Enable stricter transpilation for better output. "isolatedModules": true, - // Add type definitions for our Vite runtime. - "types": ["vite/client"] + // Add type definitions for our Astro runtime. + "types": ["astro/client"] } } diff --git a/examples/component/demo/astro.config.mjs b/examples/component/demo/astro.config.mjs index 882e6515a..2d73a2807 100644 --- a/examples/component/demo/astro.config.mjs +++ b/examples/component/demo/astro.config.mjs @@ -1,4 +1,10 @@ import { defineConfig } from 'astro/config'; // https://astro.build/config -export default defineConfig({}); +export default defineConfig({ + vite: { + ssr: { + noExternal: ['@example/my-component'], + }, + }, +}); diff --git a/examples/component/demo/package.json b/examples/component/demo/package.json index 13edb675c..5073c7506 100644 --- a/examples/component/demo/package.json +++ b/examples/component/demo/package.json @@ -10,6 +10,6 @@ }, "devDependencies": { "@example/my-component": "workspace:*", - "astro": "^1.0.0-beta.46" + "astro": "^1.0.0-beta.73" } } diff --git a/examples/component/demo/src/pages/index.astro b/examples/component/demo/src/pages/index.astro index bfdf495a8..e251a69ae 100644 --- a/examples/component/demo/src/pages/index.astro +++ b/examples/component/demo/src/pages/index.astro @@ -1,5 +1,5 @@ --- -import * as Component from '@example/my-component'; +import * as Component from "@example/my-component"; --- diff --git a/examples/component/package.json b/examples/component/package.json index e5a2d65d5..c78dc2679 100644 --- a/examples/component/package.json +++ b/examples/component/package.json @@ -8,6 +8,6 @@ "serve": "astro --root demo preview" }, "devDependencies": { - "astro": "^1.0.0-beta.46" + "astro": "^1.0.0-beta.73" } } diff --git a/examples/component/packages/my-component/Button.astro b/examples/component/packages/my-component/Button.astro index 5f32ce4e8..69b3b5eb5 100644 --- a/examples/component/packages/my-component/Button.astro +++ b/examples/component/packages/my-component/Button.astro @@ -7,7 +7,7 @@ const { type, ...props } = { ...Astro.props, } as Props; -props.type = type || 'button'; +props.type = type || "button"; --- diff --git a/examples/component/packages/my-component/Heading.astro b/examples/component/packages/my-component/Heading.astro index 813c0c11b..00f8926cc 100644 --- a/examples/component/packages/my-component/Heading.astro +++ b/examples/component/packages/my-component/Heading.astro @@ -8,8 +8,8 @@ const { level, role, ...props } = { ...Astro.props, } as Props; -props.role = role || 'heading'; -props['aria-level'] = level || '1'; +props.role = role || "heading"; +props["aria-level"] = level || "1"; --- diff --git a/examples/docs/astro.config.mjs b/examples/docs/astro.config.mjs index 7ae8d6f7b..55692c546 100644 --- a/examples/docs/astro.config.mjs +++ b/examples/docs/astro.config.mjs @@ -10,4 +10,5 @@ export default defineConfig({ // Enable React for the Algolia search component. react(), ], + site: `http://astro.build`, }); diff --git a/examples/docs/package.json b/examples/docs/package.json index a18a39021..392acdbac 100644 --- a/examples/docs/package.json +++ b/examples/docs/package.json @@ -14,12 +14,12 @@ "@docsearch/react": "^3.1.0", "@types/react": "^17.0.45", "preact": "^10.7.3", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": "^18.1.0", + "react-dom": "^18.1.0" }, "devDependencies": { - "@astrojs/preact": "^0.1.3", - "@astrojs/react": "^0.1.3", - "astro": "^1.0.0-beta.46" + "@astrojs/preact": "^0.5.2", + "@astrojs/react": "^0.4.2", + "astro": "^1.0.0-beta.73" } } diff --git a/examples/docs/src/components/Footer/AvatarList.astro b/examples/docs/src/components/Footer/AvatarList.astro index c57ee2eb1..6f3ff1a7f 100644 --- a/examples/docs/src/components/Footer/AvatarList.astro +++ b/examples/docs/src/components/Footer/AvatarList.astro @@ -1,6 +1,6 @@ --- // fetch all commits for just this page's path -const path = 'docs/' + Astro.props.path; +const path = "docs/" + Astro.props.path; const url = `https://api.github.com/repos/withastro/astro/commits?path=${path}`; const commitsURL = `https://github.com/withastro/astro/commits/main/${path}`; @@ -8,16 +8,18 @@ async function getCommits(url) { try { const token = import.meta.env.SNOWPACK_PUBLIC_GITHUB_TOKEN; if (!token) { - throw new Error('Cannot find "SNOWPACK_PUBLIC_GITHUB_TOKEN" used for escaping rate-limiting.'); + throw new Error( + 'Cannot find "SNOWPACK_PUBLIC_GITHUB_TOKEN" used for escaping rate-limiting.' + ); } - const auth = `Basic ${Buffer.from(token, 'binary').toString('base64')}`; + const auth = `Basic ${Buffer.from(token, "binary").toString("base64")}`; const res = await fetch(url, { - method: 'GET', + method: "GET", headers: { Authorization: auth, - 'User-Agent': 'astro-docs/1.0', + "User-Agent": "astro-docs/1.0", }, }); @@ -65,14 +67,22 @@ const additionalContributors = unique.length - recentContributors.length; // lis {recentContributors.map((item) => (
  • - {`Contributor + {`Contributor
  • ))} {additionalContributors > 0 && ( - {`and ${additionalContributors} additional contributor${additionalContributors > 1 ? 's' : ''}.`} + {`and ${additionalContributors} additional contributor${ + additionalContributors > 1 ? "s" : "" + }.`} )} {unique.length === 0 && Contributors} diff --git a/examples/docs/src/components/Footer/Footer.astro b/examples/docs/src/components/Footer/Footer.astro index d13f832e5..ab0634976 100644 --- a/examples/docs/src/components/Footer/Footer.astro +++ b/examples/docs/src/components/Footer/Footer.astro @@ -1,5 +1,5 @@ --- -import AvatarList from './AvatarList.astro'; +import AvatarList from "./AvatarList.astro"; const { path } = Astro.props; --- diff --git a/examples/docs/src/components/HeadCommon.astro b/examples/docs/src/components/HeadCommon.astro index b6a74cdc6..bc3a3955a 100644 --- a/examples/docs/src/components/HeadCommon.astro +++ b/examples/docs/src/components/HeadCommon.astro @@ -1,6 +1,6 @@ --- -import '../styles/theme.css'; -import '../styles/index.css'; +import "../styles/theme.css"; +import "../styles/index.css"; --- @@ -15,19 +15,24 @@ import '../styles/index.css'; - + - + diff --git a/examples/docs/src/components/HeadSEO.astro b/examples/docs/src/components/HeadSEO.astro index 003872bc9..43a19c52b 100644 --- a/examples/docs/src/components/HeadSEO.astro +++ b/examples/docs/src/components/HeadSEO.astro @@ -1,11 +1,13 @@ --- -import { SITE, OPEN_GRAPH } from '../config.ts'; +import { SITE, OPEN_GRAPH } from "../config.ts"; export interface Props { content: any; site: any; canonicalURL: URL | string; } -const { content = {}, canonicalURL } = Astro.props; + +const canonicalURL = new URL(Astro.url.pathname, Astro.site); +const { content = {} } = Astro.props; const formattedContentTitle = content.title ? `${content.title} 🚀 ${SITE.title}` : SITE.title; const imageSrc = content?.image?.src ?? OPEN_GRAPH.image.src; const canonicalImageSrc = new URL(imageSrc, Astro.site); @@ -22,14 +24,21 @@ const imageAlt = content?.image?.alt ?? OPEN_GRAPH.image.alt; - + - + diff --git a/examples/docs/src/components/Header/AstroLogo.astro b/examples/docs/src/components/Header/AstroLogo.astro index 7d6891dcb..840cbf139 100644 --- a/examples/docs/src/components/Header/AstroLogo.astro +++ b/examples/docs/src/components/Header/AstroLogo.astro @@ -2,7 +2,14 @@ const { size } = Astro.props; --- -
      {section.children.map((child) => ( @@ -44,10 +47,10 @@ const sidebarSections = SIDEBAR[langCode].reduce((col, item, i) => { @@ -100,13 +103,13 @@ const sidebarSections = SIDEBAR[langCode].reduce((col, item, i) => { background-color: var(--theme-bg-hover); } - .nav-link a[aria-current='page'] { + .nav-link a[aria-current="page"] { color: var(--theme-text-accent); background-color: var(--theme-bg-accent); font-weight: 600; } - :global(:root.theme-dark) .nav-link a[aria-current='page'] { + :global(:root.theme-dark) .nav-link a[aria-current="page"] { color: hsla(var(--color-base-white), 100%, 1); } diff --git a/examples/docs/src/components/PageContent/PageContent.astro b/examples/docs/src/components/PageContent/PageContent.astro index 32db5cd58..1d14515c1 100644 --- a/examples/docs/src/components/PageContent/PageContent.astro +++ b/examples/docs/src/components/PageContent/PageContent.astro @@ -1,6 +1,6 @@ --- -import MoreMenu from '../RightSidebar/MoreMenu.astro'; -import TableOfContents from '../RightSidebar/TableOfContents.tsx'; +import MoreMenu from "../RightSidebar/MoreMenu.astro"; +import TableOfContents from "../RightSidebar/TableOfContents.tsx"; const { content, githubEditUrl } = Astro.props; const title = content.title; diff --git a/examples/docs/src/components/RightSidebar/MoreMenu.astro b/examples/docs/src/components/RightSidebar/MoreMenu.astro index 649e02c29..a78f86d59 100644 --- a/examples/docs/src/components/RightSidebar/MoreMenu.astro +++ b/examples/docs/src/components/RightSidebar/MoreMenu.astro @@ -1,6 +1,6 @@ --- -import ThemeToggleButton from './ThemeToggleButton.tsx'; -import * as CONFIG from '../../config'; +import ThemeToggleButton from "./ThemeToggleButton.tsx"; +import * as CONFIG from "../../config"; const { editHref } = Astro.props; const showMoreSection = CONFIG.COMMUNITY_INVITE_URL || editHref; --- @@ -25,7 +25,7 @@ const showMoreSection = CONFIG.COMMUNITY_INVITE_URL || editHref; + /> Edit this page @@ -49,7 +49,7 @@ const showMoreSection = CONFIG.COMMUNITY_INVITE_URL || editHref; + /> Join our community diff --git a/examples/docs/src/components/RightSidebar/RightSidebar.astro b/examples/docs/src/components/RightSidebar/RightSidebar.astro index a0b5779dc..f61fb010f 100644 --- a/examples/docs/src/components/RightSidebar/RightSidebar.astro +++ b/examples/docs/src/components/RightSidebar/RightSidebar.astro @@ -1,6 +1,6 @@ --- -import TableOfContents from './TableOfContents.tsx'; -import MoreMenu from './MoreMenu.astro'; +import TableOfContents from "./TableOfContents.tsx"; +import MoreMenu from "./MoreMenu.astro"; const { content, githubEditUrl } = Astro.props; const headers = content.astro.headers; --- diff --git a/examples/docs/src/layouts/MainLayout.astro b/examples/docs/src/layouts/MainLayout.astro index 9939592a9..93ba323e4 100644 --- a/examples/docs/src/layouts/MainLayout.astro +++ b/examples/docs/src/layouts/MainLayout.astro @@ -1,23 +1,24 @@ --- -import HeadCommon from '../components/HeadCommon.astro'; -import HeadSEO from '../components/HeadSEO.astro'; -import Header from '../components/Header/Header.astro'; -import Footer from '../components/Footer/Footer.astro'; -import PageContent from '../components/PageContent/PageContent.astro'; -import LeftSidebar from '../components/LeftSidebar/LeftSidebar.astro'; -import RightSidebar from '../components/RightSidebar/RightSidebar.astro'; -import * as CONFIG from '../config'; +import HeadCommon from "../components/HeadCommon.astro"; +import HeadSEO from "../components/HeadSEO.astro"; +import Header from "../components/Header/Header.astro"; +import Footer from "../components/Footer/Footer.astro"; +import PageContent from "../components/PageContent/PageContent.astro"; +import LeftSidebar from "../components/LeftSidebar/LeftSidebar.astro"; +import RightSidebar from "../components/RightSidebar/RightSidebar.astro"; +import * as CONFIG from "../config"; const { content = {} } = Astro.props; -const currentPage = new URL(Astro.request.url).pathname; -const currentFile = `src/pages${currentPage.replace(/\/$/, '')}.md`; +const canonicalURL = new URL(Astro.url.pathname, Astro.site); +const currentPage = Astro.url.pathname; +const currentFile = `src/pages${currentPage.replace(/\/$/, "")}.md`; const githubEditUrl = CONFIG.GITHUB_EDIT_URL && CONFIG.GITHUB_EDIT_URL + currentFile; --- - + - + {content.title ? `${content.title} 🚀 ${CONFIG.SITE.title}` : CONFIG.SITE.title}

      - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi quam arcu, rhoncus et dui at, volutpat viverra augue. Suspendisse placerat libero tellus, ut consequat ligula - rutrum id. Vestibulum lectus libero, viverra in lacus eget, porttitor tincidunt leo. Integer sit amet turpis et felis fringilla lacinia in id nibh. Proin vitae dapibus odio. - Mauris ornare eget urna id volutpat. Duis tellus nisi, hendrerit id sodales in, rutrum a quam. Proin tempor velit turpis, et tempor lacus sagittis in. Sed congue mauris quis nibh - posuere, nec semper lacus auctor. Morbi sit amet enim sit amet arcu ullamcorper sollicitudin. Donec dignissim posuere tincidunt. Donec ultrices quam nec orci venenatis suscipit. - Maecenas sapien quam, pretium sit amet ullamcorper at, vulputate sit amet urna. Suspendisse potenti. Integer in sapien turpis. Nulla accumsan viverra diam, quis convallis magna - finibus eget. Integer sed eros bibendum, consequat velit sit amet, tincidunt orci. Mauris varius id metus in fringilla. Vestibulum dignissim massa eget erat luctus, ac congue - mauris pellentesque. In et tempor dolor. Cras blandit congue lorem at facilisis. Aenean vel lacinia quam. Pellentesque luctus metus ut scelerisque efficitur. Mauris laoreet - sodales libero eget luctus. Proin at congue dui, a cursus risus. Pellentesque lorem sem, rhoncus fermentum arcu ut, euismod fermentum ligula. Nullam eu orci posuere, laoreet leo - in, commodo dolor. Fusce at felis elementum, commodo justo at, placerat justo. Nam feugiat scelerisque arcu, ut fermentum tellus elementum in. Sed ut vulputate ante. Morbi cursus - arcu quis odio convallis egestas. Donec vulputate vestibulum dolor eget tristique. Nullam tempor semper augue, vitae lobortis neque tempor ac. Pellentesque massa leo, congue id - ligula auctor, sollicitudin pharetra lorem. Curabitur a lacus porttitor, venenatis est quis, mattis velit. Fusce hendrerit lobortis mi ac efficitur. Mauris ornare, lorem sed - varius faucibus, nisi dui pretium urna, sit amet lacinia nibh ligula in ipsum. Phasellus gravida, metus eget ornare ultrices, dolor ipsum consectetur erat, ac aliquet eros metus - sed lectus. Nullam eleifend posuere rhoncus. Curabitur semper ligula vel ante posuere, at blandit orci accumsan. Vivamus accumsan metus in lorem laoreet, a luctus arcu tempus. - Donec posuere sollicitudin nulla at vulputate. Nulla condimentum imperdiet purus, et lobortis ligula iaculis in. Donec suscipit viverra neque, ut elementum eros lacinia ut. Fusce - at odio enim. Donec rutrum lectus sit amet est auctor, ac rhoncus lorem imperdiet. Curabitur commodo ex est, non tempus massa pulvinar nec. Sed fermentum, lectus eget ultricies - luctus, enim sem sodales quam, sed laoreet tortor sem feugiat nisi. Morbi molestie vehicula viverra. Integer accumsan mi in orci ultrices posuere. Integer mi quam, faucibus et - aliquet imperdiet, ornare ac ex. Nunc mattis molestie nisi, eu venenatis nibh vehicula at. Aliquam ut elit consectetur, finibus lorem sed, condimentum sapien. Praesent fermentum - iaculis orci, vitae tincidunt est viverra nec. Morbi semper turpis sed lectus ornare tristique. Sed congue dui ex. Maecenas orci ligula, imperdiet sit amet accumsan et, finibus a - velit. Ut vitae blandit eros. Nam gravida nec ipsum non volutpat. Integer quam metus, porttitor id ante sed, rutrum porta quam. Aenean at mattis ante. Morbi id libero eget risus - sagittis gravida. Proin consequat sapien a dignissim posuere. Ut luctus sed metus ut elementum. Mauris tincidunt condimentum risus at bibendum. Aenean a sapien justo. Morbi vel - neque in eros venenatis scelerisque vitae nec justo. Vestibulum lacinia, dui eu sollicitudin ornare, est elit vestibulum arcu, nec ultrices augue turpis in massa. Duis commodo - lectus sed est posuere, et mollis nisi dapibus. Sed id ultrices arcu. Praesent tempor sodales aliquet. Donec suscipit ipsum eu odio cursus, quis sodales metus sodales. Nunc - vestibulum massa at felis ullamcorper cursus. Pellentesque facilisis ante ut lectus vulputate vestibulum. Nullam pharetra felis ac lacus sodales, vel suscipit metus faucibus. - Donec facilisis imperdiet risus, in volutpat odio tincidunt a. Aliquam vitae leo lorem. Proin scelerisque efficitur velit, vel cursus ipsum accumsan id. Morbi nibh nulla, pretium - quis venenatis et, pharetra et sapien. Cras lobortis, massa sit amet blandit pulvinar, mi magna condimentum ex, quis commodo ipsum est quis metus. Maecenas pulvinar, leo sit amet - congue pulvinar, neque magna ultrices mi, et rhoncus massa sapien quis libero. Etiam a nunc et ipsum faucibus pretium. Nulla facilisi. Nunc nec dolor velit. In semper semper mi - non condimentum. Pellentesque vehicula volutpat odio, a semper sem porta a. In sit amet lectus rutrum, sollicitudin augue auctor, maximus quam. Mauris congue, nisl non fermentum - iaculis, leo erat interdum lorem, quis bibendum arcu eros et elit. Fusce tortor ante, gravida a arcu in, lacinia finibus ante. Phasellus facilisis lectus vitae sapien feugiat - laoreet. Curabitur ultricies libero sit amet condimentum suscipit. Duis at vestibulum mi. Suspendisse at neque augue. Duis ornare a mauris id efficitur. Suspendisse in dui nec - dolor dignissim venenatis. Curabitur a magna turpis. Aliquam at commodo tellus. In id sem interdum, suscipit felis at, mattis velit. Proin accumsan sodales felis a lacinia. - Curabitur at magna a massa varius maximus. Vestibulum in auctor ante. Donec aliquam tortor sed nulla rutrum, et egestas mi efficitur. Sed viverra quam tellus, quis vulputate - felis ultrices sed. Mauris sagittis, neque quis laoreet gravida, nisi est ultrices mi, at tempus nunc justo non dui. Suspendisse porttitor tortor nulla, eget luctus quam finibus - id. Proin sodales eros mollis tellus euismod luctus a eu mi. Quisque consectetur iaculis nibh, at mollis tellus volutpat eu. Aenean a nulla vel lectus rhoncus aliquam. Donec - vitae lacinia neque. Donec non lectus eget sem finibus ultrices vel nec felis. Proin fringilla mi a leo rhoncus aliquam sit amet quis augue. Duis congue ligula at est suscipit - fringilla. Proin aliquam erat ut consequat dapibus. Suspendisse non nisi orci. Donec ac erat vel libero egestas laoreet. Nullam felis odio, tincidunt eget eleifend a, porttitor - eu nisi. Suspendisse tristique eros at dolor scelerisque hendrerit. Etiam id dignissim lectus. Fusce lacinia metus eu risus placerat, et eleifend nunc ultrices. Ut gravida a dui - sed volutpat. Sed semper quis erat sed ornare. Pellentesque sapien sem, fermentum vel nunc at, auctor posuere nisl. Maecenas aliquet lobortis leo. Vivamus tellus urna, dignissim - consectetur sapien vitae, hendrerit varius sem. Nunc dictum tristique fermentum. Duis eu suscipit odio. Curabitur quis egestas neque. Fusce eu fringilla orci, vitae euismod - sapien. Donec sit amet iaculis urna. Phasellus maximus nisl in libero bibendum volutpat. Nulla at vehicula lorem. Phasellus varius, elit ac suscipit pretium, turpis ipsum - porttitor lectus, vitae ullamcorper orci velit ut ligula. Proin mollis, orci vel commodo auctor, sapien ipsum vulputate enim, sit amet aliquam nulla sapien ut sapien. Proin - tincidunt ex non massa aliquet, quis aliquam nulla egestas. Maecenas mollis turpis dapibus, dignissim lectus tincidunt, egestas ligula. Suspendisse in lobortis purus. Sed tellus - tellus, mollis eget tempor sed, interdum ut lectus. Nulla sed ex efficitur, porta dui cursus, tristique elit. Maecenas tincidunt tortor vitae massa laoreet ultricies. Mauris ac - elit vitae orci eleifend ornare non eu ligula. Curabitur venenatis nulla ut neque tristique, non tincidunt justo pretium. Suspendisse mattis semper dui, eget vestibulum risus - elementum sed. In consequat nisi sit amet nulla euismod, at convallis tortor tincidunt. Aliquam hendrerit venenatis risus in interdum. Duis ullamcorper imperdiet elit sit amet - blandit. Mauris placerat lacinia velit id pharetra. Nam nec iaculis dui. Etiam odio mi, fringilla in rutrum in, viverra quis tellus. Aliquam egestas mauris id nisi facilisis, in - laoreet nibh malesuada. Ut eu dui laoreet, venenatis tellus ac, feugiat mauris. Nunc in velit laoreet, venenatis tellus quis, blandit dolor. Nulla ultrices et neque id placerat. - Nulla eu interdum nulla. Aliquam molestie enim quis rutrum finibus. Nulla bibendum orci vel scelerisque posuere. Praesent quis magna molestie, luctus tortor tincidunt, gravida - neque. Quisque et ligula eget magna viverra interdum at a sapien. Mauris ornare efficitur nunc sed vulputate. Praesent laoreet mollis tincidunt. Vestibulum id arcu vulputate, - eleifend enim vel, accumsan turpis. Morbi faucibus convallis tellus, semper laoreet justo lacinia nec. Sed sodales ligula consectetur dui rhoncus, et convallis metus accumsan. - Sed ullamcorper non ex sit amet ultricies. Donec finibus nulla nec blandit porttitor. Etiam aliquam quis leo a imperdiet. Cras at lobortis est. In convallis semper enim, ac porta - ligula fringilla at. Donec augue est, facilisis et odio sit amet, viverra ullamcorper nisl. Ut porta velit nec sem lacinia, sit amet mollis magna auctor. Nulla lobortis lacinia - mauris nec sagittis. Suspendisse rutrum ex vel nisi interdum hendrerit et ut purus. Sed consectetur sodales nibh eget tempus. Aenean egestas luctus viverra. Integer fermentum - tincidunt tellus, nec rhoncus velit hendrerit vitae. Proin quis neque porttitor, scelerisque risus gravida, volutpat sem. Fusce nec ex rhoncus, tempor libero nec, pellentesque - ex. Integer quis iaculis purus. Nullam vitae imperdiet orci. Sed sit amet eros condimentum, scelerisque turpis facilisis, dignissim ante. Proin quis tristique lacus, sed sagittis - nisl. Cras pharetra ultrices purus, sed ullamcorper nisi fringilla eu. Praesent risus turpis, auctor in fringilla a, fringilla eu dolor. Phasellus auctor tristique enim, eleifend - molestie diam venenatis ut. Mauris dapibus, enim eget pharetra semper, nulla dui porttitor mi, auctor hendrerit augue nulla quis urna. Aliquam in cursus justo. + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi quam arcu, rhoncus et dui at, + volutpat viverra augue. Suspendisse placerat libero tellus, ut consequat ligula rutrum id. + Vestibulum lectus libero, viverra in lacus eget, porttitor tincidunt leo. Integer sit amet turpis + et felis fringilla lacinia in id nibh. Proin vitae dapibus odio. Mauris ornare eget urna id + volutpat. Duis tellus nisi, hendrerit id sodales in, rutrum a quam. Proin tempor velit turpis, et + tempor lacus sagittis in. Sed congue mauris quis nibh posuere, nec semper lacus auctor. Morbi sit + amet enim sit amet arcu ullamcorper sollicitudin. Donec dignissim posuere tincidunt. Donec + ultrices quam nec orci venenatis suscipit. Maecenas sapien quam, pretium sit amet ullamcorper at, + vulputate sit amet urna. Suspendisse potenti. Integer in sapien turpis. Nulla accumsan viverra + diam, quis convallis magna finibus eget. Integer sed eros bibendum, consequat velit sit amet, + tincidunt orci. Mauris varius id metus in fringilla. Vestibulum dignissim massa eget erat luctus, + ac congue mauris pellentesque. In et tempor dolor. Cras blandit congue lorem at facilisis. Aenean + vel lacinia quam. Pellentesque luctus metus ut scelerisque efficitur. Mauris laoreet sodales + libero eget luctus. Proin at congue dui, a cursus risus. Pellentesque lorem sem, rhoncus fermentum + arcu ut, euismod fermentum ligula. Nullam eu orci posuere, laoreet leo in, commodo dolor. Fusce at + felis elementum, commodo justo at, placerat justo. Nam feugiat scelerisque arcu, ut fermentum + tellus elementum in. Sed ut vulputate ante. Morbi cursus arcu quis odio convallis egestas. Donec + vulputate vestibulum dolor eget tristique. Nullam tempor semper augue, vitae lobortis neque tempor + ac. Pellentesque massa leo, congue id ligula auctor, sollicitudin pharetra lorem. Curabitur a + lacus porttitor, venenatis est quis, mattis velit. Fusce hendrerit lobortis mi ac efficitur. + Mauris ornare, lorem sed varius faucibus, nisi dui pretium urna, sit amet lacinia nibh ligula in + ipsum. Phasellus gravida, metus eget ornare ultrices, dolor ipsum consectetur erat, ac aliquet + eros metus sed lectus. Nullam eleifend posuere rhoncus. Curabitur semper ligula vel ante posuere, + at blandit orci accumsan. Vivamus accumsan metus in lorem laoreet, a luctus arcu tempus. Donec + posuere sollicitudin nulla at vulputate. Nulla condimentum imperdiet purus, et lobortis ligula + iaculis in. Donec suscipit viverra neque, ut elementum eros lacinia ut. Fusce at odio enim. Donec + rutrum lectus sit amet est auctor, ac rhoncus lorem imperdiet. Curabitur commodo ex est, non + tempus massa pulvinar nec. Sed fermentum, lectus eget ultricies luctus, enim sem sodales quam, sed + laoreet tortor sem feugiat nisi. Morbi molestie vehicula viverra. Integer accumsan mi in orci + ultrices posuere. Integer mi quam, faucibus et aliquet imperdiet, ornare ac ex. Nunc mattis + molestie nisi, eu venenatis nibh vehicula at. Aliquam ut elit consectetur, finibus lorem sed, + condimentum sapien. Praesent fermentum iaculis orci, vitae tincidunt est viverra nec. Morbi semper + turpis sed lectus ornare tristique. Sed congue dui ex. Maecenas orci ligula, imperdiet sit amet + accumsan et, finibus a velit. Ut vitae blandit eros. Nam gravida nec ipsum non volutpat. Integer + quam metus, porttitor id ante sed, rutrum porta quam. Aenean at mattis ante. Morbi id libero eget + risus sagittis gravida. Proin consequat sapien a dignissim posuere. Ut luctus sed metus ut + elementum. Mauris tincidunt condimentum risus at bibendum. Aenean a sapien justo. Morbi vel neque + in eros venenatis scelerisque vitae nec justo. Vestibulum lacinia, dui eu sollicitudin ornare, est + elit vestibulum arcu, nec ultrices augue turpis in massa. Duis commodo lectus sed est posuere, et + mollis nisi dapibus. Sed id ultrices arcu. Praesent tempor sodales aliquet. Donec suscipit ipsum + eu odio cursus, quis sodales metus sodales. Nunc vestibulum massa at felis ullamcorper cursus. + Pellentesque facilisis ante ut lectus vulputate vestibulum. Nullam pharetra felis ac lacus + sodales, vel suscipit metus faucibus. Donec facilisis imperdiet risus, in volutpat odio tincidunt + a. Aliquam vitae leo lorem. Proin scelerisque efficitur velit, vel cursus ipsum accumsan id. Morbi + nibh nulla, pretium quis venenatis et, pharetra et sapien. Cras lobortis, massa sit amet blandit + pulvinar, mi magna condimentum ex, quis commodo ipsum est quis metus. Maecenas pulvinar, leo sit + amet congue pulvinar, neque magna ultrices mi, et rhoncus massa sapien quis libero. Etiam a nunc + et ipsum faucibus pretium. Nulla facilisi. Nunc nec dolor velit. In semper semper mi non + condimentum. Pellentesque vehicula volutpat odio, a semper sem porta a. In sit amet lectus rutrum, + sollicitudin augue auctor, maximus quam. Mauris congue, nisl non fermentum iaculis, leo erat + interdum lorem, quis bibendum arcu eros et elit. Fusce tortor ante, gravida a arcu in, lacinia + finibus ante. Phasellus facilisis lectus vitae sapien feugiat laoreet. Curabitur ultricies libero + sit amet condimentum suscipit. Duis at vestibulum mi. Suspendisse at neque augue. Duis ornare a + mauris id efficitur. Suspendisse in dui nec dolor dignissim venenatis. Curabitur a magna turpis. + Aliquam at commodo tellus. In id sem interdum, suscipit felis at, mattis velit. Proin accumsan + sodales felis a lacinia. Curabitur at magna a massa varius maximus. Vestibulum in auctor ante. + Donec aliquam tortor sed nulla rutrum, et egestas mi efficitur. Sed viverra quam tellus, quis + vulputate felis ultrices sed. Mauris sagittis, neque quis laoreet gravida, nisi est ultrices mi, + at tempus nunc justo non dui. Suspendisse porttitor tortor nulla, eget luctus quam finibus id. + Proin sodales eros mollis tellus euismod luctus a eu mi. Quisque consectetur iaculis nibh, at + mollis tellus volutpat eu. Aenean a nulla vel lectus rhoncus aliquam. Donec vitae lacinia neque. + Donec non lectus eget sem finibus ultrices vel nec felis. Proin fringilla mi a leo rhoncus aliquam + sit amet quis augue. Duis congue ligula at est suscipit fringilla. Proin aliquam erat ut consequat + dapibus. Suspendisse non nisi orci. Donec ac erat vel libero egestas laoreet. Nullam felis odio, + tincidunt eget eleifend a, porttitor eu nisi. Suspendisse tristique eros at dolor scelerisque + hendrerit. Etiam id dignissim lectus. Fusce lacinia metus eu risus placerat, et eleifend nunc + ultrices. Ut gravida a dui sed volutpat. Sed semper quis erat sed ornare. Pellentesque sapien sem, + fermentum vel nunc at, auctor posuere nisl. Maecenas aliquet lobortis leo. Vivamus tellus urna, + dignissim consectetur sapien vitae, hendrerit varius sem. Nunc dictum tristique fermentum. Duis eu + suscipit odio. Curabitur quis egestas neque. Fusce eu fringilla orci, vitae euismod sapien. Donec + sit amet iaculis urna. Phasellus maximus nisl in libero bibendum volutpat. Nulla at vehicula + lorem. Phasellus varius, elit ac suscipit pretium, turpis ipsum porttitor lectus, vitae + ullamcorper orci velit ut ligula. Proin mollis, orci vel commodo auctor, sapien ipsum vulputate + enim, sit amet aliquam nulla sapien ut sapien. Proin tincidunt ex non massa aliquet, quis aliquam + nulla egestas. Maecenas mollis turpis dapibus, dignissim lectus tincidunt, egestas ligula. + Suspendisse in lobortis purus. Sed tellus tellus, mollis eget tempor sed, interdum ut lectus. + Nulla sed ex efficitur, porta dui cursus, tristique elit. Maecenas tincidunt tortor vitae massa + laoreet ultricies. Mauris ac elit vitae orci eleifend ornare non eu ligula. Curabitur venenatis + nulla ut neque tristique, non tincidunt justo pretium. Suspendisse mattis semper dui, eget + vestibulum risus elementum sed. In consequat nisi sit amet nulla euismod, at convallis tortor + tincidunt. Aliquam hendrerit venenatis risus in interdum. Duis ullamcorper imperdiet elit sit amet + blandit. Mauris placerat lacinia velit id pharetra. Nam nec iaculis dui. Etiam odio mi, fringilla + in rutrum in, viverra quis tellus. Aliquam egestas mauris id nisi facilisis, in laoreet nibh + malesuada. Ut eu dui laoreet, venenatis tellus ac, feugiat mauris. Nunc in velit laoreet, + venenatis tellus quis, blandit dolor. Nulla ultrices et neque id placerat. Nulla eu interdum + nulla. Aliquam molestie enim quis rutrum finibus. Nulla bibendum orci vel scelerisque posuere. + Praesent quis magna molestie, luctus tortor tincidunt, gravida neque. Quisque et ligula eget magna + viverra interdum at a sapien. Mauris ornare efficitur nunc sed vulputate. Praesent laoreet mollis + tincidunt. Vestibulum id arcu vulputate, eleifend enim vel, accumsan turpis. Morbi faucibus + convallis tellus, semper laoreet justo lacinia nec. Sed sodales ligula consectetur dui rhoncus, et + convallis metus accumsan. Sed ullamcorper non ex sit amet ultricies. Donec finibus nulla nec + blandit porttitor. Etiam aliquam quis leo a imperdiet. Cras at lobortis est. In convallis semper + enim, ac porta ligula fringilla at. Donec augue est, facilisis et odio sit amet, viverra + ullamcorper nisl. Ut porta velit nec sem lacinia, sit amet mollis magna auctor. Nulla lobortis + lacinia mauris nec sagittis. Suspendisse rutrum ex vel nisi interdum hendrerit et ut purus. Sed + consectetur sodales nibh eget tempus. Aenean egestas luctus viverra. Integer fermentum tincidunt + tellus, nec rhoncus velit hendrerit vitae. Proin quis neque porttitor, scelerisque risus gravida, + volutpat sem. Fusce nec ex rhoncus, tempor libero nec, pellentesque ex. Integer quis iaculis + purus. Nullam vitae imperdiet orci. Sed sit amet eros condimentum, scelerisque turpis facilisis, + dignissim ante. Proin quis tristique lacus, sed sagittis nisl. Cras pharetra ultrices purus, sed + ullamcorper nisi fringilla eu. Praesent risus turpis, auctor in fringilla a, fringilla eu dolor. + Phasellus auctor tristique enim, eleifend molestie diam venenatis ut. Mauris dapibus, enim eget + pharetra semper, nulla dui porttitor mi, auctor hendrerit augue nulla quis urna. Aliquam in cursus + justo.

      diff --git a/examples/framework-lit/src/components/Test.js b/examples/integrations-playground/src/components/calc-add.js similarity index 62% rename from examples/framework-lit/src/components/Test.js rename to examples/integrations-playground/src/components/calc-add.js index 7f565f777..b0b3978bf 100644 --- a/examples/framework-lit/src/components/Test.js +++ b/examples/integrations-playground/src/components/calc-add.js @@ -1,8 +1,6 @@ import { LitElement, html } from 'lit'; -export const tagName = 'calc-add'; - -class CalcAdd extends LitElement { +export class CalcAdd extends LitElement { static get properties() { return { num: { @@ -16,4 +14,4 @@ class CalcAdd extends LitElement { } } -customElements.define(tagName, CalcAdd); +customElements.define('calc-add', CalcAdd); diff --git a/examples/framework-lit/src/components/Counter.js b/examples/integrations-playground/src/components/my-counter.js similarity index 76% rename from examples/framework-lit/src/components/Counter.js rename to examples/integrations-playground/src/components/my-counter.js index 35fa8dbbb..adc9e4a3d 100644 --- a/examples/framework-lit/src/components/Counter.js +++ b/examples/integrations-playground/src/components/my-counter.js @@ -1,8 +1,6 @@ import { LitElement, html } from 'lit'; -export const tagName = 'my-counter'; - -class Counter extends LitElement { +export class MyCounter extends LitElement { static get properties() { return { count: { @@ -31,4 +29,4 @@ class Counter extends LitElement { } } -customElements.define(tagName, Counter); +customElements.define('my-counter', MyCounter); diff --git a/examples/integrations-playground/src/pages/foo.astro b/examples/integrations-playground/src/pages/foo.astro index fbdd5bb1f..0e9785f14 100644 --- a/examples/integrations-playground/src/pages/foo.astro +++ b/examples/integrations-playground/src/pages/foo.astro @@ -1,6 +1,6 @@ --- // Page 2! -import Link from '../components/Link.jsx'; +import Link from "../components/Link.jsx"; --- @@ -10,6 +10,6 @@ import Link from '../components/Link.jsx'; Demo: Page 2 - + diff --git a/examples/integrations-playground/src/pages/index.astro b/examples/integrations-playground/src/pages/index.astro index 06c9aa3d8..f2b0d2c8a 100644 --- a/examples/integrations-playground/src/pages/index.astro +++ b/examples/integrations-playground/src/pages/index.astro @@ -1,9 +1,9 @@ --- -import Lorem from '../components/Lorem.astro'; -import Link from '../components/Link.jsx'; -import SolidCounter from '../components/SolidCounter.jsx'; -import '../components/Test.js'; -import '../components/Counter.js'; +import Lorem from "../components/Lorem.astro"; +import Link from "../components/Link.jsx"; +import SolidCounter from "../components/SolidCounter.jsx"; +import { CalcAdd } from "../components/calc-add.js"; +import { MyCounter } from "../components/my-counter.js"; --- @@ -15,39 +15,40 @@ import '../components/Counter.js';

      Test app

      - Party Mode! - Colors changing = partytown is enabled -

      - - - + Party Mode! + Colors changing = partytown is enabled + + + + - - + + - - + + diff --git a/examples/integrations-playground/tsconfig.json b/examples/integrations-playground/tsconfig.json index 7ac81809a..4db6ee701 100644 --- a/examples/integrations-playground/tsconfig.json +++ b/examples/integrations-playground/tsconfig.json @@ -9,7 +9,7 @@ "resolveJsonModule": true, // Enable stricter transpilation for better output. "isolatedModules": true, - // Add type definitions for our Vite runtime. - "types": ["vite/client"] + // Add type definitions for our Astro runtime. + "types": ["astro/client"] } } diff --git a/examples/minimal/package.json b/examples/minimal/package.json index fefe27288..ebb2a16e3 100644 --- a/examples/minimal/package.json +++ b/examples/minimal/package.json @@ -9,6 +9,6 @@ "preview": "astro preview" }, "devDependencies": { - "astro": "^1.0.0-beta.46" + "astro": "^1.0.0-beta.73" } } diff --git a/examples/minimal/src/pages/index.astro b/examples/minimal/src/pages/index.astro index 346e155c4..4389d5d25 100644 --- a/examples/minimal/src/pages/index.astro +++ b/examples/minimal/src/pages/index.astro @@ -1,6 +1,6 @@ --- +--- ---- diff --git a/examples/minimal/tsconfig.json b/examples/minimal/tsconfig.json index 7ac81809a..4db6ee701 100644 --- a/examples/minimal/tsconfig.json +++ b/examples/minimal/tsconfig.json @@ -9,7 +9,7 @@ "resolveJsonModule": true, // Enable stricter transpilation for better output. "isolatedModules": true, - // Add type definitions for our Vite runtime. - "types": ["vite/client"] + // Add type definitions for our Astro runtime. + "types": ["astro/client"] } } diff --git a/examples/non-html-pages/package.json b/examples/non-html-pages/package.json index 7c0c4aedc..2c4342d42 100644 --- a/examples/non-html-pages/package.json +++ b/examples/non-html-pages/package.json @@ -9,6 +9,6 @@ "preview": "astro preview" }, "devDependencies": { - "astro": "^1.0.0-beta.46" + "astro": "^1.0.0-beta.73" } } diff --git a/examples/non-html-pages/src/pages/index.astro b/examples/non-html-pages/src/pages/index.astro index 9abb797e4..b6fc1decf 100644 --- a/examples/non-html-pages/src/pages/index.astro +++ b/examples/non-html-pages/src/pages/index.astro @@ -1,4 +1,3 @@ - @@ -12,7 +11,9 @@ // can fetch them directly in the browser. const response = await fetch(`/about.json`); const data = await response.json(); - document.getElementById('result').innerHTML = `Load complete!
      Built with: ${data.name}!`; + document.getElementById( + "result" + ).innerHTML = `Load complete!
      Built with: ${data.name}!`; diff --git a/examples/non-html-pages/tsconfig.json b/examples/non-html-pages/tsconfig.json index 7ac81809a..4db6ee701 100644 --- a/examples/non-html-pages/tsconfig.json +++ b/examples/non-html-pages/tsconfig.json @@ -9,7 +9,7 @@ "resolveJsonModule": true, // Enable stricter transpilation for better output. "isolatedModules": true, - // Add type definitions for our Vite runtime. - "types": ["vite/client"] + // Add type definitions for our Astro runtime. + "types": ["astro/client"] } } diff --git a/examples/portfolio/package.json b/examples/portfolio/package.json index 15e00e442..69c65eb26 100644 --- a/examples/portfolio/package.json +++ b/examples/portfolio/package.json @@ -9,8 +9,8 @@ "preview": "astro preview" }, "devDependencies": { - "@astrojs/preact": "^0.1.3", - "astro": "^1.0.0-beta.46", + "@astrojs/preact": "^0.5.2", + "astro": "^1.0.0-beta.73", "sass": "^1.52.2" }, "dependencies": { diff --git a/examples/portfolio/src/components/MainHead.astro b/examples/portfolio/src/components/MainHead.astro index 978c1d245..9d9bc209d 100644 --- a/examples/portfolio/src/components/MainHead.astro +++ b/examples/portfolio/src/components/MainHead.astro @@ -1,6 +1,9 @@ --- -import '../styles/global.scss'; -const { title = 'Jeanine White: Personal Site', description = 'The personal site of Jeanine White' } = Astro.props; +import "../styles/global.scss"; +const { + title = "Jeanine White: Personal Site", + description = "The personal site of Jeanine White", +} = Astro.props; --- @@ -9,5 +12,9 @@ const { title = 'Jeanine White: Personal Site', description = 'The personal site {title} - - + + + diff --git a/examples/portfolio/src/layouts/project.astro b/examples/portfolio/src/layouts/project.astro index aba14a5ac..81d67ad39 100644 --- a/examples/portfolio/src/layouts/project.astro +++ b/examples/portfolio/src/layouts/project.astro @@ -1,13 +1,13 @@ --- -import MainHead from '../components/MainHead.astro'; -import Button from '../components/Button/index.jsx'; -import Footer from '../components/Footer/index.jsx'; -import Nav from '../components/Nav/index.jsx'; +import MainHead from "../components/MainHead.astro"; +import Button from "../components/Button/index.jsx"; +import Footer from "../components/Footer/index.jsx"; +import Nav from "../components/Nav/index.jsx"; const { content } = Astro.props; --- - + - +

      diff --git a/examples/ssr/src/components/ProductListing.astro b/examples/ssr/src/components/ProductListing.astro index c0af5a34c..9a6ed0502 100644 --- a/examples/ssr/src/components/ProductListing.astro +++ b/examples/ssr/src/components/ProductListing.astro @@ -1,6 +1,7 @@ --- const { products } = Astro.props; --- + diff --git a/examples/ssr/src/components/TextDecorationSkip.astro b/examples/ssr/src/components/TextDecorationSkip.astro index b35179ea8..191119bf4 100644 --- a/examples/ssr/src/components/TextDecorationSkip.astro +++ b/examples/ssr/src/components/TextDecorationSkip.astro @@ -1,15 +1,17 @@ --- const { text } = Astro.props; -const words = text.split(' '); +const words = text.split(" "); const last = words.length - 1; --- + {words.map((word, i) => ( - {word}{i !== last && ( )} + {word} + {i !== last && } ))} diff --git a/examples/ssr/src/pages/cart.astro b/examples/ssr/src/pages/cart.astro index 3277ff2db..2214703f2 100644 --- a/examples/ssr/src/pages/cart.astro +++ b/examples/ssr/src/pages/cart.astro @@ -1,47 +1,50 @@ --- -import Header from '../components/Header.astro'; -import Container from '../components/Container.astro'; -import { getCart } from '../api'; -import { isLoggedIn } from '../models/user'; +import Header from "../components/Header.astro"; +import Container from "../components/Container.astro"; +import { getCart } from "../api"; +import { isLoggedIn } from "../models/user"; -if(!isLoggedIn(Astro.request)) { - return Astro.redirect('/'); +if (!isLoggedIn(Astro.request)) { + return Astro.redirect("/"); } // They must be logged in. -const user = { name: 'test'}; // getUser? +const user = { name: "test" }; // getUser? const cart = await getCart(Astro.request); --- - - - Cart | Online Store - - - -
      - -

      Cart

      -

      Hi { user.name }! Here are your cart items:

      - - - - - - - - - {cart.items.map(item => - - - )} - -
      ItemCount
      {item.name}{item.count}
      -
      - + + + Cart | Online Store + + + +
      + + +

      Cart

      +

      Hi {user.name}! Here are your cart items:

      + + + + + + + + + {cart.items.map((item) => ( + + + + + ))} + +
      ItemCount
      {item.name}{item.count}
      +
      + diff --git a/examples/ssr/src/pages/index.astro b/examples/ssr/src/pages/index.astro index 8eb04ffa6..456de484c 100644 --- a/examples/ssr/src/pages/index.astro +++ b/examples/ssr/src/pages/index.astro @@ -1,36 +1,36 @@ --- -import Header from '../components/Header.astro'; -import Container from '../components/Container.astro'; -import ProductListing from '../components/ProductListing.astro'; -import { getProducts } from '../api'; -import '../styles/common.css'; +import Header from "../components/Header.astro"; +import Container from "../components/Container.astro"; +import ProductListing from "../components/ProductListing.astro"; +import { getProducts } from "../api"; +import "../styles/common.css"; const products = await getProducts(Astro.request); --- + - - Online Store - + + +
      - } - - - -
      - - - -

      Product Listing

      -
      -
      - + + +

      Product Listing

      +
      +
      + diff --git a/examples/ssr/src/pages/login.astro b/examples/ssr/src/pages/login.astro index b12a82a5e..081aafedf 100644 --- a/examples/ssr/src/pages/login.astro +++ b/examples/ssr/src/pages/login.astro @@ -1,30 +1,31 @@ --- -import Header from '../components/Header.astro'; -import Container from '../components/Container.astro'; +import Header from "../components/Header.astro"; +import Container from "../components/Container.astro"; --- + - - Online Store - - - -
      + + Online Store + + + +
      - -

      Login

      -
      - - + +

      Login

      + + + - - + + - - -
      - + + +
      + diff --git a/examples/ssr/src/pages/products/[id].astro b/examples/ssr/src/pages/products/[id].astro index f6ac67f82..9ec934aa2 100644 --- a/examples/ssr/src/pages/products/[id].astro +++ b/examples/ssr/src/pages/products/[id].astro @@ -1,46 +1,45 @@ --- -import Header from '../../components/Header.astro'; -import Container from '../../components/Container.astro'; -import AddToCart from '../../components/AddToCart.svelte'; -import { getProduct } from '../../api'; -import '../../styles/common.css'; +import Header from "../../components/Header.astro"; +import Container from "../../components/Container.astro"; +import AddToCart from "../../components/AddToCart.svelte"; +import { getProduct } from "../../api"; +import "../../styles/common.css"; const id = Number(Astro.params.id); const product = await getProduct(Astro.request, id); --- - - {product.name} | Online Store - - - -
      - - -

      {product.name}

      -
      + img { + width: 400px; + } + + + +
      + + +

      {product.name}

      +
      -
      - -

      Description here...

      -
      -
      - -
      - +
      + +

      Description here...

      +
      +
      +
      + diff --git a/examples/ssr/tsconfig.json b/examples/ssr/tsconfig.json index 7ac81809a..4db6ee701 100644 --- a/examples/ssr/tsconfig.json +++ b/examples/ssr/tsconfig.json @@ -9,7 +9,7 @@ "resolveJsonModule": true, // Enable stricter transpilation for better output. "isolatedModules": true, - // Add type definitions for our Vite runtime. - "types": ["vite/client"] + // Add type definitions for our Astro runtime. + "types": ["astro/client"] } } diff --git a/examples/starter/package.json b/examples/starter/package.json index 812c9dc68..b0109d717 100644 --- a/examples/starter/package.json +++ b/examples/starter/package.json @@ -9,6 +9,6 @@ "preview": "astro preview" }, "devDependencies": { - "astro": "^1.0.0-beta.46" + "astro": "^1.0.0-beta.73" } } diff --git a/examples/starter/src/components/Logo.astro b/examples/starter/src/components/Logo.astro index 02c68c7f0..ca45ef529 100644 --- a/examples/starter/src/components/Logo.astro +++ b/examples/starter/src/components/Logo.astro @@ -1,9 +1,10 @@ --- // Export a "Props" interface to . export interface Props { - height?: number, - width?: number, + height?: number; + width?: number; } -const {height = 80, width = 60 } = Astro.props; +const { height = 80, width = 60 } = Astro.props; --- -Astro logo + +Astro logo diff --git a/examples/starter/src/pages/index.astro b/examples/starter/src/pages/index.astro index ea853b668..4ec1c38a4 100644 --- a/examples/starter/src/pages/index.astro +++ b/examples/starter/src/pages/index.astro @@ -1,74 +1,75 @@ --- -import {Content as TourContent} from '../content/Tour.md'; -import Logo from '../components/Logo.astro'; -import '../styles/global.css'; -import '../styles/home.css'; +import { Content as TourContent } from "../content/Tour.md"; +import Logo from "../components/Logo.astro"; +import "../styles/global.css"; +import "../styles/home.css"; /* ASTRO:COMPONENT_IMPORTS */ // Component Script: // You can write any JavaScript/TypeScript that you'd like here. // It will run during the build, but never in the browser. // All variables are available to use in the HTML template below. -let title = 'My Astro Site'; +let title = "My Astro Site"; // Full Astro Component Syntax: // https://docs.astro.build/core-concepts/astro-components/ --- + - - - - {title} + + + + {title} - + - - - - -
      -
      -
      - -

      Welcome to Astro

      -
      -
      + + + + +
      +
      +
      + +

      Welcome to Astro

      +
      +
      -
      - - -
      +
      + + +
      - - -
      - + +
      + diff --git a/examples/starter/tsconfig.json b/examples/starter/tsconfig.json index 7ac81809a..4db6ee701 100644 --- a/examples/starter/tsconfig.json +++ b/examples/starter/tsconfig.json @@ -9,7 +9,7 @@ "resolveJsonModule": true, // Enable stricter transpilation for better output. "isolatedModules": true, - // Add type definitions for our Vite runtime. - "types": ["vite/client"] + // Add type definitions for our Astro runtime. + "types": ["astro/client"] } } diff --git a/examples/subpath/package.json b/examples/subpath/package.json index ede4b4ccc..d0ee033ff 100644 --- a/examples/subpath/package.json +++ b/examples/subpath/package.json @@ -9,8 +9,8 @@ "preview": "astro preview" }, "devDependencies": { - "@astrojs/react": "^0.1.3", - "astro": "^1.0.0-beta.46", + "@astrojs/react": "^0.4.2", + "astro": "^1.0.0-beta.73", "sass": "^1.52.2" }, "dependencies": { diff --git a/examples/subpath/src/pages/index.astro b/examples/subpath/src/pages/index.astro index a7620accd..7ecb1f58d 100644 --- a/examples/subpath/src/pages/index.astro +++ b/examples/subpath/src/pages/index.astro @@ -1,6 +1,6 @@ --- -import '../styles/main.scss'; -import Time from '../components/Time.jsx'; +import "../styles/main.scss"; +import Time from "../components/Time.jsx"; --- diff --git a/examples/subpath/tsconfig.json b/examples/subpath/tsconfig.json index 7ac81809a..4db6ee701 100644 --- a/examples/subpath/tsconfig.json +++ b/examples/subpath/tsconfig.json @@ -9,7 +9,7 @@ "resolveJsonModule": true, // Enable stricter transpilation for better output. "isolatedModules": true, - // Add type definitions for our Vite runtime. - "types": ["vite/client"] + // Add type definitions for our Astro runtime. + "types": ["astro/client"] } } diff --git a/examples/with-markdown-plugins/package.json b/examples/with-markdown-plugins/package.json index 937588418..63e3f8e78 100644 --- a/examples/with-markdown-plugins/package.json +++ b/examples/with-markdown-plugins/package.json @@ -9,8 +9,8 @@ "preview": "astro preview" }, "devDependencies": { - "@astrojs/markdown-remark": "^0.11.2", - "astro": "^1.0.0-beta.46", + "@astrojs/markdown-remark": "^0.12.0", + "astro": "^1.0.0-beta.73", "hast-util-select": "5.0.1", "rehype-autolink-headings": "^6.1.1", "rehype-slug": "^5.0.1", diff --git a/examples/with-markdown-plugins/src/layouts/main.astro b/examples/with-markdown-plugins/src/layouts/main.astro index 854b2b425..758e5d083 100644 --- a/examples/with-markdown-plugins/src/layouts/main.astro +++ b/examples/with-markdown-plugins/src/layouts/main.astro @@ -1,10 +1,10 @@ --- -import '../styles/global.css'; +import "../styles/global.css"; const { content } = Astro.props; --- - + @@ -27,7 +27,6 @@ const { content } = Astro.props;
      diff --git a/examples/with-markdown-plugins/src/pages/about.astro b/examples/with-markdown-plugins/src/pages/about.astro deleted file mode 100644 index 1115fcb8c..000000000 --- a/examples/with-markdown-plugins/src/pages/about.astro +++ /dev/null @@ -1,20 +0,0 @@ ---- -import { Markdown } from 'astro/components'; -import MainLayout from '../layouts/main.astro'; ---- - - - - # About - - Sint ullamco sint ut irure laborum occaecat anim minim tempor enim dolore reprehenderit Lorem. Sit qui nisi in quis ut consequat minim. Ad commodo officia nisi culpa proident duis culpa eu reprehenderit incididunt do fugiat proident tempor. Et velit dolor aliqua dolor ipsum. Sunt eiusmod amet enim ut. - - Sint ullamco sint ut irure laborum occaecat anim minim tempor enim dolore reprehenderit Lorem. Sit qui nisi in quis ut consequat minim. Ad commodo officia nisi culpa proident duis culpa eu reprehenderit incididunt do fugiat proident tempor. Et velit dolor aliqua dolor ipsum. Sunt eiusmod amet enim ut. - - ## My story - - Sint ullamco sint ut irure laborum occaecat anim minim tempor enim dolore reprehenderit Lorem. Sit qui nisi in quis ut consequat minim. Ad commodo officia nisi culpa proident duis culpa eu reprehenderit incididunt do fugiat proident tempor. Et velit dolor aliqua dolor ipsum. Sunt eiusmod amet enim ut. - - Sint ullamco sint ut irure laborum occaecat anim minim tempor enim dolore reprehenderit Lorem. Sit qui nisi in quis ut consequat minim. Ad commodo officia nisi culpa proident duis culpa eu reprehenderit incididunt do fugiat proident tempor. Et velit dolor aliqua dolor ipsum. Sunt eiusmod amet enim ut. - - diff --git a/examples/with-markdown-plugins/tsconfig.json b/examples/with-markdown-plugins/tsconfig.json index 7ac81809a..4db6ee701 100644 --- a/examples/with-markdown-plugins/tsconfig.json +++ b/examples/with-markdown-plugins/tsconfig.json @@ -9,7 +9,7 @@ "resolveJsonModule": true, // Enable stricter transpilation for better output. "isolatedModules": true, - // Add type definitions for our Vite runtime. - "types": ["vite/client"] + // Add type definitions for our Astro runtime. + "types": ["astro/client"] } } diff --git a/examples/with-markdown-shiki/README.md b/examples/with-markdown-shiki/README.md index 5b744b15d..2c39f9334 100644 --- a/examples/with-markdown-shiki/README.md +++ b/examples/with-markdown-shiki/README.md @@ -8,5 +8,4 @@ npm init astro -- --template with-markdown-shiki This example showcases Astro's [built-in Markdown support](https://docs.astro.build/en/guides/markdown-content/). -- `src/pages/index.astro` uses Astro's `` component. -- `src/pages/other.md` is a treated as a page entrypoint and uses a `layout`. +- `src/pages/index.md` is a treated as a page entrypoint and uses a `layout`. diff --git a/examples/with-markdown-shiki/package.json b/examples/with-markdown-shiki/package.json index 1a065a715..54a440a52 100644 --- a/examples/with-markdown-shiki/package.json +++ b/examples/with-markdown-shiki/package.json @@ -9,7 +9,7 @@ "preview": "astro preview" }, "devDependencies": { - "@astrojs/markdown-remark": "^0.11.2", - "astro": "^1.0.0-beta.46" + "@astrojs/markdown-remark": "^0.12.0", + "astro": "^1.0.0-beta.73" } } diff --git a/examples/with-markdown-shiki/src/layouts/main.astro b/examples/with-markdown-shiki/src/layouts/main.astro index 425f5dc08..006c4ca6c 100644 --- a/examples/with-markdown-shiki/src/layouts/main.astro +++ b/examples/with-markdown-shiki/src/layouts/main.astro @@ -1,10 +1,10 @@ --- -import '../styles/global.css'; +import "../styles/global.css"; const { content } = Astro.props; --- - + diff --git a/examples/with-markdown-shiki/tsconfig.json b/examples/with-markdown-shiki/tsconfig.json index 7ac81809a..4db6ee701 100644 --- a/examples/with-markdown-shiki/tsconfig.json +++ b/examples/with-markdown-shiki/tsconfig.json @@ -9,7 +9,7 @@ "resolveJsonModule": true, // Enable stricter transpilation for better output. "isolatedModules": true, - // Add type definitions for our Vite runtime. - "types": ["vite/client"] + // Add type definitions for our Astro runtime. + "types": ["astro/client"] } } diff --git a/examples/with-markdown/README.md b/examples/with-markdown/README.md deleted file mode 100644 index 5acc87f7c..000000000 --- a/examples/with-markdown/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# Astro Example: Markdown - -``` -npm init astro -- --template with-markdown -``` - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/astro/tree/latest/examples/with-markdown) - -This example showcases Astro's [built-in Markdown support](https://docs.astro.build/en/guides/markdown-content/). - -- `src/pages/index.astro` uses Astro's `` component. -- `src/pages/other.md` is a treated as a page entrypoint and uses a `layout`. diff --git a/examples/with-markdown/package.json b/examples/with-markdown/package.json deleted file mode 100644 index a5b9a47a0..000000000 --- a/examples/with-markdown/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "@example/with-markdown", - "version": "0.0.1", - "private": true, - "scripts": { - "dev": "astro dev", - "start": "astro dev", - "build": "astro build", - "preview": "astro preview" - }, - "devDependencies": { - "@astrojs/markdown-remark": "^0.11.2", - "@astrojs/preact": "^0.1.3", - "@astrojs/react": "^0.1.3", - "@astrojs/svelte": "^0.1.4", - "@astrojs/vue": "^0.1.5", - "astro": "^1.0.0-beta.46" - }, - "dependencies": { - "preact": "^10.7.3", - "react": "^18.1.0", - "react-dom": "^18.1.0", - "svelte": "^3.48.0", - "vue": "^3.2.36" - } -} diff --git a/examples/with-markdown/src/components/ReactCounter.jsx b/examples/with-markdown/src/components/ReactCounter.jsx deleted file mode 100644 index e322f7050..000000000 --- a/examples/with-markdown/src/components/ReactCounter.jsx +++ /dev/null @@ -1,19 +0,0 @@ -import React, { useState } from 'react'; - -/** a counter written in React */ -export default function ReactCounter({ children }) { - const [count, setCount] = useState(0); - const add = () => setCount((i) => i + 1); - const subtract = () => setCount((i) => i - 1); - - return ( - <> -
      - -
      {count}
      - -
      -
      {children}
      - - ); -} diff --git a/examples/with-markdown/src/components/SvelteCounter.svelte b/examples/with-markdown/src/components/SvelteCounter.svelte deleted file mode 100644 index 8d6b3f5e1..000000000 --- a/examples/with-markdown/src/components/SvelteCounter.svelte +++ /dev/null @@ -1,22 +0,0 @@ - - - -
      - -
      { count }
      - -
      -
      - -
      diff --git a/examples/with-markdown/src/layouts/main.astro b/examples/with-markdown/src/layouts/main.astro deleted file mode 100644 index 425f5dc08..000000000 --- a/examples/with-markdown/src/layouts/main.astro +++ /dev/null @@ -1,18 +0,0 @@ ---- -import '../styles/global.css'; - -const { content } = Astro.props; ---- - - - - - - - - {content.title} - - - - - diff --git a/examples/with-markdown/src/pages/external.astro b/examples/with-markdown/src/pages/external.astro deleted file mode 100644 index 82cac13d4..000000000 --- a/examples/with-markdown/src/pages/external.astro +++ /dev/null @@ -1,19 +0,0 @@ ---- -import { Markdown } from 'astro/components'; -import Layout from '../layouts/main.astro'; - -const title = `External Markdown`; -const content = `Markdown *content* to render`; ---- - - -
      -
      - - - -

      Some other stuff

      -
      -

      Lastly...

      -
      -
      diff --git a/examples/with-markdown/src/pages/index.astro b/examples/with-markdown/src/pages/index.astro deleted file mode 100644 index e70e12f35..000000000 --- a/examples/with-markdown/src/pages/index.astro +++ /dev/null @@ -1,65 +0,0 @@ ---- -// Component Imports -import { Markdown } from 'astro/components'; -import Layout from '../layouts/main.astro'; -import ReactCounter from '../components/ReactCounter.jsx'; -import PreactCounter from '../components/PreactCounter.tsx'; -import VueCounter from '../components/VueCounter.vue'; -import SvelteCounter from '../components/SvelteCounter.svelte'; - -// Component Script: -// You can write any JavaScript/TypeScript that you'd like here. -// It will run during the build, but never in the browser. -// All variables are available to use in the HTML template below. -const title = 'Astro Markdown'; -const variable = 'content'; -const items = ['A', 'B', 'C']; - -// Full Astro Component Syntax: -// https://docs.astro.build/core-concepts/astro-components/ ---- - - - - # Introducing {title} - - **Astro Markdown** brings native Markdown support to HTML! - - > It's inspired by [`MDX`](https://mdxjs.com/) and powered by [`remark`](https://github.com/remarkjs/remark). - - The best part? It comes with all the Astro features you expect. - - [Other example](./other) - - ## Embed framework components - - - - - - - ## Use Expressions - - You can use any {variable} in scope and use JavaScript for templating ({items.join(', ')}) - - ## Oh yeah... - - - - 🤯 It's also _recursive_! - - ### Markdown can be embedded in any child component - - - - ## Code - - Should work! - - ```js - import Something from './another'; - - const thing = new Something(); - ``` - - diff --git a/examples/with-markdown/src/pages/other.md b/examples/with-markdown/src/pages/other.md deleted file mode 100644 index d4180940d..000000000 --- a/examples/with-markdown/src/pages/other.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -title: Some Markdown Page -layout: ../layouts/main.astro ---- - -# Code - -```js -var foo = 'bar'; - -function doSomething() { - return foo; -} -``` - -# Paragraph - -text here. diff --git a/examples/with-markdown/src/styles/global.css b/examples/with-markdown/src/styles/global.css deleted file mode 100644 index 7ea16821e..000000000 --- a/examples/with-markdown/src/styles/global.css +++ /dev/null @@ -1,70 +0,0 @@ -pre, -code { - color: #d4d4d4; - font-size: 14px; - font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; - line-height: 1.5; - direction: ltr; - white-space: pre; - text-align: left; - text-shadow: none; - word-break: normal; - word-spacing: normal; - -moz-tab-size: 4; - -o-tab-size: 4; - tab-size: 4; - -webkit-hyphens: none; - -moz-hyphens: none; - -ms-hyphens: none; - hyphens: none; -} - -pre::selection, -code::selection { - text-shadow: none; - background: #b3d4fc; -} - -@media print { - pre, - code { - text-shadow: none; - } -} - -pre { - margin: 0.5rem 0 16px; - padding: 0.8rem 1rem 0.9rem; - overflow: auto; - background: #282a36; - border-radius: 4px; -} - -code { - padding: 0.1em 0.3em; - color: #db4c69; - background: #f9f2f4; - border-radius: 0.3em; - white-space: pre-wrap; -} - -pre.astro-code > code { - all: unset; -} - -/********************************************************* -* Line highlighting -*/ -pre[data-line] { - position: relative; -} - -pre > code { - position: relative; - z-index: 1; -} - -body { - max-width: 900px; - margin: auto; -} diff --git a/examples/with-markdown/.gitignore b/examples/with-mdx/.gitignore similarity index 100% rename from examples/with-markdown/.gitignore rename to examples/with-mdx/.gitignore diff --git a/examples/with-markdown/.npmrc b/examples/with-mdx/.npmrc similarity index 100% rename from examples/with-markdown/.npmrc rename to examples/with-mdx/.npmrc diff --git a/examples/with-markdown/.stackblitzrc b/examples/with-mdx/.stackblitzrc similarity index 100% rename from examples/with-markdown/.stackblitzrc rename to examples/with-mdx/.stackblitzrc diff --git a/examples/with-mdx/.vscode/extensions.json b/examples/with-mdx/.vscode/extensions.json new file mode 100644 index 000000000..bedff53ba --- /dev/null +++ b/examples/with-mdx/.vscode/extensions.json @@ -0,0 +1,4 @@ +{ + "recommendations": ["astro-build.astro-vscode", "silvenon.mdx"], + "unwantedRecommendations": [] +} diff --git a/examples/with-mdx/.vscode/launch.json b/examples/with-mdx/.vscode/launch.json new file mode 100644 index 000000000..d64220976 --- /dev/null +++ b/examples/with-mdx/.vscode/launch.json @@ -0,0 +1,11 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "command": "./node_modules/.bin/astro dev", + "name": "Development server", + "request": "launch", + "type": "node-terminal" + } + ] +} diff --git a/examples/with-mdx/README.md b/examples/with-mdx/README.md new file mode 100644 index 000000000..1a13dcdcc --- /dev/null +++ b/examples/with-mdx/README.md @@ -0,0 +1,9 @@ +# Astro Example: MDX + +``` +npm init astro -- --template with-mdx +``` + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/astro/tree/latest/examples/with-mdx) + +This example showcases using [`@astrojs/mdx`](https://www.npmjs.com/package/@astrojs/mdx) to author content using [MDX](https://mdxjs.com/). diff --git a/examples/with-mdx/astro.config.mjs b/examples/with-mdx/astro.config.mjs new file mode 100644 index 000000000..d797941ec --- /dev/null +++ b/examples/with-mdx/astro.config.mjs @@ -0,0 +1,8 @@ +import { defineConfig } from 'astro/config'; +import mdx from '@astrojs/mdx'; +import preact from '@astrojs/preact'; + +// https://astro.build/config +export default defineConfig({ + integrations: [mdx(), preact()], +}); diff --git a/examples/with-mdx/package.json b/examples/with-mdx/package.json new file mode 100644 index 000000000..8b31a8622 --- /dev/null +++ b/examples/with-mdx/package.json @@ -0,0 +1,17 @@ +{ + "name": "@example/with-mdx", + "version": "0.0.1", + "private": true, + "scripts": { + "dev": "astro dev", + "start": "astro dev", + "build": "astro build", + "preview": "astro preview" + }, + "devDependencies": { + "@astrojs/mdx": "^0.2.1", + "@astrojs/preact": "^0.5.2", + "astro": "^1.0.0-beta.73", + "preact": "^10.6.5" + } +} diff --git a/examples/with-markdown/public/favicon.ico b/examples/with-mdx/public/favicon.ico similarity index 100% rename from examples/with-markdown/public/favicon.ico rename to examples/with-mdx/public/favicon.ico diff --git a/examples/with-markdown/sandbox.config.json b/examples/with-mdx/sandbox.config.json similarity index 100% rename from examples/with-markdown/sandbox.config.json rename to examples/with-mdx/sandbox.config.json diff --git a/examples/with-markdown/src/components/PreactCounter.tsx b/examples/with-mdx/src/components/Counter.jsx similarity index 60% rename from examples/with-markdown/src/components/PreactCounter.tsx rename to examples/with-mdx/src/components/Counter.jsx index e67afb4fe..801eefe73 100644 --- a/examples/with-markdown/src/components/PreactCounter.tsx +++ b/examples/with-mdx/src/components/Counter.jsx @@ -1,20 +1,18 @@ -import { h, Fragment } from 'preact'; import { useState } from 'preact/hooks'; -/** a counter written in Preact */ -export default function PreactCounter({ children }) { +export default function Counter({ children }) { const [count, setCount] = useState(0); const add = () => setCount((i) => i + 1); const subtract = () => setCount((i) => i - 1); return ( <> -
      +
      {count}
      -
      {children}
      +
      {children}
      ); } diff --git a/examples/blog/src/components/Heading.astro b/examples/with-mdx/src/components/Title.astro similarity index 66% rename from examples/blog/src/components/Heading.astro rename to examples/with-mdx/src/components/Title.astro index fec49b538..6d0dcb86c 100644 --- a/examples/blog/src/components/Heading.astro +++ b/examples/with-mdx/src/components/Title.astro @@ -1,6 +1,4 @@ -

      - -

      +

      - - - - diff --git a/examples/with-nanostores/public/images/astronaut-figurine.png b/examples/with-nanostores/public/images/astronaut-figurine.png new file mode 100644 index 000000000..f5a278b9c Binary files /dev/null and b/examples/with-nanostores/public/images/astronaut-figurine.png differ diff --git a/examples/with-nanostores/public/robots.txt b/examples/with-nanostores/public/robots.txt deleted file mode 100644 index 1f53798bb..000000000 --- a/examples/with-nanostores/public/robots.txt +++ /dev/null @@ -1,2 +0,0 @@ -User-agent: * -Disallow: / diff --git a/examples/with-nanostores/src/cartStore.ts b/examples/with-nanostores/src/cartStore.ts new file mode 100644 index 000000000..f490a2447 --- /dev/null +++ b/examples/with-nanostores/src/cartStore.ts @@ -0,0 +1,31 @@ +import { atom, map } from 'nanostores'; + +export const isCartOpen = atom(false); + +export type CartItem = { + id: string; + name: string; + imageSrc: string; + quantity: number; +}; + +export type CartItemDisplayInfo = Pick; + +export const cartItems = map>({}); + +export function addCartItem({ id, name, imageSrc }) { + const existingEntry = cartItems.get()[id]; + if (existingEntry) { + cartItems.setKey(id, { + ...existingEntry, + quantity: existingEntry.quantity + 1, + }); + } else { + cartItems.setKey(id, { + id, + name, + imageSrc, + quantity: 1, + }); + } +} diff --git a/examples/with-nanostores/src/components/AddToCartForm.tsx b/examples/with-nanostores/src/components/AddToCartForm.tsx new file mode 100644 index 000000000..7498443f6 --- /dev/null +++ b/examples/with-nanostores/src/components/AddToCartForm.tsx @@ -0,0 +1,18 @@ +import { isCartOpen, addCartItem } from '../cartStore'; +import type { CartItemDisplayInfo } from '../cartStore'; +import type { ComponentChildren } from 'preact'; + +type Props = { + item: CartItemDisplayInfo; + children: ComponentChildren; +}; + +export default function AddToCartForm({ item, children }: Props) { + function addToCart(e: SubmitEvent) { + e.preventDefault(); + isCartOpen.set(true); + addCartItem(item); + } + + return
      {children}
      ; +} diff --git a/examples/with-nanostores/src/components/AdminsReact.jsx b/examples/with-nanostores/src/components/AdminsReact.jsx deleted file mode 100644 index f2b38a3cd..000000000 --- a/examples/with-nanostores/src/components/AdminsReact.jsx +++ /dev/null @@ -1,30 +0,0 @@ -import * as React from 'react'; -import { useStore } from '@nanostores/react'; - -import { admins } from '../store/admins.js'; -import { counter, increaseCounter, decreaseCounter } from '../store/counter.js'; - -const AdminsReact = () => { - const list = useStore(admins); - const count = useStore(counter); - - return ( - <> -

      React

      -
        - {list.map((admin) => ( -
      • {JSON.stringify(admin, null, 2)}
      • - ))} -
      -
      -

      Counter

      -

      {count.value}

      - - -
      -
      - - ); -}; - -export default AdminsReact; diff --git a/examples/with-nanostores/src/components/AdminsSolid.jsx b/examples/with-nanostores/src/components/AdminsSolid.jsx deleted file mode 100644 index 8ad2756a3..000000000 --- a/examples/with-nanostores/src/components/AdminsSolid.jsx +++ /dev/null @@ -1,30 +0,0 @@ -import { createSignal } from 'solid-js'; -import { useStore } from 'solid-nanostores'; - -import { admins } from '../store/admins.js'; -import { counter, increaseCounter, decreaseCounter } from '../store/counter.js'; - -const AdminsSolid = () => { - const list = useStore(admins); - const count = useStore(counter); - - return ( - <> -

      Solid

      -
        - {list.map((admin) => ( -
      • {JSON.stringify(admin, null, 2)}
      • - ))} -
      -
      -

      Counter

      -

      {count.value}

      - - -
      -
      - - ); -}; - -export default AdminsSolid; diff --git a/examples/with-nanostores/src/components/AdminsSvelte.svelte b/examples/with-nanostores/src/components/AdminsSvelte.svelte deleted file mode 100644 index bae3fbef8..000000000 --- a/examples/with-nanostores/src/components/AdminsSvelte.svelte +++ /dev/null @@ -1,20 +0,0 @@ - - -

      Svelte

      -
        - {#each $admins as admin} -
      • {JSON.stringify(admin, null, 2)}
      • - {/each} -
      -
      -

      Counter

      -

      {$counter.value}

      - - -
      -
      - - diff --git a/examples/with-nanostores/src/components/AdminsVue.vue b/examples/with-nanostores/src/components/AdminsVue.vue deleted file mode 100644 index 5eb73dd3d..000000000 --- a/examples/with-nanostores/src/components/AdminsVue.vue +++ /dev/null @@ -1,33 +0,0 @@ - - - diff --git a/examples/with-nanostores/src/components/CartFlyout.module.css b/examples/with-nanostores/src/components/CartFlyout.module.css new file mode 100644 index 000000000..cee43dd4c --- /dev/null +++ b/examples/with-nanostores/src/components/CartFlyout.module.css @@ -0,0 +1,29 @@ +.container { + position: fixed; + right: 0; + top: var(--nav-height); + height: 100vh; + background: var(--color-bg-2); + padding-inline: 2rem; + min-width: min(90vw, 300px); + border-left: 3px solid var(--color-bg-3); +} + +.list { + list-style: none; + padding: 0; +} + +.listItem { + display: flex; + gap: 1rem; + align-items: center; +} + +.listItem * { + margin-block: 0.3rem; +} + +.listItemImg { + width: 4rem; +} diff --git a/examples/with-nanostores/src/components/CartFlyout.tsx b/examples/with-nanostores/src/components/CartFlyout.tsx new file mode 100644 index 000000000..98fd8cbfb --- /dev/null +++ b/examples/with-nanostores/src/components/CartFlyout.tsx @@ -0,0 +1,28 @@ +import { useStore } from '@nanostores/preact'; +import { cartItems, isCartOpen } from '../cartStore'; +import styles from './CartFlyout.module.css'; + +export default function CartFlyout() { + const $isCartOpen = useStore(isCartOpen); + const $cartItems = useStore(cartItems); + + return ( + + ); +} diff --git a/examples/with-nanostores/src/components/CartFlyoutToggle.tsx b/examples/with-nanostores/src/components/CartFlyoutToggle.tsx new file mode 100644 index 000000000..14ce1c70d --- /dev/null +++ b/examples/with-nanostores/src/components/CartFlyoutToggle.tsx @@ -0,0 +1,7 @@ +import { useStore } from '@nanostores/preact'; +import { isCartOpen } from '../cartStore'; + +export default function CartFlyoutToggle() { + const $isCartOpen = useStore(isCartOpen); + return ; +} diff --git a/examples/with-nanostores/src/components/FigurineDescription.astro b/examples/with-nanostores/src/components/FigurineDescription.astro new file mode 100644 index 000000000..8d801d53a --- /dev/null +++ b/examples/with-nanostores/src/components/FigurineDescription.astro @@ -0,0 +1,36 @@ +

      Astronaut Figurine

      +

      Limited Edition

      +

      The limited edition Astronaut Figurine is the perfect gift for any Astro contributor. This fully-poseable action figurine comes equipped with:

      +
        +
      • A fabric space suit with adjustible straps
      • +
      • Boots lightly dusted by the lunar surface *
      • +
      • An adjustable space visor
      • +
      +

      + * Dust not actually from the lunar surface +

      + + diff --git a/examples/with-nanostores/src/layouts/Layout.astro b/examples/with-nanostores/src/layouts/Layout.astro new file mode 100644 index 000000000..0eb4ecb76 --- /dev/null +++ b/examples/with-nanostores/src/layouts/Layout.astro @@ -0,0 +1,106 @@ +--- +import CartFlyoutToggle from '../components/CartFlyoutToggle'; +import CartFlyout from '../components/CartFlyout'; + +export interface Props { + title: string; +} + +const { title } = Astro.props as Props; +--- + + + + + + + + {title} + + +
      + +
      + + + + + + + + diff --git a/examples/with-nanostores/src/pages/index.astro b/examples/with-nanostores/src/pages/index.astro index ad3fb4e26..965428ab3 100644 --- a/examples/with-nanostores/src/pages/index.astro +++ b/examples/with-nanostores/src/pages/index.astro @@ -1,50 +1,48 @@ --- -// Style Imports -import '../styles/global.css'; -import '../styles/home.css'; +import type { CartItemDisplayInfo } from '../cartStore'; +import Layout from '../layouts/Layout.astro'; +import AddToCartForm from '../components/AddToCartForm'; +import FigurineDescription from '../components/FigurineDescription.astro'; -// Component Imports -import AdminsReact from '../components/AdminsReact.jsx'; -import AdminsSvelte from '../components/AdminsSvelte.svelte'; -import AdminsVue from '../components/AdminsVue.vue'; -import AdminsSolid from '../components/AdminsSolid.jsx'; - -// Full Astro Component Syntax: -// https://docs.astro.build/core-concepts/astro-components/ +const item: CartItemDisplayInfo = { + id: 'astronaut-figurine', + name: 'Astronaut Figurine', + imageSrc: '/images/astronaut-figurine.png', +}; --- + +
      +
      +
      + + + + +
      + {item.name} +
      +
      +
      - - - - - Astro + - - -
      -
      -
      - Astro logo -

      - Welcome to Astro - - nanostores -

      -
      -
      - - - - -
      - - + .product-layout img { + width: 100%; + max-width: 26rem; + } + + button[type="submit"] { + margin-block-start: 1rem; + } + diff --git a/examples/with-nanostores/src/store/admins.js b/examples/with-nanostores/src/store/admins.js deleted file mode 100644 index 8a4a6f4d2..000000000 --- a/examples/with-nanostores/src/store/admins.js +++ /dev/null @@ -1,7 +0,0 @@ -import { computed } from 'nanostores'; - -import { users } from './users.js'; - -const admins = computed(users, (list) => list.filter((user) => user.isAdmin)); - -export { admins }; diff --git a/examples/with-nanostores/src/store/counter.js b/examples/with-nanostores/src/store/counter.js deleted file mode 100644 index d4c29ad62..000000000 --- a/examples/with-nanostores/src/store/counter.js +++ /dev/null @@ -1,15 +0,0 @@ -import { atom } from 'nanostores'; - -const initialValue = { value: 0 }; - -const counter = atom(initialValue); - -function increaseCounter() { - counter.set({ value: counter.get().value + 1 }); -} - -function decreaseCounter() { - counter.set({ value: counter.get().value - 1 }); -} - -export { counter, increaseCounter, decreaseCounter }; diff --git a/examples/with-nanostores/src/store/users.js b/examples/with-nanostores/src/store/users.js deleted file mode 100644 index 7a2e23e9d..000000000 --- a/examples/with-nanostores/src/store/users.js +++ /dev/null @@ -1,30 +0,0 @@ -import { atom } from 'nanostores'; - -const initialValue = [ - { - id: 1, - name: 'User Admin', - age: 28, - isAdmin: true, - }, - { - id: 2, - name: 'NOT Admin', - age: 35, - isAdmin: false, - }, - { - id: 3, - name: 'Another Admin', - age: 46, - isAdmin: true, - }, -]; - -const users = atom(initialValue); - -const addUser = function addUser(user) { - users.set([...users.get(), user]); -}; - -export { users, addUser }; diff --git a/examples/with-nanostores/src/styles/global.css b/examples/with-nanostores/src/styles/global.css deleted file mode 100644 index 8ef8122cb..000000000 --- a/examples/with-nanostores/src/styles/global.css +++ /dev/null @@ -1,29 +0,0 @@ -* { - box-sizing: border-box; - margin: 0; -} - -:root { - font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, - Apple Color Emoji, Segoe UI Emoji; - font-size: 1rem; - --user-font-scale: 1rem - 16px; - font-size: clamp(0.875rem, 0.4626rem + 1.0309vw + var(--user-font-scale), 1.125rem); -} - -body { - padding: 4rem 2rem; - width: 100%; - min-height: 100vh; - display: grid; - justify-content: center; - background: #f9fafb; - color: #111827; -} - -@media (prefers-color-scheme: dark) { - body { - background: #111827; - color: #fff; - } -} diff --git a/examples/with-nanostores/src/styles/home.css b/examples/with-nanostores/src/styles/home.css deleted file mode 100644 index c2f50cb19..000000000 --- a/examples/with-nanostores/src/styles/home.css +++ /dev/null @@ -1,40 +0,0 @@ -:root { - --font-mono: Consolas, 'Andale Mono WT', 'Andale Mono', 'Lucida Console', 'Lucida Sans Typewriter', - 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Liberation Mono', 'Nimbus Mono L', Monaco, - 'Courier New', Courier, monospace; - --color-light: #f3f4f6; -} - -@media (prefers-color-scheme: dark) { - :root { - --color-light: #1f2937; - } -} - -a { - color: inherit; -} - -header > div { - font-size: clamp(2rem, -0.4742rem + 6.1856vw, 2.75rem); -} - -header > div { - display: flex; - flex-direction: column; - align-items: center; -} - -header h1 { - font-size: 1em; - font-weight: 500; -} -header img { - width: 2em; - height: 2.667em; -} - -h2 { - font-weight: 500; - font-size: clamp(1.5rem, 1rem + 1.25vw, 2rem); -} diff --git a/examples/with-nanostores/tsconfig.json b/examples/with-nanostores/tsconfig.json index 7ac81809a..4db6ee701 100644 --- a/examples/with-nanostores/tsconfig.json +++ b/examples/with-nanostores/tsconfig.json @@ -9,7 +9,7 @@ "resolveJsonModule": true, // Enable stricter transpilation for better output. "isolatedModules": true, - // Add type definitions for our Vite runtime. - "types": ["vite/client"] + // Add type definitions for our Astro runtime. + "types": ["astro/client"] } } diff --git a/examples/with-tailwindcss/package.json b/examples/with-tailwindcss/package.json index 4c732dad9..a97429d0e 100644 --- a/examples/with-tailwindcss/package.json +++ b/examples/with-tailwindcss/package.json @@ -9,8 +9,8 @@ "preview": "astro preview" }, "devDependencies": { - "@astrojs/tailwind": "^0.2.1", - "astro": "^1.0.0-beta.46", + "@astrojs/tailwind": "^0.2.4", + "astro": "^1.0.0-beta.73", "autoprefixer": "^10.4.7", "canvas-confetti": "^1.5.1", "postcss": "^8.4.14", diff --git a/examples/with-tailwindcss/src/components/Button.astro b/examples/with-tailwindcss/src/components/Button.astro index 7d11c37ea..70962e801 100644 --- a/examples/with-tailwindcss/src/components/Button.astro +++ b/examples/with-tailwindcss/src/components/Button.astro @@ -2,11 +2,14 @@ // Click button, get confetti! // Styled by Tailwind :) --- - diff --git a/examples/with-tailwindcss/src/pages/index.astro b/examples/with-tailwindcss/src/pages/index.astro index ebccafa34..651a47fa3 100644 --- a/examples/with-tailwindcss/src/pages/index.astro +++ b/examples/with-tailwindcss/src/pages/index.astro @@ -1,6 +1,6 @@ --- // Component Imports -import Button from '../components/Button.astro'; +import Button from "../components/Button.astro"; // Full Astro Component Syntax: // https://docs.astro.build/core-concepts/astro-components/ diff --git a/examples/with-tailwindcss/tsconfig.json b/examples/with-tailwindcss/tsconfig.json index 7ac81809a..4db6ee701 100644 --- a/examples/with-tailwindcss/tsconfig.json +++ b/examples/with-tailwindcss/tsconfig.json @@ -9,7 +9,7 @@ "resolveJsonModule": true, // Enable stricter transpilation for better output. "isolatedModules": true, - // Add type definitions for our Vite runtime. - "types": ["vite/client"] + // Add type definitions for our Astro runtime. + "types": ["astro/client"] } } diff --git a/examples/with-vite-plugin-pwa/package.json b/examples/with-vite-plugin-pwa/package.json index 5f450231a..76a948bfd 100644 --- a/examples/with-vite-plugin-pwa/package.json +++ b/examples/with-vite-plugin-pwa/package.json @@ -9,7 +9,7 @@ "preview": "astro preview" }, "devDependencies": { - "astro": "^1.0.0-beta.46", + "astro": "^1.0.0-beta.73", "vite-plugin-pwa": "0.11.11", "workbox-window": "^6.5.3" } diff --git a/examples/with-vite-plugin-pwa/src/pages/index.astro b/examples/with-vite-plugin-pwa/src/pages/index.astro index 6214033dd..94596d8df 100644 --- a/examples/with-vite-plugin-pwa/src/pages/index.astro +++ b/examples/with-vite-plugin-pwa/src/pages/index.astro @@ -11,6 +11,8 @@

      Welcome to Astro

      - + diff --git a/examples/with-vite-plugin-pwa/tsconfig.json b/examples/with-vite-plugin-pwa/tsconfig.json index 7ac81809a..4db6ee701 100644 --- a/examples/with-vite-plugin-pwa/tsconfig.json +++ b/examples/with-vite-plugin-pwa/tsconfig.json @@ -9,7 +9,7 @@ "resolveJsonModule": true, // Enable stricter transpilation for better output. "isolatedModules": true, - // Add type definitions for our Vite runtime. - "types": ["vite/client"] + // Add type definitions for our Astro runtime. + "types": ["astro/client"] } } diff --git a/package.json b/package.json index 3be9d8e87..55263594a 100644 --- a/package.json +++ b/package.json @@ -7,25 +7,24 @@ "url": "https://github.com/withastro/astro.git" }, "scripts": { - "postinstall": "patch-package", "release": "pnpm run build && changeset publish", - "build": "turbo run build --no-deps --scope=astro --scope=create-astro --scope=\"@astrojs/*\"", - "build:ci": "turbo run build:ci --no-deps --scope=astro --scope=create-astro --scope=\"@astrojs/*\"", + "build": "turbo run build --output-logs=new-only --no-deps --scope=astro --scope=create-astro --scope=\"@astrojs/*\"", + "build:ci": "turbo run build:ci --output-logs=new-only --no-deps --scope=astro --scope=create-astro --scope=\"@astrojs/*\"", "build:examples": "turbo run build --scope=\"@example/*\"", "dev": "turbo run dev --no-deps --no-cache --parallel --scope=astro --scope=create-astro --scope=\"@astrojs/*\"", "format": "pnpm run format:code", "format:ci": "pnpm run format:imports && pnpm run format:code", - "format:code": "prettier -w .", + "format:code": "prettier -w . --cache", "format:imports": "organize-imports-cli ./packages/*/tsconfig.json ./packages/*/*/tsconfig.json", - "test": "turbo run test --concurrency=1", + "test": "turbo run test --output-logs=new-only --concurrency=1", "test:match": "cd packages/astro && pnpm run test:match", "test:templates": "turbo run test --filter=create-astro --concurrency=1", - "test:smoke": "node scripts/smoke/index.js", - "test:vite-ci": "turbo run test --no-deps --scope=astro --concurrency=1", + "test:smoke": "turbo run build --filter=\"@example/*\" --filter=\"astro.build\" --filter=\"docs\" --output-logs=new-only --concurrency=1", + "test:vite-ci": "turbo run test --output-logs=new-only --no-deps --scope=astro --concurrency=1", "test:e2e": "cd packages/astro && pnpm playwright install && pnpm run test:e2e", "test:e2e:match": "cd packages/astro && pnpm playwright install && pnpm run test:e2e:match", "benchmark": "turbo run benchmark --scope=astro", - "lint": "eslint \"packages/**/*.ts\"", + "lint": "eslint .", "version": "changeset version && pnpm install --no-frozen-lockfile && pnpm run format" }, "workspaces": [ @@ -43,40 +42,58 @@ "packages/astro/test/fixtures/static build/pkg" ], "engines": { - "node": "^14.15.0 || >=16.0.0", - "pnpm": ">=7.0.0" + "node": "^14.18.0 || >=16.12.0", + "pnpm": ">=7.5.0" }, - "packageManager": "pnpm@7.0.0", + "packageManager": "pnpm@7.5.0", "pnpm": { + "packageExtensions": { + "svelte2tsx": { + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + } + }, "peerDependencyRules": { "ignoreMissing": [ + "rollup", "@babel/core", "@babel/plugin-transform-react-jsx", - "vite" + "vite", + "react", + "react-dom", + "@types/react" ] + }, + "patchedDependencies": { + "@changesets/cli@2.23.0": "patches/@changesets__cli@2.23.0.patch", + "@changesets/assemble-release-plan@5.1.3": "patches/@changesets__assemble-release-plan@5.1.3.patch" } }, "dependencies": { "@astrojs/webapi": "workspace:*" }, "devDependencies": { + "@changesets/assemble-release-plan": "5.1.3", "@changesets/changelog-github": "0.4.4", - "@changesets/cli": "2.22.0", + "@changesets/cli": "2.23.0", "@octokit/action": "^3.18.1", - "@typescript-eslint/eslint-plugin": "^5.27.0", - "@typescript-eslint/parser": "^5.27.0", + "@typescript-eslint/eslint-plugin": "^5.27.1", + "@typescript-eslint/parser": "^5.27.1", "del": "^6.1.1", - "esbuild": "^0.14.42", - "eslint": "^8.16.0", + "esbuild": "^0.14.43", + "eslint": "^8.17.0", "eslint-config-prettier": "^8.5.0", + "eslint-plugin-no-only-tests": "^2.6.0", "eslint-plugin-prettier": "^4.0.0", "execa": "^6.1.0", "organize-imports-cli": "^0.10.0", - "patch-package": "^6.4.7", - "prettier": "^2.6.2", + "prettier": "^2.7.0", "pretty-bytes": "^6.0.0", "tiny-glob": "^0.2.9", "turbo": "1.2.5", - "typescript": "~4.7.2" + "typescript": "~4.7.3" } } diff --git a/packages/astro-prism/CHANGELOG.md b/packages/astro-prism/CHANGELOG.md index 4d6e8f056..c251264ee 100644 --- a/packages/astro-prism/CHANGELOG.md +++ b/packages/astro-prism/CHANGELOG.md @@ -1,5 +1,23 @@ # @astrojs/prism +## 0.6.1 + +### Patch Changes + +- [#3937](https://github.com/withastro/astro/pull/3937) [`31f9c0bf0`](https://github.com/withastro/astro/commit/31f9c0bf029ffa4b470e620f2c32e1370643e81e) Thanks [@delucis](https://github.com/delucis)! - Roll back supported Node engines + +## 0.6.0 + +### Minor Changes + +- [#3914](https://github.com/withastro/astro/pull/3914) [`b48767985`](https://github.com/withastro/astro/commit/b48767985359bd359df8071324952ea5f2bc0d86) Thanks [@ran-dall](https://github.com/ran-dall)! - Rollback supported `node@16` version. Minimum versions are now `node@14.20.0` or `node@16.14.0`. + +## 0.5.0 + +### Minor Changes + +- [#3871](https://github.com/withastro/astro/pull/3871) [`1cc5b7890`](https://github.com/withastro/astro/commit/1cc5b78905633608e5b07ad291f916f54e67feb1) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Update supported `node` versions. Minimum versions are now `node@14.20.0` or `node@16.16.0`. + ## 0.4.1 ### Patch Changes diff --git a/packages/astro-prism/package.json b/packages/astro-prism/package.json index fd554bf9e..853417165 100644 --- a/packages/astro-prism/package.json +++ b/packages/astro-prism/package.json @@ -1,6 +1,6 @@ { "name": "@astrojs/prism", - "version": "0.4.1", + "version": "0.6.1", "description": "Supports Prism highlighting in Astro projects", "author": "withastro", "license": "MIT", @@ -23,6 +23,6 @@ "prismjs": "^1.28.0" }, "engines": { - "node": "^14.15.0 || >=16.0.0" + "node": "^14.18.0 || >=16.12.0" } } diff --git a/packages/astro-rss/CHANGELOG.md b/packages/astro-rss/CHANGELOG.md index 033af5adc..d1d879b1f 100644 --- a/packages/astro-rss/CHANGELOG.md +++ b/packages/astro-rss/CHANGELOG.md @@ -1,5 +1,17 @@ # @astrojs/rss +## 0.2.2 + +### Patch Changes + +- [#3956](https://github.com/withastro/astro/pull/3956) [`57e529e4c`](https://github.com/withastro/astro/commit/57e529e4c13f3e7829311ac6f92682eb6333fd96) Thanks [@esafev](https://github.com/esafev)! - Throw the error when 'site' option is missing + +## 0.2.1 + +### Patch Changes + +- [#3913](https://github.com/withastro/astro/pull/3913) [`cd2dbfedb`](https://github.com/withastro/astro/commit/cd2dbfedb15969274df40b1c41b6680ea8885e8d) Thanks [@matthewp](https://github.com/matthewp)! - Adds error messages for missing required fields + ## 0.2.0 ### Minor Changes diff --git a/packages/astro-rss/package.json b/packages/astro-rss/package.json index 4f2572431..c95242f0a 100644 --- a/packages/astro-rss/package.json +++ b/packages/astro-rss/package.json @@ -1,7 +1,7 @@ { "name": "@astrojs/rss", "description": "Add RSS feeds to your Astro projects", - "version": "0.2.0", + "version": "0.2.2", "type": "module", "types": "./dist/index.d.ts", "author": "withastro", diff --git a/packages/astro-rss/src/index.ts b/packages/astro-rss/src/index.ts index 5f7e63b89..20d509f14 100644 --- a/packages/astro-rss/src/index.ts +++ b/packages/astro-rss/src/index.ts @@ -76,10 +76,17 @@ function mapGlobResult(items: GlobResult): Promise { } export default async function getRSS(rssOptions: RSSOptions) { + const { site } = rssOptions; let { items } = rssOptions; + + if (!site) { + throw new Error('[RSS] the "site" option is required, but no value was given.'); + } + if (isGlobResult(items)) { items = await mapGlobResult(items); } + return { body: await generateRSS({ rssOptions, @@ -113,6 +120,7 @@ export async function generateRSS({ rssOptions, items }: GenerateRSSArgs): Promi if (typeof rssOptions.customData === 'string') xml += rssOptions.customData; // items for (const result of items) { + validate(result); xml += ``; xml += `<![CDATA[${result.title}]]>`; // If the item's link is already a valid URL, don't mess with it. @@ -146,3 +154,16 @@ export async function generateRSS({ rssOptions, items }: GenerateRSSArgs): Promi return xml; } + +const requiredFields = Object.freeze(['link', 'title']); + +// Perform validation to make sure all required fields are passed. +function validate(item: RSSFeedItem) { + for (const field of requiredFields) { + if (!(field in item)) { + throw new Error( + `@astrojs/rss: Required field [${field}] is missing. RSS cannot be generated without it.` + ); + } + } +} diff --git a/packages/astro-rss/test/rss.test.js b/packages/astro-rss/test/rss.test.js index 9962e83f9..08d56fa92 100644 --- a/packages/astro-rss/test/rss.test.js +++ b/packages/astro-rss/test/rss.test.js @@ -123,4 +123,42 @@ describe('rss', () => { ).to.be.rejected; }); }); + + describe('errors', () => { + it('should provide a error message when a "site" option is missing', async () => { + try { + await rss({ + title, + description, + items: [phpFeedItem, web1FeedItem], + }); + + chai.expect(false).to.equal(true, 'Should have errored'); + } catch (err) { + chai + .expect(err.message) + .to.contain('[RSS] the "site" option is required, but no value was given.'); + } + }); + + it('should provide a good error message when a link is not provided', async () => { + try { + await rss({ + title: 'Your Website Title', + description: 'Your Website Description', + site: 'https://astro-demo', + items: [ + { + pubDate: new Date(), + title: 'Some title', + slug: 'foo', + }, + ], + }); + chai.expect(false).to.equal(true, 'Should have errored'); + } catch (err) { + chai.expect(err.message).to.contain('Required field [link] is missing'); + } + }); + }); }); diff --git a/packages/astro/CHANGELOG.md b/packages/astro/CHANGELOG.md index 7c06ff120..0f821ed8d 100644 --- a/packages/astro/CHANGELOG.md +++ b/packages/astro/CHANGELOG.md @@ -1,5 +1,380 @@ # astro +## 1.0.0-beta.73 + +### Patch Changes + +- [#3937](https://github.com/withastro/astro/pull/3937) [`31f9c0bf0`](https://github.com/withastro/astro/commit/31f9c0bf029ffa4b470e620f2c32e1370643e81e) Thanks [@delucis](https://github.com/delucis)! - Roll back supported Node engines + +* [#3588](https://github.com/withastro/astro/pull/3588) [`5d0edfc3b`](https://github.com/withastro/astro/commit/5d0edfc3b9a20bf68b16c463bbf9cbf31324143a) Thanks [@charlesvdv](https://github.com/charlesvdv)! - Fix missing props (url, file) in markdown layout + +- [#3960](https://github.com/withastro/astro/pull/3960) [`ceda294e1`](https://github.com/withastro/astro/commit/ceda294e133d4cc32e68488393287be6077fd3d5) Thanks [@matthewp](https://github.com/matthewp)! - Fixes hydration of maps/sets + +* [#3958](https://github.com/withastro/astro/pull/3958) [`8eba6d9d9`](https://github.com/withastro/astro/commit/8eba6d9d977920bdb0830cc219e636236433b2fd) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Fix JSX definitions being too strict as to what an element is, which lead to type issues in certain cases (Markdown imports, JSX components etc) + +- [#3915](https://github.com/withastro/astro/pull/3915) [`f5d4ebf0e`](https://github.com/withastro/astro/commit/f5d4ebf0e242a7d33fedfe924f9dea678a7e673c) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Fix metadata handling for building MDX files + +* [#3930](https://github.com/withastro/astro/pull/3930) [`3acb9ec26`](https://github.com/withastro/astro/commit/3acb9ec264de6ca6eecf49313c0f4d02c3908afa) Thanks [@matthewp](https://github.com/matthewp)! - Include hoisted scripts inside Astro.glob in dev + +- [#3906](https://github.com/withastro/astro/pull/3906) [`b37695c34`](https://github.com/withastro/astro/commit/b37695c34c84274af873cf5c69d484ee33c82098) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Fixed many long-standing issues with `astro check` + + - Fixed it not working on Windows at all + - Fixed red squiggles not showing in the proper place in certain contexts, notably with strings using non-latin characters + - Fixed IDE links pointing to the wrong line number and character + - Fixed line numbers being off by one + - Fixed IDE links not working when the project wasn't at the root of the folder + + Additionally added some features: + + - Added more pretty colors + - Fixed it not working at all on Windows + - Warnings and hints are now printed alongside errors + - Surrounding lines are now shown when relevant (aka not empty) + +* [#3955](https://github.com/withastro/astro/pull/3955) [`92b48b152`](https://github.com/withastro/astro/commit/92b48b1525f12663a4932dd6b63bc18f7f0f35fa) Thanks [@matthewp](https://github.com/matthewp)! - Set import.meta.env.BASE_URL in dev mode + +- [#3963](https://github.com/withastro/astro/pull/3963) [`5fde2fd8b`](https://github.com/withastro/astro/commit/5fde2fd8bcc7f10e8a449146fa89843f6e6b6aa3) Thanks [@matthewp](https://github.com/matthewp)! - Makes the Debug component's styles be inlined + +- Updated dependencies [[`31f9c0bf0`](https://github.com/withastro/astro/commit/31f9c0bf029ffa4b470e620f2c32e1370643e81e), [`07fb544da`](https://github.com/withastro/astro/commit/07fb544dab142a3d4bb9d0d878aab34eaea447b2)]: + - @astrojs/prism@0.6.1 + - @astrojs/telemetry@0.4.1 + - @astrojs/markdown-remark@0.12.0 + +## 1.0.0-beta.72 + +### Patch Changes + +- [#3922](https://github.com/withastro/astro/pull/3922) [`7094d6a45`](https://github.com/withastro/astro/commit/7094d6a45f06b61f2a35af3408380654f24fc8f5) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Properly handle `false` in `class:list` + +* [#3927](https://github.com/withastro/astro/pull/3927) [`7c5c4106d`](https://github.com/withastro/astro/commit/7c5c4106d7b9d73103eb6e899f39125e630280ff) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Updated `astro/components` exports to a `.ts` file so it's automatically typed + +## 1.0.0-beta.71 + +### Patch Changes + +- [#3918](https://github.com/withastro/astro/pull/3918) [`6a7a17f73`](https://github.com/withastro/astro/commit/6a7a17f735bd8a58cdc08f25a1442277aa7d2fb0) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Update `@astrojs/compiler`, fixing various edge cases around nested expressions, tables, and conditional slots. See the [`@astrojs/compiler@0.19.0 changelog`](https://github.com/withastro/compiler/blob/main/packages/compiler/CHANGELOG.md#0190) for more information. + +- Updated dependencies [[`01a55467d`](https://github.com/withastro/astro/commit/01a55467d561974f843a9e0cd6963af7c840abb9)]: + - @astrojs/markdown-remark@0.11.7 + +## 1.0.0-beta.70 + +### Patch Changes + +- [#3902](https://github.com/withastro/astro/pull/3902) [`d8af02a94`](https://github.com/withastro/astro/commit/d8af02a9443de5fa4cfe8e3ef7beddde9ef8cf09) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Fix: markdown "require is not defined" issue + +* [#3914](https://github.com/withastro/astro/pull/3914) [`b48767985`](https://github.com/withastro/astro/commit/b48767985359bd359df8071324952ea5f2bc0d86) Thanks [@ran-dall](https://github.com/ran-dall)! - Rollback supported `node@16` version. Minimum versions are now `node@14.20.0` or `node@16.14.0`. + +* Updated dependencies [[`ca45c0c27`](https://github.com/withastro/astro/commit/ca45c0c270f5ca3f7d2fb113a235d415cecdb333), [`b48767985`](https://github.com/withastro/astro/commit/b48767985359bd359df8071324952ea5f2bc0d86)]: + - @astrojs/markdown-remark@0.11.6 + - @astrojs/prism@0.6.0 + - @astrojs/telemetry@0.4.0 + +## 1.0.0-beta.69 + +### Patch Changes + +- [#3830](https://github.com/withastro/astro/pull/3830) [`4097f0622`](https://github.com/withastro/astro/commit/4097f06226ab393280658e81c258593bc41452fe) Thanks [@delucis](https://github.com/delucis)! - Update funding link in README + +* [#3880](https://github.com/withastro/astro/pull/3880) [`402c4181d`](https://github.com/withastro/astro/commit/402c4181dcea8f7b741061452746f304cb952d77) Thanks [@crutchcorn](https://github.com/crutchcorn)! - Fix rendering HTML comments in `mode="md"` configuration + +## 1.0.0-beta.68 + +### Patch Changes + +- [#3883](https://github.com/withastro/astro/pull/3883) [`b4cb4a40d`](https://github.com/withastro/astro/commit/b4cb4a40df33b82bcd36e63bd488bd037e94dbc0) Thanks [@crutchcorn](https://github.com/crutchcorn)! - Added "mode" to Astro config file TypeScript definitions + +- Updated dependencies [[`c4f6fdf37`](https://github.com/withastro/astro/commit/c4f6fdf3722b9bc2192cab735498f4e0c30c982e)]: + - @astrojs/telemetry@0.3.1 + +## 1.0.0-beta.67 + +### Patch Changes + +- [#3669](https://github.com/withastro/astro/pull/3669) [`93e1020b1`](https://github.com/withastro/astro/commit/93e1020b1e8549b08cf5646e1ebc3ae34e14ebc8) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Tooling: reintroduce smoke test across example projects + +* [#3889](https://github.com/withastro/astro/pull/3889) [`5f4ecbad1`](https://github.com/withastro/astro/commit/5f4ecbad1bbcf3e08b399b23c70c7b766dac48e2) Thanks [@matthewp](https://github.com/matthewp)! - Allow defining Astro components in Vite plugins + +* Updated dependencies [[`93e1020b1`](https://github.com/withastro/astro/commit/93e1020b1e8549b08cf5646e1ebc3ae34e14ebc8)]: + - @astrojs/markdown-remark@0.11.5 + +## 1.0.0-beta.66 + +### Patch Changes + +- [#3891](https://github.com/withastro/astro/pull/3891) [`9cf7e4064`](https://github.com/withastro/astro/commit/9cf7e406412bcc9c1a17b57072dc1c4a1b94b635) Thanks [@matthewp](https://github.com/matthewp)! - Fix Safari client:visible refresh bug + +* [#3851](https://github.com/withastro/astro/pull/3851) [`21869a614`](https://github.com/withastro/astro/commit/21869a614a89446a25175e45580943c28ab7413c) Thanks [@matthewp](https://github.com/matthewp)! - Replaces vite/client types with astro/client + +- [#3871](https://github.com/withastro/astro/pull/3871) [`1cc5b7890`](https://github.com/withastro/astro/commit/1cc5b78905633608e5b07ad291f916f54e67feb1) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Update supported `node` versions. Minimum versions are now `node@14.20.0` or `node@16.16.0`. + +* [#3892](https://github.com/withastro/astro/pull/3892) [`7c49096e8`](https://github.com/withastro/astro/commit/7c49096e864815d63179a467d9d3d89c76ccd523) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Update `@astrojs/compiler` to latest + +* Updated dependencies [[`1cc5b7890`](https://github.com/withastro/astro/commit/1cc5b78905633608e5b07ad291f916f54e67feb1)]: + - @astrojs/prism@0.5.0 + - @astrojs/telemetry@0.3.0 + - @astrojs/markdown-remark@0.11.4 + +## 1.0.0-beta.65 + +### Patch Changes + +- [#3842](https://github.com/withastro/astro/pull/3842) [`08fa0772`](https://github.com/withastro/astro/commit/08fa0772abb49b892fa03198fa16964161b9618d) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Docs: add complete "adapter" configuration reference + +* [#3860](https://github.com/withastro/astro/pull/3860) [`c2c4e5c2`](https://github.com/withastro/astro/commit/c2c4e5c238463a09d621237698a5399eb7b3e9ad) Thanks [@matthewp](https://github.com/matthewp)! - Fixes response.arrayBuffer() handling in large pages + +- [#3854](https://github.com/withastro/astro/pull/3854) [`b012ee55`](https://github.com/withastro/astro/commit/b012ee55b107dea0730286263b27d83e530fad5d) Thanks [@bholmesdev](https://github.com/bholmesdev)! - [astro add] Support adapters and third party packages + +* [#3848](https://github.com/withastro/astro/pull/3848) [`502f0631`](https://github.com/withastro/astro/commit/502f0631317fe1b23582d4126c44f44cb0b0716f) Thanks [@matthewp](https://github.com/matthewp)! - Allow importing the Image component from @astrojs/image + +- [#3873](https://github.com/withastro/astro/pull/3873) [`957fb505`](https://github.com/withastro/astro/commit/957fb50541e15d3876a87f91cd52f29e10a92cc9) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Fix hydration for SSR components that return null + +* [#3801](https://github.com/withastro/astro/pull/3801) [`b84bd7db`](https://github.com/withastro/astro/commit/b84bd7db63c29aede9a63940e2e7dbdc7eca28db) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Update JSX definitions with element specific types and added some missing attributes + +- [#3837](https://github.com/withastro/astro/pull/3837) [`5afb8076`](https://github.com/withastro/astro/commit/5afb807688750fce7024e630203fbc48dcef267a) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Fix usage of slots inside expressions + +- Updated dependencies [[`eedb32c7`](https://github.com/withastro/astro/commit/eedb32c79716a8e04acd46cb2c74c5af112e016f)]: + - @astrojs/telemetry@0.2.5 + +## 1.0.0-beta.64 + +### Patch Changes + +- [#3821](https://github.com/withastro/astro/pull/3821) [`c2165c34`](https://github.com/withastro/astro/commit/c2165c34a76c183b3af6303526ae292a1f2426ce) Thanks [@matthewp](https://github.com/matthewp)! - Fix for putting the into its own component + +* [#3841](https://github.com/withastro/astro/pull/3841) [`820a26dd`](https://github.com/withastro/astro/commit/820a26dde5cdc11b5bf430bc2a1e3b09084ae045) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Fix: add default content type to endpoints with { body } shorthand + +- [#3839](https://github.com/withastro/astro/pull/3839) [`cd3f6348`](https://github.com/withastro/astro/commit/cd3f6348c4e918b5367587bce58d724aec44eddd) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Fix `client:visible` directive in safari + +- Updated dependencies [[`e4b2dca1`](https://github.com/withastro/astro/commit/e4b2dca1f3f03bd951f1d623695631cebf638c67)]: + - @astrojs/telemetry@0.2.4 + +## 1.0.0-beta.63 + +### Patch Changes + +- [#3799](https://github.com/withastro/astro/pull/3799) [`5fe52737`](https://github.com/withastro/astro/commit/5fe52737cbb3676af69bb446afa7f3b53b78dc34) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Fix internal error for MDX integration + +## 1.0.0-beta.62 + +### Patch Changes + +- [#3788](https://github.com/withastro/astro/pull/3788) [`f4943e0f`](https://github.com/withastro/astro/commit/f4943e0fbced044f0ba4435cb41d77b67c98e69f) Thanks [@tony-sull](https://github.com/tony-sull)! - Adds support for the new `astrojs/image` integration + +## 1.0.0-beta.61 + +### Patch Changes + +- [#3777](https://github.com/withastro/astro/pull/3777) [`976e1f17`](https://github.com/withastro/astro/commit/976e1f175a95ea39f737b8575e4fdf3c3d89e1ee) Thanks [@tony-sull](https://github.com/tony-sull)! - Adds an option to disable HTTP streaming in Astro's production `App` server + +## 1.0.0-beta.60 + +### Patch Changes + +- [#3779](https://github.com/withastro/astro/pull/3779) [`192c4bcf`](https://github.com/withastro/astro/commit/192c4bcfd69aa44f735866378d8ba08ba902d290) Thanks [@FredKSchott](https://github.com/FredKSchott)! - Fix an issue with throwAndExit not awaiting + +* [#3706](https://github.com/withastro/astro/pull/3706) [`032ad1c0`](https://github.com/withastro/astro/commit/032ad1c047a62dd663067cc562537d16f2872aa7) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Internal changes needed to support `@astrojs/mdx` + +- [#3768](https://github.com/withastro/astro/pull/3768) [`913591d1`](https://github.com/withastro/astro/commit/913591d13761d7c99f4b5bf547942922736a9f3a) Thanks [@FredKSchott](https://github.com/FredKSchott)! - Fix an issue with unfriendly config validation error output + +- Updated dependencies [[`8045c8ad`](https://github.com/withastro/astro/commit/8045c8ade16fe4306448b7f98a4560ef0557d378)]: + - @astrojs/telemetry@0.2.3 + +## 1.0.0-beta.59 + +### Patch Changes + +- [#3767](https://github.com/withastro/astro/pull/3767) [`1eab496e`](https://github.com/withastro/astro/commit/1eab496e9d733a13f3a2eb2129e90949b130901d) Thanks [@tony-sull](https://github.com/tony-sull)! - Updates an error handler to expect updated `@astrojs/lit` behavior + +* [#3763](https://github.com/withastro/astro/pull/3763) [`54cd6b8d`](https://github.com/withastro/astro/commit/54cd6b8dd184fb0acb2facaa9b6843be59f9c57f) Thanks [@tony-sull](https://github.com/tony-sull)! - Fixes how `injectRoute` parses route patterns on Windows + +- [#3750](https://github.com/withastro/astro/pull/3750) [`dd176ca5`](https://github.com/withastro/astro/commit/dd176ca58d9ce8ab757075491568a014c0943de2) Thanks [@FredKSchott](https://github.com/FredKSchott)! - Add basic error reporting to astro telemetry + +- Updated dependencies [[`dd176ca5`](https://github.com/withastro/astro/commit/dd176ca58d9ce8ab757075491568a014c0943de2)]: + - @astrojs/telemetry@0.2.2 + +## 1.0.0-beta.58 + +### Patch Changes + +- [#3715](https://github.com/withastro/astro/pull/3715) [`4d6d8644`](https://github.com/withastro/astro/commit/4d6d8644e623522ca6c19dbb2078865b17044c38) Thanks [@FredKSchott](https://github.com/FredKSchott)! - Update "astro add" output to remove confusing multi-select prompt. + +* [#3715](https://github.com/withastro/astro/pull/3715) [`4d6d8644`](https://github.com/withastro/astro/commit/4d6d8644e623522ca6c19dbb2078865b17044c38) Thanks [@FredKSchott](https://github.com/FredKSchott)! - Update the help output to improve formatting + +- [#3713](https://github.com/withastro/astro/pull/3713) [`ebd7e7ad`](https://github.com/withastro/astro/commit/ebd7e7ad81e5245deffa331f11e5196ff1b21d84) Thanks [@FredKSchott](https://github.com/FredKSchott)! - Update telemetry to support a more anonymized project id. `anonymousProjectId` is now hashed based on anonymous git data instead of your git remote URL. + +- Updated dependencies [[`ebd7e7ad`](https://github.com/withastro/astro/commit/ebd7e7ad81e5245deffa331f11e5196ff1b21d84)]: + - @astrojs/telemetry@0.2.0 + +## 1.0.0-beta.57 + +### Patch Changes + +- [#3724](https://github.com/withastro/astro/pull/3724) [`86635e03`](https://github.com/withastro/astro/commit/86635e035b209845b4e1cdf370a4c78451271b70) Thanks [@matthewp](https://github.com/matthewp)! - Fixes define:vars w/ styles used inside of components + +## 1.0.0-beta.56 + +### Patch Changes + +- [#3705](https://github.com/withastro/astro/pull/3705) [`b5e3403f`](https://github.com/withastro/astro/commit/b5e3403fa151710be4837f6ad265d836adb08025) Thanks [@matthewp](https://github.com/matthewp)! - Fixes build some times breaking in large sites + +* [#3702](https://github.com/withastro/astro/pull/3702) [`b11e3b38`](https://github.com/withastro/astro/commit/b11e3b38ebb59ceec3479cbf580276d3b3bd657c) Thanks [@matthewp](https://github.com/matthewp)! - Ensure import.meta.env.SSR is true in SSR mode + +## 1.0.0-beta.55 + +### Patch Changes + +- [#3696](https://github.com/withastro/astro/pull/3696) [`3daaf510`](https://github.com/withastro/astro/commit/3daaf510ea767fba47ef52d2253b6221967f3b53) Thanks [@matthewp](https://github.com/matthewp)! - Support for streaming responses + + Astro supports streaming in its templates. Any time Astro encounters an async boundary it will stream out HTML that occurs before it. For example: + + ```astro + --- + import LoadTodos from '../components/LoadTodos.astro'; + --- + + + App + + + + + + ``` + + In this arbtrary example Astro will streaming out the `` section and everything else until it encounters `` and then stop. LoadTodos, which is also an Astro component will stream its contents as well; stopping and waiting at any other asynchronous components. + + As part of this Astro also now supports async iterables within its templates. This means you can do this: + + ```astro +
        + {(async function * () { + for(const number of numbers) { + await wait(1000); + + yield
      • Number: {number}
      • + yield '\n' + } + })()} +
      + ``` + + Which will stream out `
    • `s one at a time, waiting a second between each. + +* [#3700](https://github.com/withastro/astro/pull/3700) [`47c81eff`](https://github.com/withastro/astro/commit/47c81effa69fb5d7f1e576f88c27d5071f1888e3) Thanks [@matthewp](https://github.com/matthewp)! - Make Astro.redirect use a 302 status code + +## 1.0.0-beta.54 + +### Patch Changes + +- [#3652](https://github.com/withastro/astro/pull/3652) [`7373d61c`](https://github.com/withastro/astro/commit/7373d61cdcaedd64bf5fd60521b157cfa4343558) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Add renderer support for passing named slots to framework components. + + **BREAKING**: integrations using the `addRenderer()` API are now passed all named slots via `Record` rather than `string`. Previously only the default slot was passed. + +* [#3649](https://github.com/withastro/astro/pull/3649) [`446f8c4f`](https://github.com/withastro/astro/commit/446f8c4f13de04324697e958af027ac8943a039b) Thanks [@dc7290](https://github.com/dc7290)! - Added test for dir parameter in astro:build:done + +- [#3679](https://github.com/withastro/astro/pull/3679) [`fa7ed3f3`](https://github.com/withastro/astro/commit/fa7ed3f3a9ce89c1c46e637b584271a6e199d211) Thanks [@matthewp](https://github.com/matthewp)! - Moves head injection to happen during rendering + + This change makes it so that head injection; to insert component stylesheets, hoisted scripts, for example, to happen during rendering than as a post-rendering step. + + This is to enable streaming. This change will only be noticeable if you are rendering your `` element inside of a framework component. If that is the case then the head items will be injected before the first non-head element in an Astro file instead. + + In the future we may offer a `` component as a way to control where these scripts/styles are inserted. + +## 1.0.0-beta.53 + +### Patch Changes + +- [#3685](https://github.com/withastro/astro/pull/3685) [`3d554fdb`](https://github.com/withastro/astro/commit/3d554fdbfb49d85d2945b7775825f7d9ace959ce) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Fix PostCSS config not applied to Svelte component by default + +* [#3665](https://github.com/withastro/astro/pull/3665) [`9a813268`](https://github.com/withastro/astro/commit/9a813268db2e3a7ed5644739b7a12e83e5d239b2) Thanks [@matthewp](https://github.com/matthewp)! - Allow TypeScript inside script tags + + This makes it so that you can use TypeScript inside of script tags like so: + + ```html + + ``` + + Note that the the VSCode extension does not currently support this, however. + +- [#3633](https://github.com/withastro/astro/pull/3633) [`921d9a27`](https://github.com/withastro/astro/commit/921d9a27e243c27e40e429a0a5c7d562d7b9633f) Thanks [@FredKSchott](https://github.com/FredKSchott)! - Fix a bug with `astro add react` adding a too-complex semver to your package.json + +* [#3676](https://github.com/withastro/astro/pull/3676) [`85c33751`](https://github.com/withastro/astro/commit/85c33751c20002e29bd646325a6e39f83cbb1f4d) Thanks [@matthewp](https://github.com/matthewp)! - Allow specifying entryFileNames for client JS + +## 1.0.0-beta.52 + +### Patch Changes + +- [#3667](https://github.com/withastro/astro/pull/3667) [`df02fad1`](https://github.com/withastro/astro/commit/df02fad13ef7c8a8a563ee3720513d437090ee2e) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Fix: add @nanostores/preact to ALWAYS_NOEXTERNAL list for easier onboarding + +* [#3678](https://github.com/withastro/astro/pull/3678) [`89884540`](https://github.com/withastro/astro/commit/898845402cd82995bd4878c93d3ccfcce89ebf27) Thanks [@matthewp](https://github.com/matthewp)! - Fix regression with SSRManifest and client assets + +- [#3658](https://github.com/withastro/astro/pull/3658) [`aeab8909`](https://github.com/withastro/astro/commit/aeab890971e5f425f877545c674d1cb532cee754) Thanks [@matthewp](https://github.com/matthewp)! - Inlines small hoisted scripts + + This enables a perf improvement, whereby small hoisted scripts without dependencies are inlined into the HTML, rather than loaded externally. This uses `vite.build.assetInlineLimit` to determine if the script should be inlined. + +## 1.0.0-beta.51 + +### Patch Changes + +- [#3675](https://github.com/withastro/astro/pull/3675) [`ef6282d5`](https://github.com/withastro/astro/commit/ef6282d5d99a428f7084f7174c9290cb5ad0fa31) Thanks [@hippotastic](https://github.com/hippotastic)! - Fix `import.meta.env` also without trailing dot + +* [#3673](https://github.com/withastro/astro/pull/3673) [`ba5ad785`](https://github.com/withastro/astro/commit/ba5ad7855c4252e10e76b41b88fd4c74b4b7295b) Thanks [@hippotastic](https://github.com/hippotastic)! - Fix react dependencies to improve test reliability + +## 1.0.0-beta.50 + +### Patch Changes + +- [#3663](https://github.com/withastro/astro/pull/3663) [`c20b93c4`](https://github.com/withastro/astro/commit/c20b93c48448861f2b5c324d81dc30b601a0be0d) Thanks [@matthewp](https://github.com/matthewp)! - Resolve .jsx -> .tsx in hydrated components + +## 1.0.0-beta.49 + +### Patch Changes + +- [#3657](https://github.com/withastro/astro/pull/3657) [`7d4699b8`](https://github.com/withastro/astro/commit/7d4699b8f99ca4835e597a28d4f85b58133ff9ce) Thanks [@leader22](https://github.com/leader22)! - Check null for props serialization + +## 1.0.0-beta.48 + +### Patch Changes + +- [#3625](https://github.com/withastro/astro/pull/3625) [`f5afaf24`](https://github.com/withastro/astro/commit/f5afaf24984ee7d4d6e908a7eeed17f5ca18c61e) Thanks [@matthewp](https://github.com/matthewp)! - Significantly improved build performance + + This change reflects in a significantly improved build performance, especially on larger sites. + + With this change Astro is not building everything by statically analyzing `.astro` files. This means it no longer needs to dynamically _run_ your code in order to know what JavaScript needs to be built. + + With one particular large site we found it to build **32%** faster. + +* [#3612](https://github.com/withastro/astro/pull/3612) [`fca58cfd`](https://github.com/withastro/astro/commit/fca58cfd91b68501ec82350ab023170b208d8ce7) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Fix: "vpath" import error when building for netlify edge + +- [#3650](https://github.com/withastro/astro/pull/3650) [`d9f6dcf6`](https://github.com/withastro/astro/commit/d9f6dcf6ea05f78a33606509de0714f8b0625f96) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Properly catch falsy components + +* [#3610](https://github.com/withastro/astro/pull/3610) [`6ab749be`](https://github.com/withastro/astro/commit/6ab749be5c60c4b57aae8a0ba6083d010fe3b791) Thanks [@hippotastic](https://github.com/hippotastic)! - Add component hydration in Markdown E2E tests + +- [#3620](https://github.com/withastro/astro/pull/3620) [`05aa7244`](https://github.com/withastro/astro/commit/05aa72442cd4512b94abdb39623e8caa2c1839b0) Thanks [@hippotastic](https://github.com/hippotastic)! - Remove extra newlines around Markdown components + +- Updated dependencies [[`80c71c7c`](https://github.com/withastro/astro/commit/80c71c7c56d15dc05ec0c5a848130aad222d7d51), [`fca58cfd`](https://github.com/withastro/astro/commit/fca58cfd91b68501ec82350ab023170b208d8ce7), [`9c8a7c0b`](https://github.com/withastro/astro/commit/9c8a7c0b09db2fb6925929d4efe01d5ececbf08e), [`9c8a7c0b`](https://github.com/withastro/astro/commit/9c8a7c0b09db2fb6925929d4efe01d5ececbf08e), [`48e67fe0`](https://github.com/withastro/astro/commit/48e67fe05398dc4b1fca12db36c1b37bb341277a), [`05aa7244`](https://github.com/withastro/astro/commit/05aa72442cd4512b94abdb39623e8caa2c1839b0)]: + - @astrojs/markdown-remark@0.11.3 + - @astrojs/telemetry@0.1.3 + +## 1.0.0-beta.47 + +### Patch Changes + +- [#3599](https://github.com/withastro/astro/pull/3599) [`0ffc350c`](https://github.com/withastro/astro/commit/0ffc350c8d6bcf7fe4f6bde7ce1c10c014d7b4a1) Thanks [@arimgibson](https://github.com/arimgibson)! - Fix: find a hosting network differently based on Node version + +* [#3605](https://github.com/withastro/astro/pull/3605) [`4916b733`](https://github.com/withastro/astro/commit/4916b733c2b8265ab46762bbbc85aa4171296515) Thanks [@matthewp](https://github.com/matthewp)! - Inlines hydration scripts + ## 1.0.0-beta.46 ### Patch Changes @@ -26,7 +401,8 @@ ```ts integration: [ // Only run `compress` integration when in production environments, etc... - import.meta.env.production ? compress() : null, + // Note that `import.meta.env` is not available inside the `astro.config.mjs` file! + process.env.production ? compress() : null, ]; ``` diff --git a/packages/astro/README.md b/packages/astro/README.md index a47e0be0e..d3b81d05f 100644 --- a/packages/astro/README.md +++ b/packages/astro/README.md @@ -41,6 +41,6 @@ Join us on [Discord](https://astro.build/chat) to meet other maintainers. We'll Astro is generously supported by [Netlify](https://www.netlify.com/), [Vercel](https://vercel.com/), and several other amazing organizations [listed here.](https://astro.build/) -[❤️ Sponsor Astro! ❤️](https://github.com/withastro/astro/blob/main/FUNDING.md) +[❤️ Sponsor Astro! ❤️](https://github.com/withastro/.github/blob/main/FUNDING.md) diff --git a/packages/astro/astro-jsx.d.ts b/packages/astro/astro-jsx.d.ts index c9cfd9e17..59ef899f2 100644 --- a/packages/astro/astro-jsx.d.ts +++ b/packages/astro/astro-jsx.d.ts @@ -1,16 +1,15 @@ /// /* eslint @typescript-eslint/no-unused-vars: off */ /** - * Adapted from jsx-dom - * @see https://github.com/proteriax/jsx-dom/blob/be06937ba16908d87bf8aa4372a3583133e02b8a/index.d.ts + * Adapted from babel-plugin-react-html-attrs's TypeScript definition from DefinitelyTyped. + * @see https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/babel-plugin-react-html-attrs/index.d.ts * - * which was adapted from + * and * * Adapted from React’s TypeScript definition from DefinitelyTyped. * @see https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.ts */ declare namespace astroHTML.JSX { - /* html jsx */ export type Child = Node | Node[] | string | number | boolean | null | undefined | unknown; export type Children = Child | Child[]; @@ -24,176 +23,154 @@ declare namespace astroHTML.JSX { children?: Children; } - type AstroBuiltinProps = import('astro').AstroBuiltinProps; - type AstroBuiltinAttributes = import('astro').AstroBuiltinAttributes; - type AstroDefineVarsAttribute = import('astro').AstroDefineVarsAttribute; - type AstroScriptAttributes = import('astro').AstroScriptAttributes & AstroDefineVarsAttribute; - type AstroStyleAttributes = import('astro').AstroStyleAttributes & AstroDefineVarsAttribute; + type AstroBuiltinProps = import('./dist/types/@types/astro').AstroBuiltinProps; + type AstroBuiltinAttributes = import('./dist/types/@types/astro').AstroBuiltinAttributes; + type AstroDefineVarsAttribute = import('./dist/types/@types/astro').AstroDefineVarsAttribute; + type AstroScriptAttributes = import('./dist/types/@types/astro').AstroScriptAttributes & + AstroDefineVarsAttribute; + type AstroStyleAttributes = import('./dist/types/@types/astro').AstroStyleAttributes & + AstroDefineVarsAttribute; - // Certain Astro methods returns AstroComponent using AstroComponentFactory - // The language-server does not really like this because it expects Elements to - // all be compatible with HTMLElement so we'll add AstroComponentFactory as a valid element type - type AstroComponent = import('astro').AstroComponentFactory; - type Element = HTMLElement | AstroComponent; + // This is an unfortunate use of `any`, but unfortunately we can't make a type that works for every framework + // without importing every single framework's types (which comes with its own set of problems). + // Using any isn't that bad here however as in Astro files the return type of a component isn't relevant in most cases + type Element = HTMLElement | any; - // - // Event Handler Types - // ---------------------------------------------------------------------- - type EventHandler = ( - event: E & { currentTarget: EventTarget & T } - ) => any; - - type ClipboardEventHandler = EventHandler; - type CompositionEventHandler = EventHandler; - type DragEventHandler = EventHandler; - type FocusEventHandler = EventHandler; - type FormEventHandler = EventHandler; - type ChangeEventHandler = EventHandler; - type KeyboardEventHandler = EventHandler; - type MouseEventHandler = EventHandler; - type TouchEventHandler = EventHandler; - type PointerEventHandler = EventHandler; - type UIEventHandler = EventHandler; - type WheelEventHandler = EventHandler; - type AnimationEventHandler = EventHandler; - type TransitionEventHandler = EventHandler; - type MessageEventHandler = EventHandler; - - interface DOMAttributes { + interface DOMAttributes { children?: Children; // Clipboard Events - oncopy?: ClipboardEventHandler | string | undefined | null; - oncut?: ClipboardEventHandler | string | undefined | null; - onpaste?: ClipboardEventHandler | string | undefined | null; + oncopy?: string | undefined | null; + oncut?: string | undefined | null; + onpaste?: string | undefined | null; // Composition Events - oncompositionend?: CompositionEventHandler | string | undefined | null; - oncompositionstart?: CompositionEventHandler | string | undefined | null; - oncompositionupdate?: CompositionEventHandler | string | undefined | null; + oncompositionend?: string | undefined | null; + oncompositionstart?: string | undefined | null; + oncompositionupdate?: string | undefined | null; // Focus Events - onfocus?: FocusEventHandler | string | undefined | null; - onfocusin?: FocusEventHandler | string | undefined | null; - onfocusout?: FocusEventHandler | string | undefined | null; - onblur?: FocusEventHandler | string | undefined | null; + onfocus?: string | undefined | null; + onfocusin?: string | undefined | null; + onfocusout?: string | undefined | null; + onblur?: string | undefined | null; // Form Events - onchange?: FormEventHandler | string | undefined | null; - oninput?: FormEventHandler | string | undefined | null; - onreset?: FormEventHandler | string | undefined | null; - onsubmit?: EventHandler | string | undefined | null; - oninvalid?: EventHandler | string | undefined | null; - onbeforeinput?: EventHandler | string | undefined | null; + onchange?: string | undefined | null; + oninput?: string | undefined | null; + onreset?: string | undefined | null; + onsubmit?: string | undefined | null; + oninvalid?: string | undefined | null; + onbeforeinput?: string | undefined | null; // Image Events - onload?: EventHandler | string | undefined | null; - onerror?: EventHandler | string | undefined | null; // also a Media Event + onload?: string | undefined | null; + onerror?: string | undefined | null; // also a Media Event // Detail Events - ontoggle?: EventHandler | string | undefined | null; + ontoggle?: string | undefined | null; // Keyboard Events - onkeydown?: KeyboardEventHandler | string | undefined | null; - onkeypress?: KeyboardEventHandler | string | undefined | null; - onkeyup?: KeyboardEventHandler | string | undefined | null; + onkeydown?: string | undefined | null; + onkeypress?: string | undefined | null; + onkeyup?: string | undefined | null; // Media Events - onabort?: EventHandler | string | undefined | null; - oncanplay?: EventHandler | string | undefined | null; - oncanplaythrough?: EventHandler | string | undefined | null; - oncuechange?: EventHandler | string | undefined | null; - ondurationchange?: EventHandler | string | undefined | null; - onemptied?: EventHandler | string | undefined | null; - onencrypted?: EventHandler | string | undefined | null; - onended?: EventHandler | string | undefined | null; - onloadeddata?: EventHandler | string | undefined | null; - onloadedmetadata?: EventHandler | string | undefined | null; - onloadstart?: EventHandler | string | undefined | null; - onpause?: EventHandler | string | undefined | null; - onplay?: EventHandler | string | undefined | null; - onplaying?: EventHandler | string | undefined | null; - onprogress?: EventHandler | string | undefined | null; - onratechange?: EventHandler | string | undefined | null; - onseeked?: EventHandler | string | undefined | null; - onseeking?: EventHandler | string | undefined | null; - onstalled?: EventHandler | string | undefined | null; - onsuspend?: EventHandler | string | undefined | null; - ontimeupdate?: EventHandler | string | undefined | null; - onvolumechange?: EventHandler | string | undefined | null; - onwaiting?: EventHandler | string | undefined | null; + onabort?: string | undefined | null; + oncanplay?: string | undefined | null; + oncanplaythrough?: string | undefined | null; + oncuechange?: string | undefined | null; + ondurationchange?: string | undefined | null; + onemptied?: string | undefined | null; + onencrypted?: string | undefined | null; + onended?: string | undefined | null; + onloadeddata?: string | undefined | null; + onloadedmetadata?: string | undefined | null; + onloadstart?: string | undefined | null; + onpause?: string | undefined | null; + onplay?: string | undefined | null; + onplaying?: string | undefined | null; + onprogress?: string | undefined | null; + onratechange?: string | undefined | null; + onseeked?: string | undefined | null; + onseeking?: string | undefined | null; + onstalled?: string | undefined | null; + onsuspend?: string | undefined | null; + ontimeupdate?: string | undefined | null; + onvolumechange?: string | undefined | null; + onwaiting?: string | undefined | null; // MouseEvents - onauxclick?: MouseEventHandler | string | undefined | null; - onclick?: MouseEventHandler | string | undefined | null; - oncontextmenu?: MouseEventHandler | string | undefined | null; - ondblclick?: MouseEventHandler | string | undefined | null; - ondrag?: DragEventHandler | string | undefined | null; - ondragend?: DragEventHandler | string | undefined | null; - ondragenter?: DragEventHandler | string | undefined | null; - ondragexit?: DragEventHandler | string | undefined | null; - ondragleave?: DragEventHandler | string | undefined | null; - ondragover?: DragEventHandler | string | undefined | null; - ondragstart?: DragEventHandler | string | undefined | null; - ondrop?: DragEventHandler | string | undefined | null; - onmousedown?: MouseEventHandler | string | undefined | null; - onmouseenter?: MouseEventHandler | string | undefined | null; - onmouseleave?: MouseEventHandler | string | undefined | null; - onmousemove?: MouseEventHandler | string | undefined | null; - onmouseout?: MouseEventHandler | string | undefined | null; - onmouseover?: MouseEventHandler | string | undefined | null; - onmouseup?: MouseEventHandler | string | undefined | null; + onauxclick?: string | undefined | null; + onclick?: string | undefined | null; + oncontextmenu?: string | undefined | null; + ondblclick?: string | undefined | null; + ondrag?: string | undefined | null; + ondragend?: string | undefined | null; + ondragenter?: string | undefined | null; + ondragexit?: string | undefined | null; + ondragleave?: string | undefined | null; + ondragover?: string | undefined | null; + ondragstart?: string | undefined | null; + ondrop?: string | undefined | null; + onmousedown?: string | undefined | null; + onmouseenter?: string | undefined | null; + onmouseleave?: string | undefined | null; + onmousemove?: string | undefined | null; + onmouseout?: string | undefined | null; + onmouseover?: string | undefined | null; + onmouseup?: string | undefined | null; // Selection Events - onselect?: EventHandler | string | undefined | null; - onselectionchange?: EventHandler | string | undefined | null; - onselectstart?: EventHandler | string | undefined | null; + onselect?: string | undefined | null; + onselectionchange?: string | undefined | null; + onselectstart?: string | undefined | null; // Touch Events - ontouchcancel?: TouchEventHandler | string | undefined | null; - ontouchend?: TouchEventHandler | string | undefined | null; - ontouchmove?: TouchEventHandler | string | undefined | null; - ontouchstart?: TouchEventHandler | string | undefined | null; + ontouchcancel?: string | undefined | null; + ontouchend?: string | undefined | null; + ontouchmove?: string | undefined | null; + ontouchstart?: string | undefined | null; // Pointer Events - ongotpointercapture?: PointerEventHandler | string | undefined | null; - onpointercancel?: PointerEventHandler | string | undefined | null; - onpointerdown?: PointerEventHandler | string | undefined | null; - onpointerenter?: PointerEventHandler | string | undefined | null; - onpointerleave?: PointerEventHandler | string | undefined | null; - onpointermove?: PointerEventHandler | string | undefined | null; - onpointerout?: PointerEventHandler | string | undefined | null; - onpointerover?: PointerEventHandler | string | undefined | null; - onpointerup?: PointerEventHandler | string | undefined | null; - onlostpointercapture?: PointerEventHandler | string | undefined | null; + ongotpointercapture?: string | undefined | null; + onpointercancel?: string | undefined | null; + onpointerdown?: string | undefined | null; + onpointerenter?: string | undefined | null; + onpointerleave?: string | undefined | null; + onpointermove?: string | undefined | null; + onpointerout?: string | undefined | null; + onpointerover?: string | undefined | null; + onpointerup?: string | undefined | null; + onlostpointercapture?: string | undefined | null; // UI Events - onscroll?: UIEventHandler | string | undefined | null; - onresize?: UIEventHandler | string | undefined | null; + onscroll?: string | undefined | null; + onresize?: string | undefined | null; // Wheel Events - onwheel?: WheelEventHandler | string | undefined | null; + onwheel?: string | undefined | null; // Animation Events - onanimationstart?: AnimationEventHandler | string | undefined | null; - onanimationend?: AnimationEventHandler | string | undefined | null; - onanimationiteration?: AnimationEventHandler | string | undefined | null; + onanimationstart?: string | undefined | null; + onanimationend?: string | undefined | null; + onanimationiteration?: string | undefined | null; // Transition Events - ontransitionstart?: TransitionEventHandler | string | undefined | null; - ontransitionrun?: TransitionEventHandler | string | undefined | null; - ontransitionend?: TransitionEventHandler | string | undefined | null; - ontransitioncancel?: TransitionEventHandler | string | undefined | null; + ontransitionstart?: string | undefined | null; + ontransitionrun?: string | undefined | null; + ontransitionend?: string | undefined | null; + ontransitioncancel?: string | undefined | null; // Message Events - onmessage?: MessageEventHandler | string | undefined | null; - onmessageerror?: MessageEventHandler | string | undefined | null; + onmessage?: string | undefined | null; + onmessageerror?: string | undefined | null; // Global Events - oncancel?: EventHandler | string | undefined | null; - onclose?: EventHandler | string | undefined | null; - onfullscreenchange?: EventHandler | string | undefined | null; - onfullscreenerror?: EventHandler | string | undefined | null; + oncancel?: string | undefined | null; + onclose?: string | undefined | null; + onfullscreenchange?: string | undefined | null; + onfullscreenerror?: string | undefined | null; } // All the WAI-ARIA 1.1 attributes from https://www.w3.org/TR/wai-aria-1.1/ @@ -218,17 +195,17 @@ declare namespace astroHTML.JSX { * Defines the total number of columns in a table, grid, or treegrid. * @see aria-colindex. */ - 'aria-colcount'?: number | undefined | null; + 'aria-colcount'?: number | string | undefined | null; /** * Defines an element's column index or position with respect to the total number of columns within a table, grid, or treegrid. * @see aria-colcount @see aria-colspan. */ - 'aria-colindex'?: number | undefined | null; + 'aria-colindex'?: number | string | undefined | null; /** * Defines the number of columns spanned by a cell or gridcell within a table, grid, or treegrid. * @see aria-colindex @see aria-rowspan. */ - 'aria-colspan'?: number | undefined | null; + 'aria-colspan'?: number | string | undefined | null; /** * Identifies the element (or elements) whose contents or presence are controlled by the current element. * @see aria-owns. @@ -318,7 +295,7 @@ declare namespace astroHTML.JSX { */ 'aria-labelledby'?: string | undefined | null; /** Defines the hierarchical level of an element within a structure. */ - 'aria-level'?: number | undefined | null; + 'aria-level'?: number | string | undefined | null; /** Indicates that an element will be updated, and describes the types of updates the user agents, assistive technologies, and user can expect from the live region. */ 'aria-live'?: 'off' | 'assertive' | 'polite' | undefined | null; /** Indicates whether an element is modal when displayed. */ @@ -344,7 +321,7 @@ declare namespace astroHTML.JSX { * Defines an element's number or position in the current set of listitems or treeitems. Not required if all elements in the set are present in the DOM. * @see aria-setsize. */ - 'aria-posinset'?: number | undefined | null; + 'aria-posinset'?: number | string | undefined | null; /** * Indicates the current "pressed" state of toggle buttons. * @see aria-checked @see aria-selected. @@ -380,17 +357,17 @@ declare namespace astroHTML.JSX { * Defines the total number of rows in a table, grid, or treegrid. * @see aria-rowindex. */ - 'aria-rowcount'?: number | undefined | null; + 'aria-rowcount'?: number | string | undefined | null; /** * Defines an element's row index or position with respect to the total number of rows within a table, grid, or treegrid. * @see aria-rowcount @see aria-rowspan. */ - 'aria-rowindex'?: number | undefined | null; + 'aria-rowindex'?: number | string | undefined | null; /** * Defines the number of rows spanned by a cell or gridcell within a table, grid, or treegrid. * @see aria-rowindex @see aria-colspan. */ - 'aria-rowspan'?: number | undefined | null; + 'aria-rowspan'?: number | string | undefined | null; /** * Indicates the current "selected" state of various widgets. * @see aria-checked @see aria-pressed. @@ -400,86 +377,103 @@ declare namespace astroHTML.JSX { * Defines the number of items in the current set of listitems or treeitems. Not required if all elements in the set are present in the DOM. * @see aria-posinset. */ - 'aria-setsize'?: number | undefined | null; + 'aria-setsize'?: number | string | undefined | null; /** Indicates if items in a table or grid are sorted in ascending or descending order. */ 'aria-sort'?: 'none' | 'ascending' | 'descending' | 'other' | undefined | null; /** Defines the maximum allowed value for a range widget. */ - 'aria-valuemax'?: number | undefined | null; + 'aria-valuemax'?: number | string | undefined | null; /** Defines the minimum allowed value for a range widget. */ - 'aria-valuemin'?: number | undefined | null; + 'aria-valuemin'?: number | string | undefined | null; /** * Defines the current value for a range widget. * @see aria-valuetext. */ - 'aria-valuenow'?: number | undefined | null; + 'aria-valuenow'?: number | string | undefined | null; /** Defines the human readable text alternative of aria-valuenow for a range widget. */ 'aria-valuetext'?: string | undefined | null; } - interface HTMLAttributes - extends AriaAttributes, - DOMAttributes, - AstroBuiltinAttributes { + // All the WAI-ARIA 1.1 role attribute values from https://www.w3.org/TR/wai-aria-1.1/#role_definitions + type AriaRole = + | 'alert' + | 'alertdialog' + | 'application' + | 'article' + | 'banner' + | 'button' + | 'cell' + | 'checkbox' + | 'columnheader' + | 'combobox' + | 'complementary' + | 'contentinfo' + | 'definition' + | 'dialog' + | 'directory' + | 'document' + | 'feed' + | 'figure' + | 'form' + | 'grid' + | 'gridcell' + | 'group' + | 'heading' + | 'img' + | 'link' + | 'list' + | 'listbox' + | 'listitem' + | 'log' + | 'main' + | 'marquee' + | 'math' + | 'menu' + | 'menubar' + | 'menuitem' + | 'menuitemcheckbox' + | 'menuitemradio' + | 'navigation' + | 'none' + | 'note' + | 'option' + | 'presentation' + | 'progressbar' + | 'radio' + | 'radiogroup' + | 'region' + | 'row' + | 'rowgroup' + | 'rowheader' + | 'scrollbar' + | 'search' + | 'searchbox' + | 'separator' + | 'slider' + | 'spinbutton' + | 'status' + | 'switch' + | 'tab' + | 'table' + | 'tablist' + | 'tabpanel' + | 'term' + | 'textbox' + | 'timer' + | 'toolbar' + | 'tooltip' + | 'tree' + | 'treegrid' + | 'treeitem'; + + interface HTMLAttributes extends AriaAttributes, DOMAttributes, AstroBuiltinAttributes { // Standard HTML Attributes - class?: string | undefined | null; - dataset?: object | undefined | null; // eslint-disable-line - accept?: string | undefined | null; - acceptcharset?: string | undefined | null; accesskey?: string | undefined | null; - action?: string | undefined | null; - allow?: string | undefined | null; - allowfullscreen?: boolean | undefined | null; - allowtransparency?: boolean | undefined | null; - allowpaymentrequest?: boolean | undefined | null; - alt?: string | undefined | null; - as?: string | undefined | null; - async?: boolean | undefined | null; - autocomplete?: string | undefined | null; - autofocus?: boolean | undefined | null; - autoplay?: boolean | undefined | null; - capture?: 'environment' | 'user' | boolean | undefined | null; - cellpadding?: number | string | undefined | null; - cellspacing?: number | string | undefined | null; - charset?: string | undefined | null; - challenge?: string | undefined | null; - checked?: boolean | undefined | null; - cite?: string | undefined | null; - classid?: string | undefined | null; - cols?: number | undefined | null; - colspan?: number | undefined | null; - content?: string | URL | undefined | null; - contenteditable?: 'true' | 'false' | boolean | undefined | null; - - // Doesn't work when used as HTML attribute - /** - * Elements with the contenteditable attribute support innerHTML and textContent bindings. - */ - innerHTML?: string | undefined | null; - // Doesn't work when used as HTML attribute - /** - * Elements with the contenteditable attribute support innerHTML and textContent bindings. - */ - - textContent?: string | undefined | null; - - contextmenu?: string | undefined | null; - controls?: boolean | undefined | null; - coords?: string | undefined | null; - crossorigin?: string | boolean | undefined | null; - currenttime?: number | undefined | null; - decoding?: 'async' | 'sync' | 'auto' | undefined | null; - data?: string | undefined | null; - datetime?: string | undefined | null; - default?: boolean | undefined | null; - defaultmuted?: boolean | undefined | null; - defaultplaybackrate?: number | undefined | null; - defer?: boolean | undefined | null; + autocapitalize?: string | undefined | null; + autofocus?: boolean | string | undefined | null; + class?: string | undefined | null; + contenteditable?: 'true' | 'false' | boolean | 'inherit' | string | undefined | null; dir?: string | undefined | null; - dirname?: string | undefined | null; - disabled?: boolean | undefined | null; - download?: any | undefined | null; - draggable?: boolean | 'true' | 'false' | undefined | null; - enctype?: string | undefined | null; + draggable?: 'true' | 'false' | boolean | undefined | null; enterkeyhint?: | 'enter' | 'done' @@ -490,107 +484,44 @@ declare namespace astroHTML.JSX { | 'send' | undefined | null; - for?: string | undefined | null; - form?: string | undefined | null; - formaction?: string | undefined | null; - formenctype?: string | undefined | null; - formmethod?: string | undefined | null; - formnovalidate?: boolean | undefined | null; - formtarget?: string | undefined | null; - frameborder?: number | string | undefined | null; - headers?: string | undefined | null; - height?: number | string | undefined | null; - hidden?: boolean | undefined | null; - high?: number | undefined | null; - href?: string | URL | undefined | null; - hreflang?: string | undefined | null; - htmlfor?: string | undefined | null; - httpequiv?: string | undefined | null; + hidden?: boolean | string | undefined | null; id?: string | undefined | null; - inputmode?: string | undefined | null; - integrity?: string | undefined | null; + inert?: boolean | string | undefined | null; + inputmode?: + | 'none' + | 'text' + | 'tel' + | 'url' + | 'email' + | 'numeric' + | 'decimal' + | 'search' + | undefined + | null; is?: string | undefined | null; - ismap?: boolean | undefined | null; - keyparams?: string | undefined | null; - keytype?: string | undefined | null; - kind?: string | undefined | null; - label?: string | undefined | null; + itemid?: string | undefined | null; + itemprop?: string | undefined | null; + itemref?: string | undefined | null; + itemscope?: boolean | string | undefined | null; + itemtype?: string | undefined | null; lang?: string | undefined | null; - list?: string | undefined | null; - loading?: string | undefined | null; - loop?: boolean | undefined | null; - low?: number | undefined | null; - manifest?: string | undefined | null; - marginheight?: number | undefined | null; - marginwidth?: number | undefined | null; - max?: number | string | undefined | null; - maxlength?: number | undefined | null; - media?: string | undefined | null; - mediagroup?: string | undefined | null; - method?: string | undefined | null; - min?: number | string | undefined | null; - minlength?: number | undefined | null; - multiple?: boolean | undefined | null; - muted?: boolean | undefined | null; - name?: string | undefined | null; - nonce?: string | undefined | null; - novalidate?: boolean | undefined | null; - open?: boolean | undefined | null; - optimum?: number | undefined | null; - part?: string | undefined | null; - pattern?: string | undefined | null; - placeholder?: string | undefined | null; - playsinline?: boolean | undefined | null; - poster?: string | undefined | null; - preload?: string | undefined | null; - radiogroup?: string | undefined | null; - readonly?: boolean | undefined | null; - referrerpolicy?: string | undefined | null; - rel?: string | undefined | null; - required?: boolean | undefined | null; - reversed?: boolean | undefined | null; - role?: string | undefined | null; - rows?: number | undefined | null; - rowspan?: number | undefined | null; - sandbox?: string | undefined | null; - scope?: string | undefined | null; - scoped?: boolean | undefined | null; - scrolling?: string | undefined | null; - seamless?: boolean | undefined | null; - selected?: boolean | undefined | null; - shape?: string | undefined | null; - size?: number | undefined | null; - sizes?: string | undefined | null; slot?: string | undefined | null; - span?: number | undefined | null; - spellcheck?: boolean | 'true' | 'false' | undefined | null; - src?: string | undefined | null; - srcdoc?: string | undefined | null; - srclang?: string | undefined | null; - srcset?: string | undefined | null; - start?: number | undefined | null; - step?: number | string | undefined | null; - style?: string | undefined | null; - summary?: string | undefined | null; - tabindex?: number | undefined | null; - target?: string | undefined | null; + spellcheck?: 'true' | 'false' | boolean | undefined | null; + style?: string | Record | undefined | null; + tabindex?: number | string | undefined | null; title?: string | undefined | null; - translate?: 'yes' | 'no' | '' | undefined | null; - type?: string | undefined | null; - usemap?: string | undefined | null; - value?: any | undefined | null; - /** - * a value between 0 and 1 - */ - volume?: number | undefined | null; - width?: number | string | undefined | null; - wmode?: string | undefined | null; - wrap?: string | undefined | null; + translate?: 'yes' | 'no' | undefined | null; + + // , + radiogroup?: string | undefined | null; + + // WAI-ARIA + role?: AriaRole | undefined | null; // RDFa Attributes about?: string | undefined | null; datatype?: string | undefined | null; - inlist?: any | undefined | null; + inlist?: any; prefix?: string | undefined | null; property?: string | undefined | null; resource?: string | undefined | null; @@ -598,19 +529,472 @@ declare namespace astroHTML.JSX { vocab?: string | undefined | null; // Non-standard Attributes - autocapitalize?: string | undefined | null; - autocorrect?: string | undefined | null; - autosave?: string | undefined | null; + contextmenu?: string | undefined | null; // Obsolete + autosave?: string | undefined | null; // Apple exclusive color?: string | undefined | null; - controlslist?: 'nodownload' | 'nofullscreen' | 'noplaybackrate' | 'noremoteplayback'; - itemprop?: string | undefined | null; - itemscope?: boolean | undefined | null; - itemtype?: string | undefined | null; - itemid?: string | undefined | null; - itemref?: string | undefined | null; - results?: number | undefined | null; + results?: number | string | undefined | null; security?: string | undefined | null; - unselectable?: boolean | undefined | null; + unselectable?: 'on' | 'off' | undefined | null; // Internet Explorer + } + + type HTMLAttributeReferrerPolicy = + | '' + | 'no-referrer' + | 'no-referrer-when-downgrade' + | 'origin' + | 'origin-when-cross-origin' + | 'same-origin' + | 'strict-origin' + | 'strict-origin-when-cross-origin' + | 'unsafe-url'; + + type HTMLAttributeAnchorTarget = '_self' | '_blank' | '_parent' | '_top'; + + interface AnchorHTMLAttributes extends HTMLAttributes { + download?: string | boolean | undefined | null; + href?: string | URL | undefined | null; + hreflang?: string | undefined | null; + media?: string | undefined | null; + ping?: string | undefined | null; + rel?: string | undefined | null; + target?: HTMLAttributeAnchorTarget | undefined | null; + type?: string | undefined | null; + referrerpolicy?: HTMLAttributeReferrerPolicy | undefined | null; + } + + interface AudioHTMLAttributes extends MediaHTMLAttributes {} + + interface AreaHTMLAttributes extends HTMLAttributes { + alt?: string | undefined | null; + coords?: string | undefined | null; + download?: any; + href?: string | undefined | null; + hreflang?: string | undefined | null; + media?: string | undefined | null; + referrerpolicy?: HTMLAttributeReferrerPolicy | undefined | null; + rel?: string | undefined | null; + shape?: string | undefined | null; + target?: string | undefined | null; + } + + interface BaseHTMLAttributes extends HTMLAttributes { + href?: string | undefined | null; + target?: string | undefined | null; + } + + interface BlockquoteHTMLAttributes extends HTMLAttributes { + cite?: string | undefined | null; + } + + interface ButtonHTMLAttributes extends HTMLAttributes { + disabled?: boolean | string | undefined | null; + form?: string | undefined | null; + formaction?: string | undefined | null; + formenctype?: string | undefined | null; + formmethod?: string | undefined | null; + formnovalidate?: boolean | string | undefined | null; + formtarget?: string | undefined | null; + name?: string | undefined | null; + type?: 'submit' | 'reset' | 'button' | undefined | null; + value?: string | string[] | number | undefined | null; + } + + interface CanvasHTMLAttributes extends HTMLAttributes { + height?: number | string | undefined | null; + width?: number | string | undefined | null; + } + + interface ColHTMLAttributes extends HTMLAttributes { + span?: number | string | undefined | null; + width?: number | string | undefined | null; + } + + interface ColgroupHTMLAttributes extends HTMLAttributes { + span?: number | string | undefined | null; + } + + interface DataHTMLAttributes extends HTMLAttributes { + value?: string | string[] | number | undefined | null; + } + + interface DetailsHTMLAttributes extends HTMLAttributes { + open?: boolean | string | undefined | null; + } + + interface DelHTMLAttributes extends HTMLAttributes { + cite?: string | undefined | null; + datetime?: string | undefined | null; + } + + interface DialogHTMLAttributes extends HTMLAttributes { + open?: boolean | string | undefined | null; + } + + interface EmbedHTMLAttributes extends HTMLAttributes { + height?: number | string | undefined | null; + src?: string | undefined | null; + type?: string | undefined | null; + width?: number | string | undefined | null; + } + + interface FieldsetHTMLAttributes extends HTMLAttributes { + disabled?: boolean | string | undefined | null; + form?: string | undefined | null; + name?: string | undefined | null; + } + + interface FormHTMLAttributes extends HTMLAttributes { + 'accept-charset'?: string | undefined | null; + action?: string | undefined | null; + autocomplete?: string | undefined | null; + autocorrect?: string | undefined | null; + enctype?: string | undefined | null; + method?: string | undefined | null; + name?: string | undefined | null; + novalidate?: boolean | string | undefined | null; + target?: string | undefined | null; + } + + interface HtmlHTMLAttributes extends HTMLAttributes { + manifest?: string | undefined | null; + } + + interface IframeHTMLAttributes extends HTMLAttributes { + allow?: string | undefined | null; + allowfullscreen?: boolean | string | undefined | null; + allowtransparency?: boolean | string | undefined | null; + /** @deprecated */ + frameborder?: number | string | undefined | null; + height?: number | string | undefined | null; + /** @deprecated */ + marginheight?: number | string | undefined | null; + /** @deprecated */ + marginwidth?: number | string | undefined | null; + name?: string | undefined | null; + referrerpolicy?: HTMLAttributeReferrerPolicy | undefined | null; + sandbox?: string | undefined | null; + /** @deprecated */ + scrolling?: string | undefined | null; + seamless?: boolean | string | undefined | null; + src?: string | undefined | null; + srcdoc?: string | undefined | null; + width?: number | string | undefined | null; + } + + interface ImgHTMLAttributes extends HTMLAttributes { + alt?: string | undefined | null; + crossorigin?: 'anonymous' | 'use-credentials' | '' | undefined | null; + decoding?: 'async' | 'auto' | 'sync' | undefined | null; + height?: number | string | undefined | null; + loading?: 'eager' | 'lazy' | undefined | null; + referrerpolicy?: HTMLAttributeReferrerPolicy | undefined | null; + sizes?: string | undefined | null; + src?: string | undefined | null; + srcset?: string | undefined | null; + usemap?: string | undefined | null; + width?: number | string | undefined | null; + } + + interface InsHTMLAttributes extends HTMLAttributes { + cite?: string | undefined | null; + datetime?: string | undefined | null; + } + + type HTMLInputTypeAttribute = + | 'button' + | 'checkbox' + | 'color' + | 'date' + | 'datetime-local' + | 'email' + | 'file' + | 'hidden' + | 'image' + | 'month' + | 'number' + | 'password' + | 'radio' + | 'range' + | 'reset' + | 'search' + | 'submit' + | 'tel' + | 'text' + | 'time' + | 'url' + | 'week'; + + interface InputHTMLAttributes extends HTMLAttributes { + accept?: string | undefined | null; + alt?: string | undefined | null; + autocomplete?: string | undefined | null; + autocorrect?: string | undefined | null; + capture?: boolean | string | undefined | null; + checked?: boolean | string | undefined | null; + crossorigin?: string | undefined | null; + dirname?: string | undefined | null; + disabled?: boolean | string | undefined | null; + form?: string | undefined | null; + formaction?: string | undefined | null; + formenctype?: string | undefined | null; + formmethod?: string | undefined | null; + formnovalidate?: boolean | string | undefined | null; + formtarget?: string | undefined | null; + height?: number | string | undefined | null; + list?: string | undefined | null; + max?: number | string | undefined | null; + maxlength?: number | string | undefined | null; + min?: number | string | undefined | null; + minlength?: number | string | undefined | null; + multiple?: boolean | string | undefined | null; + name?: string | undefined | null; + pattern?: string | undefined | null; + placeholder?: string | undefined | null; + readonly?: boolean | string | undefined | null; + required?: boolean | string | undefined | null; + size?: number | string | undefined | null; + src?: string | undefined | null; + step?: number | string | undefined | null; + type?: HTMLInputTypeAttribute | string | undefined | null; + value?: string | string[] | number | undefined | null; + width?: number | string | undefined | null; + } + + interface KeygenHTMLAttributes extends HTMLAttributes { + challenge?: string | undefined | null; + disabled?: boolean | string | undefined | null; + form?: string | undefined | null; + keytype?: string | undefined | null; + keyparams?: string | undefined | null; + name?: string | undefined | null; + } + + interface LabelHTMLAttributes extends HTMLAttributes { + form?: string | undefined | null; + for?: string | undefined | null; + } + + interface LiHTMLAttributes extends HTMLAttributes { + value?: string | number | undefined | null; + } + + interface LinkHTMLAttributes extends HTMLAttributes { + as?: string | undefined | null; + crossorigin?: boolean | string | undefined | null; + href?: string | URL | undefined | null; + hreflang?: string | undefined | null; + integrity?: string | undefined | null; + media?: string | undefined | null; + imageSrcSet?: string | undefined | null; + imageSizes?: string | undefined | null; + referrerPolicy?: HTMLAttributeReferrerPolicy | undefined | null; + rel?: string | undefined | null; + sizes?: string | undefined | null; + type?: string | undefined | null; + charset?: string | undefined | null; + } + + interface MapHTMLAttributes extends HTMLAttributes { + name?: string | undefined | null; + } + + interface MenuHTMLAttributes extends HTMLAttributes { + type?: string | undefined | null; + } + + interface MediaHTMLAttributes extends HTMLAttributes { + autoplay?: boolean | string | undefined | null; + controls?: boolean | string | undefined | null; + controlslist?: string | undefined | null; + crossorigin?: string | undefined | null; + loop?: boolean | string | undefined | null; + mediagroup?: string | undefined | null; + muted?: boolean | string | undefined | null; + playsinline?: boolean | string | undefined | null; + preload?: string | undefined | null; + src?: string | undefined | null; + } + + interface MetaHTMLAttributes extends HTMLAttributes { + charset?: string | undefined | null; + content?: string | URL | undefined | null; + 'http-equiv'?: string | undefined | null; + name?: string | undefined | null; + media?: string | undefined | null; + } + + interface MeterHTMLAttributes extends HTMLAttributes { + form?: string | undefined | null; + high?: number | string | undefined | null; + low?: number | string | undefined | null; + max?: number | string | undefined | null; + min?: number | string | undefined | null; + optimum?: number | string | undefined | null; + value?: string | string[] | number | undefined | null; + } + + interface QuoteHTMLAttributes extends HTMLAttributes { + cite?: string | undefined | null; + } + + interface ObjectHTMLAttributes extends HTMLAttributes { + classid?: string | undefined | null; + data?: string | undefined | null; + form?: string | undefined | null; + height?: number | string | undefined | null; + name?: string | undefined | null; + type?: string | undefined | null; + usemap?: string | undefined | null; + width?: number | string | undefined | null; + wmode?: string | undefined | null; + } + + interface OlHTMLAttributes extends HTMLAttributes { + reversed?: boolean | string | undefined | null; + start?: number | string | undefined | null; + type?: '1' | 'a' | 'A' | 'i' | 'I' | undefined | null; + } + + interface OptgroupHTMLAttributes extends HTMLAttributes { + disabled?: boolean | string | undefined | null; + label?: string | undefined | null; + } + + interface OptionHTMLAttributes extends HTMLAttributes { + disabled?: boolean | string | undefined | null; + label?: string | undefined | null; + selected?: boolean | string | undefined | null; + value?: string | string[] | number | undefined | null; + } + + interface OutputHTMLAttributes extends HTMLAttributes { + form?: string | undefined | null; + for?: string | undefined | null; + name?: string | undefined | null; + } + + interface ParamHTMLAttributes extends HTMLAttributes { + name?: string | undefined | null; + value?: string | string[] | number | undefined | null; + } + + interface ProgressHTMLAttributes extends HTMLAttributes { + max?: number | string | undefined | null; + value?: string | string[] | number | undefined | null; + } + + interface SlotHTMLAttributes extends HTMLAttributes { + name?: string | undefined | null; + } + + interface ScriptHTMLAttributes extends HTMLAttributes { + async?: boolean | string | undefined | null; + charset?: string | undefined | null; + crossorigin?: string | undefined | null; + defer?: boolean | string | undefined | null; + integrity?: string | undefined | null; + nomodule?: boolean | string | undefined | null; + nonce?: string | undefined | null; + src?: string | undefined | null; + type?: string | undefined | null; + } + + interface SelectHTMLAttributes extends HTMLAttributes { + autocomplete?: string | undefined | null; + autocorrect?: string | undefined | null; + disabled?: boolean | string | undefined | null; + form?: string | undefined | null; + multiple?: boolean | string | undefined | null; + name?: string | undefined | null; + required?: boolean | string | undefined | null; + size?: number | string | undefined | null; + value?: string | string[] | number | undefined | null; + } + + interface SourceHTMLAttributes extends HTMLAttributes { + height?: number | string | undefined | null; + media?: string | undefined | null; + sizes?: string | undefined | null; + src?: string | undefined | null; + srcset?: string | undefined | null; + type?: string | undefined | null; + width?: number | string | undefined | null; + } + + interface StyleHTMLAttributes extends HTMLAttributes { + media?: string | undefined | null; + nonce?: string | undefined | null; + scoped?: boolean | string | undefined | null; + type?: string | undefined | null; + } + + interface TableHTMLAttributes extends HTMLAttributes { + align?: 'left' | 'center' | 'right' | undefined | null; + bgcolor?: string | undefined | null; + border?: number | undefined | null; + cellpadding?: number | string | undefined | null; + cellspacing?: number | string | undefined | null; + frame?: boolean | undefined | null; + rules?: 'none' | 'groups' | 'rows' | 'columns' | 'all' | undefined | null; + summary?: string | undefined | null; + width?: number | string | undefined | null; + } + + interface TextareaHTMLAttributes extends HTMLAttributes { + autocomplete?: string | undefined | null; + autocorrect?: string | undefined | null; + cols?: number | string | undefined | null; + dirname?: string | undefined | null; + disabled?: boolean | string | undefined | null; + form?: string | undefined | null; + maxlength?: number | string | undefined | null; + minlength?: number | string | undefined | null; + name?: string | undefined | null; + placeholder?: string | undefined | null; + readonly?: boolean | string | undefined | null; + required?: boolean | string | undefined | null; + rows?: number | string | undefined | null; + value?: string | string[] | number | undefined | null; + wrap?: string | undefined | null; + } + + interface TdHTMLAttributes extends HTMLAttributes { + align?: 'left' | 'center' | 'right' | 'justify' | 'char' | undefined | null; + colspan?: number | string | undefined | null; + headers?: string | undefined | null; + rowspan?: number | string | undefined | null; + scope?: string | undefined | null; + abbr?: string | undefined | null; + valign?: 'top' | 'middle' | 'bottom' | 'baseline' | undefined | null; + } + + interface ThHTMLAttributes extends HTMLAttributes { + align?: 'left' | 'center' | 'right' | 'justify' | 'char' | undefined | null; + colspan?: number | string | undefined | null; + headers?: string | undefined | null; + rowspan?: number | string | undefined | null; + scope?: string | undefined | null; + abbr?: string | undefined | null; + } + + interface TimeHTMLAttributes extends HTMLAttributes { + datetime?: string | undefined | null; + } + + interface TrackHTMLAttributes extends HTMLAttributes { + default?: boolean | string | undefined | null; + kind?: string | undefined | null; + label?: string | undefined | null; + src?: string | undefined | null; + srclang?: string | undefined | null; + } + + interface VideoHTMLAttributes extends MediaHTMLAttributes { + height?: number | string | undefined | null; + playsinline?: boolean | string | undefined | null; + poster?: string | undefined | null; + width?: number | string | undefined | null; + disablepictureinpicture?: boolean | string | undefined | null; } // this list is "complete" in that it contains every SVG attribute @@ -621,12 +1005,8 @@ declare namespace astroHTML.JSX { // - "number | string" // - "string" // - union of string literals - interface SVGAttributes - extends AriaAttributes, - DOMAttributes, - AstroBuiltinAttributes { + interface SVGAttributes extends AriaAttributes, DOMAttributes, AstroBuiltinAttributes { // Attributes which also defined in HTMLAttributes - className?: string | undefined | null; class?: string | undefined | null; color?: string | undefined | null; height?: number | string | undefined | null; @@ -637,14 +1017,14 @@ declare namespace astroHTML.JSX { method?: string | undefined | null; min?: number | string | undefined | null; name?: string | undefined | null; - style?: string | undefined | null; + style?: string | Record | undefined | null; target?: string | undefined | null; type?: string | undefined | null; width?: number | string | undefined | null; // Other HTML properties supported by SVG elements in browsers - role?: string | undefined | null; - tabindex?: number | undefined | null; + role?: AriaRole | undefined | null; + tabindex?: number | string | undefined | null; crossorigin?: 'anonymous' | 'use-credentials' | '' | undefined | null; // SVG Specific attributes @@ -906,184 +1286,181 @@ declare namespace astroHTML.JSX { zoomAndPan?: string | undefined | null; } - // eslint-disable-next-line @typescript-eslint/no-empty-interface - interface HTMLProps extends HTMLAttributes {} - // eslint-disable-next-line @typescript-eslint/no-empty-interface - interface SVGProps extends SVGAttributes {} - interface IntrinsicElements { // HTML - a: HTMLProps; - abbr: HTMLProps; - address: HTMLProps; - area: HTMLProps; - article: HTMLProps; - aside: HTMLProps; - audio: HTMLProps; - b: HTMLProps; - base: HTMLProps; - bdi: HTMLProps; - bdo: HTMLProps; - big: HTMLProps; - blockquote: HTMLProps; - body: HTMLProps; - br: HTMLProps; - button: HTMLProps; - canvas: HTMLProps; - caption: HTMLProps; - cite: HTMLProps; - code: HTMLProps; - col: HTMLProps; - colgroup: HTMLProps; - data: HTMLProps; - datalist: HTMLProps; - dd: HTMLProps; - del: HTMLProps; - details: HTMLProps; - dfn: HTMLProps; - dialog: HTMLProps; - div: HTMLProps; - dl: HTMLProps; - dt: HTMLProps; - em: HTMLProps; - embed: HTMLProps; - fieldset: HTMLProps; - figcaption: HTMLProps; - figure: HTMLProps; - footer: HTMLProps; - form: HTMLProps; - h1: HTMLProps; - h2: HTMLProps; - h3: HTMLProps; - h4: HTMLProps; - h5: HTMLProps; - h6: HTMLProps; - head: HTMLProps; - header: HTMLProps; - hgroup: HTMLProps; - hr: HTMLProps; - html: HTMLProps; - i: HTMLProps; - iframe: HTMLProps; - img: HTMLProps; - input: HTMLProps; - ins: HTMLProps; - kbd: HTMLProps; - keygen: HTMLProps; - label: HTMLProps; - legend: HTMLProps; - li: HTMLProps; - link: HTMLProps; - main: HTMLProps; - map: HTMLProps; - mark: HTMLProps; - menu: HTMLProps; - menuitem: HTMLProps; - meta: HTMLProps; - meter: HTMLProps; - nav: HTMLProps; - noindex: HTMLProps; - noscript: HTMLProps; - object: HTMLProps; - ol: HTMLProps; - optgroup: HTMLProps; - option: HTMLProps; - output: HTMLProps; - p: HTMLProps; - param: HTMLProps; - picture: HTMLProps; - pre: HTMLProps; - progress: HTMLProps; - q: HTMLProps; - rp: HTMLProps; - rt: HTMLProps; - ruby: HTMLProps; - s: HTMLProps; - samp: HTMLProps; - script: HTMLProps & AstroScriptAttributes; - section: HTMLProps; - select: HTMLProps; - small: HTMLProps; - source: HTMLProps; - span: HTMLProps; - strong: HTMLProps; - style: HTMLProps & AstroStyleAttributes; - sub: HTMLProps; - summary: HTMLProps; - sup: HTMLProps; - table: HTMLProps; - tbody: HTMLProps; - td: HTMLProps; - textarea: HTMLProps; - tfoot: HTMLProps; - th: HTMLProps; - thead: HTMLProps; - time: HTMLProps; - title: HTMLProps; - tr: HTMLProps; - track: HTMLProps; - u: HTMLProps; - ul: HTMLProps; - var: HTMLProps; - video: HTMLProps; - wbr: HTMLProps; + a: AnchorHTMLAttributes; + abbr: HTMLAttributes; + address: HTMLAttributes; + area: AreaHTMLAttributes; + article: HTMLAttributes; + aside: HTMLAttributes; + audio: AudioHTMLAttributes; + b: HTMLAttributes; + base: BaseHTMLAttributes; + bdi: HTMLAttributes; + bdo: HTMLAttributes; + big: HTMLAttributes; + blockquote: BlockquoteHTMLAttributes; + body: HTMLAttributes; + br: HTMLAttributes; + button: ButtonHTMLAttributes; + canvas: CanvasHTMLAttributes; + caption: HTMLAttributes; + cite: HTMLAttributes; + code: HTMLAttributes; + col: ColHTMLAttributes; + colgroup: ColgroupHTMLAttributes; + data: DataHTMLAttributes; + datalist: HTMLAttributes; + dd: HTMLAttributes; + del: DelHTMLAttributes; + details: DetailsHTMLAttributes; + dfn: HTMLAttributes; + dialog: DialogHTMLAttributes; + div: HTMLAttributes; + dl: HTMLAttributes; + dt: HTMLAttributes; + em: HTMLAttributes; + embed: EmbedHTMLAttributes; + fieldset: FieldsetHTMLAttributes; + figcaption: HTMLAttributes; + figure: HTMLAttributes; + footer: HTMLAttributes; + form: FormHTMLAttributes; + h1: HTMLAttributes; + h2: HTMLAttributes; + h3: HTMLAttributes; + h4: HTMLAttributes; + h5: HTMLAttributes; + h6: HTMLAttributes; + head: HTMLAttributes; + header: HTMLAttributes; + hgroup: HTMLAttributes; + hr: HTMLAttributes; + html: HtmlHTMLAttributes; + i: HTMLAttributes; + iframe: IframeHTMLAttributes; + img: ImgHTMLAttributes; + input: InputHTMLAttributes; + ins: InsHTMLAttributes; + kbd: HTMLAttributes; + keygen: KeygenHTMLAttributes; + label: LabelHTMLAttributes; + legend: HTMLAttributes; + li: LiHTMLAttributes; + link: LinkHTMLAttributes; + main: HTMLAttributes; + map: MapHTMLAttributes; + mark: HTMLAttributes; + menu: MenuHTMLAttributes; + menuitem: HTMLAttributes; + meta: MetaHTMLAttributes; + meter: MeterHTMLAttributes; + nav: HTMLAttributes; + noindex: HTMLAttributes; // https://en.wikipedia.org/wiki/Noindex#%3Cnoindex%3E_tag + noscript: HTMLAttributes; + object: ObjectHTMLAttributes; + ol: OlHTMLAttributes; + optgroup: OptgroupHTMLAttributes; + option: OptionHTMLAttributes; + output: OutputHTMLAttributes; + p: HTMLAttributes; + param: ParamHTMLAttributes; + picture: HTMLAttributes; + pre: HTMLAttributes; + progress: ProgressHTMLAttributes; + q: QuoteHTMLAttributes; + rp: HTMLAttributes; + rt: HTMLAttributes; + ruby: HTMLAttributes; + s: HTMLAttributes; + samp: HTMLAttributes; + slot: SlotHTMLAttributes; + script: ScriptHTMLAttributes & AstroScriptAttributes; + section: HTMLAttributes; + select: SelectHTMLAttributes; + small: HTMLAttributes; + source: SourceHTMLAttributes; + span: HTMLAttributes; + strong: HTMLAttributes; + style: StyleHTMLAttributes & AstroStyleAttributes; + sub: HTMLAttributes; + summary: HTMLAttributes; + sup: HTMLAttributes; + table: TableHTMLAttributes; + tbody: HTMLAttributes; + td: TdHTMLAttributes; + textarea: TextareaHTMLAttributes; + tfoot: HTMLAttributes; + th: ThHTMLAttributes; + thead: HTMLAttributes; + time: TimeHTMLAttributes; + title: HTMLAttributes; + tr: HTMLAttributes; + track: TrackHTMLAttributes; + u: HTMLAttributes; + ul: HTMLAttributes; + var: HTMLAttributes; + video: VideoHTMLAttributes; + wbr: HTMLAttributes; - svg: SVGProps; - - animate: SVGProps; - circle: SVGProps; - clipPath: SVGProps; - defs: SVGProps; - desc: SVGProps; - ellipse: SVGProps; - feBlend: SVGProps; - feColorMatrix: SVGProps; - feComponentTransfer: SVGProps; - feComposite: SVGProps; - feConvolveMatrix: SVGProps; - feDiffuseLighting: SVGProps; - feDisplacementMap: SVGProps; - feDistantLight: SVGProps; - feFlood: SVGProps; - feFuncA: SVGProps; - feFuncB: SVGProps; - feFuncG: SVGProps; - feFuncR: SVGProps; - feGaussianBlur: SVGProps; - feImage: SVGProps; - feMerge: SVGProps; - feMergeNode: SVGProps; - feMorphology: SVGProps; - feOffset: SVGProps; - fePointLight: SVGProps; - feSpecularLighting: SVGProps; - feSpotLight: SVGProps; - feTile: SVGProps; - feTurbulence: SVGProps; - filter: SVGProps; - foreignObject: SVGProps; - g: SVGProps; - image: SVGProps; - line: SVGProps; - linearGradient: SVGProps; - marker: SVGProps; - mask: SVGProps; - metadata: SVGProps; - path: SVGProps; - pattern: SVGProps; - polygon: SVGProps; - polyline: SVGProps; - radialGradient: SVGProps; - rect: SVGProps; - stop: SVGProps; - switch: SVGProps; - symbol: SVGProps; - text: SVGProps; - textPath: SVGProps; - tspan: SVGProps; - use: SVGProps; - view: SVGProps; + // SVG + svg: SVGAttributes; + animate: SVGAttributes; + circle: SVGAttributes; + clipPath: SVGAttributes; + defs: SVGAttributes; + desc: SVGAttributes; + ellipse: SVGAttributes; + feBlend: SVGAttributes; + feColorMatrix: SVGAttributes; + feComponentTransfer: SVGAttributes; + feComposite: SVGAttributes; + feConvolveMatrix: SVGAttributes; + feDiffuseLighting: SVGAttributes; + feDisplacementMap: SVGAttributes; + feDistantLight: SVGAttributes; + feFlood: SVGAttributes; + feFuncA: SVGAttributes; + feFuncB: SVGAttributes; + feFuncG: SVGAttributes; + feFuncR: SVGAttributes; + feGaussianBlur: SVGAttributes; + feImage: SVGAttributes; + feMerge: SVGAttributes; + feMergeNode: SVGAttributes; + feMorphology: SVGAttributes; + feOffset: SVGAttributes; + fePointLight: SVGAttributes; + feSpecularLighting: SVGAttributes; + feSpotLight: SVGAttributes; + feTile: SVGAttributes; + feTurbulence: SVGAttributes; + filter: SVGAttributes; + foreignObject: SVGAttributes; + g: SVGAttributes; + image: SVGAttributes; + line: SVGAttributes; + linearGradient: SVGAttributes; + marker: SVGAttributes; + mask: SVGAttributes; + metadata: SVGAttributes; + path: SVGAttributes; + pattern: SVGAttributes; + polygon: SVGAttributes; + polyline: SVGAttributes; + radialGradient: SVGAttributes; + rect: SVGAttributes; + stop: SVGAttributes; + switch: SVGAttributes; + symbol: SVGAttributes; + text: SVGAttributes; + textPath: SVGAttributes; + tspan: SVGAttributes; + use: SVGAttributes; + view: SVGAttributes; + // Allow for arbitrary elements [name: string]: { [name: string]: any }; } } diff --git a/packages/astro/astro.js b/packages/astro/astro.js index d763b0302..311f9cdda 100755 --- a/packages/astro/astro.js +++ b/packages/astro/astro.js @@ -50,7 +50,7 @@ async function main() { // it's okay to hard-code the valid Node versions here since they will not change over time. if (typeof require === 'undefined') { console.error(`\nNode.js v${version} is not supported by Astro! -Please upgrade to a version of Node.js with complete ESM support: "^14.15.0 || >=16.0.0"\n`); +Please upgrade to a version of Node.js with complete ESM support: "^14.18.0 || >=16.12.0"\n`); } // Not supported: Report the most helpful error message possible. diff --git a/packages/astro/client.d.ts b/packages/astro/client.d.ts new file mode 100644 index 000000000..cfbb65ef0 --- /dev/null +++ b/packages/astro/client.d.ts @@ -0,0 +1,207 @@ +/// + +// CSS modules +type CSSModuleClasses = { readonly [key: string]: string }; + +declare module '*.module.css' { + const classes: CSSModuleClasses; + export default classes; +} +declare module '*.module.scss' { + const classes: CSSModuleClasses; + export default classes; +} +declare module '*.module.sass' { + const classes: CSSModuleClasses; + export default classes; +} +declare module '*.module.less' { + const classes: CSSModuleClasses; + export default classes; +} +declare module '*.module.styl' { + const classes: CSSModuleClasses; + export default classes; +} +declare module '*.module.stylus' { + const classes: CSSModuleClasses; + export default classes; +} +declare module '*.module.pcss' { + const classes: CSSModuleClasses; + export default classes; +} + +// CSS +declare module '*.css' { + const css: string; + export default css; +} +declare module '*.scss' { + const css: string; + export default css; +} +declare module '*.sass' { + const css: string; + export default css; +} +declare module '*.less' { + const css: string; + export default css; +} +declare module '*.styl' { + const css: string; + export default css; +} +declare module '*.stylus' { + const css: string; + export default css; +} +declare module '*.pcss' { + const css: string; + export default css; +} + +// Built-in asset types +// see `src/constants.ts` + +// images +declare module '*.jpg' { + const src: string; + export default src; +} +declare module '*.jpeg' { + const src: string; + export default src; +} +declare module '*.png' { + const src: string; + export default src; +} +declare module '*.gif' { + const src: string; + export default src; +} +declare module '*.svg' { + const src: string; + export default src; +} +declare module '*.ico' { + const src: string; + export default src; +} +declare module '*.webp' { + const src: string; + export default src; +} +declare module '*.avif' { + const src: string; + export default src; +} + +// media +declare module '*.mp4' { + const src: string; + export default src; +} +declare module '*.webm' { + const src: string; + export default src; +} +declare module '*.ogg' { + const src: string; + export default src; +} +declare module '*.mp3' { + const src: string; + export default src; +} +declare module '*.wav' { + const src: string; + export default src; +} +declare module '*.flac' { + const src: string; + export default src; +} +declare module '*.aac' { + const src: string; + export default src; +} + +// fonts +declare module '*.woff' { + const src: string; + export default src; +} +declare module '*.woff2' { + const src: string; + export default src; +} +declare module '*.eot' { + const src: string; + export default src; +} +declare module '*.ttf' { + const src: string; + export default src; +} +declare module '*.otf' { + const src: string; + export default src; +} + +// other +declare module '*.wasm' { + const initWasm: (options: WebAssembly.Imports) => Promise; + export default initWasm; +} +declare module '*.webmanifest' { + const src: string; + export default src; +} +declare module '*.pdf' { + const src: string; + export default src; +} +declare module '*.txt' { + const src: string; + export default src; +} + +// web worker +declare module '*?worker' { + const workerConstructor: { + new (): Worker; + }; + export default workerConstructor; +} + +declare module '*?worker&inline' { + const workerConstructor: { + new (): Worker; + }; + export default workerConstructor; +} + +declare module '*?sharedworker' { + const sharedWorkerConstructor: { + new (): SharedWorker; + }; + export default sharedWorkerConstructor; +} + +declare module '*?raw' { + const src: string; + export default src; +} + +declare module '*?url' { + const src: string; + export default src; +} + +declare module '*?inline' { + const src: string; + export default src; +} diff --git a/packages/astro/components/Code.astro b/packages/astro/components/Code.astro index e829f87be..a2052c816 100644 --- a/packages/astro/components/Code.astro +++ b/packages/astro/components/Code.astro @@ -36,8 +36,8 @@ const { code, lang = 'plaintext', theme = 'github-dark', wrap = false } = Astro. /** Replace the shiki class name with a custom astro class name. */ function repairShikiTheme(html: string): string { - // Replace "shiki" class naming with "astro" and add "is:raw". - html = html.replace('
      -	
      -

      Debug "{key}"

      +
      +
      +

      Debug "{key}"

      - diff --git a/packages/astro/e2e/fixtures/nested-recursive/src/components/VueCounter.vue b/packages/astro/e2e/fixtures/nested-recursive/src/components/VueCounter.vue new file mode 100644 index 000000000..d404cc965 --- /dev/null +++ b/packages/astro/e2e/fixtures/nested-recursive/src/components/VueCounter.vue @@ -0,0 +1,34 @@ + + + diff --git a/packages/astro/e2e/fixtures/nested-recursive/src/pages/index.astro b/packages/astro/e2e/fixtures/nested-recursive/src/pages/index.astro new file mode 100644 index 000000000..685c7fb5e --- /dev/null +++ b/packages/astro/e2e/fixtures/nested-recursive/src/pages/index.astro @@ -0,0 +1,28 @@ +--- +import ReactCounter from '../components/ReactCounter.jsx'; +import PreactCounter from '../components/PreactCounter.tsx'; +import SolidCounter from '../components/SolidCounter.tsx'; +import VueCounter from '../components/VueCounter.vue'; +import SvelteCounter from '../components/SvelteCounter.svelte'; +--- + + + + + + + + +
      + + + + + + + + + +
      + + diff --git a/packages/astro/e2e/fixtures/pass-js/astro.config.mjs b/packages/astro/e2e/fixtures/pass-js/astro.config.mjs new file mode 100644 index 000000000..8a6f1951c --- /dev/null +++ b/packages/astro/e2e/fixtures/pass-js/astro.config.mjs @@ -0,0 +1,7 @@ +import { defineConfig } from 'astro/config'; +import react from '@astrojs/react'; + +// https://astro.build/config +export default defineConfig({ + integrations: [react()], +}); diff --git a/packages/astro/e2e/fixtures/pass-js/package.json b/packages/astro/e2e/fixtures/pass-js/package.json new file mode 100644 index 000000000..b01293b84 --- /dev/null +++ b/packages/astro/e2e/fixtures/pass-js/package.json @@ -0,0 +1,13 @@ +{ + "name": "@e2e/pass-js", + "version": "0.0.0", + "private": true, + "devDependencies": { + "@astrojs/react": "workspace:*", + "astro": "workspace:*" + }, + "dependencies": { + "react": "^18.1.0", + "react-dom": "^18.1.0" + } +} diff --git a/packages/astro/e2e/fixtures/pass-js/src/components/React.tsx b/packages/astro/e2e/fixtures/pass-js/src/components/React.tsx new file mode 100644 index 000000000..02023fc9d --- /dev/null +++ b/packages/astro/e2e/fixtures/pass-js/src/components/React.tsx @@ -0,0 +1,39 @@ +import type { BigNestedObject } from '../types'; +import { useState } from 'react'; + +interface Props { + obj: BigNestedObject; + num: bigint; + arr: any[]; + map: Map; + set: Set; +} + +const isNode = typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]'; + +/** a counter written in React */ +export default function Component({ obj, num, arr, map, set }: Props) { + // We are testing hydration, so don't return anything in the server. + if(isNode) { + return
      + } + + return ( +
      + {obj.nested.date.toUTCString()} + {Object.prototype.toString.call(obj.more.another.exp)} + {obj.more.another.exp.source} + {Object.prototype.toString.call(num)} + {num.toString()} + {Object.prototype.toString.call(arr)} + {arr.join(',')} + {Object.prototype.toString.call(map)} +
        {Array.from(map).map(([key, value]) => ( +
      • {key}: {value}
      • + ))} +
      + {Object.prototype.toString.call(set)} + {Array.from(set).join(',')} +
      + ); +} diff --git a/packages/astro/e2e/fixtures/pass-js/src/pages/index.astro b/packages/astro/e2e/fixtures/pass-js/src/pages/index.astro new file mode 100644 index 000000000..be40948d8 --- /dev/null +++ b/packages/astro/e2e/fixtures/pass-js/src/pages/index.astro @@ -0,0 +1,36 @@ +--- +import Component from '../components/React'; +import { BigNestedObject } from '../types'; + +const obj: BigNestedObject = { + nested: { + date: new Date('Thu, 09 Jun 2022 14:18:27 GMT') + }, + more: { + another: { + exp: /ok/ + } + } +}; + +const map = new Map(); +map.set('test1', 'test2'); +map.set('test3', 'test4'); + +const set = new Set(); +set.add('test1'); +set.add('test2'); +--- + + + + + + + + +
      + +
      + + diff --git a/packages/astro/e2e/fixtures/pass-js/src/types.ts b/packages/astro/e2e/fixtures/pass-js/src/types.ts new file mode 100644 index 000000000..736c33e1a --- /dev/null +++ b/packages/astro/e2e/fixtures/pass-js/src/types.ts @@ -0,0 +1,11 @@ + +export interface BigNestedObject { + nested: { + date: Date; + }; + more: { + another: { + exp: RegExp; + } + } +} diff --git a/packages/astro/e2e/fixtures/preact-compat-component/astro.config.mjs b/packages/astro/e2e/fixtures/preact-compat-component/astro.config.mjs new file mode 100644 index 000000000..2cd377763 --- /dev/null +++ b/packages/astro/e2e/fixtures/preact-compat-component/astro.config.mjs @@ -0,0 +1,10 @@ +import { defineConfig } from 'astro/config'; +import preact from '@astrojs/preact'; + +// https://astro.build/config +export default defineConfig({ + legacy: { + astroFlavoredMarkdown: true, + }, + integrations: [preact({ compat: true })], +}); diff --git a/packages/astro/e2e/fixtures/preact-compat-component/package.json b/packages/astro/e2e/fixtures/preact-compat-component/package.json new file mode 100644 index 000000000..489d24338 --- /dev/null +++ b/packages/astro/e2e/fixtures/preact-compat-component/package.json @@ -0,0 +1,10 @@ +{ + "name": "@e2e/preact-component", + "version": "0.0.0", + "private": true, + "dependencies": { + "@astrojs/preact": "workspace:*", + "astro": "workspace:*", + "preact": "^10.7.3" + } +} diff --git a/packages/astro/e2e/fixtures/preact-compat-component/src/components/Counter.css b/packages/astro/e2e/fixtures/preact-compat-component/src/components/Counter.css new file mode 100644 index 000000000..fb21044d7 --- /dev/null +++ b/packages/astro/e2e/fixtures/preact-compat-component/src/components/Counter.css @@ -0,0 +1,11 @@ +.counter { + display: grid; + font-size: 2em; + grid-template-columns: repeat(3, minmax(0, 1fr)); + margin-top: 2em; + place-items: center; +} + +.counter-message { + text-align: center; +} diff --git a/packages/astro/e2e/fixtures/preact-compat-component/src/components/Counter.jsx b/packages/astro/e2e/fixtures/preact-compat-component/src/components/Counter.jsx new file mode 100644 index 000000000..4f1b381e4 --- /dev/null +++ b/packages/astro/e2e/fixtures/preact-compat-component/src/components/Counter.jsx @@ -0,0 +1,19 @@ +import { useState } from 'react'; +import './Counter.css'; + +export default function Counter({ children, count: initialCount, id }) { + const [count, setCount] = useState(initialCount); + const add = () => setCount((i) => i + 1); + const subtract = () => setCount((i) => i - 1); + + return ( + <> +
      + +
      {count}
      + +
      +
      {children}
      + + ); +} diff --git a/packages/astro/e2e/fixtures/preact-compat-component/src/components/JSXComponent.jsx b/packages/astro/e2e/fixtures/preact-compat-component/src/components/JSXComponent.jsx new file mode 100644 index 000000000..dcafa028c --- /dev/null +++ b/packages/astro/e2e/fixtures/preact-compat-component/src/components/JSXComponent.jsx @@ -0,0 +1,5 @@ +import React from 'react'; + +export default function({ id }) { + return
      Framework client:only component
      +} diff --git a/packages/astro/e2e/fixtures/preact-compat-component/src/components/Layout.astro b/packages/astro/e2e/fixtures/preact-compat-component/src/components/Layout.astro new file mode 100644 index 000000000..7aa058a2d --- /dev/null +++ b/packages/astro/e2e/fixtures/preact-compat-component/src/components/Layout.astro @@ -0,0 +1,4 @@ + + Preact compat component + + diff --git a/packages/astro/e2e/fixtures/preact-compat-component/src/pages/index.astro b/packages/astro/e2e/fixtures/preact-compat-component/src/pages/index.astro new file mode 100644 index 000000000..30824b76d --- /dev/null +++ b/packages/astro/e2e/fixtures/preact-compat-component/src/pages/index.astro @@ -0,0 +1,37 @@ +--- +import Counter from '../components/Counter.jsx'; +import PreactCompatComponent from '../components/JSXComponent.jsx'; + +const someProps = { + count: 0, +}; +--- + + + + + + + +

      Hello, server!

      +
      + + +

      Hello, client:idle!

      +
      + + +

      Hello, client:load!

      +
      + + +

      Hello, client:visible!

      +
      + + +

      Hello, client:media!

      +
      + + + + diff --git a/packages/astro/e2e/fixtures/preact-compat-component/src/pages/markdown.md b/packages/astro/e2e/fixtures/preact-compat-component/src/pages/markdown.md new file mode 100644 index 000000000..7c521de77 --- /dev/null +++ b/packages/astro/e2e/fixtures/preact-compat-component/src/pages/markdown.md @@ -0,0 +1,32 @@ +--- +layout: ../components/Layout.astro +setup: | + import Counter from '../components/Counter.jsx'; + import PreactComponent from '../components/JSXComponent.jsx'; + + const someProps = { + count: 0, + }; +--- + + + # Hello, server! + + + + # Hello, client:idle! + + + + # Hello, client:load! + + + + # Hello, client:visible! + + + + # Hello, client:media! + + + diff --git a/packages/astro/e2e/fixtures/preact-component/astro.config.mjs b/packages/astro/e2e/fixtures/preact-component/astro.config.mjs index 08916b1fe..bcaa451eb 100644 --- a/packages/astro/e2e/fixtures/preact-component/astro.config.mjs +++ b/packages/astro/e2e/fixtures/preact-component/astro.config.mjs @@ -1,7 +1,11 @@ import { defineConfig } from 'astro/config'; import preact from '@astrojs/preact'; +import mdx from '@astrojs/mdx'; // https://astro.build/config export default defineConfig({ - integrations: [preact()], + legacy: { + astroFlavoredMarkdown: true, + }, + integrations: [preact(), mdx()], }); diff --git a/packages/astro/e2e/fixtures/preact-component/package.json b/packages/astro/e2e/fixtures/preact-component/package.json index 489d24338..0d9b84026 100644 --- a/packages/astro/e2e/fixtures/preact-component/package.json +++ b/packages/astro/e2e/fixtures/preact-component/package.json @@ -4,6 +4,7 @@ "private": true, "dependencies": { "@astrojs/preact": "workspace:*", + "@astrojs/mdx": "workspace:*", "astro": "workspace:*", "preact": "^10.7.3" } diff --git a/packages/astro/e2e/fixtures/preact-component/src/components/JSXComponent.jsx b/packages/astro/e2e/fixtures/preact-component/src/components/JSXComponent.jsx index 6cc7b7858..16b98f6d4 100644 --- a/packages/astro/e2e/fixtures/preact-component/src/components/JSXComponent.jsx +++ b/packages/astro/e2e/fixtures/preact-component/src/components/JSXComponent.jsx @@ -1,5 +1,5 @@ import { h } from 'preact'; export default function({ id }) { - return
      Preact client:only component
      + return
      Framework client:only component
      } diff --git a/packages/astro/e2e/fixtures/preact-component/src/components/Layout.astro b/packages/astro/e2e/fixtures/preact-component/src/components/Layout.astro new file mode 100644 index 000000000..3c3cf4e4d --- /dev/null +++ b/packages/astro/e2e/fixtures/preact-component/src/components/Layout.astro @@ -0,0 +1,4 @@ + + Preact component + + diff --git a/packages/astro/e2e/fixtures/preact-component/src/pages/index.astro b/packages/astro/e2e/fixtures/preact-component/src/pages/index.astro index 946b90be0..2fe26a575 100644 --- a/packages/astro/e2e/fixtures/preact-component/src/pages/index.astro +++ b/packages/astro/e2e/fixtures/preact-component/src/pages/index.astro @@ -8,10 +8,10 @@ const someProps = { --- - - - - + + + +

      Hello, server!

      @@ -24,14 +24,14 @@ const someProps = {

      Hello, client:load!

      - +

      Hello, client:visible!

      - +

      Hello, client:media!

      - + diff --git a/packages/astro/e2e/fixtures/preact-component/src/pages/markdown.md b/packages/astro/e2e/fixtures/preact-component/src/pages/markdown.md new file mode 100644 index 000000000..7c521de77 --- /dev/null +++ b/packages/astro/e2e/fixtures/preact-component/src/pages/markdown.md @@ -0,0 +1,32 @@ +--- +layout: ../components/Layout.astro +setup: | + import Counter from '../components/Counter.jsx'; + import PreactComponent from '../components/JSXComponent.jsx'; + + const someProps = { + count: 0, + }; +--- + + + # Hello, server! + + + + # Hello, client:idle! + + + + # Hello, client:load! + + + + # Hello, client:visible! + + + + # Hello, client:media! + + + diff --git a/packages/astro/e2e/fixtures/preact-component/src/pages/mdx.mdx b/packages/astro/e2e/fixtures/preact-component/src/pages/mdx.mdx new file mode 100644 index 000000000..0ba961550 --- /dev/null +++ b/packages/astro/e2e/fixtures/preact-component/src/pages/mdx.mdx @@ -0,0 +1,29 @@ +export { default } from '../components/Layout.astro'; +import Counter from '../components/Counter.jsx'; +import PreactComponent from '../components/JSXComponent.jsx'; + +export const someProps = { + count: 0, +}; + + + # Hello, server! + + + + # Hello, client:idle! + + + + # Hello, client:load! + + + + # Hello, client:visible! + + + + # Hello, client:media! + + + diff --git a/packages/astro/e2e/fixtures/react-component/astro.config.mjs b/packages/astro/e2e/fixtures/react-component/astro.config.mjs index 8a6f1951c..badddf1d3 100644 --- a/packages/astro/e2e/fixtures/react-component/astro.config.mjs +++ b/packages/astro/e2e/fixtures/react-component/astro.config.mjs @@ -1,7 +1,11 @@ import { defineConfig } from 'astro/config'; import react from '@astrojs/react'; +import mdx from '@astrojs/mdx'; // https://astro.build/config export default defineConfig({ - integrations: [react()], + legacy: { + astroFlavoredMarkdown: true, + }, + integrations: [react(), mdx()], }); diff --git a/packages/astro/e2e/fixtures/react-component/package.json b/packages/astro/e2e/fixtures/react-component/package.json index 9236558f0..4e56631bd 100644 --- a/packages/astro/e2e/fixtures/react-component/package.json +++ b/packages/astro/e2e/fixtures/react-component/package.json @@ -5,6 +5,7 @@ "dependencies": { "@astrojs/react": "workspace:*", "astro": "workspace:*", + "@astrojs/mdx": "workspace:*", "react": "^18.1.0", "react-dom": "^18.1.0" } diff --git a/packages/astro/e2e/fixtures/react-component/src/components/JSXComponent.jsx b/packages/astro/e2e/fixtures/react-component/src/components/JSXComponent.jsx index 90a4d7c42..dcafa028c 100644 --- a/packages/astro/e2e/fixtures/react-component/src/components/JSXComponent.jsx +++ b/packages/astro/e2e/fixtures/react-component/src/components/JSXComponent.jsx @@ -1,5 +1,5 @@ import React from 'react'; export default function({ id }) { - return
      React client:only component
      + return
      Framework client:only component
      } diff --git a/packages/astro/e2e/fixtures/react-component/src/components/Layout.astro b/packages/astro/e2e/fixtures/react-component/src/components/Layout.astro new file mode 100644 index 000000000..7c166b532 --- /dev/null +++ b/packages/astro/e2e/fixtures/react-component/src/components/Layout.astro @@ -0,0 +1,4 @@ + + React component + + diff --git a/packages/astro/e2e/fixtures/react-component/src/pages/index.astro b/packages/astro/e2e/fixtures/react-component/src/pages/index.astro index 388fc1d98..0a9a212d0 100644 --- a/packages/astro/e2e/fixtures/react-component/src/pages/index.astro +++ b/packages/astro/e2e/fixtures/react-component/src/pages/index.astro @@ -8,10 +8,10 @@ const someProps = { --- - - - - + + + +

      Hello, server!

      @@ -24,7 +24,7 @@ const someProps = {

      Hello, client:load!

      - +

      Hello, client:visible!

      @@ -33,5 +33,5 @@ const someProps = {
      - + diff --git a/packages/astro/e2e/fixtures/react-component/src/pages/markdown.md b/packages/astro/e2e/fixtures/react-component/src/pages/markdown.md new file mode 100644 index 000000000..fbc685a5b --- /dev/null +++ b/packages/astro/e2e/fixtures/react-component/src/pages/markdown.md @@ -0,0 +1,32 @@ +--- +layout: ../components/Layout.astro +setup: | + import Counter from '../components/Counter.jsx'; + import ReactComponent from '../components/JSXComponent.jsx'; + + const someProps = { + count: 0, + }; +--- + + + # Hello, server! + + + + # Hello, client:idle! + + + + # Hello, client:load! + + + + # Hello, client:visible! + + + + # Hello, client:media! + + + diff --git a/packages/astro/e2e/fixtures/react-component/src/pages/mdx.mdx b/packages/astro/e2e/fixtures/react-component/src/pages/mdx.mdx new file mode 100644 index 000000000..fe6520933 --- /dev/null +++ b/packages/astro/e2e/fixtures/react-component/src/pages/mdx.mdx @@ -0,0 +1,29 @@ +export { default } from '../components/Layout.astro'; +import Counter from '../components/Counter.jsx'; +import ReactComponent from '../components/JSXComponent.jsx'; + +export const someProps = { + count: 0, +}; + + + # Hello, server! + + + + # Hello, client:idle! + + + + # Hello, client:load! + + + + # Hello, client:visible! + + + + # Hello, client:media! + + + diff --git a/packages/astro/e2e/fixtures/solid-component/astro.config.mjs b/packages/astro/e2e/fixtures/solid-component/astro.config.mjs index a6c39b853..35d38c8f1 100644 --- a/packages/astro/e2e/fixtures/solid-component/astro.config.mjs +++ b/packages/astro/e2e/fixtures/solid-component/astro.config.mjs @@ -1,7 +1,11 @@ import { defineConfig } from 'astro/config'; +import mdx from '@astrojs/mdx'; import solid from '@astrojs/solid-js'; // https://astro.build/config export default defineConfig({ - integrations: [solid()], + legacy: { + astroFlavoredMarkdown: true, + }, + integrations: [solid(), mdx()], }); diff --git a/packages/astro/e2e/fixtures/solid-component/package.json b/packages/astro/e2e/fixtures/solid-component/package.json index 5eef50d71..1ed5a5742 100644 --- a/packages/astro/e2e/fixtures/solid-component/package.json +++ b/packages/astro/e2e/fixtures/solid-component/package.json @@ -4,7 +4,8 @@ "private": true, "dependencies": { "@astrojs/solid-js": "workspace:*", - "astro": "workspace:*" + "astro": "workspace:*", + "@astrojs/mdx": "workspace:*" }, "devDependencies": { "solid-js": "^1.4.3" diff --git a/packages/astro/e2e/fixtures/solid-component/src/components/Layout.astro b/packages/astro/e2e/fixtures/solid-component/src/components/Layout.astro new file mode 100644 index 000000000..63e0ff449 --- /dev/null +++ b/packages/astro/e2e/fixtures/solid-component/src/components/Layout.astro @@ -0,0 +1,4 @@ + + Solid component + + diff --git a/packages/astro/e2e/fixtures/solid-component/src/components/SolidComponent.jsx b/packages/astro/e2e/fixtures/solid-component/src/components/SolidComponent.jsx new file mode 100644 index 000000000..4010cdb95 --- /dev/null +++ b/packages/astro/e2e/fixtures/solid-component/src/components/SolidComponent.jsx @@ -0,0 +1,7 @@ +import 'solid-js'; + +export default function SolidComponent({ id }) { + return ( +
      Framework client:only component
      + ); +} diff --git a/packages/astro/e2e/fixtures/solid-component/src/pages/index.astro b/packages/astro/e2e/fixtures/solid-component/src/pages/index.astro index 91013ad0e..9cfbedc7c 100644 --- a/packages/astro/e2e/fixtures/solid-component/src/pages/index.astro +++ b/packages/astro/e2e/fixtures/solid-component/src/pages/index.astro @@ -1,5 +1,6 @@ --- import Counter from '../components/Counter.jsx'; +import SolidComponent from '../components/SolidComponent.jsx'; const someProps = { count: 0, @@ -7,10 +8,10 @@ const someProps = { --- - - - - + + + +

      Hello, server!

      @@ -23,12 +24,14 @@ const someProps = {

      Hello, client:load!

      - +

      Hello, client:visible!

      Hello, client:media!

      - + + + diff --git a/packages/astro/e2e/fixtures/solid-component/src/pages/markdown.md b/packages/astro/e2e/fixtures/solid-component/src/pages/markdown.md new file mode 100644 index 000000000..21a779c9d --- /dev/null +++ b/packages/astro/e2e/fixtures/solid-component/src/pages/markdown.md @@ -0,0 +1,32 @@ +--- +layout: ../components/Layout.astro +setup: | + import Counter from '../components/Counter.jsx'; + import SolidComponent from '../components/SolidComponent.jsx'; + + const someProps = { + count: 0, + }; +--- + + + # Hello, server! + + + + # Hello, client:idle! + + + + # Hello, client:load! + + + + # Hello, client:visible! + + + + # Hello, client:media! + + + diff --git a/packages/astro/e2e/fixtures/solid-component/src/pages/mdx.mdx b/packages/astro/e2e/fixtures/solid-component/src/pages/mdx.mdx new file mode 100644 index 000000000..16186ba53 --- /dev/null +++ b/packages/astro/e2e/fixtures/solid-component/src/pages/mdx.mdx @@ -0,0 +1,29 @@ +export { default } from '../components/Layout.astro'; +import Counter from '../components/Counter.jsx'; +import SolidComponent from '../components/SolidComponent.jsx'; + +export const someProps = { + count: 0, +}; + + + # Hello, server! + + + + # Hello, client:idle! + + + + # Hello, client:load! + + + + # Hello, client:visible! + + + + # Hello, client:media! + + + diff --git a/packages/astro/e2e/fixtures/svelte-component/astro.config.mjs b/packages/astro/e2e/fixtures/svelte-component/astro.config.mjs index 77fdcd1b9..99f557d43 100644 --- a/packages/astro/e2e/fixtures/svelte-component/astro.config.mjs +++ b/packages/astro/e2e/fixtures/svelte-component/astro.config.mjs @@ -1,7 +1,11 @@ import { defineConfig } from 'astro/config'; import svelte from '@astrojs/svelte'; +import mdx from '@astrojs/mdx'; // https://astro.build/config export default defineConfig({ - integrations: [svelte()], + legacy: { + astroFlavoredMarkdown: true, + }, + integrations: [svelte(), mdx()], }); diff --git a/packages/astro/e2e/fixtures/svelte-component/package.json b/packages/astro/e2e/fixtures/svelte-component/package.json index 2777c8ecd..999a248c7 100644 --- a/packages/astro/e2e/fixtures/svelte-component/package.json +++ b/packages/astro/e2e/fixtures/svelte-component/package.json @@ -5,6 +5,7 @@ "dependencies": { "@astrojs/svelte": "workspace:*", "astro": "workspace:*", + "@astrojs/mdx": "workspace:*", "svelte": "^3.48.0" } } diff --git a/packages/astro/e2e/fixtures/svelte-component/src/components/Counter.svelte b/packages/astro/e2e/fixtures/svelte-component/src/components/Counter.svelte index a2353f071..2f05ce798 100644 --- a/packages/astro/e2e/fixtures/svelte-component/src/components/Counter.svelte +++ b/packages/astro/e2e/fixtures/svelte-component/src/components/Counter.svelte @@ -1,7 +1,6 @@ + +
      Framework client:only component
      diff --git a/packages/astro/e2e/fixtures/svelte-component/src/pages/index.astro b/packages/astro/e2e/fixtures/svelte-component/src/pages/index.astro index 3c8117124..9bd8f23bf 100644 --- a/packages/astro/e2e/fixtures/svelte-component/src/pages/index.astro +++ b/packages/astro/e2e/fixtures/svelte-component/src/pages/index.astro @@ -1,5 +1,6 @@ --- import Counter from '../components/Counter.svelte'; +import SvelteComponent from '../components/SvelteComponent.svelte'; const someProps = { count: 0, @@ -7,28 +8,30 @@ const someProps = { --- - - - - - + + + + +

      Hello, server!

      - +

      Hello, client:idle!

      - +

      Hello, client:load!

      - +

      Hello, client:visible!

      - +

      Hello, client:media!

      - + + + diff --git a/packages/astro/e2e/fixtures/svelte-component/src/pages/markdown.md b/packages/astro/e2e/fixtures/svelte-component/src/pages/markdown.md new file mode 100644 index 000000000..ebc4d8795 --- /dev/null +++ b/packages/astro/e2e/fixtures/svelte-component/src/pages/markdown.md @@ -0,0 +1,32 @@ +--- +layout: ../components/Layout.astro +setup: | + import Counter from '../components/Counter.svelte'; + import SvelteComponent from '../components/SvelteComponent.svelte'; + + const someProps = { + count: 0, + }; +--- + + + # Hello, server! + + + + # Hello, client:idle! + + + + # Hello, client:load! + + + + # Hello, client:visible! + + + + # Hello, client:media! + + + diff --git a/packages/astro/e2e/fixtures/svelte-component/src/pages/mdx.mdx b/packages/astro/e2e/fixtures/svelte-component/src/pages/mdx.mdx new file mode 100644 index 000000000..60a59a509 --- /dev/null +++ b/packages/astro/e2e/fixtures/svelte-component/src/pages/mdx.mdx @@ -0,0 +1,29 @@ +export { default } from '../components/Layout.astro'; +import Counter from '../components/Counter.svelte'; +import SvelteComponent from '../components/SvelteComponent.svelte'; + +export const someProps = { + count: 0, +}; + + + # Hello, server! + + + + # Hello, client:idle! + + + + # Hello, client:load! + + + + # Hello, client:visible! + + + + # Hello, client:media! + + + diff --git a/packages/astro/e2e/fixtures/tailwindcss/src/pages/markdown-page.md b/packages/astro/e2e/fixtures/tailwindcss/src/pages/markdown-page.md deleted file mode 100644 index e4c6b6bc9..000000000 --- a/packages/astro/e2e/fixtures/tailwindcss/src/pages/markdown-page.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: "Markdown + Tailwind" -setup: | - import Button from '../components/Button.astro'; - import Complex from '../components/Complex.astro'; ---- - -
      - - -
      \ No newline at end of file diff --git a/packages/astro/e2e/fixtures/ts-resolution/astro.config.mjs b/packages/astro/e2e/fixtures/ts-resolution/astro.config.mjs new file mode 100644 index 000000000..8a6f1951c --- /dev/null +++ b/packages/astro/e2e/fixtures/ts-resolution/astro.config.mjs @@ -0,0 +1,7 @@ +import { defineConfig } from 'astro/config'; +import react from '@astrojs/react'; + +// https://astro.build/config +export default defineConfig({ + integrations: [react()], +}); diff --git a/packages/astro/e2e/fixtures/ts-resolution/package.json b/packages/astro/e2e/fixtures/ts-resolution/package.json new file mode 100644 index 000000000..7544800f9 --- /dev/null +++ b/packages/astro/e2e/fixtures/ts-resolution/package.json @@ -0,0 +1,11 @@ +{ + "name": "@e2e/ts-resolution", + "version": "0.0.0", + "private": true, + "dependencies": { + "@astrojs/react": "workspace:*", + "astro": "workspace:*", + "react": "^18.1.0", + "react-dom": "^18.1.0" + } +} diff --git a/packages/astro/e2e/fixtures/ts-resolution/src/components/Counter.tsx b/packages/astro/e2e/fixtures/ts-resolution/src/components/Counter.tsx new file mode 100644 index 000000000..9d91921f4 --- /dev/null +++ b/packages/astro/e2e/fixtures/ts-resolution/src/components/Counter.tsx @@ -0,0 +1,18 @@ +import React, { useState } from 'react'; + +export default function Counter({ children, count: initialCount, id }) { + const [count, setCount] = useState(initialCount); + const add = () => setCount((i) => i + 1); + const subtract = () => setCount((i) => i - 1); + + return ( + <> +
      + +
      {count}
      + +
      +
      {children}
      + + ); +} diff --git a/packages/astro/e2e/fixtures/ts-resolution/src/pages/index.astro b/packages/astro/e2e/fixtures/ts-resolution/src/pages/index.astro new file mode 100644 index 000000000..38133a646 --- /dev/null +++ b/packages/astro/e2e/fixtures/ts-resolution/src/pages/index.astro @@ -0,0 +1,18 @@ +--- +import Counter from '../components/Counter.jsx'; + +const someProps = { + count: 0, +}; +--- + + + + + + + +

      Hello, client:idle!

      +
      + + diff --git a/packages/astro/e2e/fixtures/vue-component/astro.config.mjs b/packages/astro/e2e/fixtures/vue-component/astro.config.mjs index 94bdad87f..84c024e68 100644 --- a/packages/astro/e2e/fixtures/vue-component/astro.config.mjs +++ b/packages/astro/e2e/fixtures/vue-component/astro.config.mjs @@ -1,13 +1,20 @@ import { defineConfig } from 'astro/config'; import vue from '@astrojs/vue'; +import mdx from '@astrojs/mdx'; // https://astro.build/config export default defineConfig({ - integrations: [vue({ - template: { - compilerOptions: { - isCustomElement: tag => tag.includes('my-button') + legacy: { + astroFlavoredMarkdown: true, + }, + integrations: [ + mdx(), + vue({ + template: { + compilerOptions: { + isCustomElement: tag => tag.includes('my-button') + } } } - })], + )], }); diff --git a/packages/astro/e2e/fixtures/vue-component/package.json b/packages/astro/e2e/fixtures/vue-component/package.json index 2322b5d2d..206bb68ca 100644 --- a/packages/astro/e2e/fixtures/vue-component/package.json +++ b/packages/astro/e2e/fixtures/vue-component/package.json @@ -4,6 +4,7 @@ "private": true, "dependencies": { "@astrojs/vue": "workspace:*", - "astro": "workspace:*" + "astro": "workspace:*", + "@astrojs/mdx": "workspace:*" } } diff --git a/packages/astro/e2e/fixtures/vue-component/src/components/Counter.vue b/packages/astro/e2e/fixtures/vue-component/src/components/Counter.vue index b96e6381b..ed6fb5fb4 100644 --- a/packages/astro/e2e/fixtures/vue-component/src/components/Counter.vue +++ b/packages/astro/e2e/fixtures/vue-component/src/components/Counter.vue @@ -1,44 +1,38 @@ diff --git a/packages/astro/e2e/fixtures/vue-component/src/components/Layout.astro b/packages/astro/e2e/fixtures/vue-component/src/components/Layout.astro new file mode 100644 index 000000000..285bc56e2 --- /dev/null +++ b/packages/astro/e2e/fixtures/vue-component/src/components/Layout.astro @@ -0,0 +1,4 @@ + + Vue component + + diff --git a/packages/astro/e2e/fixtures/vue-component/src/components/Result.vue b/packages/astro/e2e/fixtures/vue-component/src/components/VueComponent.vue similarity index 53% rename from packages/astro/e2e/fixtures/vue-component/src/components/Result.vue rename to packages/astro/e2e/fixtures/vue-component/src/components/VueComponent.vue index 90bf218b2..ab0cee328 100644 --- a/packages/astro/e2e/fixtures/vue-component/src/components/Result.vue +++ b/packages/astro/e2e/fixtures/vue-component/src/components/VueComponent.vue @@ -1,14 +1,13 @@ `; + case 'directive': + return ``; + } + return ''; +} diff --git a/packages/astro/src/runtime/server/serialize.ts b/packages/astro/src/runtime/server/serialize.ts new file mode 100644 index 000000000..21996a932 --- /dev/null +++ b/packages/astro/src/runtime/server/serialize.ts @@ -0,0 +1,62 @@ +type ValueOf = T[keyof T]; + +const PROP_TYPE = { + Value: 0, + JSON: 1, + RegExp: 2, + Date: 3, + Map: 4, + Set: 5, + BigInt: 6, + URL: 7, +}; + +function serializeArray(value: any[]): any[] { + return value.map((v) => convertToSerializedForm(v)); +} + +function serializeObject(value: Record): Record { + return Object.fromEntries( + Object.entries(value).map(([k, v]) => { + return [k, convertToSerializedForm(v)]; + }) + ); +} + +function convertToSerializedForm(value: any): [ValueOf, any] { + const tag = Object.prototype.toString.call(value); + switch (tag) { + case '[object Date]': { + return [PROP_TYPE.Date, (value as Date).toISOString()]; + } + case '[object RegExp]': { + return [PROP_TYPE.RegExp, (value as RegExp).source]; + } + case '[object Map]': { + return [PROP_TYPE.Map, JSON.stringify(serializeArray(Array.from(value as Map)))]; + } + case '[object Set]': { + return [PROP_TYPE.Set, JSON.stringify(serializeArray(Array.from(value as Set)))]; + } + case '[object BigInt]': { + return [PROP_TYPE.BigInt, (value as bigint).toString()]; + } + case '[object URL]': { + return [PROP_TYPE.URL, (value as URL).toString()]; + } + case '[object Array]': { + return [PROP_TYPE.JSON, JSON.stringify(serializeArray(value))]; + } + default: { + if (value !== null && typeof value === 'object') { + return [PROP_TYPE.Value, serializeObject(value)]; + } else { + return [PROP_TYPE.Value, value]; + } + } + } +} + +export function serializeProps(props: any) { + return JSON.stringify(serializeObject(props)); +} diff --git a/packages/astro/src/runtime/server/util.ts b/packages/astro/src/runtime/server/util.ts index 22f38f970..24dfa2b1a 100644 --- a/packages/astro/src/runtime/server/util.ts +++ b/packages/astro/src/runtime/server/util.ts @@ -23,7 +23,7 @@ export function serializeListValue(value: any) { // otherwise, push any other values as a string else { // get the item as a string - item = item == null ? '' : String(item).trim(); + item = item === false || item == null ? '' : String(item).trim(); // add the item if it is filled if (item) { @@ -34,12 +34,3 @@ export function serializeListValue(value: any) { } } } - -/** - * Get the import specifier for a given hydration directive. - * @param hydrate The hydration directive such as `idle` or `visible` - * @returns - */ -export function hydrationSpecifier(hydrate: string) { - return `astro/client/${hydrate}.js`; -} diff --git a/packages/astro/src/template/5xx.ts b/packages/astro/src/template/5xx.ts deleted file mode 100644 index 0354fbbfb..000000000 --- a/packages/astro/src/template/5xx.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { encode } from 'html-entities'; -import { baseCSS } from './css.js'; - -interface ErrorTemplateOptions { - /** a short description of the error */ - message: string; - /** information about where the error occurred */ - stack?: string; - /** HTTP error code */ - statusCode?: number; - /** HTML */ - tabTitle: string; - /** page title */ - title: string; - /** show user a URL for more info or action to take */ - url?: string; -} - -/** Display all errors */ -export default function template({ - title, - url, - message, - stack, - statusCode, - tabTitle, -}: ErrorTemplateOptions): string { - let error = url ? message.replace(url, '') : message; - return `<!doctype html> - <html lang="en"> - <head> - <meta charset="UTF-8"> - <title>${tabTitle} - - - -
      -
      - -

      ${ - statusCode ? `${statusCode}: ` : '' - }${title}

      -
      -
      ${encode(error)}
      - ${url ? `${url}` : ''} -
      ${encode(stack)}
      -
      - - `; -} diff --git a/packages/astro/src/vite-plugin-astro-server/index.ts b/packages/astro/src/vite-plugin-astro-server/index.ts index d3ad53eff..86012991e 100644 --- a/packages/astro/src/vite-plugin-astro-server/index.ts +++ b/packages/astro/src/vite-plugin-astro-server/index.ts @@ -1,22 +1,27 @@ import type http from 'http'; -import { Readable } from 'stream'; -import stripAnsi from 'strip-ansi'; +import mime from 'mime'; import type * as vite from 'vite'; import type { AstroConfig, ManifestData } from '../@types/astro'; +import type { SSROptions } from '../core/render/dev/index'; + +import { Readable } from 'stream'; import { call as callEndpoint } from '../core/endpoint/dev/index.js'; -import { fixViteErrorMessage } from '../core/errors.js'; +import { + collectErrorMetadata, + ErrorWithMetadata, + fixViteErrorMessage, + getViteErrorPayload, +} from '../core/errors.js'; import { error, info, LogOptions, warn } from '../core/logger/core.js'; import * as msg from '../core/messages.js'; import { appendForwardSlash } from '../core/path.js'; import { getParamsAndProps, GetParamsAndPropsError } from '../core/render/core.js'; -import type { RenderResponse, SSROptions } from '../core/render/dev/index'; import { preload, ssr } from '../core/render/dev/index.js'; import { RouteCache } from '../core/render/route-cache.js'; import { createRequest } from '../core/request.js'; import { createRouteManifest, matchRoute } from '../core/routing/index.js'; import { createSafeError, isBuildingToSSR, resolvePages } from '../core/util.js'; import notFoundTemplate, { subpathNotUsedTemplate } from '../template/4xx.js'; -import serverErrorTemplate from '../template/5xx.js'; interface AstroPluginOptions { config: AstroConfig; @@ -75,9 +80,16 @@ async function writeWebResponse(res: http.ServerResponse, webResponse: Response) res.writeHead(status, _headers); if (body) { - if (body instanceof Readable) { + if (Symbol.for('astro.responseBody') in webResponse) { + let stream = (webResponse as any)[Symbol.for('astro.responseBody')]; + for await (const chunk of stream) { + res.write(chunk.toString()); + } + } else if (body instanceof Readable) { body.pipe(res); return; + } else if (typeof body === 'string') { + res.write(body); } else { const reader = body.getReader(); while (true) { @@ -92,24 +104,8 @@ async function writeWebResponse(res: http.ServerResponse, webResponse: Response) res.end(); } -async function writeSSRResult( - result: RenderResponse, - res: http.ServerResponse, - statusCode: 200 | 404 -) { - if (result.type === 'response') { - const { response } = result; - await writeWebResponse(res, response); - return; - } - - const { html, response: init } = result; - const headers = init.headers as Headers; - - headers.set('Content-Type', 'text/html; charset=utf-8'); - headers.set('Content-Length', Buffer.byteLength(html, 'utf-8').toString()); - - return writeWebResponse(res, new Response(html, init)); +async function writeSSRResult(webResponse: Response, res: http.ServerResponse) { + return writeWebResponse(res, webResponse); } async function handle404Response( @@ -118,38 +114,14 @@ async function handle404Response( req: http.IncomingMessage, res: http.ServerResponse ) { - const site = config.site ? new URL(config.base, config.site) : undefined; - const devRoot = site ? site.pathname : '/'; const pathname = decodeURI(new URL(origin + req.url).pathname); - let html = ''; - if (pathname === '/' && !pathname.startsWith(devRoot)) { - html = subpathNotUsedTemplate(devRoot, pathname); - } else { - // HACK: redirect without the base path for assets in publicDir - const redirectTo = - req.method === 'GET' && - config.base !== '/' && - pathname.startsWith(config.base) && - pathname.replace(config.base, '/'); - if (redirectTo && redirectTo !== '/') { - const response = new Response(null, { - status: 302, - headers: { - Location: redirectTo, - }, - }); - await writeWebResponse(res, response); - return; - } - - html = notFoundTemplate({ - statusCode: 404, - title: 'Not found', - tabTitle: '404: Not Found', - pathname, - }); - } + const html = notFoundTemplate({ + statusCode: 404, + title: 'Not found', + tabTitle: '404: Not Found', + pathname, + }); writeHtmlResponse(res, 404, html); } @@ -158,19 +130,18 @@ async function handle500Response( origin: string, req: http.IncomingMessage, res: http.ServerResponse, - err: any + err: ErrorWithMetadata ) { - const pathname = decodeURI(new URL('./index.html', origin + req.url).pathname); - const html = serverErrorTemplate({ - statusCode: 500, - title: 'Internal Error', - tabTitle: '500: Error', - message: stripAnsi(err.hint ?? err.message), - url: err.url || undefined, - stack: truncateString(stripAnsi(err.stack), 500), - }); - const transformedHtml = await viteServer.transformIndexHtml(pathname, html); - writeHtmlResponse(res, 500, transformedHtml); + res.on('close', () => setTimeout(() => viteServer.ws.send(getViteErrorPayload(err)), 200)); + if (res.headersSent) { + res.end(); + } else { + writeHtmlResponse( + res, + 500, + `${err.name}` + ); + } } function getCustom404Route(config: AstroConfig, manifest: ManifestData) { @@ -184,6 +155,44 @@ function log404(logging: LogOptions, pathname: string) { info(logging, 'serve', msg.req({ url: pathname, statusCode: 404 })); } +export function baseMiddleware( + config: AstroConfig, + logging: LogOptions +): vite.Connect.NextHandleFunction { + const site = config.site ? new URL(config.base, config.site) : undefined; + const devRoot = site ? site.pathname : '/'; + + return function devBaseMiddleware(req, res, next) { + const url = req.url!; + + const pathname = decodeURI(new URL(url, 'http://vitejs.dev').pathname); + + if (pathname.startsWith(devRoot)) { + req.url = url.replace(devRoot, '/'); + return next(); + } + + if (pathname === '/' || pathname === '/index.html') { + log404(logging, pathname); + const html = subpathNotUsedTemplate(devRoot, pathname); + return writeHtmlResponse(res, 404, html); + } + + if (req.headers.accept?.includes('text/html')) { + log404(logging, pathname); + const html = notFoundTemplate({ + statusCode: 404, + title: 'Not found', + tabTitle: '404: Not Found', + pathname, + }); + return writeHtmlResponse(res, 404, html); + } + + next(); + }; +} + /** The main logic to route dev server requests to pages in Astro. */ async function handleRequest( routeCache: RouteCache, @@ -195,8 +204,6 @@ async function handleRequest( res: http.ServerResponse ) { const reqStart = performance.now(); - const site = config.site ? new URL(config.base, config.site) : undefined; - const devRoot = site ? site.pathname : '/'; const origin = `${viteServer.config.server.https ? 'https' : 'http'}://${req.headers.host}`; const buildingToSSR = isBuildingToSSR(config); // Ignore `.html` extensions and `index.html` in request URLS to ensure that @@ -204,8 +211,12 @@ async function handleRequest( // build formats, and is necessary based on how the manifest tracks build targets. const url = new URL(origin + req.url?.replace(/(index)?\.html$/, '')); const pathname = decodeURI(url.pathname); - const rootRelativeUrl = pathname.substring(devRoot.length - 1); - if (!buildingToSSR) { + + // Add config.base back to url before passing it to SSR + url.pathname = config.base.substring(0, config.base.length - 1) + url.pathname; + + // HACK! @astrojs/image uses query params for the injected route in `dev` + if (!buildingToSSR && pathname !== '/_image') { // Prevent user from depending on search params when not doing SSR. // NOTE: Create an array copy here because deleting-while-iterating // creates bugs where not all search params are removed. @@ -234,16 +245,14 @@ async function handleRequest( body, logging, ssr: buildingToSSR, + clientAddress: buildingToSSR ? req.socket.remoteAddress : undefined, }); + let filePath: URL | undefined; try { - if (!pathname.startsWith(devRoot)) { - log404(logging, pathname); - return handle404Response(origin, config, req, res); - } // Attempt to match the URL to a valid page route. // If that fails, switch the response to a 404 response. - let route = matchRoute(rootRelativeUrl, manifest); + let route = matchRoute(pathname, manifest); const statusCode = route ? 200 : 404; if (!route) { @@ -256,7 +265,7 @@ async function handleRequest( } } - const filePath = new URL(`./${route.component}`, config.root); + filePath = new URL(`./${route.component}`, config.root); const preloadedComponent = await preload({ astroConfig: config, filePath, viteServer }); const [, mod] = preloadedComponent; // attempt to get static paths @@ -265,7 +274,7 @@ async function handleRequest( mod, route, routeCache, - pathname: rootRelativeUrl, + pathname: pathname, logging, ssr: isBuildingToSSR(config), }); @@ -290,13 +299,13 @@ async function handleRequest( logging, mode: 'development', origin, - pathname: rootRelativeUrl, + pathname: pathname, request, route: routeCustom404, routeCache, viteServer, }); - return await writeSSRResult(result, res, statusCode); + return await writeSSRResult(result, res); } else { return handle404Response(origin, config, req, res); } @@ -308,7 +317,7 @@ async function handleRequest( logging, mode: 'development', origin, - pathname: rootRelativeUrl, + pathname: pathname, route, routeCache, viteServer, @@ -321,45 +330,26 @@ async function handleRequest( if (result.type === 'response') { await writeWebResponse(res, result.response); } else { - res.writeHead(200); + let contentType = 'text/plain'; + const computedMimeType = route.pathname ? mime.getType(route.pathname) : null; + if (computedMimeType) { + contentType = computedMimeType; + } + res.writeHead(200, { 'Content-Type': `${contentType};charset=utf-8` }); res.end(result.body); } } else { const result = await ssr(preloadedComponent, options); - return await writeSSRResult(result, res, statusCode); + return await writeSSRResult(result, res); } } catch (_err) { - const err = fixViteErrorMessage(createSafeError(_err), viteServer); - error(logging, null, msg.formatErrorMessage(err)); - handle500Response(viteServer, origin, req, res, err); + const err = fixViteErrorMessage(createSafeError(_err), viteServer, filePath); + const errorWithMetadata = collectErrorMetadata(err); + error(logging, null, msg.formatErrorMessage(errorWithMetadata)); + handle500Response(viteServer, origin, req, res, errorWithMetadata); } } -/** - * Vite HMR sends requests for new CSS and those get returned as JS, but we want it to be CSS - * since they are inside of a link tag for Astro. - */ -const forceTextCSSForStylesMiddleware: vite.Connect.NextHandleFunction = function (req, res, next) { - if (req.url) { - // We are just using this to parse the URL to get the search params object - // so the second arg here doesn't matter - const url = new URL(req.url, 'https://astro.build'); - // lang.css is a search param that exists on Astro, Svelte, and Vue components. - // We only want to override for astro files. - if (url.searchParams.has('astro') && url.searchParams.has('lang.css')) { - // Override setHeader so we can set the correct content-type for this request. - const setHeader = res.setHeader; - res.setHeader = function (key, value) { - if (key.toLowerCase() === 'content-type') { - return setHeader.call(this, key, 'text/css'); - } - return setHeader.apply(this, [key, value]); - }; - } - } - next(); -}; - export default function createPlugin({ config, logging }: AstroPluginOptions): vite.Plugin { return { name: 'astro:server', @@ -381,10 +371,12 @@ export default function createPlugin({ config, logging }: AstroPluginOptions): v removeViteHttpMiddleware(viteServer.middlewares); // Push this middleware to the front of the stack so that it can intercept responses. - viteServer.middlewares.stack.unshift({ - route: '', - handle: forceTextCSSForStylesMiddleware, - }); + if (config.base !== '/') { + viteServer.middlewares.stack.unshift({ + route: '', + handle: baseMiddleware(config, logging), + }); + } viteServer.middlewares.use(async (req, res) => { if (!req.url || !req.method) { throw new Error('Incomplete request'); diff --git a/packages/astro/src/vite-plugin-astro/compile.ts b/packages/astro/src/vite-plugin-astro/compile.ts index 5a6e199d7..02c3753c4 100644 --- a/packages/astro/src/vite-plugin-astro/compile.ts +++ b/packages/astro/src/vite-plugin-astro/compile.ts @@ -1,16 +1,20 @@ import type { TransformResult } from '@astrojs/compiler'; -import type { SourceMapInput } from 'rollup'; +import type { PluginContext, SourceMapInput } from 'rollup'; import type { AstroConfig } from '../@types/astro'; import type { TransformHook } from './styles'; import { transform } from '@astrojs/compiler'; import { fileURLToPath } from 'url'; +import { AstroErrorCodes } from '../core/errors.js'; import { prependForwardSlash } from '../core/path.js'; import { viteID } from '../core/util.js'; import { transformWithVite } from './styles.js'; type CompilationCache = Map; -type CompileResult = TransformResult & { rawCSSDeps: Set }; +type CompileResult = TransformResult & { + rawCSSDeps: Set; + source: string; +}; /** * Note: this is currently needed because Astro is directly using a Vite internal CSS transform. This gives us @@ -33,13 +37,24 @@ function safelyReplaceImportPlaceholder(code: string) { const configCache = new WeakMap(); -interface CompileProps { +export interface CompileProps { config: AstroConfig; filename: string; moduleId: string; source: string; ssr: boolean; viteTransform: TransformHook; + pluginContext: PluginContext; +} + +function getNormalizedID(filename: string): string { + try { + const filenameURL = new URL(`file://${filename}`); + return fileURLToPath(filenameURL); + } catch (err) { + // Not a real file, so just use the provided filename as the normalized id + return filename; + } } async function compile({ @@ -49,10 +64,9 @@ async function compile({ source, ssr, viteTransform, + pluginContext, }: CompileProps): Promise { - const filenameURL = new URL(`file://${filename}`); - const normalizedID = fileURLToPath(filenameURL); - + const normalizedID = getNormalizedID(filename); let rawCSSDeps = new Set(); let cssTransformError: Error | undefined; @@ -63,9 +77,7 @@ async function compile({ // For Windows compat, prepend the module ID with `/@fs` pathname: `/@fs${prependForwardSlash(moduleId)}`, projectRoot: config.root.toString(), - site: config.site - ? new URL(config.base, config.site).toString() - : `http://localhost:${config.server.port}/`, + site: config.site?.toString(), sourcefile: filename, sourcemap: 'both', internalURL: `/@fs${prependForwardSlash( @@ -98,6 +110,7 @@ async function compile({ id: normalizedID, transformHook: viteTransform, ssr, + pluginContext, }); let map: SourceMapInput | undefined; @@ -117,15 +130,29 @@ async function compile({ return null; } }, - }); - - // throw CSS transform errors here if encountered - if (cssTransformError) throw cssTransformError; + }) + .catch((err) => { + // throw compiler errors here if encountered + err.code = err.code || AstroErrorCodes.UnknownCompilerError; + throw err; + }) + .then((result) => { + // throw CSS transform errors here if encountered + if (cssTransformError) { + (cssTransformError as any).code = + (cssTransformError as any).code || AstroErrorCodes.UnknownCompilerCSSError; + throw cssTransformError; + } + return result; + }); const compileResult: CompileResult = Object.create(transformResult, { rawCSSDeps: { value: rawCSSDeps, }, + source: { + value: source, + }, }); return compileResult; @@ -135,6 +162,13 @@ export function isCached(config: AstroConfig, filename: string) { return configCache.has(config) && configCache.get(config)!.has(filename); } +export function getCachedSource(config: AstroConfig, filename: string): string | null { + if (!isCached(config, filename)) return null; + let src = configCache.get(config)!.get(filename); + if (!src) return null; + return src.source; +} + export function invalidateCompilation(config: AstroConfig, filename: string) { if (configCache.has(config)) { const cache = configCache.get(config)!; diff --git a/packages/astro/src/vite-plugin-astro/hmr.ts b/packages/astro/src/vite-plugin-astro/hmr.ts index cc9b26770..d4b72a061 100644 --- a/packages/astro/src/vite-plugin-astro/hmr.ts +++ b/packages/astro/src/vite-plugin-astro/hmr.ts @@ -1,3 +1,4 @@ +import { fileURLToPath } from 'node:url'; import type { PluginContext as RollupPluginContext, ResolvedId } from 'rollup'; import type { HmrContext, ModuleNode, ViteDevServer } from 'vite'; import type { AstroConfig } from '../@types/astro'; @@ -41,7 +42,7 @@ export async function trackCSSDependencies( } // Update the module graph, telling it about our CSS deps. - moduleGraph.updateModuleInfo(mod, depModules, new Set(), true); + moduleGraph.updateModuleInfo(mod, depModules, new Map(), new Set(), new Set(), true); for (const dep of cssDeps) { this.addWatchFile(dep); } @@ -49,21 +50,31 @@ export async function trackCSSDependencies( } } +const PKG_PREFIX = new URL('../../', import.meta.url); +const isPkgFile = (id: string | null) => { + return id?.startsWith(fileURLToPath(PKG_PREFIX)) || id?.startsWith(PKG_PREFIX.pathname); +}; + export async function handleHotUpdate(ctx: HmrContext, config: AstroConfig, logging: LogOptions) { // Invalidate the compilation cache so it recompiles invalidateCompilation(config, ctx.file); + // Skip monorepo files to avoid console spam + if (isPkgFile(ctx.file)) { + return; + } + // go through each of these modules importers and invalidate any .astro compilation // that needs to be rerun. const filtered = new Set(ctx.modules); const files = new Set(); for (const mod of ctx.modules) { - // This is always the HMR script, we skip it to avoid spamming - // the browser console with HMR updates about this file - if (mod.id?.endsWith('.astro?html-proxy&index=0.js')) { + // Skip monorepo files to avoid console spam + if (isPkgFile(mod.id ?? mod.file)) { filtered.delete(mod); continue; } + if (mod.file && isCached(config, mod.file)) { filtered.add(mod); files.add(mod.file); diff --git a/packages/astro/src/vite-plugin-astro/index.ts b/packages/astro/src/vite-plugin-astro/index.ts index 4823b6839..b4925d0fd 100644 --- a/packages/astro/src/vite-plugin-astro/index.ts +++ b/packages/astro/src/vite-plugin-astro/index.ts @@ -1,20 +1,20 @@ -import type { PluginContext } from 'rollup'; +import type { PluginContext, SourceDescription } from 'rollup'; import type * as vite from 'vite'; import type { AstroConfig } from '../@types/astro'; import type { LogOptions } from '../core/logger/core.js'; +import type { PluginMetadata as AstroPluginMetadata } from './types'; import ancestor from 'common-ancestor-path'; import esbuild from 'esbuild'; -import fs from 'fs'; import slash from 'slash'; import { fileURLToPath } from 'url'; import { isRelativePath, startsWithForwardSlash } from '../core/path.js'; import { resolvePages } from '../core/util.js'; import { PAGE_SCRIPT_ID, PAGE_SSR_SCRIPT_ID } from '../vite-plugin-scripts/index.js'; import { getFileInfo } from '../vite-plugin-utils/index.js'; -import { cachedCompilation } from './compile.js'; +import { cachedCompilation, CompileProps, getCachedSource } from './compile.js'; import { handleHotUpdate, trackCSSDependencies } from './hmr.js'; -import { parseAstroRequest } from './query.js'; +import { parseAstroRequest, ParsedRequestResult } from './query.js'; import { getViteTransform, TransformHook } from './styles.js'; const FRONTMATTER_PARSE_REGEXP = /^\-\-\-(.*)^\-\-\-/ms; @@ -47,6 +47,16 @@ export default function astro({ config, logging }: AstroPluginOptions): vite.Plu const srcRootWeb = config.srcDir.pathname.slice(config.root.pathname.length - 1); const isBrowserPath = (path: string) => path.startsWith(srcRootWeb); + function resolveRelativeFromAstroParent(id: string, parsedFrom: ParsedRequestResult): string { + const filename = normalizeFilename(parsedFrom.filename); + const resolvedURL = new URL(id, `file://${filename}`); + const resolved = resolvedURL.pathname; + if (isBrowserPath(resolved)) { + return relativeToRoot(resolved + resolvedURL.search); + } + return slash(fileURLToPath(resolvedURL)) + resolvedURL.search; + } + return { name: 'astro:build', enforce: 'pre', // run transforms before other plugins can @@ -57,20 +67,18 @@ export default function astro({ config, logging }: AstroPluginOptions): vite.Plu configureServer(server) { viteDevServer = server; }, - // note: don’t claim .astro files with resolveId() — it prevents Vite from transpiling the final JS (import.meta.globEager, etc.) - async resolveId(id, from) { + // note: don’t claim .astro files with resolveId() — it prevents Vite from transpiling the final JS (import.meta.glob, etc.) + async resolveId(id, from, opts) { // If resolving from an astro subresource such as a hoisted script, // we need to resolve relative paths ourselves. if (from) { const parsedFrom = parseAstroRequest(from); - if (parsedFrom.query.astro && isRelativePath(id) && parsedFrom.query.type === 'script') { - const filename = normalizeFilename(parsedFrom.filename); - const resolvedURL = new URL(id, `file://${filename}`); - const resolved = resolvedURL.pathname; - if (isBrowserPath(resolved)) { - return relativeToRoot(resolved + resolvedURL.search); - } - return slash(fileURLToPath(resolvedURL)) + resolvedURL.search; + const isAstroScript = parsedFrom.query.astro && parsedFrom.query.type === 'script'; + if (isAstroScript && isRelativePath(id)) { + return this.resolve(resolveRelativeFromAstroParent(id, parsedFrom), from, { + custom: opts.custom, + skipSelf: true, + }); } } @@ -87,34 +95,37 @@ export default function astro({ config, logging }: AstroPluginOptions): vite.Plu return id; } }, - async load(this: PluginContext, id, opts) { + async load(id, opts) { const parsedId = parseAstroRequest(id); const query = parsedId.query; - if (!id.endsWith('.astro') && !query.astro) { + if (!query.astro) { return null; } - // if we still get a relative path here, vite couldn't resolve the import - if (isRelativePath(parsedId.filename)) { + let filename = parsedId.filename; + // For CSS / hoisted scripts we need to load the source ourselves. + // It should be in the compilation cache at this point. + let raw = await this.resolve(filename, undefined); + if (!raw) { return null; } - const filename = normalizeFilename(parsedId.filename); - const fileUrl = new URL(`file://${filename}`); - let source = await fs.promises.readFile(fileUrl, 'utf-8'); - const isPage = fileUrl.pathname.startsWith(resolvePages(config).pathname); - if (isPage && config._ctx.scripts.some((s) => s.stage === 'page')) { - source += `\n +
      test
      diff --git a/packages/astro/test/fixtures/alias-tsconfig/src/pages/index.astro b/packages/astro/test/fixtures/alias-tsconfig/src/pages/index.astro new file mode 100644 index 000000000..c00b9f083 --- /dev/null +++ b/packages/astro/test/fixtures/alias-tsconfig/src/pages/index.astro @@ -0,0 +1,15 @@ +--- +import Client from '@components/Client.svelte' +--- + + + + + Aliases using tsconfig + + +
      + +
      + + diff --git a/packages/astro/test/fixtures/alias-tsconfig/tsconfig.json b/packages/astro/test/fixtures/alias-tsconfig/tsconfig.json new file mode 100644 index 000000000..01dd88abe --- /dev/null +++ b/packages/astro/test/fixtures/alias-tsconfig/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@components/*": [ + "src/components/*" + ], + "@layouts/*": [ + "src/layouts/*" + ], + "@assets/*": [ + "src/assets/*" + ], + } + } +} diff --git a/packages/astro/test/fixtures/api-routes/package.json b/packages/astro/test/fixtures/api-routes/package.json new file mode 100644 index 000000000..0f7052df4 --- /dev/null +++ b/packages/astro/test/fixtures/api-routes/package.json @@ -0,0 +1,8 @@ +{ + "name": "@test/api-routes", + "version": "0.0.0", + "private": true, + "dependencies": { + "astro": "workspace:*" + } +} diff --git a/packages/astro/test/fixtures/astro-attrs/package.json b/packages/astro/test/fixtures/astro-attrs/package.json index bbf4131d9..41146a6fa 100644 --- a/packages/astro/test/fixtures/astro-attrs/package.json +++ b/packages/astro/test/fixtures/astro-attrs/package.json @@ -4,6 +4,8 @@ "private": true, "dependencies": { "@astrojs/react": "workspace:*", - "astro": "workspace:*" + "astro": "workspace:*", + "react": "^18.1.0", + "react-dom": "^18.1.0" } } diff --git a/packages/astro/test/fixtures/astro-check-errors/astro.config.mjs b/packages/astro/test/fixtures/astro-check-errors/astro.config.mjs new file mode 100644 index 000000000..db9a6db87 --- /dev/null +++ b/packages/astro/test/fixtures/astro-check-errors/astro.config.mjs @@ -0,0 +1,6 @@ +import { defineConfig } from 'astro/config'; + +// https://astro.build/config +export default defineConfig({ + integrations: [], +}); diff --git a/packages/astro/test/fixtures/astro-check-errors/package.json b/packages/astro/test/fixtures/astro-check-errors/package.json new file mode 100644 index 000000000..30e9b96b9 --- /dev/null +++ b/packages/astro/test/fixtures/astro-check-errors/package.json @@ -0,0 +1,8 @@ +{ + "name": "@test/astro-check-errors", + "version": "0.0.0", + "private": true, + "dependencies": { + "astro": "workspace:*" + } +} diff --git a/packages/astro/test/fixtures/astro-check-errors/src/pages/index.astro b/packages/astro/test/fixtures/astro-check-errors/src/pages/index.astro new file mode 100644 index 000000000..c161df438 --- /dev/null +++ b/packages/astro/test/fixtures/astro-check-errors/src/pages/index.astro @@ -0,0 +1,15 @@ +--- + console.log(doesntExist) +--- + + + + + + + Document + + +
      Hello, Astro!
      + + diff --git a/packages/astro/test/fixtures/astro-check-errors/tsconfig.json b/packages/astro/test/fixtures/astro-check-errors/tsconfig.json new file mode 100644 index 000000000..d64f47875 --- /dev/null +++ b/packages/astro/test/fixtures/astro-check-errors/tsconfig.json @@ -0,0 +1,2 @@ +// Having a `tsconfig.json`, even empty speeds up the test massively since TypeScript does not have to look for one +{} diff --git a/packages/astro/test/fixtures/astro-check-no-errors/astro.config.mjs b/packages/astro/test/fixtures/astro-check-no-errors/astro.config.mjs new file mode 100644 index 000000000..db9a6db87 --- /dev/null +++ b/packages/astro/test/fixtures/astro-check-no-errors/astro.config.mjs @@ -0,0 +1,6 @@ +import { defineConfig } from 'astro/config'; + +// https://astro.build/config +export default defineConfig({ + integrations: [], +}); diff --git a/packages/astro/test/fixtures/astro-check-no-errors/package.json b/packages/astro/test/fixtures/astro-check-no-errors/package.json new file mode 100644 index 000000000..6e7c91fdc --- /dev/null +++ b/packages/astro/test/fixtures/astro-check-no-errors/package.json @@ -0,0 +1,8 @@ +{ + "name": "@test/astro-check-no-errors", + "version": "0.0.0", + "private": true, + "dependencies": { + "astro": "workspace:*" + } +} diff --git a/packages/astro/test/fixtures/astro-check-no-errors/src/pages/index.astro b/packages/astro/test/fixtures/astro-check-no-errors/src/pages/index.astro new file mode 100644 index 000000000..49d106456 --- /dev/null +++ b/packages/astro/test/fixtures/astro-check-no-errors/src/pages/index.astro @@ -0,0 +1,11 @@ + + + + + + Document + + +
      Hello, Astro!
      + + diff --git a/packages/astro/test/fixtures/astro-check-no-errors/tsconfig.json b/packages/astro/test/fixtures/astro-check-no-errors/tsconfig.json new file mode 100644 index 000000000..d64f47875 --- /dev/null +++ b/packages/astro/test/fixtures/astro-check-no-errors/tsconfig.json @@ -0,0 +1,2 @@ +// Having a `tsconfig.json`, even empty speeds up the test massively since TypeScript does not have to look for one +{} diff --git a/packages/astro/test/fixtures/astro-class-list/src/pages/component.astro b/packages/astro/test/fixtures/astro-class-list/src/pages/component.astro index e904a0899..5eb64bb12 100644 --- a/packages/astro/test/fixtures/astro-class-list/src/pages/component.astro +++ b/packages/astro/test/fixtures/astro-class-list/src/pages/component.astro @@ -16,3 +16,7 @@ import Component from '../components/Span.astro' + + + + diff --git a/packages/astro/test/fixtures/astro-class-list/src/pages/index.astro b/packages/astro/test/fixtures/astro-class-list/src/pages/index.astro index a642557de..d8ad8aec2 100644 --- a/packages/astro/test/fixtures/astro-class-list/src/pages/index.astro +++ b/packages/astro/test/fixtures/astro-class-list/src/pages/index.astro @@ -13,3 +13,7 @@ + + + + diff --git a/packages/astro/test/fixtures/astro-client-only/package.json b/packages/astro/test/fixtures/astro-client-only/package.json index 96f83eac2..dd987f6c2 100644 --- a/packages/astro/test/fixtures/astro-client-only/package.json +++ b/packages/astro/test/fixtures/astro-client-only/package.json @@ -5,6 +5,8 @@ "dependencies": { "@astrojs/svelte": "workspace:*", "@astrojs/react": "workspace:*", - "astro": "workspace:*" + "astro": "workspace:*", + "react": "^18.1.0", + "react-dom": "^18.1.0" } } diff --git a/packages/astro/test/fixtures/astro-directives/src/components/Title.astro b/packages/astro/test/fixtures/astro-directives/src/components/Title.astro new file mode 100644 index 000000000..113d5b1fe --- /dev/null +++ b/packages/astro/test/fixtures/astro-directives/src/components/Title.astro @@ -0,0 +1,11 @@ +--- +const textColor = 'red' +--- + +

      hello there

      + + diff --git a/packages/astro/test/fixtures/astro-directives/src/pages/define-vars.astro b/packages/astro/test/fixtures/astro-directives/src/pages/define-vars.astro index db03705ad..86ec2e32d 100644 --- a/packages/astro/test/fixtures/astro-directives/src/pages/define-vars.astro +++ b/packages/astro/test/fixtures/astro-directives/src/pages/define-vars.astro @@ -1,4 +1,5 @@ --- +import Title from "../components/Title.astro" let foo = 'bar' let bg = 'white' let fg = 'black' @@ -6,9 +7,13 @@ let fg = 'black' - + @@ -17,5 +22,13 @@ let fg = 'black' + + + + </body> </html> diff --git a/packages/astro/test/fixtures/astro-dynamic/package.json b/packages/astro/test/fixtures/astro-dynamic/package.json index 7a675b3ef..c9c8c194a 100644 --- a/packages/astro/test/fixtures/astro-dynamic/package.json +++ b/packages/astro/test/fixtures/astro-dynamic/package.json @@ -5,6 +5,8 @@ "dependencies": { "@astrojs/react": "workspace:*", "@astrojs/svelte": "workspace:*", - "astro": "workspace:*" + "astro": "workspace:*", + "react": "^18.1.0", + "react-dom": "^18.1.0" } } diff --git a/packages/astro/test/fixtures/astro-envs/astro.config.mjs b/packages/astro/test/fixtures/astro-envs/astro.config.mjs index 7bb1b85f1..1fee9eb36 100644 --- a/packages/astro/test/fixtures/astro-envs/astro.config.mjs +++ b/packages/astro/test/fixtures/astro-envs/astro.config.mjs @@ -4,5 +4,6 @@ import vue from '@astrojs/vue'; // https://astro.build/config export default defineConfig({ site: 'http://example.com', + base: '/blog', integrations: [vue()], }); diff --git a/packages/astro/test/fixtures/astro-envs/src/components/Client.vue b/packages/astro/test/fixtures/astro-envs/src/components/Client.vue index 7162c5632..e7b79c0f7 100644 --- a/packages/astro/test/fixtures/astro-envs/src/components/Client.vue +++ b/packages/astro/test/fixtures/astro-envs/src/components/Client.vue @@ -10,6 +10,7 @@ export default { return { PUBLIC_PLACE: import.meta.env.PUBLIC_PLACE, SECRET_PLACE: import.meta.env.SECRET_PLACE, + BASE_URL: import.meta.env.BASE_URL, }; }, }; diff --git a/packages/astro/test/fixtures/astro-envs/src/pages/destructured.astro b/packages/astro/test/fixtures/astro-envs/src/pages/destructured.astro index e85b9bf81..6c2c803fc 100644 --- a/packages/astro/test/fixtures/astro-envs/src/pages/destructured.astro +++ b/packages/astro/test/fixtures/astro-envs/src/pages/destructured.astro @@ -4,3 +4,4 @@ const { PUBLIC_PLACE, SECRET_PLACE, SITE } = import.meta.env; <environment-variable>{PUBLIC_PLACE}</environment-variable> <environment-variable>{SECRET_PLACE}</environment-variable> <environment-variable>{SITE}</environment-variable> +<environment-variable id="base-url">{import.meta.env.BASE_URL}</environment-variable> diff --git a/packages/astro/test/fixtures/astro-envs/src/pages/index.astro b/packages/astro/test/fixtures/astro-envs/src/pages/index.astro index 3c265dbef..f56c3cbc1 100644 --- a/packages/astro/test/fixtures/astro-envs/src/pages/index.astro +++ b/packages/astro/test/fixtures/astro-envs/src/pages/index.astro @@ -4,4 +4,5 @@ import Client from '../components/Client.vue'; <environment-variable>{import.meta.env.PUBLIC_PLACE}</environment-variable> <environment-variable>{import.meta.env.SECRET_PLACE}</environment-variable> <environment-variable>{import.meta.env.SITE}</environment-variable> +<environment-variable id="base-url">{import.meta.env.BASE_URL}</environment-variable> <Client client:load /> diff --git a/packages/astro/test/fixtures/astro-expr/src/pages/switch.astro b/packages/astro/test/fixtures/astro-expr/src/pages/switch.astro new file mode 100644 index 000000000..ded58613e --- /dev/null +++ b/packages/astro/test/fixtures/astro-expr/src/pages/switch.astro @@ -0,0 +1,20 @@ +--- +let title = 'Switch'; +let colors = ['red', 'yellow', 'blue']; +--- + +<html> +<head> + <title>{title} + + + {() => { + const color = colors[1]; + switch (color) { + case 'red': return
      red
      ; + case 'yellow': return
      yellow
      + case 'blue': return
      blue
      + } + }} + + diff --git a/packages/astro/test/fixtures/astro-get-static-paths/src/pages/posts/[page].astro b/packages/astro/test/fixtures/astro-get-static-paths/src/pages/posts/[page].astro index 8d7a0c0c5..8ec05bc7c 100644 --- a/packages/astro/test/fixtures/astro-get-static-paths/src/pages/posts/[page].astro +++ b/packages/astro/test/fixtures/astro-get-static-paths/src/pages/posts/[page].astro @@ -14,6 +14,7 @@ export async function getStaticPaths() { }; const { page } = Astro.params +const canonicalURL = new URL(Astro.url.pathname, Astro.site); --- @@ -21,7 +22,7 @@ const { page } = Astro.params Posts Page {page} - +

      Welcome to page {page}

      diff --git a/packages/astro/test/fixtures/astro-global/src/components/Child.astro b/packages/astro/test/fixtures/astro-global/src/components/Child.astro index 911e5464b..aede72b6f 100644 --- a/packages/astro/test/fixtures/astro-global/src/components/Child.astro +++ b/packages/astro/test/fixtures/astro-global/src/components/Child.astro @@ -1,5 +1,5 @@ --- import NestedChild from './NestedChild.astro'; --- -
      {new URL(Astro.request.url).pathname}
      +
      {Astro.url.pathname}
      diff --git a/packages/astro/test/fixtures/astro-global/src/components/NestedChild.astro b/packages/astro/test/fixtures/astro-global/src/components/NestedChild.astro index 809a0d68d..b186e9cd1 100644 --- a/packages/astro/test/fixtures/astro-global/src/components/NestedChild.astro +++ b/packages/astro/test/fixtures/astro-global/src/components/NestedChild.astro @@ -1 +1 @@ -
      {new URL(Astro.request.url).pathname}
      +
      {Astro.url.pathname}
      diff --git a/packages/astro/test/fixtures/astro-global/src/layouts/post.astro b/packages/astro/test/fixtures/astro-global/src/layouts/post.astro index ba9377278..7ffde0531 100644 --- a/packages/astro/test/fixtures/astro-global/src/layouts/post.astro +++ b/packages/astro/test/fixtures/astro-global/src/layouts/post.astro @@ -1,10 +1,11 @@ --- const { content } = Astro.props; +const canonicalURL = new URL(Astro.url.pathname, Astro.site ?? `http://example.com`); --- {content.title} - + diff --git a/packages/astro/test/fixtures/astro-global/src/pages/index.astro b/packages/astro/test/fixtures/astro-global/src/pages/index.astro index 6e51e2768..ad6012ce6 100644 --- a/packages/astro/test/fixtures/astro-global/src/pages/index.astro +++ b/packages/astro/test/fixtures/astro-global/src/pages/index.astro @@ -1,14 +1,15 @@ --- import Child from '../components/Child.astro'; +const canonicalURL = new URL(Astro.url.pathname, Astro.site ?? `http://example.com`); --- Test - + -
      {new URL(Astro.request.url).pathname}
      -
      {JSON.stringify(new URL(Astro.request.url).searchParams)}
      +
      {Astro.url.pathname}
      +
      {JSON.stringify(Astro.url.searchParams)}
      Home diff --git a/packages/astro/test/fixtures/astro-global/src/pages/posts/[page].astro b/packages/astro/test/fixtures/astro-global/src/pages/posts/[page].astro index ee34156db..0950ebe26 100644 --- a/packages/astro/test/fixtures/astro-global/src/pages/posts/[page].astro +++ b/packages/astro/test/fixtures/astro-global/src/pages/posts/[page].astro @@ -4,7 +4,7 @@ export async function getStaticPaths({paginate}) { return paginate(data, {pageSize: 1}); } const { page } = Astro.props; -const { params, canonicalURL } = Astro; +const canonicalURL = new URL(Astro.url.pathname, Astro.site ?? `http://example.com`); --- @@ -13,7 +13,7 @@ const { params, canonicalURL } = Astro; - {page.data.map((data) => ( + {page.data.map((data: any) => (

      {data.frontmatter.title}

      Read diff --git a/packages/astro/test/fixtures/astro-head/src/components/Head.astro b/packages/astro/test/fixtures/astro-head/src/components/Head.astro new file mode 100644 index 000000000..cc289f7b4 --- /dev/null +++ b/packages/astro/test/fixtures/astro-head/src/components/Head.astro @@ -0,0 +1,11 @@ +--- +// Head.astro +const { title } = Astro.props; +--- + + + + + + {title} + diff --git a/packages/astro/test/fixtures/astro-head/src/pages/head-own-component.astro b/packages/astro/test/fixtures/astro-head/src/pages/head-own-component.astro new file mode 100644 index 000000000..cbc99cb04 --- /dev/null +++ b/packages/astro/test/fixtures/astro-head/src/pages/head-own-component.astro @@ -0,0 +1,16 @@ +--- +// Layout.astro +import Head from "../components/Head.astro"; +--- + + + + + +

      Title Here

      + + diff --git a/packages/astro/test/fixtures/astro-markdown-css/astro.config.mjs b/packages/astro/test/fixtures/astro-markdown-css/astro.config.mjs index 50eaa792c..410c20408 100644 --- a/packages/astro/test/fixtures/astro-markdown-css/astro.config.mjs +++ b/packages/astro/test/fixtures/astro-markdown-css/astro.config.mjs @@ -2,5 +2,8 @@ import { defineConfig } from 'astro/config'; // https://astro.build/config export default defineConfig({ + legacy: { + astroFlavoredMarkdown: true, + }, integrations: [] }); diff --git a/packages/astro/test/fixtures/astro-markdown-md-mode/astro.config.mjs b/packages/astro/test/fixtures/astro-markdown-md-mode/astro.config.mjs new file mode 100644 index 000000000..908e3442f --- /dev/null +++ b/packages/astro/test/fixtures/astro-markdown-md-mode/astro.config.mjs @@ -0,0 +1,8 @@ +import { defineConfig } from 'astro/config'; +import svelte from "@astrojs/svelte"; + +// https://astro.build/config +export default defineConfig({ + integrations: [svelte()], + site: 'https://astro.build/', +}); diff --git a/packages/astro/test/fixtures/astro-markdown-md-mode/package.json b/packages/astro/test/fixtures/astro-markdown-md-mode/package.json new file mode 100644 index 000000000..48a6c6816 --- /dev/null +++ b/packages/astro/test/fixtures/astro-markdown-md-mode/package.json @@ -0,0 +1,9 @@ +{ + "name": "@test/astro-markdown-md-mode", + "version": "0.0.0", + "private": true, + "dependencies": { + "@astrojs/svelte": "workspace:*", + "astro": "workspace:*" + } +} diff --git a/packages/astro/test/fixtures/astro-markdown-md-mode/src/components/Counter.svelte b/packages/astro/test/fixtures/astro-markdown-md-mode/src/components/Counter.svelte new file mode 100644 index 000000000..4e91b2659 --- /dev/null +++ b/packages/astro/test/fixtures/astro-markdown-md-mode/src/components/Counter.svelte @@ -0,0 +1,5 @@ + + + diff --git a/packages/astro/test/fixtures/astro-markdown-md-mode/src/pages/code-in-md.md b/packages/astro/test/fixtures/astro-markdown-md-mode/src/pages/code-in-md.md new file mode 100644 index 000000000..72206a868 --- /dev/null +++ b/packages/astro/test/fixtures/astro-markdown-md-mode/src/pages/code-in-md.md @@ -0,0 +1,7 @@ +# Fenced code blocks + +```html + +
      This should also work without any problems.
      + +``` diff --git a/packages/astro/test/fixtures/astro-markdown-md-mode/src/pages/components.md b/packages/astro/test/fixtures/astro-markdown-md-mode/src/pages/components.md new file mode 100644 index 000000000..cd27bc09f --- /dev/null +++ b/packages/astro/test/fixtures/astro-markdown-md-mode/src/pages/components.md @@ -0,0 +1,5 @@ +--- +setup: import Counter from '../components/Counter.svelte' +--- + + diff --git a/packages/astro/test/fixtures/astro-markdown-md-mode/src/pages/jsx-expressions.md b/packages/astro/test/fixtures/astro-markdown-md-mode/src/pages/jsx-expressions.md new file mode 100644 index 000000000..b87efbb2d --- /dev/null +++ b/packages/astro/test/fixtures/astro-markdown-md-mode/src/pages/jsx-expressions.md @@ -0,0 +1,13 @@ +--- +title: Blog Post with JSX expressions +paragraph: JSX at the start of the line! +list: ['test-1', 'test-2', 'test-3'] +--- + +## {frontmatter.title} + +{frontmatter.paragraph} + +
        + {frontmatter.list.map(item =>
      • {item}
      • )} +
      diff --git a/packages/astro/test/fixtures/astro-markdown-shiki/langs/src/pages/index.md b/packages/astro/test/fixtures/astro-markdown-shiki/langs/src/pages/index.md index d5b554e05..d2d756b95 100644 --- a/packages/astro/test/fixtures/astro-markdown-shiki/langs/src/pages/index.md +++ b/packages/astro/test/fixtures/astro-markdown-shiki/langs/src/pages/index.md @@ -20,3 +20,7 @@ comenzar Iniciar(Rinfo, 1, 1) fin ``` + +```unknown +This language does not exist +``` diff --git a/packages/astro/test/fixtures/astro-markdown/astro.config.mjs b/packages/astro/test/fixtures/astro-markdown/astro.config.mjs index be33a26cc..baefed8cc 100644 --- a/packages/astro/test/fixtures/astro-markdown/astro.config.mjs +++ b/packages/astro/test/fixtures/astro-markdown/astro.config.mjs @@ -6,4 +6,7 @@ import svelte from "@astrojs/svelte"; export default defineConfig({ integrations: [preact(), svelte()], site: 'https://astro.build/', + legacy: { + astroFlavoredMarkdown: true, + } }); diff --git a/packages/astro/test/fixtures/astro-markdown/src/layouts/layout-props.astro b/packages/astro/test/fixtures/astro-markdown/src/layouts/layout-props.astro new file mode 100644 index 000000000..a11abb8fb --- /dev/null +++ b/packages/astro/test/fixtures/astro-markdown/src/layouts/layout-props.astro @@ -0,0 +1,17 @@ +--- + interface Props { + url: string; + file: string; + title: string; + } + + const { title, url, file } = Astro.props.content as Props; +--- + + + +
      {title}
      +
      {url}
      +
      {file}
      + + \ No newline at end of file diff --git a/packages/astro/test/fixtures/astro-markdown/src/pages/comment-with-js.md b/packages/astro/test/fixtures/astro-markdown/src/pages/comment-with-js.md index 387b8380e..374463d2d 100644 --- a/packages/astro/test/fixtures/astro-markdown/src/pages/comment-with-js.md +++ b/packages/astro/test/fixtures/astro-markdown/src/pages/comment-with-js.md @@ -14,4 +14,10 @@ function test() { ``` --> +``` + +``` + +`` + # It still works! diff --git a/packages/astro/test/fixtures/astro-markdown/src/pages/content.astro b/packages/astro/test/fixtures/astro-markdown/src/pages/content.astro deleted file mode 100644 index 8c07debd2..000000000 --- a/packages/astro/test/fixtures/astro-markdown/src/pages/content.astro +++ /dev/null @@ -1,6 +0,0 @@ ---- -import { Markdown } from 'astro/components'; -const content = '# Foo'; ---- - - \ No newline at end of file diff --git a/packages/astro/test/fixtures/astro-markdown/src/pages/layout-props.md b/packages/astro/test/fixtures/astro-markdown/src/pages/layout-props.md new file mode 100644 index 000000000..0f87c1bd0 --- /dev/null +++ b/packages/astro/test/fixtures/astro-markdown/src/pages/layout-props.md @@ -0,0 +1,4 @@ +--- +title: 'Hello world!' +layout: '../layouts/layout-props.astro' +--- \ No newline at end of file diff --git a/packages/astro/test/fixtures/astro-markdown/src/pages/no-elements.astro b/packages/astro/test/fixtures/astro-markdown/src/pages/no-elements.astro deleted file mode 100644 index d865e9046..000000000 --- a/packages/astro/test/fixtures/astro-markdown/src/pages/no-elements.astro +++ /dev/null @@ -1,5 +0,0 @@ ---- -import { Markdown } from 'astro/components'; ---- - - \ No newline at end of file diff --git a/packages/astro/test/fixtures/astro-markdown/src/pages/vite-env-vars.md b/packages/astro/test/fixtures/astro-markdown/src/pages/vite-env-vars.md index 78908cba3..30a9ab177 100644 --- a/packages/astro/test/fixtures/astro-markdown/src/pages/vite-env-vars.md +++ b/packages/astro/test/fixtures/astro-markdown/src/pages/vite-env-vars.md @@ -1,5 +1,5 @@ --- -title: Referencing Vite Env Vars like import.meta.env.SITE and import.meta.env.TITLE +title: Referencing Vite Env Vars like import.meta.env.SITE, import.meta.env.TITLE and import.meta.env layout: ../layouts/content.astro --- @@ -9,9 +9,12 @@ You can get the configured site URL with `import.meta.env.SITE`. The variable `import.meta.env.TITLE` is not configured. +You can reference all env vars through `import.meta.env`. + This should also work outside of code blocks: - import.meta.env.SITE - import.meta.env.TITLE +- import.meta.env ## Usage in fenced code blocks with syntax highlighting @@ -20,6 +23,7 @@ This should also work outside of code blocks: import rss from '@astrojs/rss'; export const get = () => rss({ + // Use Vite env vars with import.meta.env site: import.meta.env.SITE, title: import.meta.env.TITLE, items: import.meta.glob('./**/*.md'), diff --git a/packages/astro/test/fixtures/astro-pagination/src/pages/index.astro b/packages/astro/test/fixtures/astro-pagination/src/pages/index.astro index afd2203de..bdff86266 100644 --- a/packages/astro/test/fixtures/astro-pagination/src/pages/index.astro +++ b/packages/astro/test/fixtures/astro-pagination/src/pages/index.astro @@ -1,12 +1,13 @@ --- +const canonicalURL = new URL(Astro.url.pathname, Astro.site); --- Test - + -
      {new URL(Astro.request.url).pathname}
      +
      {Astro.url.pathname}
      Home diff --git a/packages/astro/test/fixtures/astro-pagination/src/pages/posts/[slug]/[page].astro b/packages/astro/test/fixtures/astro-pagination/src/pages/posts/[slug]/[page].astro index ba51548a1..49a2f702e 100644 --- a/packages/astro/test/fixtures/astro-pagination/src/pages/posts/[slug]/[page].astro +++ b/packages/astro/test/fixtures/astro-pagination/src/pages/posts/[slug]/[page].astro @@ -11,7 +11,8 @@ export async function getStaticPaths({paginate}) { }); } const { page, filter } = Astro.props; -const { params, canonicalURL} = Astro; +const { params } = Astro; +const canonicalURL = new URL(Astro.url.pathname, Astro.site); --- diff --git a/packages/astro/test/fixtures/astro-pagination/src/pages/posts/named-root-page/[page].astro b/packages/astro/test/fixtures/astro-pagination/src/pages/posts/named-root-page/[page].astro index a3efb9b45..c908f1c43 100644 --- a/packages/astro/test/fixtures/astro-pagination/src/pages/posts/named-root-page/[page].astro +++ b/packages/astro/test/fixtures/astro-pagination/src/pages/posts/named-root-page/[page].astro @@ -3,8 +3,7 @@ export async function getStaticPaths({paginate}) { const data = await Astro.glob('../../post/*.md'); return paginate(data, {pageSize: 1}); } -const { page } = Astro.props; -const { params, canonicalURL} = Astro; +const canonicalURL = new URL(Astro.url.pathname, Astro.site); --- diff --git a/packages/astro/test/fixtures/astro-pagination/src/pages/posts/optional-root-page/[...page].astro b/packages/astro/test/fixtures/astro-pagination/src/pages/posts/optional-root-page/[...page].astro index a3efb9b45..c908f1c43 100644 --- a/packages/astro/test/fixtures/astro-pagination/src/pages/posts/optional-root-page/[...page].astro +++ b/packages/astro/test/fixtures/astro-pagination/src/pages/posts/optional-root-page/[...page].astro @@ -3,8 +3,7 @@ export async function getStaticPaths({paginate}) { const data = await Astro.glob('../../post/*.md'); return paginate(data, {pageSize: 1}); } -const { page } = Astro.props; -const { params, canonicalURL} = Astro; +const canonicalURL = new URL(Astro.url.pathname, Astro.site); --- diff --git a/packages/astro/test/fixtures/astro-partial-html/package.json b/packages/astro/test/fixtures/astro-partial-html/package.json index 55dce70b9..2f795916c 100644 --- a/packages/astro/test/fixtures/astro-partial-html/package.json +++ b/packages/astro/test/fixtures/astro-partial-html/package.json @@ -4,6 +4,8 @@ "private": true, "dependencies": { "@astrojs/react": "workspace:*", - "astro": "workspace:*" + "astro": "workspace:*", + "react": "^18.1.0", + "react-dom": "^18.1.0" } } diff --git a/packages/astro/test/fixtures/astro-partial-html/src/pages/with-head.astro b/packages/astro/test/fixtures/astro-partial-html/src/pages/with-head.astro new file mode 100644 index 000000000..fbbcecd1e --- /dev/null +++ b/packages/astro/test/fixtures/astro-partial-html/src/pages/with-head.astro @@ -0,0 +1,9 @@ + + + testing + + + +

      testing

      + + diff --git a/packages/astro/test/fixtures/astro-response/package.json b/packages/astro/test/fixtures/astro-response/package.json new file mode 100644 index 000000000..a83253490 --- /dev/null +++ b/packages/astro/test/fixtures/astro-response/package.json @@ -0,0 +1,8 @@ +{ + "name": "@test/astro-response", + "version": "0.0.0", + "private": true, + "dependencies": { + "astro": "workspace:*" + } +} diff --git a/packages/astro/test/fixtures/astro-response/src/components/not-found.astro b/packages/astro/test/fixtures/astro-response/src/components/not-found.astro deleted file mode 100644 index dd339e72b..000000000 --- a/packages/astro/test/fixtures/astro-response/src/components/not-found.astro +++ /dev/null @@ -1,6 +0,0 @@ ---- -return new Response(null, { - status: 404, - statusText: `Not found` -}); ---- diff --git a/packages/astro/test/fixtures/astro-response/src/pages/not-found-component.astro b/packages/astro/test/fixtures/astro-response/src/pages/not-found-component.astro deleted file mode 100644 index e1077e9c9..000000000 --- a/packages/astro/test/fixtures/astro-response/src/pages/not-found-component.astro +++ /dev/null @@ -1,4 +0,0 @@ ---- -import NotFound from '../components/not-found.astro'; ---- - diff --git a/packages/astro/test/fixtures/astro-scripts/src/components/Glob/GlobComponent.astro b/packages/astro/test/fixtures/astro-scripts/src/components/Glob/GlobComponent.astro new file mode 100644 index 000000000..dca1588f5 --- /dev/null +++ b/packages/astro/test/fixtures/astro-scripts/src/components/Glob/GlobComponent.astro @@ -0,0 +1,4 @@ + +

      My Component

      diff --git a/packages/astro/test/fixtures/astro-scripts/src/components/Inline.astro b/packages/astro/test/fixtures/astro-scripts/src/components/Inline.astro index dfe895d6c..13c64eb37 100644 --- a/packages/astro/test/fixtures/astro-scripts/src/components/Inline.astro +++ b/packages/astro/test/fixtures/astro-scripts/src/components/Inline.astro @@ -1,3 +1,11 @@ diff --git a/packages/astro/test/fixtures/astro-scripts/src/components/InlineShared.astro b/packages/astro/test/fixtures/astro-scripts/src/components/InlineShared.astro new file mode 100644 index 000000000..2be6f7d7f --- /dev/null +++ b/packages/astro/test/fixtures/astro-scripts/src/components/InlineShared.astro @@ -0,0 +1,3 @@ + diff --git a/packages/astro/test/fixtures/astro-scripts/src/pages/glob.astro b/packages/astro/test/fixtures/astro-scripts/src/pages/glob.astro new file mode 100644 index 000000000..5d7c77bd5 --- /dev/null +++ b/packages/astro/test/fixtures/astro-scripts/src/pages/glob.astro @@ -0,0 +1,16 @@ +--- +const components = await Astro.glob('/src/components/Glob/*'); +const MyComponent = components[0].default; +--- + + + + + + Astro + + +

      My Component is below...

      + + + diff --git a/packages/astro/test/fixtures/astro-scripts/src/pages/inline-shared-one.astro b/packages/astro/test/fixtures/astro-scripts/src/pages/inline-shared-one.astro new file mode 100644 index 000000000..a035fa8c7 --- /dev/null +++ b/packages/astro/test/fixtures/astro-scripts/src/pages/inline-shared-one.astro @@ -0,0 +1,14 @@ +--- +import InlineShared from '../components/InlineShared.astro'; +--- + + + Testing + + + + + + diff --git a/packages/astro/test/fixtures/astro-scripts/src/pages/inline-shared-two.astro b/packages/astro/test/fixtures/astro-scripts/src/pages/inline-shared-two.astro new file mode 100644 index 000000000..97f7403fc --- /dev/null +++ b/packages/astro/test/fixtures/astro-scripts/src/pages/inline-shared-two.astro @@ -0,0 +1,14 @@ +--- +import InlineShared from '../components/InlineShared.astro'; +--- + + + Testing + + + + + + diff --git a/packages/astro/test/fixtures/astro-scripts/src/scripts/some-files/one.ts b/packages/astro/test/fixtures/astro-scripts/src/scripts/some-files/one.ts new file mode 100644 index 000000000..6125b5a48 --- /dev/null +++ b/packages/astro/test/fixtures/astro-scripts/src/scripts/some-files/one.ts @@ -0,0 +1 @@ +console.log('some-files/one'); diff --git a/packages/astro/test/fixtures/astro-scripts/src/scripts/some-files/two.ts b/packages/astro/test/fixtures/astro-scripts/src/scripts/some-files/two.ts new file mode 100644 index 000000000..113f7075f --- /dev/null +++ b/packages/astro/test/fixtures/astro-scripts/src/scripts/some-files/two.ts @@ -0,0 +1 @@ +console.log('some-files/two'); diff --git a/packages/astro/test/fixtures/astro-slots/src/pages/conditional.astro b/packages/astro/test/fixtures/astro-slots/src/pages/conditional.astro new file mode 100644 index 000000000..e5ae7cd07 --- /dev/null +++ b/packages/astro/test/fixtures/astro-slots/src/pages/conditional.astro @@ -0,0 +1,17 @@ +--- +import Slotted from '../components/Slotted.astro'; +--- + + + + + + + + {true && A} + {true ? B : null} + {() => C} + {true && Default} + + + diff --git a/packages/astro/test/fixtures/client-address/src/pages/index.astro b/packages/astro/test/fixtures/client-address/src/pages/index.astro new file mode 100644 index 000000000..ea2cf65ca --- /dev/null +++ b/packages/astro/test/fixtures/client-address/src/pages/index.astro @@ -0,0 +1,12 @@ +--- +const address = Astro.clientAddress; +--- + + + Astro.clientAddress + + +

      Astro.clientAddress

      +
      { address }
      + + diff --git a/packages/astro/test/fixtures/code-component/package.json b/packages/astro/test/fixtures/code-component/package.json new file mode 100644 index 000000000..a33708105 --- /dev/null +++ b/packages/astro/test/fixtures/code-component/package.json @@ -0,0 +1,8 @@ +{ + "name": "@test/code-component", + "version": "0.0.0", + "private": true, + "dependencies": { + "astro": "workspace:*" + } +} diff --git a/packages/astro/test/fixtures/code-component/src/pages/index.astro b/packages/astro/test/fixtures/code-component/src/pages/index.astro new file mode 100644 index 000000000..763f32cae --- /dev/null +++ b/packages/astro/test/fixtures/code-component/src/pages/index.astro @@ -0,0 +1,11 @@ +--- +import { Code } from 'astro/components'; +--- + + + Testing + + + + + diff --git a/packages/astro/test/fixtures/config-vite/package.json b/packages/astro/test/fixtures/config-vite/package.json new file mode 100644 index 000000000..c226030fb --- /dev/null +++ b/packages/astro/test/fixtures/config-vite/package.json @@ -0,0 +1,8 @@ +{ + "name": "@test/config-vite", + "version": "0.0.0", + "private": true, + "dependencies": { + "astro": "workspace:*" + } +} diff --git a/packages/astro/test/fixtures/custom-404/src/pages/404.astro b/packages/astro/test/fixtures/custom-404/src/pages/404.astro index 85b800bc9..63d560b0f 100644 --- a/packages/astro/test/fixtures/custom-404/src/pages/404.astro +++ b/packages/astro/test/fixtures/custom-404/src/pages/404.astro @@ -1,4 +1,5 @@ --- +const canonicalURL = new URL(Astro.url.pathname, Astro.site); --- @@ -7,6 +8,6 @@

      Page not found

      -

      {Astro.canonicalURL.pathname}

      +

      {canonicalURL.pathname}

      diff --git a/packages/astro/test/fixtures/custom-elements/my-component-lib/index.js b/packages/astro/test/fixtures/custom-elements/my-component-lib/index.js index a550dfee2..5b9bba7e6 100644 --- a/packages/astro/test/fixtures/custom-elements/my-component-lib/index.js +++ b/packages/astro/test/fixtures/custom-elements/my-component-lib/index.js @@ -13,9 +13,9 @@ export default function () { hooks: { 'astro:config:setup': ({ updateConfig, addRenderer, injectScript }) => { // Inject the necessary polyfills on every page - injectScript('head-inline', `import '@test/custom-element-renderer/polyfill.js';`); + injectScript('head-inline', `import('@test/custom-element-renderer/polyfill.js');`); // Inject the hydration code, before a component is hydrated. - injectScript('before-hydration', `import '@test/custom-element-renderer/hydration-polyfill.js';`); + injectScript('before-hydration', `import('@test/custom-element-renderer/hydration-polyfill.js');`); // Add the lit renderer so that Astro can understand lit components. addRenderer({ name: '@test/custom-element-renderer', diff --git a/packages/astro/test/fixtures/custom-elements/src/pages/load.astro b/packages/astro/test/fixtures/custom-elements/src/pages/load.astro deleted file mode 100644 index c67750bc5..000000000 --- a/packages/astro/test/fixtures/custom-elements/src/pages/load.astro +++ /dev/null @@ -1,15 +0,0 @@ ---- -import '../components/my-element.js'; -const title = 'My App'; ---- - - - - {title} - - -

      {title}

      - - - - diff --git a/packages/astro/test/fixtures/entry-file-names/astro.config.mjs b/packages/astro/test/fixtures/entry-file-names/astro.config.mjs new file mode 100644 index 000000000..fbca4b567 --- /dev/null +++ b/packages/astro/test/fixtures/entry-file-names/astro.config.mjs @@ -0,0 +1,16 @@ +import { defineConfig } from 'astro/config'; +import preact from '@astrojs/preact'; + +// https://astro.build/config +export default defineConfig({ + integrations: [preact()], + vite: { + build: { + rollupOptions: { + output: { + entryFileNames: `assets/js/[name].js`, + }, + }, + }, + }, +}); diff --git a/packages/astro/test/fixtures/entry-file-names/package.json b/packages/astro/test/fixtures/entry-file-names/package.json new file mode 100644 index 000000000..760acaedb --- /dev/null +++ b/packages/astro/test/fixtures/entry-file-names/package.json @@ -0,0 +1,9 @@ +{ + "name": "@test/entry-file-names", + "version": "0.0.0", + "private": true, + "dependencies": { + "@astrojs/preact": "workspace:", + "astro": "workspace:*" + } +} diff --git a/packages/astro/test/fixtures/entry-file-names/src/components/Hello.jsx b/packages/astro/test/fixtures/entry-file-names/src/components/Hello.jsx new file mode 100644 index 000000000..833f20f8e --- /dev/null +++ b/packages/astro/test/fixtures/entry-file-names/src/components/Hello.jsx @@ -0,0 +1,6 @@ + +export default function() { + return ( +
      Hello world
      + ) +} diff --git a/packages/astro/test/fixtures/entry-file-names/src/pages/index.astro b/packages/astro/test/fixtures/entry-file-names/src/pages/index.astro new file mode 100644 index 000000000..aac79cece --- /dev/null +++ b/packages/astro/test/fixtures/entry-file-names/src/pages/index.astro @@ -0,0 +1,10 @@ +--- +import Hello from '../components/Hello.jsx'; +--- + + + Test + + + + diff --git a/packages/astro/test/fixtures/fontsource-package/astro.config.mjs b/packages/astro/test/fixtures/fontsource-package/astro.config.mjs new file mode 100644 index 000000000..03d5ecbec --- /dev/null +++ b/packages/astro/test/fixtures/fontsource-package/astro.config.mjs @@ -0,0 +1,13 @@ +import { defineConfig } from 'astro/config'; + +// https://astro.build/config +export default defineConfig({ + vite: { + ssr: { + noExternal: [ + '@fontsource/montserrat', + '@fontsource/monofett', + ] + } + } +}); diff --git a/packages/astro/test/fixtures/hmr-css/package.json b/packages/astro/test/fixtures/hmr-css/package.json new file mode 100644 index 000000000..36bf56c91 --- /dev/null +++ b/packages/astro/test/fixtures/hmr-css/package.json @@ -0,0 +1,8 @@ +{ + "name": "@test/hmr-css", + "version": "0.0.0", + "private": true, + "dependencies": { + "astro": "workspace:*" + } +} diff --git a/packages/astro/test/fixtures/hmr-css/src/pages/index.astro b/packages/astro/test/fixtures/hmr-css/src/pages/index.astro deleted file mode 100644 index 840e60e01..000000000 --- a/packages/astro/test/fixtures/hmr-css/src/pages/index.astro +++ /dev/null @@ -1,11 +0,0 @@ - - - Testing - - - -

      Testing

      - - diff --git a/packages/astro/test/fixtures/html-component/package.json b/packages/astro/test/fixtures/html-component/package.json new file mode 100644 index 000000000..548f0bc7b --- /dev/null +++ b/packages/astro/test/fixtures/html-component/package.json @@ -0,0 +1,8 @@ +{ + "name": "@test/html-component", + "version": "0.0.0", + "private": true, + "dependencies": { + "astro": "workspace:*" + } +} diff --git a/packages/astro/test/fixtures/html-component/src/components/Test.html b/packages/astro/test/fixtures/html-component/src/components/Test.html new file mode 100644 index 000000000..ec16bf314 --- /dev/null +++ b/packages/astro/test/fixtures/html-component/src/components/Test.html @@ -0,0 +1,3 @@ +

      Hello component!

      + +
      bar
      diff --git a/packages/astro/test/fixtures/html-component/src/pages/index.astro b/packages/astro/test/fixtures/html-component/src/pages/index.astro new file mode 100644 index 000000000..821d12538 --- /dev/null +++ b/packages/astro/test/fixtures/html-component/src/pages/index.astro @@ -0,0 +1,5 @@ +--- +import Test from '../components/Test.html'; +--- + + diff --git a/packages/astro/test/fixtures/html-escape/package.json b/packages/astro/test/fixtures/html-escape/package.json new file mode 100644 index 000000000..b6eb74765 --- /dev/null +++ b/packages/astro/test/fixtures/html-escape/package.json @@ -0,0 +1,8 @@ +{ + "name": "@test/html-escape", + "version": "0.0.0", + "private": true, + "dependencies": { + "astro": "workspace:*" + } +} diff --git a/packages/astro/test/fixtures/html-escape/src/components/Test.html b/packages/astro/test/fixtures/html-escape/src/components/Test.html new file mode 100644 index 000000000..6ee4b5200 --- /dev/null +++ b/packages/astro/test/fixtures/html-escape/src/components/Test.html @@ -0,0 +1,4 @@ +
      ${foo}
      + + + diff --git a/packages/astro/test/fixtures/html-escape/src/pages/index.astro b/packages/astro/test/fixtures/html-escape/src/pages/index.astro new file mode 100644 index 000000000..821d12538 --- /dev/null +++ b/packages/astro/test/fixtures/html-escape/src/pages/index.astro @@ -0,0 +1,5 @@ +--- +import Test from '../components/Test.html'; +--- + + diff --git a/packages/astro/test/fixtures/html-page/package.json b/packages/astro/test/fixtures/html-page/package.json new file mode 100644 index 000000000..070024b1e --- /dev/null +++ b/packages/astro/test/fixtures/html-page/package.json @@ -0,0 +1,8 @@ +{ + "name": "@test/html-page", + "version": "0.0.0", + "private": true, + "dependencies": { + "astro": "workspace:*" + } +} diff --git a/packages/astro/test/fixtures/html-page/src/pages/index.html b/packages/astro/test/fixtures/html-page/src/pages/index.html new file mode 100644 index 000000000..5d4d22827 --- /dev/null +++ b/packages/astro/test/fixtures/html-page/src/pages/index.html @@ -0,0 +1 @@ +

      Hello page!

      diff --git a/packages/astro/test/fixtures/html-slots/package.json b/packages/astro/test/fixtures/html-slots/package.json new file mode 100644 index 000000000..10b04cfd4 --- /dev/null +++ b/packages/astro/test/fixtures/html-slots/package.json @@ -0,0 +1,8 @@ +{ + "name": "@test/html-slots", + "version": "0.0.0", + "private": true, + "dependencies": { + "astro": "workspace:*" + } +} diff --git a/packages/astro/test/fixtures/html-slots/src/components/Default.html b/packages/astro/test/fixtures/html-slots/src/components/Default.html new file mode 100644 index 000000000..9f012095f --- /dev/null +++ b/packages/astro/test/fixtures/html-slots/src/components/Default.html @@ -0,0 +1 @@ +
      diff --git a/packages/astro/test/fixtures/html-slots/src/components/Inline.html b/packages/astro/test/fixtures/html-slots/src/components/Inline.html new file mode 100644 index 000000000..121164e38 --- /dev/null +++ b/packages/astro/test/fixtures/html-slots/src/components/Inline.html @@ -0,0 +1 @@ +
      diff --git a/packages/astro/test/fixtures/html-slots/src/components/Named.html b/packages/astro/test/fixtures/html-slots/src/components/Named.html new file mode 100644 index 000000000..0993cfb27 --- /dev/null +++ b/packages/astro/test/fixtures/html-slots/src/components/Named.html @@ -0,0 +1,3 @@ +
      +
      +
      diff --git a/packages/astro/test/fixtures/html-slots/src/pages/index.astro b/packages/astro/test/fixtures/html-slots/src/pages/index.astro new file mode 100644 index 000000000..aa4a3bd25 --- /dev/null +++ b/packages/astro/test/fixtures/html-slots/src/pages/index.astro @@ -0,0 +1,13 @@ +--- +import Default from '../components/Default.html'; +import Named from '../components/Named.html'; +import Inline from '../components/Inline.html'; +--- + +Default + + A + B + C + + diff --git a/packages/astro/test/fixtures/import-ts-with-js/astro.config.mjs b/packages/astro/test/fixtures/import-ts-with-js/astro.config.mjs new file mode 100644 index 000000000..410c20408 --- /dev/null +++ b/packages/astro/test/fixtures/import-ts-with-js/astro.config.mjs @@ -0,0 +1,9 @@ +import { defineConfig } from 'astro/config'; + +// https://astro.build/config +export default defineConfig({ + legacy: { + astroFlavoredMarkdown: true, + }, + integrations: [] +}); diff --git a/packages/astro/test/fixtures/import-ts-with-js/package.json b/packages/astro/test/fixtures/import-ts-with-js/package.json new file mode 100644 index 000000000..53405e943 --- /dev/null +++ b/packages/astro/test/fixtures/import-ts-with-js/package.json @@ -0,0 +1,8 @@ +{ + "name": "@test/import-ts-with-js", + "version": "0.0.0", + "private": true, + "dependencies": { + "astro": "workspace:*" + } +} diff --git a/packages/astro/test/fixtures/integration-add-page-extension/astro.config.mjs b/packages/astro/test/fixtures/integration-add-page-extension/astro.config.mjs new file mode 100644 index 000000000..0a0a33697 --- /dev/null +++ b/packages/astro/test/fixtures/integration-add-page-extension/astro.config.mjs @@ -0,0 +1,6 @@ +import { defineConfig } from 'rollup' +import test from './integration.js' + +export default defineConfig({ + integrations: [test()] +}) diff --git a/packages/astro/test/fixtures/integration-add-page-extension/integration.js b/packages/astro/test/fixtures/integration-add-page-extension/integration.js new file mode 100644 index 000000000..8050a061d --- /dev/null +++ b/packages/astro/test/fixtures/integration-add-page-extension/integration.js @@ -0,0 +1,10 @@ +export default function() { + return { + name: '@astrojs/test-integration', + hooks: { + 'astro:config:setup': ({ addPageExtension }) => { + addPageExtension('.mjs') + } + } + } +} diff --git a/packages/astro/test/fixtures/integration-add-page-extension/package.json b/packages/astro/test/fixtures/integration-add-page-extension/package.json new file mode 100644 index 000000000..cae9492df --- /dev/null +++ b/packages/astro/test/fixtures/integration-add-page-extension/package.json @@ -0,0 +1,9 @@ +{ + "name": "@test/integration-add-page-extension", + "type": "module", + "version": "0.0.0", + "private": true, + "dependencies": { + "astro": "workspace:*" + } +} diff --git a/packages/astro/test/fixtures/integration-add-page-extension/src/components/test.astro b/packages/astro/test/fixtures/integration-add-page-extension/src/components/test.astro new file mode 100644 index 000000000..597ecf5fc --- /dev/null +++ b/packages/astro/test/fixtures/integration-add-page-extension/src/components/test.astro @@ -0,0 +1 @@ +

      Hello world!

      diff --git a/packages/astro/test/fixtures/integration-add-page-extension/src/pages/test.mjs b/packages/astro/test/fixtures/integration-add-page-extension/src/pages/test.mjs new file mode 100644 index 000000000..b6bed7c56 --- /dev/null +++ b/packages/astro/test/fixtures/integration-add-page-extension/src/pages/test.mjs @@ -0,0 +1,3 @@ +// Convulted test case, rexport astro file from new `.mjs` page +import Test from '../components/test.astro'; +export default Test; diff --git a/packages/astro/test/fixtures/jsx/astro.config.mjs b/packages/astro/test/fixtures/jsx/astro.config.mjs new file mode 100644 index 000000000..5b84d23a8 --- /dev/null +++ b/packages/astro/test/fixtures/jsx/astro.config.mjs @@ -0,0 +1,25 @@ +import { defineConfig } from 'astro/config'; +import renderer from 'astro/jsx/renderer.js'; +import preact from '@astrojs/preact'; +import react from '@astrojs/react'; +import svelte from '@astrojs/svelte'; +import vue from '@astrojs/vue'; +import solid from '@astrojs/solid-js'; + +export default defineConfig({ + integrations: [ + { + name: '@astrojs/test-jsx', + hooks: { + 'astro:config:setup': ({ addRenderer }) => { + addRenderer(renderer); + } + } + }, + preact(), + react(), + svelte(), + vue(), + solid(), + ] +}) diff --git a/packages/astro/test/fixtures/jsx/package.json b/packages/astro/test/fixtures/jsx/package.json new file mode 100644 index 000000000..eb2c75d69 --- /dev/null +++ b/packages/astro/test/fixtures/jsx/package.json @@ -0,0 +1,21 @@ +{ + "name": "@test/jsx", + "version": "0.0.0", + "private": true, + "devDependencies": { + "@astrojs/preact": "workspace:*", + "@astrojs/react": "workspace:*", + "@astrojs/solid-js": "workspace:*", + "@astrojs/svelte": "workspace:*", + "@astrojs/vue": "workspace:*", + "astro": "workspace:*" + }, + "dependencies": { + "preact": "^10.7.3", + "react": "^18.1.0", + "react-dom": "^18.1.0", + "solid-js": "^1.4.3", + "svelte": "^3.48.0", + "vue": "^3.2.36" + } +} diff --git a/packages/astro/test/fixtures/jsx/src/components/Frameworks.jsx b/packages/astro/test/fixtures/jsx/src/components/Frameworks.jsx new file mode 100644 index 000000000..2cc175964 --- /dev/null +++ b/packages/astro/test/fixtures/jsx/src/components/Frameworks.jsx @@ -0,0 +1,28 @@ +import 'astro/jsx-runtime'; +import { Test } from "./Test"; + +import PreactCounter from "./PreactCounter"; +import ReactCounter from "./ReactCounter"; +import SolidCounter from "./SolidCounter"; +import SvelteCounter from "./SvelteCounter.svelte"; +import VueCounter from "./VueCounter.vue"; + +export function Preact() { + return +} + +export function React() { + return +} + +export function Solid() { + return +} + +export function Svelte() { + return +} + +export function Vue() { + return +} diff --git a/packages/astro/test/fixtures/jsx/src/components/PreactCounter.tsx b/packages/astro/test/fixtures/jsx/src/components/PreactCounter.tsx new file mode 100644 index 000000000..cdb368377 --- /dev/null +++ b/packages/astro/test/fixtures/jsx/src/components/PreactCounter.tsx @@ -0,0 +1,20 @@ +import { h, Fragment } from 'preact'; +import { useState } from 'preact/hooks'; + +/** a counter written in Preact */ +export default function PreactCounter() { + const [count, setCount] = useState(0); + const add = () => setCount((i) => i + 1); + const subtract = () => setCount((i) => i - 1); + + return ( +
      +
      + +
      {count}
      + +
      +
      Preact
      +
      + ); +} diff --git a/packages/astro/test/fixtures/jsx/src/components/ReactCounter.jsx b/packages/astro/test/fixtures/jsx/src/components/ReactCounter.jsx new file mode 100644 index 000000000..5c5a001e8 --- /dev/null +++ b/packages/astro/test/fixtures/jsx/src/components/ReactCounter.jsx @@ -0,0 +1,19 @@ +import React, { useState } from 'react'; + +/** a counter written in React */ +export default function ReactCounter() { + const [count, setCount] = useState(0); + const add = () => setCount((i) => i + 1); + const subtract = () => setCount((i) => i - 1); + + return ( +
      +
      + +
      {count}
      + +
      +
      React
      +
      + ); +} diff --git a/packages/astro/test/fixtures/jsx/src/components/SolidCounter.jsx b/packages/astro/test/fixtures/jsx/src/components/SolidCounter.jsx new file mode 100644 index 000000000..9cfd85d02 --- /dev/null +++ b/packages/astro/test/fixtures/jsx/src/components/SolidCounter.jsx @@ -0,0 +1,19 @@ +import { createSignal } from 'solid-js'; + +/** a counter written with Solid */ +export default function SolidCounter() { + const [count, setCount] = createSignal(0); + const add = () => setCount(count() + 1); + const subtract = () => setCount(count() - 1); + + return ( +
      +
      + +
      {count()}
      + +
      +
      Solid
      +
      + ); +} diff --git a/packages/astro/test/fixtures/jsx/src/components/SvelteCounter.svelte b/packages/astro/test/fixtures/jsx/src/components/SvelteCounter.svelte new file mode 100644 index 000000000..3d6f1b2bd --- /dev/null +++ b/packages/astro/test/fixtures/jsx/src/components/SvelteCounter.svelte @@ -0,0 +1,21 @@ + + + +
      +
      + +
      {count}
      + +
      +
      Svelte
      +
      diff --git a/packages/astro/test/fixtures/jsx/src/components/Test.jsx b/packages/astro/test/fixtures/jsx/src/components/Test.jsx new file mode 100644 index 000000000..007c8f617 --- /dev/null +++ b/packages/astro/test/fixtures/jsx/src/components/Test.jsx @@ -0,0 +1,5 @@ +import 'astro'; + +export function Test({ case: id, ...slots }) { + return
      {Object.values(slots)}
      +} diff --git a/examples/with-markdown/src/components/VueCounter.vue b/packages/astro/test/fixtures/jsx/src/components/VueCounter.vue similarity index 61% rename from examples/with-markdown/src/components/VueCounter.vue rename to packages/astro/test/fixtures/jsx/src/components/VueCounter.vue index 2f25066dc..f7492911e 100644 --- a/examples/with-markdown/src/components/VueCounter.vue +++ b/packages/astro/test/fixtures/jsx/src/components/VueCounter.vue @@ -1,11 +1,11 @@ diff --git a/packages/astro/test/fixtures/jsx/src/pages/component.astro b/packages/astro/test/fixtures/jsx/src/pages/component.astro new file mode 100644 index 000000000..7ee06da84 --- /dev/null +++ b/packages/astro/test/fixtures/jsx/src/pages/component.astro @@ -0,0 +1,6 @@ +--- +import { Test } from '../components/Test' +--- + +Basic +Named diff --git a/packages/astro/test/fixtures/jsx/src/pages/frameworks.astro b/packages/astro/test/fixtures/jsx/src/pages/frameworks.astro new file mode 100644 index 000000000..ede0f542c --- /dev/null +++ b/packages/astro/test/fixtures/jsx/src/pages/frameworks.astro @@ -0,0 +1,13 @@ +--- +import * as Framework from '../components/Frameworks' +--- + + + + + + + + + + diff --git a/packages/astro/test/fixtures/large-array/astro.config.mjs b/packages/astro/test/fixtures/large-array/astro.config.mjs new file mode 100644 index 000000000..a6c39b853 --- /dev/null +++ b/packages/astro/test/fixtures/large-array/astro.config.mjs @@ -0,0 +1,7 @@ +import { defineConfig } from 'astro/config'; +import solid from '@astrojs/solid-js'; + +// https://astro.build/config +export default defineConfig({ + integrations: [solid()], +}); diff --git a/packages/astro/test/fixtures/large-array/package.json b/packages/astro/test/fixtures/large-array/package.json new file mode 100644 index 000000000..c8e001365 --- /dev/null +++ b/packages/astro/test/fixtures/large-array/package.json @@ -0,0 +1,9 @@ +{ + "name": "@test/large-array-solid", + "version": "0.0.0", + "private": true, + "dependencies": { + "@astrojs/solid-js": "workspace:*", + "astro": "workspace:*" + } +} diff --git a/packages/astro/test/fixtures/large-array/src/components/Counter.jsx b/packages/astro/test/fixtures/large-array/src/components/Counter.jsx new file mode 100644 index 000000000..fb8706e03 --- /dev/null +++ b/packages/astro/test/fixtures/large-array/src/components/Counter.jsx @@ -0,0 +1,18 @@ +import { createSignal } from 'solid-js'; + +export default function Counter({ children, largeProp }) { + const [count, setCount] = createSignal(0); + const add = () => setCount(count() + 1); + const subtract = () => setCount(count() - 1); + + return ( + <> +
      + +
      {count()}
      + +
      +
      {children}
      + + ); +} diff --git a/packages/astro/test/fixtures/large-array/src/pages/index.astro b/packages/astro/test/fixtures/large-array/src/pages/index.astro new file mode 100644 index 000000000..1a77ebed6 --- /dev/null +++ b/packages/astro/test/fixtures/large-array/src/pages/index.astro @@ -0,0 +1,32 @@ +--- +import Counter from '../components/Counter.jsx'; +const largeArray = [] +for (let i = 0; i < 600; i++) { + largeArray.push({ a: 'abc', b: 'abc', c: 'abc', d: 'abc', e: 'abc', foo: 'bar' }) +} +--- + + + + + + + + + +
      + +

      Hello, Solid!

      +
      +
      + + diff --git a/packages/astro/test/fixtures/lit-element/src/components/my-element.js b/packages/astro/test/fixtures/lit-element/src/components/my-element.js index d3137c0ba..e946924cf 100644 --- a/packages/astro/test/fixtures/lit-element/src/components/my-element.js +++ b/packages/astro/test/fixtures/lit-element/src/components/my-element.js @@ -1,7 +1,5 @@ import { LitElement, html } from 'lit'; -export const tagName = 'my-element'; - export class MyElement extends LitElement { static properties = { bool: {type: Boolean}, @@ -31,6 +29,10 @@ export class MyElement extends LitElement {
      ${this.str}
      data: ${this.obj.data}
      ${typeofwindow}
      + + +
      +
      `; } } diff --git a/packages/astro/test/fixtures/lit-element/src/pages/index.astro b/packages/astro/test/fixtures/lit-element/src/pages/index.astro index 10b6624e4..408360157 100644 --- a/packages/astro/test/fixtures/lit-element/src/pages/index.astro +++ b/packages/astro/test/fixtures/lit-element/src/pages/index.astro @@ -1,5 +1,5 @@ --- -import '../components/my-element.js'; +import {MyElement} from '../components/my-element.js'; --- @@ -7,12 +7,12 @@ import '../components/my-element.js'; LitElements - - + diff --git a/packages/astro/test/fixtures/lit-element/src/pages/slots.astro b/packages/astro/test/fixtures/lit-element/src/pages/slots.astro new file mode 100644 index 000000000..b8fc4963c --- /dev/null +++ b/packages/astro/test/fixtures/lit-element/src/pages/slots.astro @@ -0,0 +1,15 @@ +--- +import {MyElement} from '../components/my-element.js'; +--- + + + + LitElement | Slot + + + +
      default
      +
      named
      +
      + + diff --git a/packages/astro/test/fixtures/page-level-styles/package.json b/packages/astro/test/fixtures/page-level-styles/package.json new file mode 100644 index 000000000..a5df4918d --- /dev/null +++ b/packages/astro/test/fixtures/page-level-styles/package.json @@ -0,0 +1,8 @@ +{ + "name": "@test/page-level-styles", + "version": "0.0.0", + "private": true, + "dependencies": { + "astro": "workspace:*" + } +} diff --git a/packages/astro/test/fixtures/postcss/package.json b/packages/astro/test/fixtures/postcss/package.json index ff4f0e14d..417914c12 100644 --- a/packages/astro/test/fixtures/postcss/package.json +++ b/packages/astro/test/fixtures/postcss/package.json @@ -9,5 +9,8 @@ "astro": "workspace:*", "autoprefixer": "^10.4.7", "postcss": "^8.4.14" + }, + "devDependencies": { + "postcss-preset-env": "^7.7.1" } } diff --git a/packages/astro/test/fixtures/postcss/postcss.config.cjs b/packages/astro/test/fixtures/postcss/postcss.config.cjs index 019f40040..7ed7dd7e2 100644 --- a/packages/astro/test/fixtures/postcss/postcss.config.cjs +++ b/packages/astro/test/fixtures/postcss/postcss.config.cjs @@ -1,7 +1,12 @@ +const postcssPresetEnv = require('postcss-preset-env') +const autoPrefixer = require('autoprefixer') + module.exports = { - plugins: { - autoprefixer: { + plugins: [ + // included to ensure public/ CSS resources are NOT transformed + autoPrefixer({ overrideBrowserslist: ['> 0.1%', 'IE 11'] // enforce `appearance: none;` is prefixed with -webkit and -moz - } - } -}; + }), + postcssPresetEnv({ features: { 'nesting-rules': true } }), + ] +} diff --git a/packages/astro/test/fixtures/postcss/src/components/Astro.astro b/packages/astro/test/fixtures/postcss/src/components/Astro.astro index c85cd0415..5563e4778 100644 --- a/packages/astro/test/fixtures/postcss/src/components/Astro.astro +++ b/packages/astro/test/fixtures/postcss/src/components/Astro.astro @@ -1,9 +1,11 @@ -
      - Astro +
      + Astro
      diff --git a/packages/astro/test/fixtures/postcss/src/components/Solid.css b/packages/astro/test/fixtures/postcss/src/components/Solid.css index 9c4272b56..6d06e4d89 100644 --- a/packages/astro/test/fixtures/postcss/src/components/Solid.css +++ b/packages/astro/test/fixtures/postcss/src/components/Solid.css @@ -1,3 +1,5 @@ .solid { - appearance: none; + &.nested { + color: red; + } } diff --git a/packages/astro/test/fixtures/postcss/src/components/Solid.jsx b/packages/astro/test/fixtures/postcss/src/components/Solid.jsx index 9f172eb3b..63ee46a52 100644 --- a/packages/astro/test/fixtures/postcss/src/components/Solid.jsx +++ b/packages/astro/test/fixtures/postcss/src/components/Solid.jsx @@ -3,8 +3,8 @@ import './Solid.css'; export default function Counter() { return ( -
      - Solid +
      + Solid
      ); } diff --git a/packages/astro/test/fixtures/postcss/src/components/Svelte.svelte b/packages/astro/test/fixtures/postcss/src/components/Svelte.svelte index 0b55ab627..031146443 100644 --- a/packages/astro/test/fixtures/postcss/src/components/Svelte.svelte +++ b/packages/astro/test/fixtures/postcss/src/components/Svelte.svelte @@ -1,9 +1,11 @@ -
      - Svelte +
      + Svelte
      diff --git a/packages/astro/test/fixtures/postcss/src/components/Vue.vue b/packages/astro/test/fixtures/postcss/src/components/Vue.vue index 20b928e08..103eda0aa 100644 --- a/packages/astro/test/fixtures/postcss/src/components/Vue.vue +++ b/packages/astro/test/fixtures/postcss/src/components/Vue.vue @@ -1,12 +1,14 @@ diff --git a/packages/astro/test/fixtures/postcss/src/pages/index.astro b/packages/astro/test/fixtures/postcss/src/pages/index.astro index 2f73d045b..c239cff64 100644 --- a/packages/astro/test/fixtures/postcss/src/pages/index.astro +++ b/packages/astro/test/fixtures/postcss/src/pages/index.astro @@ -12,13 +12,15 @@ import Vue from '../components/Vue.vue'; -
      +
      diff --git a/packages/astro/test/fixtures/public-base-404/package.json b/packages/astro/test/fixtures/public-base-404/package.json new file mode 100644 index 000000000..d8fe64b7c --- /dev/null +++ b/packages/astro/test/fixtures/public-base-404/package.json @@ -0,0 +1,8 @@ +{ + "name": "@test/public-base-404", + "version": "0.0.0", + "private": true, + "dependencies": { + "astro": "workspace:*" + } +} diff --git a/packages/astro/test/fixtures/public-base-404/public/twitter.png b/packages/astro/test/fixtures/public-base-404/public/twitter.png new file mode 100644 index 000000000..ad4cae1e9 Binary files /dev/null and b/packages/astro/test/fixtures/public-base-404/public/twitter.png differ diff --git a/packages/astro/test/fixtures/public-base-404/src/pages/404.astro b/packages/astro/test/fixtures/public-base-404/src/pages/404.astro new file mode 100644 index 000000000..d5dfb7c74 --- /dev/null +++ b/packages/astro/test/fixtures/public-base-404/src/pages/404.astro @@ -0,0 +1,8 @@ + + + Not Found + + +

      404

      + + diff --git a/packages/astro/test/fixtures/public-base-404/src/pages/index.astro b/packages/astro/test/fixtures/public-base-404/src/pages/index.astro new file mode 100644 index 000000000..810c3b673 --- /dev/null +++ b/packages/astro/test/fixtures/public-base-404/src/pages/index.astro @@ -0,0 +1,8 @@ + + + This Site + + + + + diff --git a/packages/astro/test/fixtures/react-component/package.json b/packages/astro/test/fixtures/react-component/package.json index 73a159f61..dc9b2fd6f 100644 --- a/packages/astro/test/fixtures/react-component/package.json +++ b/packages/astro/test/fixtures/react-component/package.json @@ -8,6 +8,6 @@ "astro": "workspace:*", "react": "^18.1.0", "react-dom": "^18.1.0", - "vue": "^3.2.36" + "vue": "^3.2.37" } } diff --git a/packages/astro/test/fixtures/reexport-astro-containing-client-component/astro.config.mjs b/packages/astro/test/fixtures/reexport-astro-containing-client-component/astro.config.mjs new file mode 100644 index 000000000..c9662ed09 --- /dev/null +++ b/packages/astro/test/fixtures/reexport-astro-containing-client-component/astro.config.mjs @@ -0,0 +1,5 @@ +import preact from '@astrojs/preact'; + +export default { + integrations: [preact()] +}; diff --git a/packages/astro/test/fixtures/reexport-astro-containing-client-component/package.json b/packages/astro/test/fixtures/reexport-astro-containing-client-component/package.json new file mode 100644 index 000000000..13a0cd46c --- /dev/null +++ b/packages/astro/test/fixtures/reexport-astro-containing-client-component/package.json @@ -0,0 +1,7 @@ +{ + "name": "@test/reexport-astro-containing-client-component", + "dependencies": { + "astro": "workspace:", + "@astrojs/preact": "workspace:" + } +} diff --git a/packages/astro/test/fixtures/reexport-astro-containing-client-component/src/components/One/One.astro b/packages/astro/test/fixtures/reexport-astro-containing-client-component/src/components/One/One.astro new file mode 100644 index 000000000..3e86bf020 --- /dev/null +++ b/packages/astro/test/fixtures/reexport-astro-containing-client-component/src/components/One/One.astro @@ -0,0 +1,4 @@ +--- +import {One} from './One.jsx'; +--- + diff --git a/packages/astro/test/fixtures/reexport-astro-containing-client-component/src/components/One/One.jsx b/packages/astro/test/fixtures/reexport-astro-containing-client-component/src/components/One/One.jsx new file mode 100644 index 000000000..cb23a337e --- /dev/null +++ b/packages/astro/test/fixtures/reexport-astro-containing-client-component/src/components/One/One.jsx @@ -0,0 +1,6 @@ + +export function One() { + return ( +
      testing
      + ); +} diff --git a/packages/astro/test/fixtures/reexport-astro-containing-client-component/src/components/One/index.js b/packages/astro/test/fixtures/reexport-astro-containing-client-component/src/components/One/index.js new file mode 100644 index 000000000..a239385d7 --- /dev/null +++ b/packages/astro/test/fixtures/reexport-astro-containing-client-component/src/components/One/index.js @@ -0,0 +1 @@ +export { default as One } from './One.astro'; diff --git a/packages/astro/test/fixtures/reexport-astro-containing-client-component/src/pages/index.astro b/packages/astro/test/fixtures/reexport-astro-containing-client-component/src/pages/index.astro new file mode 100644 index 000000000..5ed54c3b8 --- /dev/null +++ b/packages/astro/test/fixtures/reexport-astro-containing-client-component/src/pages/index.astro @@ -0,0 +1,9 @@ +--- +import { One as OneWrapper } from '../components/One'; +--- + +Testing + + + + diff --git a/packages/astro/test/fixtures/slots-preact/astro.config.mjs b/packages/astro/test/fixtures/slots-preact/astro.config.mjs index cd324a40f..01ce725cc 100644 --- a/packages/astro/test/fixtures/slots-preact/astro.config.mjs +++ b/packages/astro/test/fixtures/slots-preact/astro.config.mjs @@ -1,7 +1,11 @@ import { defineConfig } from 'astro/config'; +import mdx from '@astrojs/mdx'; import preact from '@astrojs/preact'; // https://astro.build/config export default defineConfig({ - integrations: [preact()], -}); \ No newline at end of file + legacy: { + astroFlavoredMarkdown: true, + }, + integrations: [preact(), mdx()], +}); diff --git a/packages/astro/test/fixtures/slots-preact/package.json b/packages/astro/test/fixtures/slots-preact/package.json index 95f33ee50..240071578 100644 --- a/packages/astro/test/fixtures/slots-preact/package.json +++ b/packages/astro/test/fixtures/slots-preact/package.json @@ -3,6 +3,7 @@ "version": "0.0.0", "private": true, "dependencies": { + "@astrojs/mdx": "workspace:*", "@astrojs/preact": "workspace:*", "astro": "workspace:*" } diff --git a/packages/astro/test/fixtures/slots-preact/src/components/Counter.jsx b/packages/astro/test/fixtures/slots-preact/src/components/Counter.jsx index cc11b9ee3..16d2a95b9 100644 --- a/packages/astro/test/fixtures/slots-preact/src/components/Counter.jsx +++ b/packages/astro/test/fixtures/slots-preact/src/components/Counter.jsx @@ -1,7 +1,7 @@ import { h, Fragment } from 'preact'; import { useState } from 'preact/hooks' -export default function Counter({ children, count: initialCount, case: id }) { +export default function Counter({ named, dashCase, children, count: initialCount, case: id }) { const [count, setCount] = useState(initialCount); const add = () => setCount((i) => i + 1); const subtract = () => setCount((i) => i - 1); @@ -15,6 +15,8 @@ export default function Counter({ children, count: initialCount, case: id }) {
      {children ||

      Fallback

      } + {named} + {dashCase}
      ); diff --git a/packages/astro/test/fixtures/slots-preact/src/pages/index.astro b/packages/astro/test/fixtures/slots-preact/src/pages/index.astro index f8f101e73..b2b039566 100644 --- a/packages/astro/test/fixtures/slots-preact/src/pages/index.astro +++ b/packages/astro/test/fixtures/slots-preact/src/pages/index.astro @@ -8,4 +8,6 @@ import Counter from '../components/Counter.jsx' {false} {''}

      Hello world!

      +

      / Named

      +

      / Dash Case

      diff --git a/packages/astro/test/fixtures/slots-preact/src/pages/markdown.md b/packages/astro/test/fixtures/slots-preact/src/pages/markdown.md new file mode 100644 index 000000000..f86720fea --- /dev/null +++ b/packages/astro/test/fixtures/slots-preact/src/pages/markdown.md @@ -0,0 +1,9 @@ +--- +setup: import Counter from '../components/Counter.jsx' +--- + +# Slots: Preact + +

      Hello world!

      +

      / Named

      +

      / Dash Case

      diff --git a/packages/astro/test/fixtures/slots-preact/src/pages/mdx.mdx b/packages/astro/test/fixtures/slots-preact/src/pages/mdx.mdx new file mode 100644 index 000000000..6b7bcea55 --- /dev/null +++ b/packages/astro/test/fixtures/slots-preact/src/pages/mdx.mdx @@ -0,0 +1,7 @@ +import Counter from '../components/Counter.jsx' + +# Slots: Preact + +

      Hello world!

      +

      / Named

      +

      / Dash Case

      diff --git a/packages/astro/test/fixtures/slots-react/astro.config.mjs b/packages/astro/test/fixtures/slots-react/astro.config.mjs index f03a45258..20fa1428e 100644 --- a/packages/astro/test/fixtures/slots-react/astro.config.mjs +++ b/packages/astro/test/fixtures/slots-react/astro.config.mjs @@ -1,7 +1,11 @@ import { defineConfig } from 'astro/config'; +import mdx from '@astrojs/mdx'; import react from '@astrojs/react'; // https://astro.build/config export default defineConfig({ - integrations: [react()], -}); \ No newline at end of file + legacy: { + astroFlavoredMarkdown: true, + }, + integrations: [react(), mdx()], +}); diff --git a/packages/astro/test/fixtures/slots-react/package.json b/packages/astro/test/fixtures/slots-react/package.json index 2cba4ab09..bea72fe3d 100644 --- a/packages/astro/test/fixtures/slots-react/package.json +++ b/packages/astro/test/fixtures/slots-react/package.json @@ -3,7 +3,10 @@ "version": "0.0.0", "private": true, "dependencies": { + "@astrojs/mdx": "workspace:*", "@astrojs/react": "workspace:*", - "astro": "workspace:*" + "astro": "workspace:*", + "react": "^18.1.0", + "react-dom": "^18.1.0" } } diff --git a/packages/astro/test/fixtures/slots-react/src/components/Counter.jsx b/packages/astro/test/fixtures/slots-react/src/components/Counter.jsx index 93f267ca4..733cc47cc 100644 --- a/packages/astro/test/fixtures/slots-react/src/components/Counter.jsx +++ b/packages/astro/test/fixtures/slots-react/src/components/Counter.jsx @@ -1,6 +1,6 @@ import React, { useState } from 'react'; -export default function Counter({ children, count: initialCount, case: id }) { +export default function Counter({ named, dashCase, children, count: initialCount, case: id }) { const [count, setCount] = useState(initialCount); const add = () => setCount((i) => i + 1); const subtract = () => setCount((i) => i - 1); @@ -14,6 +14,8 @@ export default function Counter({ children, count: initialCount, case: id }) {
      {children ||

      Fallback

      } + {named} + {dashCase}
      ); diff --git a/packages/astro/test/fixtures/slots-react/src/pages/index.astro b/packages/astro/test/fixtures/slots-react/src/pages/index.astro index f8f101e73..b2b039566 100644 --- a/packages/astro/test/fixtures/slots-react/src/pages/index.astro +++ b/packages/astro/test/fixtures/slots-react/src/pages/index.astro @@ -8,4 +8,6 @@ import Counter from '../components/Counter.jsx' {false} {''}

      Hello world!

      +

      / Named

      +

      / Dash Case

      diff --git a/packages/astro/test/fixtures/slots-react/src/pages/markdown.md b/packages/astro/test/fixtures/slots-react/src/pages/markdown.md new file mode 100644 index 000000000..308450506 --- /dev/null +++ b/packages/astro/test/fixtures/slots-react/src/pages/markdown.md @@ -0,0 +1,9 @@ +--- +setup: import Counter from '../components/Counter.jsx' +--- + +# Slots: React + +

      Hello world!

      +

      / Named

      +

      / Dash Case

      diff --git a/packages/astro/test/fixtures/slots-react/src/pages/mdx.mdx b/packages/astro/test/fixtures/slots-react/src/pages/mdx.mdx new file mode 100644 index 000000000..f50196171 --- /dev/null +++ b/packages/astro/test/fixtures/slots-react/src/pages/mdx.mdx @@ -0,0 +1,7 @@ +import Counter from '../components/Counter.jsx' + +# Slots: React + +

      Hello world!

      +

      / Named

      +

      / Dash Case

      diff --git a/packages/astro/test/fixtures/slots-solid/astro.config.mjs b/packages/astro/test/fixtures/slots-solid/astro.config.mjs index 6bc082cce..35d38c8f1 100644 --- a/packages/astro/test/fixtures/slots-solid/astro.config.mjs +++ b/packages/astro/test/fixtures/slots-solid/astro.config.mjs @@ -1,7 +1,11 @@ import { defineConfig } from 'astro/config'; +import mdx from '@astrojs/mdx'; import solid from '@astrojs/solid-js'; // https://astro.build/config export default defineConfig({ - integrations: [solid()], -}); \ No newline at end of file + legacy: { + astroFlavoredMarkdown: true, + }, + integrations: [solid(), mdx()], +}); diff --git a/packages/astro/test/fixtures/slots-solid/package.json b/packages/astro/test/fixtures/slots-solid/package.json index e378bd772..be9555ace 100644 --- a/packages/astro/test/fixtures/slots-solid/package.json +++ b/packages/astro/test/fixtures/slots-solid/package.json @@ -3,6 +3,7 @@ "version": "0.0.0", "private": true, "dependencies": { + "@astrojs/mdx": "workspace:*", "@astrojs/solid-js": "workspace:*", "astro": "workspace:*" } diff --git a/packages/astro/test/fixtures/slots-solid/src/components/Counter.jsx b/packages/astro/test/fixtures/slots-solid/src/components/Counter.jsx index 6a585b8e3..4b9c63c66 100644 --- a/packages/astro/test/fixtures/slots-solid/src/components/Counter.jsx +++ b/packages/astro/test/fixtures/slots-solid/src/components/Counter.jsx @@ -1,6 +1,6 @@ import { createSignal } from 'solid-js'; -export default function Counter({ children, count: initialCount, case: id }) { +export default function Counter({ named, dashCase, children, count: initialCount, case: id }) { const [count] = createSignal(0); return ( <> @@ -9,6 +9,8 @@ export default function Counter({ children, count: initialCount, case: id }) {
      {children ||

      Fallback

      } + {named} + {dashCase}
      ); diff --git a/packages/astro/test/fixtures/slots-solid/src/pages/index.astro b/packages/astro/test/fixtures/slots-solid/src/pages/index.astro index f8f101e73..b2b039566 100644 --- a/packages/astro/test/fixtures/slots-solid/src/pages/index.astro +++ b/packages/astro/test/fixtures/slots-solid/src/pages/index.astro @@ -8,4 +8,6 @@ import Counter from '../components/Counter.jsx' {false} {''}

      Hello world!

      +

      / Named

      +

      / Dash Case

      diff --git a/packages/astro/test/fixtures/slots-solid/src/pages/markdown.md b/packages/astro/test/fixtures/slots-solid/src/pages/markdown.md new file mode 100644 index 000000000..d9bc2dabd --- /dev/null +++ b/packages/astro/test/fixtures/slots-solid/src/pages/markdown.md @@ -0,0 +1,9 @@ +--- +setup: import Counter from '../components/Counter.jsx' +--- + +# Slots: Solid + +

      Hello world!

      +

      / Named

      +

      / Dash Case

      diff --git a/packages/astro/test/fixtures/slots-solid/src/pages/mdx.mdx b/packages/astro/test/fixtures/slots-solid/src/pages/mdx.mdx new file mode 100644 index 000000000..679f42ab9 --- /dev/null +++ b/packages/astro/test/fixtures/slots-solid/src/pages/mdx.mdx @@ -0,0 +1,7 @@ +import Counter from '../components/Counter.jsx' + +# Slots: Solid + +

      Hello world!

      +

      / Named

      +

      / Dash Case

      diff --git a/packages/astro/test/fixtures/slots-svelte/astro.config.mjs b/packages/astro/test/fixtures/slots-svelte/astro.config.mjs index dbf6d6b8f..afd7dd326 100644 --- a/packages/astro/test/fixtures/slots-svelte/astro.config.mjs +++ b/packages/astro/test/fixtures/slots-svelte/astro.config.mjs @@ -1,7 +1,11 @@ import { defineConfig } from 'astro/config'; +import mdx from '@astrojs/mdx'; import svelte from '@astrojs/svelte'; // https://astro.build/config export default defineConfig({ - integrations: [svelte()], -}); \ No newline at end of file + legacy: { + astroFlavoredMarkdown: true, + }, + integrations: [svelte(), mdx()], +}); diff --git a/packages/astro/test/fixtures/slots-svelte/package.json b/packages/astro/test/fixtures/slots-svelte/package.json index 53af8ea93..95dbd239d 100644 --- a/packages/astro/test/fixtures/slots-svelte/package.json +++ b/packages/astro/test/fixtures/slots-svelte/package.json @@ -3,6 +3,7 @@ "version": "0.0.0", "private": true, "dependencies": { + "@astrojs/mdx": "workspace:*", "@astrojs/svelte": "workspace:*", "astro": "workspace:*" } diff --git a/packages/astro/test/fixtures/slots-svelte/src/components/Counter.svelte b/packages/astro/test/fixtures/slots-svelte/src/components/Counter.svelte index 11901049e..24f4e734e 100644 --- a/packages/astro/test/fixtures/slots-svelte/src/components/Counter.svelte +++ b/packages/astro/test/fixtures/slots-svelte/src/components/Counter.svelte @@ -17,9 +17,7 @@
      - -

      Fallback

      -
      +

      Fallback

      +`; + } + }, + }; +} diff --git a/packages/astro/test/hmr-css.test.js b/packages/astro/test/hmr-css.test.js deleted file mode 100644 index f8f741904..000000000 --- a/packages/astro/test/hmr-css.test.js +++ /dev/null @@ -1,31 +0,0 @@ -import { isWindows, loadFixture } from './test-utils.js'; -import { expect } from 'chai'; -import * as cheerio from 'cheerio'; - -describe('HMR - CSS', () => { - if (isWindows) return; - - /** @type {import('./test-utils').Fixture} */ - let fixture; - /** @type {import('./test-utils').DevServer} */ - let devServer; - - before(async () => { - fixture = await loadFixture({ - root: './fixtures/hmr-css/', - }); - devServer = await fixture.startDevServer(); - }); - - after(async () => { - await devServer.stop(); - }); - - it('Timestamp URL used by Vite gets the right mime type', async () => { - let res = await fixture.fetch( - '/src/pages/index.astro?astro=&type=style&index=0&lang.css=&t=1653657441095' - ); - let headers = res.headers; - expect(headers.get('content-type')).to.equal('text/css'); - }); -}); diff --git a/packages/astro/test/html-component.test.js b/packages/astro/test/html-component.test.js new file mode 100644 index 000000000..0145a22aa --- /dev/null +++ b/packages/astro/test/html-component.test.js @@ -0,0 +1,57 @@ +import { expect } from 'chai'; +import * as cheerio from 'cheerio'; +import { loadFixture } from './test-utils.js'; + +describe('HTML Component', () => { + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/html-component/', + }); + }); + + describe('build', () => { + before(async () => { + await fixture.build(); + }); + + it('works', async () => { + const html = await fixture.readFile('/index.html'); + const $ = cheerio.load(html); + + const h1 = $('h1'); + const foo = $('#foo'); + + expect(h1.text()).to.equal('Hello component!'); + expect(foo.text()).to.equal('bar'); + }); + }); + + describe('dev', () => { + let devServer; + + before(async () => { + devServer = await fixture.startDevServer(); + }); + + after(async () => { + await devServer.stop(); + }); + + it('works', async () => { + const res = await fixture.fetch('/'); + + expect(res.status).to.equal(200); + + const html = await res.text(); + const $ = cheerio.load(html); + + const h1 = $('h1'); + const foo = $('#foo'); + + expect(h1.text()).to.equal('Hello component!'); + expect(foo.text()).to.equal('bar'); + }); + }); +}); diff --git a/packages/astro/test/html-escape.test.js b/packages/astro/test/html-escape.test.js new file mode 100644 index 000000000..047a56670 --- /dev/null +++ b/packages/astro/test/html-escape.test.js @@ -0,0 +1,69 @@ +import { expect } from 'chai'; +import * as cheerio from 'cheerio'; +import { loadFixture } from './test-utils.js'; + +describe('HTML Escape', () => { + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/html-escape/', + }); + }); + + describe('build', () => { + before(async () => { + await fixture.build(); + }); + + it('works', async () => { + const html = await fixture.readFile('/index.html'); + const $ = cheerio.load(html); + + const div = $('div'); + expect(div.text()).to.equal('${foo}'); + + const span = $('span'); + expect(span.attr('${attr}')).to.equal(''); + + const ce = $('custom-element'); + expect(ce.attr('x-data')).to.equal('`${test}`'); + + const script = $('script'); + expect(script.text()).to.equal('console.log(`hello ${"world"}!`)'); + }); + }); + + describe('dev', () => { + let devServer; + + before(async () => { + devServer = await fixture.startDevServer(); + }); + + after(async () => { + await devServer.stop(); + }); + + it('works', async () => { + const res = await fixture.fetch('/'); + + expect(res.status).to.equal(200); + + const html = await res.text(); + const $ = cheerio.load(html); + + const div = $('div'); + expect(div.text()).to.equal('${foo}'); + + const span = $('span'); + expect(span.attr('${attr}')).to.equal(''); + + const ce = $('custom-element'); + expect(ce.attr('x-data')).to.equal('`${test}`'); + + const script = $('script'); + expect(script.text()).to.equal('console.log(`hello ${"world"}!`)'); + }); + }); +}); diff --git a/packages/astro/test/html-page.test.js b/packages/astro/test/html-page.test.js new file mode 100644 index 000000000..8fc45a384 --- /dev/null +++ b/packages/astro/test/html-page.test.js @@ -0,0 +1,53 @@ +import { expect } from 'chai'; +import * as cheerio from 'cheerio'; +import { loadFixture } from './test-utils.js'; + +describe('HTML Page', () => { + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/html-page/', + }); + }); + + describe('build', () => { + before(async () => { + await fixture.build(); + }); + + it('works', async () => { + const html = await fixture.readFile('/index.html'); + const $ = cheerio.load(html); + + const h1 = $('h1'); + + expect(h1.text()).to.equal('Hello page!'); + }); + }); + + describe('dev', () => { + let devServer; + + before(async () => { + devServer = await fixture.startDevServer(); + }); + + after(async () => { + await devServer.stop(); + }); + + it('works', async () => { + const res = await fixture.fetch('/'); + + expect(res.status).to.equal(200); + + const html = await res.text(); + const $ = cheerio.load(html); + + const h1 = $('h1'); + + expect(h1.text()).to.equal('Hello page!'); + }); + }); +}); diff --git a/packages/astro/test/html-slots.test.js b/packages/astro/test/html-slots.test.js new file mode 100644 index 000000000..af1a05a83 --- /dev/null +++ b/packages/astro/test/html-slots.test.js @@ -0,0 +1,75 @@ +import { expect } from 'chai'; +import * as cheerio from 'cheerio'; +import { loadFixture } from './test-utils.js'; + +describe('HTML Slots', () => { + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/html-slots/', + }); + }); + + describe('build', () => { + before(async () => { + await fixture.build(); + }); + + it('works', async () => { + const html = await fixture.readFile('/index.html'); + const $ = cheerio.load(html); + + const slotDefault = $('#default'); + expect(slotDefault.text()).to.equal('Default'); + + const a = $('#a'); + expect(a.text().trim()).to.equal('A'); + + const b = $('#b'); + expect(b.text().trim()).to.equal('B'); + + const c = $('#c'); + expect(c.text().trim()).to.equal('C'); + + const inline = $('#inline'); + expect(inline.html()).to.equal(''); + }); + }); + + describe('dev', () => { + let devServer; + + before(async () => { + devServer = await fixture.startDevServer(); + }); + + after(async () => { + await devServer.stop(); + }); + + it('works', async () => { + const res = await fixture.fetch('/'); + + expect(res.status).to.equal(200); + + const html = await res.text(); + const $ = cheerio.load(html); + + const slotDefault = $('#default'); + expect(slotDefault.text()).to.equal('Default'); + + const a = $('#a'); + expect(a.text().trim()).to.equal('A'); + + const b = $('#b'); + expect(b.text().trim()).to.equal('B'); + + const c = $('#c'); + expect(c.text().trim()).to.equal('C'); + + const inline = $('#inline'); + expect(inline.html()).to.equal(''); + }); + }); +}); diff --git a/packages/astro/test/integration-add-page-extension.test.js b/packages/astro/test/integration-add-page-extension.test.js new file mode 100644 index 000000000..28c11d4fc --- /dev/null +++ b/packages/astro/test/integration-add-page-extension.test.js @@ -0,0 +1,19 @@ +import { expect } from 'chai'; +import * as cheerio from 'cheerio'; +import { loadFixture } from './test-utils.js'; + +describe('Integration addPageExtension', () => { + /** @type {import('./test-utils').Fixture} */ + let fixture; + + before(async () => { + fixture = await loadFixture({ root: './fixtures/integration-add-page-extension/' }); + await fixture.build(); + }); + + it('supports .mjs files', async () => { + const html = await fixture.readFile('/test/index.html'); + const $ = cheerio.load(html); + expect($('h1').text()).to.equal('Hello world!'); + }); +}); diff --git a/packages/astro/test/jsx.test.js b/packages/astro/test/jsx.test.js new file mode 100644 index 000000000..41671699c --- /dev/null +++ b/packages/astro/test/jsx.test.js @@ -0,0 +1,62 @@ +import { expect } from 'chai'; +import * as cheerio from 'cheerio'; +import { loadFixture } from './test-utils.js'; + +describe('jsx-runtime', () => { + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/jsx/', + }); + await fixture.build(); + }); + + it('Can load simple JSX components', async () => { + const html = await fixture.readFile('/component/index.html'); + const $ = cheerio.load(html); + + expect($('#basic').text()).to.equal('Basic'); + expect($('#named').text()).to.equal('Named'); + }); + + it('Can load Preact component inside Astro JSX', async () => { + const html = await fixture.readFile('/frameworks/index.html'); + const $ = cheerio.load(html); + + expect($('#has-preact #preact').length).to.equal(1); + expect($('#preact').text()).to.include('Preact'); + }); + + it('Can load React component inside Astro JSX', async () => { + const html = await fixture.readFile('/frameworks/index.html'); + const $ = cheerio.load(html); + + expect($('#has-react #react').length).to.equal(1); + expect($('#react').text()).to.include('React'); + }); + + it('Can load Solid component inside Astro JSX', async () => { + const html = await fixture.readFile('/frameworks/index.html'); + const $ = cheerio.load(html); + + expect($('#has-solid #solid').length).to.equal(1); + expect($('#solid').text()).to.include('Solid'); + }); + + it('Can load Svelte component inside Astro JSX', async () => { + const html = await fixture.readFile('/frameworks/index.html'); + const $ = cheerio.load(html); + + expect($('#has-svelte #svelte').length).to.equal(1); + expect($('#svelte').text()).to.include('Svelte'); + }); + + it('Can load Vue component inside Astro JSX', async () => { + const html = await fixture.readFile('/frameworks/index.html'); + const $ = cheerio.load(html); + + expect($('#has-vue #vue').length).to.equal(1); + expect($('#vue').text()).to.include('Vue'); + }); +}); diff --git a/packages/astro/test/lit-element.test.js b/packages/astro/test/lit-element.test.js index 34237ae33..d314593a0 100644 --- a/packages/astro/test/lit-element.test.js +++ b/packages/astro/test/lit-element.test.js @@ -21,7 +21,7 @@ describe('LitElement test', function () { await fixture.build(); }); - it('Renders a custom element by tag name', async () => { + it('Renders a custom element by Constructor', async () => { // @lit-labs/ssr/ requires Node 13.9 or higher if (NODE_VERSION < 13.9) { return; @@ -62,15 +62,22 @@ describe('LitElement test', function () { expect($('my-element').attr('reflected-str-prop')).to.equal('initialized reflected'); }); - // Skipped because not supported by Lit - it.skip('Renders a custom element by the constructor', async () => { - const html = await fixture.fetch('/ctr/index.html'); + it('Correctly passes child slots', async () => { + // @lit-labs/ssr/ requires Node 13.9 or higher + if (NODE_VERSION < 13.9) { + return; + } + const html = await fixture.readFile('/slots/index.html'); const $ = cheerio.load(html); - // test 1: attributes rendered - expect($('my-element').attr('foo')).to.equal('bar'); + expect($('my-element').length).to.equal(1); - // test 2: shadow rendered - expect($('my-element').html()).to.include(`
      Testing...
      `); + const [defaultSlot, namedSlot] = $('template').siblings().toArray(); + + // has default slot content in lightdom + expect($(defaultSlot).text()).to.equal('default'); + + // has named slot content in lightdom + expect($(namedSlot).text()).to.equal('named'); }); }); diff --git a/packages/astro/test/postcss.test.js b/packages/astro/test/postcss.test.js index d5360ba1d..28de600da 100644 --- a/packages/astro/test/postcss.test.js +++ b/packages/astro/test/postcss.test.js @@ -3,12 +3,13 @@ import * as cheerio from 'cheerio'; import eol from 'eol'; import { loadFixture } from './test-utils.js'; -describe('PostCSS', () => { +describe('PostCSS', function () { const PREFIXED_CSS = `{-webkit-appearance:none;appearance:none`; let fixture; let bundledCSS; before(async () => { + this.timeout(45000); // test needs a little more time in CI fixture = await loadFixture({ root: './fixtures/postcss', }); @@ -23,24 +24,25 @@ describe('PostCSS', () => { .replace('/n', ''); }); + /** All test cases check whether nested styles (i.e. &.nested {}) are correctly transformed */ it('works in Astro page styles', () => { - expect(bundledCSS).to.match(new RegExp(`.astro-page.astro-[^{]+${PREFIXED_CSS}`)); + expect(bundledCSS).to.match(new RegExp(`\.astro-page(\.(\w|-)*)*\.nested`)); }); it('works in Astro component styles', () => { - expect(bundledCSS).to.match(new RegExp(`.astro-component.astro-[^{]+${PREFIXED_CSS}`)); + expect(bundledCSS).to.match(new RegExp(`\.astro-component(\.(\w|-)*)*\.nested`)); }); it('works in JSX', () => { - expect(bundledCSS).to.match(new RegExp(`.solid[^{]*${PREFIXED_CSS}`)); + expect(bundledCSS).to.match(new RegExp(`\.solid(\.(\w|-)*)*\.nested`)); }); it('works in Vue', () => { - expect(bundledCSS).to.match(new RegExp(`.vue[^{]*${PREFIXED_CSS}`)); + expect(bundledCSS).to.match(new RegExp(`\.vue(\.(\w|-)*)*\.nested`)); }); it('works in Svelte', () => { - expect(bundledCSS).to.match(new RegExp(`.svelte.s[^{]+${PREFIXED_CSS}`)); + expect(bundledCSS).to.match(new RegExp(`\.svelte(\.(\w|-)*)*\.nested`)); }); it('ignores CSS in public/', async () => { diff --git a/packages/astro/test/public-base-404.test.js b/packages/astro/test/public-base-404.test.js new file mode 100644 index 000000000..bf98967cb --- /dev/null +++ b/packages/astro/test/public-base-404.test.js @@ -0,0 +1,64 @@ +import { expect } from 'chai'; +import * as cheerio from 'cheerio'; +import { loadFixture } from './test-utils.js'; + +describe('Public dev with base', () => { + /** @type {import('./test-utils').Fixture} */ + let fixture; + /** @type {import('./test-utils').DevServer} */ + let devServer; + let $; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/public-base-404/', + site: 'http://example.com/', + base: '/blog', + }); + devServer = await fixture.startDevServer(); + }); + + it('200 when loading /@vite/client', async () => { + const response = await fixture.fetch('/@vite/client', { + redirect: 'manual', + }); + expect(response.status).to.equal(200); + const content = await response.text(); + expect(content).to.contain('vite'); + }); + + it('200 when loading /blog/twitter.png', async () => { + const response = await fixture.fetch('/blog/twitter.png', { + redirect: 'manual', + }); + expect(response.status).to.equal(200); + }); + + it('custom 404 page when loading /blog/blog/', async () => { + const response = await fixture.fetch('/blog/blog/'); + const html = await response.text(); + $ = cheerio.load(html); + expect($('h1').text()).to.equal('404'); + }); + + it('default 404 hint page when loading /', async () => { + const response = await fixture.fetch('/'); + expect(response.status).to.equal(404); + const html = await response.text(); + $ = cheerio.load(html); + expect($('a').first().text()).to.equal('/blog/'); + }); + + it('default 404 page when loading /none/', async () => { + const response = await fixture.fetch('/none/', { + headers: { + accept: 'text/html,*/*', + }, + }); + expect(response.status).to.equal(404); + const html = await response.text(); + $ = cheerio.load(html); + expect($('h1').text()).to.equal('404: Not found'); + expect($('pre').text()).to.equal('Path: /none/'); + }); +}); diff --git a/packages/astro/test/react-component.test.js b/packages/astro/test/react-component.test.js index 749fc0c16..68624aed6 100644 --- a/packages/astro/test/react-component.test.js +++ b/packages/astro/test/react-component.test.js @@ -42,10 +42,10 @@ describe('React Components', () => { expect($('#pure')).to.have.lengthOf(1); // test 8: Check number of islands - expect($('astro-root[uid]')).to.have.lengthOf(5); + expect($('astro-island[uid]')).to.have.lengthOf(5); // test 9: Check island deduplication - const uniqueRootUIDs = new Set($('astro-root').map((i, el) => $(el).attr('uid'))); + const uniqueRootUIDs = new Set($('astro-island').map((i, el) => $(el).attr('uid'))); expect(uniqueRootUIDs.size).to.equal(4); }); diff --git a/packages/astro/test/reexport-astro-containing-client-component.test.js b/packages/astro/test/reexport-astro-containing-client-component.test.js new file mode 100644 index 000000000..8b37e8180 --- /dev/null +++ b/packages/astro/test/reexport-astro-containing-client-component.test.js @@ -0,0 +1,19 @@ +import { expect } from 'chai'; +import * as cheerio from 'cheerio'; +import { loadFixture } from './test-utils.js'; + +describe('Re-exported astro components with client components', () => { + let fixture; + + before(async () => { + fixture = await loadFixture({ root: './fixtures/reexport-astro-containing-client-component/' }); + await fixture.build(); + }); + + it('Is able to build and renders and stuff', async () => { + const html = await fixture.readFile('/index.html'); + const $ = cheerio.load(html); + expect($('astro-island').length).to.equal(1); + expect($('astro-island').attr('component-export')).to.equal('One'); + }); +}); diff --git a/packages/astro/test/sass.test.js b/packages/astro/test/sass.test.js deleted file mode 100644 index 4072d5547..000000000 --- a/packages/astro/test/sass.test.js +++ /dev/null @@ -1,26 +0,0 @@ -import { expect } from 'chai'; -import os from 'os'; -import { loadFixture } from './test-utils.js'; - -// note: many Sass tests live in 0-css.test.js to test within context of a framework. -// these tests are independent of framework. -describe('Sass', () => { - let fixture; - let devServer; - - before(async () => { - fixture = await loadFixture({ root: './fixtures/sass/' }); - devServer = await fixture.startDevServer(); - }); - - after(async () => { - await devServer.stop(); - }); - - // TODO: Sass cannot be found on macOS for some reason... Vite issue? - const test = os.platform() === 'darwin' ? it.skip : it; - test('shows helpful error on failure', async () => { - const res = await fixture.fetch('/error').then((res) => res.text()); - expect(res).to.include('Undefined variable'); - }); -}); diff --git a/packages/astro/test/slots-preact.test.js b/packages/astro/test/slots-preact.test.js index c86a25fb7..b7330a182 100644 --- a/packages/astro/test/slots-preact.test.js +++ b/packages/astro/test/slots-preact.test.js @@ -21,4 +21,56 @@ describe('Slots: Preact', () => { expect($('#string').text().trim()).to.equal(''); expect($('#content').text().trim()).to.equal('Hello world!'); }); + + it('Renders named slot', async () => { + const html = await fixture.readFile('/index.html'); + const $ = cheerio.load(html); + expect($('#named').text().trim()).to.equal('Fallback / Named'); + }); + + it('Converts dash-case slot to camelCase', async () => { + const html = await fixture.readFile('/index.html'); + const $ = cheerio.load(html); + expect($('#dash-case').text().trim()).to.equal('Fallback / Dash Case'); + }); + + describe('For Markdown Pages', () => { + it('Renders default slot', async () => { + const html = await fixture.readFile('/markdown/index.html'); + const $ = cheerio.load(html); + expect($('#content').text().trim()).to.equal('Hello world!'); + }); + + it('Renders named slot', async () => { + const html = await fixture.readFile('/markdown/index.html'); + const $ = cheerio.load(html); + expect($('#named').text().trim()).to.equal('Fallback / Named'); + }); + + it('Converts dash-case slot to camelCase', async () => { + const html = await fixture.readFile('/markdown/index.html'); + const $ = cheerio.load(html); + expect($('#dash-case').text().trim()).to.equal('Fallback / Dash Case'); + }); + }); + + describe('For MDX Pages', () => { + it('Renders default slot', async () => { + const html = await fixture.readFile('/mdx/index.html'); + const $ = cheerio.load(html); + expect($('#content').text().trim()).to.equal('Hello world!'); + }); + + it('Renders named slot', async () => { + const html = await fixture.readFile('/mdx/index.html'); + const $ = cheerio.load(html); + expect($('#named').text().trim()).to.equal('Fallback / Named'); + }); + + it('Converts dash-case slot to camelCase', async () => { + const html = await fixture.readFile('/mdx/index.html'); + const $ = cheerio.load(html); + expect($('#dash-case').text().trim()).to.equal('Fallback / Dash Case'); + }); + }); }); diff --git a/packages/astro/test/slots-react.test.js b/packages/astro/test/slots-react.test.js index da6953142..8e61d41ec 100644 --- a/packages/astro/test/slots-react.test.js +++ b/packages/astro/test/slots-react.test.js @@ -21,4 +21,56 @@ describe('Slots: React', () => { expect($('#string').text().trim()).to.equal(''); expect($('#content').text().trim()).to.equal('Hello world!'); }); + + it('Renders named slot', async () => { + const html = await fixture.readFile('/index.html'); + const $ = cheerio.load(html); + expect($('#named').text().trim()).to.equal('Fallback / Named'); + }); + + it('Converts dash-case slot to camelCase', async () => { + const html = await fixture.readFile('/index.html'); + const $ = cheerio.load(html); + expect($('#dash-case').text().trim()).to.equal('Fallback / Dash Case'); + }); + + describe('For Markdown Pages', () => { + it('Renders default slot', async () => { + const html = await fixture.readFile('/markdown/index.html'); + const $ = cheerio.load(html); + expect($('#content').text().trim()).to.equal('Hello world!'); + }); + + it('Renders named slot', async () => { + const html = await fixture.readFile('/markdown/index.html'); + const $ = cheerio.load(html); + expect($('#named').text().trim()).to.equal('Fallback / Named'); + }); + + it('Converts dash-case slot to camelCase', async () => { + const html = await fixture.readFile('/markdown/index.html'); + const $ = cheerio.load(html); + expect($('#dash-case').text().trim()).to.equal('Fallback / Dash Case'); + }); + }); + + describe('For MDX Pages', () => { + it('Renders default slot', async () => { + const html = await fixture.readFile('/mdx/index.html'); + const $ = cheerio.load(html); + expect($('#content').text().trim()).to.equal('Hello world!'); + }); + + it('Renders named slot', async () => { + const html = await fixture.readFile('/mdx/index.html'); + const $ = cheerio.load(html); + expect($('#named').text().trim()).to.equal('Fallback / Named'); + }); + + it('Converts dash-case slot to camelCase', async () => { + const html = await fixture.readFile('/mdx/index.html'); + const $ = cheerio.load(html); + expect($('#dash-case').text().trim()).to.equal('Fallback / Dash Case'); + }); + }); }); diff --git a/packages/astro/test/slots-solid.test.js b/packages/astro/test/slots-solid.test.js index d7659f033..60e3231c9 100644 --- a/packages/astro/test/slots-solid.test.js +++ b/packages/astro/test/slots-solid.test.js @@ -21,4 +21,56 @@ describe('Slots: Solid', () => { expect($('#string').text().trim()).to.equal(''); expect($('#content').text().trim()).to.equal('Hello world!'); }); + + it('Renders named slot', async () => { + const html = await fixture.readFile('/index.html'); + const $ = cheerio.load(html); + expect($('#named').text().trim()).to.equal('Fallback / Named'); + }); + + it('Converts dash-case slot to camelCase', async () => { + const html = await fixture.readFile('/index.html'); + const $ = cheerio.load(html); + expect($('#dash-case').text().trim()).to.equal('Fallback / Dash Case'); + }); + + describe('For Markdown Pages', () => { + it('Renders default slot', async () => { + const html = await fixture.readFile('/markdown/index.html'); + const $ = cheerio.load(html); + expect($('#content').text().trim()).to.equal('Hello world!'); + }); + + it('Renders named slot', async () => { + const html = await fixture.readFile('/markdown/index.html'); + const $ = cheerio.load(html); + expect($('#named').text().trim()).to.equal('Fallback / Named'); + }); + + it('Converts dash-case slot to camelCase', async () => { + const html = await fixture.readFile('/markdown/index.html'); + const $ = cheerio.load(html); + expect($('#dash-case').text().trim()).to.equal('Fallback / Dash Case'); + }); + }); + + describe('For MDX Pages', () => { + it('Renders default slot', async () => { + const html = await fixture.readFile('/mdx/index.html'); + const $ = cheerio.load(html); + expect($('#content').text().trim()).to.equal('Hello world!'); + }); + + it('Renders named slot', async () => { + const html = await fixture.readFile('/mdx/index.html'); + const $ = cheerio.load(html); + expect($('#named').text().trim()).to.equal('Fallback / Named'); + }); + + it('Converts dash-case slot to camelCase', async () => { + const html = await fixture.readFile('/mdx/index.html'); + const $ = cheerio.load(html); + expect($('#dash-case').text().trim()).to.equal('Fallback / Dash Case'); + }); + }); }); diff --git a/packages/astro/test/slots-svelte.test.js b/packages/astro/test/slots-svelte.test.js index 0bbbae25a..a96a397e3 100644 --- a/packages/astro/test/slots-svelte.test.js +++ b/packages/astro/test/slots-svelte.test.js @@ -16,9 +16,61 @@ describe('Slots: Svelte', () => { expect($('#default-self-closing').text().trim()).to.equal('Fallback'); expect($('#default-empty').text().trim()).to.equal('Fallback'); - expect($('#zero').text().trim()).to.equal(''); + expect($('#zero').text().trim()).to.equal('0'); expect($('#false').text().trim()).to.equal(''); expect($('#string').text().trim()).to.equal(''); expect($('#content').text().trim()).to.equal('Hello world!'); }); + + it('Renders named slot', async () => { + const html = await fixture.readFile('/index.html'); + const $ = cheerio.load(html); + expect($('#named').text().trim()).to.equal('Fallback / Named'); + }); + + it('Preserves dash-case slot', async () => { + const html = await fixture.readFile('/index.html'); + const $ = cheerio.load(html); + expect($('#dash-case').text().trim()).to.equal('Fallback / Dash Case'); + }); + + describe('For Markdown Pages', () => { + it('Renders default slot', async () => { + const html = await fixture.readFile('/markdown/index.html'); + const $ = cheerio.load(html); + expect($('#content').text().trim()).to.equal('Hello world!'); + }); + + it('Renders named slot', async () => { + const html = await fixture.readFile('/markdown/index.html'); + const $ = cheerio.load(html); + expect($('#named').text().trim()).to.equal('Fallback / Named'); + }); + + it('Converts dash-case slot to camelCase', async () => { + const html = await fixture.readFile('/markdown/index.html'); + const $ = cheerio.load(html); + expect($('#dash-case').text().trim()).to.equal('Fallback / Dash Case'); + }); + }); + + describe('For MDX Pages', () => { + it('Renders default slot', async () => { + const html = await fixture.readFile('/mdx/index.html'); + const $ = cheerio.load(html); + expect($('#content').text().trim()).to.equal('Hello world!'); + }); + + it('Renders named slot', async () => { + const html = await fixture.readFile('/mdx/index.html'); + const $ = cheerio.load(html); + expect($('#named').text().trim()).to.equal('Fallback / Named'); + }); + + it('Preserves dash-case slot', async () => { + const html = await fixture.readFile('/index.html'); + const $ = cheerio.load(html); + expect($('#dash-case').text().trim()).to.equal('Fallback / Dash Case'); + }); + }); }); diff --git a/packages/astro/test/slots-vue.test.js b/packages/astro/test/slots-vue.test.js index 2b0dbc743..2999904b7 100644 --- a/packages/astro/test/slots-vue.test.js +++ b/packages/astro/test/slots-vue.test.js @@ -21,4 +21,56 @@ describe('Slots: Vue', () => { expect($('#string').text().trim()).to.equal(''); expect($('#content').text().trim()).to.equal('Hello world!'); }); + + it('Renders named slot', async () => { + const html = await fixture.readFile('/index.html'); + const $ = cheerio.load(html); + expect($('#named').text().trim()).to.equal('Fallback / Named'); + }); + + it('Preserves dash-case slot', async () => { + const html = await fixture.readFile('/index.html'); + const $ = cheerio.load(html); + expect($('#dash-case').text().trim()).to.equal('Fallback / Dash Case'); + }); + + describe('For Markdown Pages', () => { + it('Renders default slot', async () => { + const html = await fixture.readFile('/markdown/index.html'); + const $ = cheerio.load(html); + expect($('#content').text().trim()).to.equal('Hello world!'); + }); + + it('Renders named slot', async () => { + const html = await fixture.readFile('/markdown/index.html'); + const $ = cheerio.load(html); + expect($('#named').text().trim()).to.equal('Fallback / Named'); + }); + + it('Converts dash-case slot to camelCase', async () => { + const html = await fixture.readFile('/markdown/index.html'); + const $ = cheerio.load(html); + expect($('#dash-case').text().trim()).to.equal('Fallback / Dash Case'); + }); + }); + + describe('For MDX Pages', () => { + it('Renders default slot', async () => { + const html = await fixture.readFile('/mdx/index.html'); + const $ = cheerio.load(html); + expect($('#content').text().trim()).to.equal('Hello world!'); + }); + + it('Renders named slot', async () => { + const html = await fixture.readFile('/mdx/index.html'); + const $ = cheerio.load(html); + expect($('#named').text().trim()).to.equal('Fallback / Named'); + }); + + it('Converts dash-case slot to camelCase', async () => { + const html = await fixture.readFile('/markdown/index.html'); + const $ = cheerio.load(html); + expect($('#dash-case').text().trim()).to.equal('Fallback / Dash Case'); + }); + }); }); diff --git a/packages/astro/test/ssr-404-500-pages.test.js b/packages/astro/test/ssr-404-500-pages.test.js new file mode 100644 index 000000000..37ff3d3a5 --- /dev/null +++ b/packages/astro/test/ssr-404-500-pages.test.js @@ -0,0 +1,40 @@ +import { expect } from 'chai'; +import { loadFixture } from './test-utils.js'; +import testAdapter from './test-adapter.js'; +import * as cheerio from 'cheerio'; + +describe('404 and 500 pages', () => { + /** @type {import('./test-utils').Fixture} */ + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/ssr-api-route-custom-404/', + experimental: { + ssr: true, + }, + adapter: testAdapter(), + }); + await fixture.build({}); + }); + + it('404 page returned when a route does not match', async () => { + const app = await fixture.loadTestAdapterApp(); + const request = new Request('http://example.com/some/fake/route'); + const response = await app.render(request); + expect(response.status).to.equal(404); + const html = await response.text(); + const $ = cheerio.load(html); + expect($('h1').text()).to.equal('Something went horribly wrong!'); + }); + + it('500 page returned when there is an error', async () => { + const app = await fixture.loadTestAdapterApp(); + const request = new Request('http://example.com/causes-error'); + const response = await app.render(request); + expect(response.status).to.equal(500); + const html = await response.text(); + const $ = cheerio.load(html); + expect($('h1').text()).to.equal('This is an error page'); + }); +}); diff --git a/packages/astro/test/ssr-adapter-build-config.test.js b/packages/astro/test/ssr-adapter-build-config.test.js index bb1c4514a..1f76d7e6a 100644 --- a/packages/astro/test/ssr-adapter-build-config.test.js +++ b/packages/astro/test/ssr-adapter-build-config.test.js @@ -26,8 +26,10 @@ describe('Integration buildConfig hook', () => { if (id === '@my-ssr') { return id; } else if (id === 'astro/app') { - const id = viteID(new URL('../dist/core/app/index.js', import.meta.url)); - return id; + const viteId = viteID( + new URL('../dist/core/app/index.js', import.meta.url) + ); + return viteId; } }, load(id) { diff --git a/packages/astro/test/ssr-api-route.test.js b/packages/astro/test/ssr-api-route.test.js index e4758f10e..ec6e65641 100644 --- a/packages/astro/test/ssr-api-route.test.js +++ b/packages/astro/test/ssr-api-route.test.js @@ -30,7 +30,7 @@ describe('API routes in SSR', () => { const request = new Request('http://example.com/food.json'); const response = await app.render(request); expect(response.status).to.equal(200); - expect(response.headers.get('Content-Type')).to.equal('application/json'); + expect(response.headers.get('Content-Type')).to.equal('application/json;charset=utf-8'); expect(response.headers.get('Content-Length')).to.not.be.empty; const body = await response.json(); expect(body.length).to.equal(3); @@ -56,6 +56,13 @@ describe('API routes in SSR', () => { expect(text).to.equal(`ok`); }); + it('Infer content type with charset for { body } shorthand', async () => { + const response = await fixture.fetch('/food.json', { + method: 'GET', + }); + expect(response.headers.get('Content-Type')).to.equal('application/json;charset=utf-8'); + }); + it('Can set multiple headers of the same type', async () => { const response = await fixture.fetch('/login', { method: 'POST', diff --git a/packages/astro/test/ssr-dynamic.test.js b/packages/astro/test/ssr-dynamic.test.js index 8c200f1c5..f2795794f 100644 --- a/packages/astro/test/ssr-dynamic.test.js +++ b/packages/astro/test/ssr-dynamic.test.js @@ -18,6 +18,12 @@ describe('Dynamic pages in SSR', () => { await fixture.build(); }); + async function matchRoute(path) { + const app = await fixture.loadTestAdapterApp(); + const request = new Request('https://example.com' + path); + return app.match(request); + } + async function fetchHTML(path) { const app = await fixture.loadTestAdapterApp(); const request = new Request('http://example.com' + path); @@ -50,4 +56,9 @@ describe('Dynamic pages in SSR', () => { const json = await fetchJSON('/api/products/33'); expect(json.id).to.equal('33'); }); + + it('Public assets take priority', async () => { + const favicon = await matchRoute('/favicon.ico'); + expect(favicon).to.equal(undefined); + }); }); diff --git a/packages/astro/test/ssr-env.test.js b/packages/astro/test/ssr-env.test.js new file mode 100644 index 000000000..da823fa20 --- /dev/null +++ b/packages/astro/test/ssr-env.test.js @@ -0,0 +1,29 @@ +import { expect } from 'chai'; +import * as cheerio from 'cheerio'; +import { loadFixture } from './test-utils.js'; +import testAdapter from './test-adapter.js'; + +describe('SSR Environment Variables', () => { + /** @type {import('./test-utils').Fixture} */ + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/ssr-env/', + experimental: { + ssr: true, + }, + adapter: testAdapter(), + }); + await fixture.build(); + }); + + it('import.meta.env.SSR is true', async () => { + const app = await fixture.loadTestAdapterApp(); + const request = new Request('http://example.com/ssr'); + const response = await app.render(request); + const html = await response.text(); + const $ = cheerio.load(html); + expect($('#ssr').text()).to.equal('true'); + }); +}); diff --git a/packages/astro/test/ssr-large-array.test.js b/packages/astro/test/ssr-large-array.test.js new file mode 100644 index 000000000..64a82222b --- /dev/null +++ b/packages/astro/test/ssr-large-array.test.js @@ -0,0 +1,35 @@ +import { expect } from 'chai'; +import * as cheerio from 'cheerio'; +import { loadFixture } from './test-utils.js'; +import testAdapter from './test-adapter.js'; + +describe('SSR with Large Array and client rendering', () => { + /** @type {import('./test-utils').Fixture} */ + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/large-array/', + experimental: { + ssr: true, + }, + adapter: testAdapter(), + }); + await fixture.build(); + }); + + it('Using response.arrayBuffer() gets the right HTML', async () => { + const app = await fixture.loadTestAdapterApp(); + const request = new Request('http://example.com/'); + const response = await app.render(request); + const data = await response.arrayBuffer(); + const html = new TextDecoder().decode(data); + + const $ = cheerio.load(html); + expect($('head meta[name="viewport"]')).to.have.a.lengthOf(1); + expect($('head link[rel="icon"]')).to.have.a.lengthOf(1); + expect($('main')).to.have.a.lengthOf(1); + expect($('astro-island')).to.have.a.lengthOf(1); + expect($('h1').text()).to.equal('Hello, Solid!'); + }); +}); diff --git a/packages/astro/test/ssr-markdown.test.js b/packages/astro/test/ssr-markdown.test.js index a33fc85d6..40c12449e 100644 --- a/packages/astro/test/ssr-markdown.test.js +++ b/packages/astro/test/ssr-markdown.test.js @@ -31,10 +31,4 @@ describe('Markdown pages in SSR', () => { const $ = cheerioLoad(html); expect($('#subheading').text()).to.equal('Subheading'); }); - - it('Renders the Markdown component correctly', async () => { - const html = await fetchHTML('/page'); - const $ = cheerioLoad(html); - expect($('#something')).to.have.lengthOf(1); - }); }); diff --git a/packages/astro/test/ssr-partytown.test.js b/packages/astro/test/ssr-partytown.test.js new file mode 100644 index 000000000..5ea2bcde5 --- /dev/null +++ b/packages/astro/test/ssr-partytown.test.js @@ -0,0 +1,34 @@ +import { expect } from 'chai'; +import { load as cheerioLoad } from 'cheerio'; +import { loadFixture } from './test-utils.js'; +import testAdapter from './test-adapter.js'; + +describe('Using the Partytown integration in SSR', () => { + /** @type {import('./test-utils').Fixture} */ + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/ssr-partytown/', + adapter: testAdapter(), + experimental: { + ssr: true, + }, + }); + await fixture.build(); + }); + + it('Has the scripts in the page', async () => { + const app = await fixture.loadTestAdapterApp(); + const request = new Request('http://example.com/'); + const response = await app.render(request); + const html = await response.text(); + const $ = cheerioLoad(html); + expect($('script')).to.have.a.lengthOf(1); + }); + + it('The partytown scripts are in the manifest', async () => { + const app = await fixture.loadTestAdapterApp(); + expect(app.manifest.assets).to.contain('/~partytown/partytown-sw.js'); + }); +}); diff --git a/packages/astro/test/ssr-redirect.test.js b/packages/astro/test/ssr-redirect.test.js new file mode 100644 index 000000000..29fe701f7 --- /dev/null +++ b/packages/astro/test/ssr-redirect.test.js @@ -0,0 +1,27 @@ +import { expect } from 'chai'; +import { loadFixture } from './test-utils.js'; +import testAdapter from './test-adapter.js'; + +describe('Astro.redirect', () => { + /** @type {import('./test-utils').Fixture} */ + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/ssr-redirect/', + experimental: { + ssr: true, + }, + adapter: testAdapter(), + }); + await fixture.build(); + }); + + it('Returns a 302 status', async () => { + const app = await fixture.loadTestAdapterApp(); + const request = new Request('http://example.com/secret'); + const response = await app.render(request); + expect(response.status).to.equal(302); + expect(response.headers.get('location')).to.equal('/login'); + }); +}); diff --git a/packages/astro/test/ssr-response.test.js b/packages/astro/test/ssr-response.test.js index 1b517d9ee..ffabcbba4 100644 --- a/packages/astro/test/ssr-response.test.js +++ b/packages/astro/test/ssr-response.test.js @@ -32,13 +32,6 @@ describe('Using Astro.response in SSR', () => { expect(response.statusText).to.equal('Oops'); }); - it('Child component can set status', async () => { - const app = await fixture.loadTestAdapterApp(); - const request = new Request('http://example.com/child-set-status'); - const response = await app.render(request); - expect(response.status).to.equal(403); - }); - it('Can add headers', async () => { const app = await fixture.loadTestAdapterApp(); const request = new Request('http://example.com/some-header'); @@ -46,17 +39,5 @@ describe('Using Astro.response in SSR', () => { const headers = response.headers; expect(headers.get('one-two')).to.equal('three'); expect(headers.get('four-five')).to.equal('six'); - expect(headers.get('seven-eight')).to.equal('nine'); - }); - - it('Child component cannot override headers object', async () => { - const app = await fixture.loadTestAdapterApp(); - const request = new Request('http://example.com/child-tries-to-overwrite'); - const response = await app.render(request); - const headers = response.headers; - expect(headers.get('seven-eight')).to.equal('nine'); - const html = await response.text(); - const $ = cheerioLoad(html); - expect($('#overwrite-error').html()).to.equal('true'); }); }); diff --git a/packages/astro/test/ssr-scripts.test.js b/packages/astro/test/ssr-scripts.test.js new file mode 100644 index 000000000..f44099e41 --- /dev/null +++ b/packages/astro/test/ssr-scripts.test.js @@ -0,0 +1,27 @@ +import { expect } from 'chai'; +import { loadFixture } from './test-utils.js'; +import testAdapter from './test-adapter.js'; + +describe('SSR Hydrated component scripts', () => { + /** @type {import('./test-utils').Fixture} */ + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/ssr-scripts/', + experimental: { + ssr: true, + }, + adapter: testAdapter(), + }); + await fixture.build(); + }); + + it('Are included in the manifest.assets so that an adapter can know to serve static', async () => { + const app = await fixture.loadTestAdapterApp(); + + /** @type {Set} */ + const assets = app.manifest.assets; + expect(assets.size).to.be.greaterThan(0); + }); +}); diff --git a/packages/astro/test/static-build-dir.test.js b/packages/astro/test/static-build-dir.test.js new file mode 100644 index 000000000..d09756af2 --- /dev/null +++ b/packages/astro/test/static-build-dir.test.js @@ -0,0 +1,29 @@ +import { expect } from 'chai'; +import { loadFixture } from './test-utils.js'; + +describe('Static build: dir takes the URL path to the output directory', () => { + /** @type {URL} */ + let checkDir; + before(async () => { + const fixture = await loadFixture({ + root: './fixtures/static-build-dir/', + integrations: [ + { + name: '@astrojs/dir', + hooks: { + 'astro:build:done': ({ dir }) => { + checkDir = dir; + }, + }, + }, + ], + }); + await fixture.build(); + }); + it('dir takes the URL path to the output directory', async () => { + const removeTrailingSlash = (str) => str.replace(/\/$/, ''); + expect(removeTrailingSlash(checkDir.toString())).to.be.equal( + removeTrailingSlash(new URL('./fixtures/static-build-dir/dist', import.meta.url).toString()) + ); + }); +}); diff --git a/packages/astro/test/static-build-page-dist-url.test.js b/packages/astro/test/static-build-page-dist-url.test.js index 59adbc57c..cf9839926 100644 --- a/packages/astro/test/static-build-page-dist-url.test.js +++ b/packages/astro/test/static-build-page-dist-url.test.js @@ -2,11 +2,10 @@ import { expect } from 'chai'; import { loadFixture } from './test-utils.js'; describe('Static build: pages routes have distURL', () => { - /** @type {import('./test-utils').Fixture} */ - let fixture; /** @type {RouteData[]} */ let checkRoutes; before(async () => { + /** @type {import('./test-utils').Fixture} */ const fixture = await loadFixture({ root: './fixtures/astro pages/', integrations: [ diff --git a/packages/astro/test/streaming.test.js b/packages/astro/test/streaming.test.js new file mode 100644 index 000000000..fc7afba05 --- /dev/null +++ b/packages/astro/test/streaming.test.js @@ -0,0 +1,142 @@ +import { isWindows, loadFixture } from './test-utils.js'; +import { expect } from 'chai'; +import testAdapter from './test-adapter.js'; +import * as cheerio from 'cheerio'; + +describe('Streaming', () => { + if (isWindows) return; + + /** @type {import('./test-utils').Fixture} */ + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/streaming/', + adapter: testAdapter(), + experimental: { + ssr: true, + }, + }); + }); + + describe('Development', () => { + /** @type {import('./test-utils').DevServer} */ + let devServer; + + before(async () => { + devServer = await fixture.startDevServer(); + }); + + after(async () => { + await devServer.stop(); + }); + + it('Body is chunked', async () => { + let res = await fixture.fetch('/'); + let chunks = []; + for await (const bytes of res.body) { + let chunk = bytes.toString('utf-8'); + chunks.push(chunk); + } + expect(chunks.length).to.be.greaterThan(1); + }); + }); + + describe('Production', () => { + before(async () => { + await fixture.build(); + }); + + it('Can get the full html body', async () => { + const app = await fixture.loadTestAdapterApp(); + const request = new Request('http://example.com/'); + const response = await app.render(request); + const html = await response.text(); + const $ = cheerio.load(html); + expect($('header h1')).to.have.a.lengthOf(1); + expect($('ul li')).to.have.a.lengthOf(10); + }); + + it('Body is chunked', async () => { + const app = await fixture.loadTestAdapterApp(); + const request = new Request('http://example.com/'); + const response = await app.render(request); + let chunks = []; + let decoder = new TextDecoder(); + for await (const bytes of response.body) { + let chunk = decoder.decode(bytes); + chunks.push(chunk); + } + expect(chunks.length).to.be.greaterThan(1); + }); + }); +}); + +describe('Streaming disabled', () => { + if (isWindows) return; + + /** @type {import('./test-utils').Fixture} */ + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/streaming/', + adapter: testAdapter(), + experimental: { + ssr: true, + }, + server: { + streaming: false, + }, + }); + }); + + describe('Development', () => { + /** @type {import('./test-utils').DevServer} */ + let devServer; + + before(async () => { + devServer = await fixture.startDevServer(); + }); + + after(async () => { + await devServer.stop(); + }); + + it('Body is chunked', async () => { + let res = await fixture.fetch('/'); + let chunks = []; + for await (const bytes of res.body) { + let chunk = bytes.toString('utf-8'); + chunks.push(chunk); + } + expect(chunks.length).to.be.greaterThan(1); + }); + }); + + // TODO: find a different solution for the test-adapter, + // currently there's no way to resolve two different versions with one + // having streaming disabled + describe('Production', () => { + before(async () => { + await fixture.build(); + }); + + it('Can get the full html body', async () => { + const app = await fixture.loadTestAdapterApp(false); + const request = new Request('http://example.com/'); + const response = await app.render(request); + + expect(response.status).to.equal(200); + expect(response.headers.get('content-type')).to.equal('text/html'); + expect(response.headers.has('content-length')).to.equal(true); + expect(parseInt(response.headers.get('content-length'))).to.be.greaterThan(0); + + const html = await response.text(); + const $ = cheerio.load(html); + + expect($('header h1')).to.have.a.lengthOf(1); + expect($('ul li')).to.have.a.lengthOf(10); + }); + }); +}); diff --git a/packages/astro/test/tailwindcss.test.js b/packages/astro/test/tailwindcss.test.js index 15723c456..7a59aebe5 100644 --- a/packages/astro/test/tailwindcss.test.js +++ b/packages/astro/test/tailwindcss.test.js @@ -2,8 +2,6 @@ import { expect } from 'chai'; import * as cheerio from 'cheerio'; import { loadFixture } from './test-utils.js'; -let fixture; - describe('Tailwind', () => { let fixture; @@ -62,10 +60,10 @@ describe('Tailwind', () => { it('handles Markdown pages', async () => { const html = await fixture.readFile('/markdown-page/index.html'); - const $ = cheerio.load(html); - const bundledCSSHREF = $('link[rel=stylesheet][href^=/assets/]').attr('href'); - const bundledCSS = await fixture.readFile(bundledCSSHREF.replace(/^\/?/, '/')); - expect(bundledCSS, 'includes used component classes').to.match(/\.bg-purple-600{/); + const $md = cheerio.load(html); + const bundledCSSHREF = $md('link[rel=stylesheet][href^=/assets/]').attr('href'); + const mdBundledCSS = await fixture.readFile(bundledCSSHREF.replace(/^\/?/, '/')); + expect(mdBundledCSS, 'includes used component classes').to.match(/\.bg-purple-600{/); }); }); }); diff --git a/packages/astro/test/test-adapter.js b/packages/astro/test/test-adapter.js index 99ab34e5d..297e117a2 100644 --- a/packages/astro/test/test-adapter.js +++ b/packages/astro/test/test-adapter.js @@ -4,7 +4,7 @@ import { viteID } from '../dist/core/util.js'; * * @returns {import('../src/@types/astro').AstroIntegration} */ -export default function () { +export default function ({ provideAddress } = { provideAddress: true }) { return { name: 'my-ssr-adapter', hooks: { @@ -17,13 +17,29 @@ export default function () { if (id === '@my-ssr') { return id; } else if (id === 'astro/app') { - const id = viteID(new URL('../dist/core/app/index.js', import.meta.url)); - return id; + const viteId = viteID(new URL('../dist/core/app/index.js', import.meta.url)); + return viteId; } }, load(id) { if (id === '@my-ssr') { - return `import { App } from 'astro/app';export function createExports(manifest) { return { manifest, createApp: () => new App(manifest) }; }`; + return ` + import { App } from 'astro/app'; + + class MyApp extends App { + render(request) { + ${provideAddress ? `request[Symbol.for('astro.clientAddress')] = '0.0.0.0';` : ''} + return super.render(request); + } + } + + export function createExports(manifest) { + return { + manifest, + createApp: (streaming) => new MyApp(manifest, streaming) + }; + } + `; } }, }, diff --git a/packages/astro/test/test-utils.js b/packages/astro/test/test-utils.js index 523344c53..ab43a94cc 100644 --- a/packages/astro/test/test-utils.js +++ b/packages/astro/test/test-utils.js @@ -2,7 +2,7 @@ import { execa } from 'execa'; import { polyfill } from '@astrojs/webapi'; import fs from 'fs'; import { fileURLToPath } from 'url'; -import { resolveConfig, loadConfig } from '../dist/core/config.js'; +import { loadConfig } from '../dist/core/config.js'; import dev from '../dist/core/dev/index.js'; import build from '../dist/core/build/index.js'; import preview from '../dist/core/preview/index.js'; @@ -71,17 +71,23 @@ export async function loadFixture(inlineConfig) { cwd = new URL(cwd.replace(/\/?$/, '/'), import.meta.url); } } + // Load the config. let config = await loadConfig({ cwd: fileURLToPath(cwd) }); config = merge(config, { ...inlineConfig, root: cwd }); - // Note: the inline config doesn't run through config validation where these normalizations usually occur + // HACK: the inline config doesn't run through config validation where these normalizations usually occur if (typeof inlineConfig.site === 'string') { config.site = new URL(inlineConfig.site); } if (inlineConfig.base && !inlineConfig.base.endsWith('/')) { config.base = inlineConfig.base + '/'; } + if (config.integrations.find((integration) => integration.name === '@astrojs/mdx')) { + // Enable default JSX integration. It needs to come first, so unshift rather than push! + const { default: jsxRenderer } = await import('astro/jsx/renderer.js'); + config._ctx.renderers.unshift(jsxRenderer); + } /** @type {import('../src/core/logger/core').LogOptions} */ const logging = { @@ -121,6 +127,7 @@ export async function loadFixture(inlineConfig) { // Also do it on process exit, just in case. process.on('exit', resetAllFiles); + let fixtureId = new Date().valueOf(); let devServer; return { @@ -143,10 +150,10 @@ export async function loadFixture(inlineConfig) { clean: async () => { await fs.promises.rm(config.outDir, { maxRetries: 10, recursive: true, force: true }); }, - loadTestAdapterApp: async () => { - const url = new URL('./server/entry.mjs', config.outDir); + loadTestAdapterApp: async (streaming) => { + const url = new URL(`./server/entry.mjs?id=${fixtureId}`, config.outDir); const { createApp, manifest } = await import(url); - const app = createApp(); + const app = createApp(streaming); app.manifest = manifest; return app; }, diff --git a/packages/astro/test/virtual-astro-file.js b/packages/astro/test/virtual-astro-file.js new file mode 100644 index 000000000..e5247a684 --- /dev/null +++ b/packages/astro/test/virtual-astro-file.js @@ -0,0 +1,27 @@ +import { expect } from 'chai'; +import * as cheerio from 'cheerio'; +import { loadFixture } from './test-utils.js'; + +describe('Loading virtual Astro files', () => { + let fixture; + + before(async () => { + fixture = await loadFixture({ root: './fixtures/virtual-astro-file/' }); + await fixture.build(); + }); + + it('renders the component', async () => { + const html = await fixture.readFile('/index.html'); + const $ = cheerio.load(html); + expect($('#something')).to.have.a.lengthOf(1); + expect($('#works').text()).to.equal('true'); + }); + + it('builds component CSS', async () => { + const html = await fixture.readFile('/index.html'); + const $ = cheerio.load(html); + const href = $('link').attr('href'); + const css = await fixture.readFile(href); + expect(css).to.match(/green/, 'css bundled from virtual astro module'); + }); +}); diff --git a/packages/astro/test/vue-component.test.js b/packages/astro/test/vue-component.test.js index 3c57c6544..5ee632a47 100644 --- a/packages/astro/test/vue-component.test.js +++ b/packages/astro/test/vue-component.test.js @@ -27,17 +27,17 @@ describe('Vue component', () => { // test 1: renders all components correctly expect(allPreValues).to.deep.equal(['0', '1', '1', '1', '10', '100', '1000']); - // test 2: renders 3 s - expect($('astro-root')).to.have.lengthOf(6); + // test 2: renders 3 s + expect($('astro-island')).to.have.lengthOf(6); - // test 3: all s have uid attributes - expect($('astro-root[uid]')).to.have.lengthOf(6); + // test 3: all s have uid attributes + expect($('astro-island[uid]')).to.have.lengthOf(6); // test 4: treats as a custom element expect($('my-button')).to.have.lengthOf(7); // test 5: components with identical render output and props have been deduplicated - const uniqueRootUIDs = $('astro-root').map((i, el) => $(el).attr('uid')); + const uniqueRootUIDs = $('astro-island').map((i, el) => $(el).attr('uid')); expect(new Set(uniqueRootUIDs).size).to.equal(5); }); }); diff --git a/packages/astro/tsconfig.json b/packages/astro/tsconfig.json index c6b6bb7d1..58e865c0c 100644 --- a/packages/astro/tsconfig.json +++ b/packages/astro/tsconfig.json @@ -7,6 +7,6 @@ "module": "ES2020", "outDir": "./dist", "target": "ES2020", - "types": ["vite/client"] + "types": ["./client"] } } diff --git a/packages/create-astro/CHANGELOG.md b/packages/create-astro/CHANGELOG.md index 0238e00ca..f951815e5 100644 --- a/packages/create-astro/CHANGELOG.md +++ b/packages/create-astro/CHANGELOG.md @@ -1,5 +1,45 @@ # create-astro +## 0.14.1 + +### Patch Changes + +- [#3937](https://github.com/withastro/astro/pull/3937) [`31f9c0bf0`](https://github.com/withastro/astro/commit/31f9c0bf029ffa4b470e620f2c32e1370643e81e) Thanks [@delucis](https://github.com/delucis)! - Roll back supported Node engines + +## 0.14.0 + +### Minor Changes + +- [#3914](https://github.com/withastro/astro/pull/3914) [`b48767985`](https://github.com/withastro/astro/commit/b48767985359bd359df8071324952ea5f2bc0d86) Thanks [@ran-dall](https://github.com/ran-dall)! - Rollback supported `node@16` version. Minimum versions are now `node@14.20.0` or `node@16.14.0`. + +## 0.13.0 + +### Minor Changes + +- [#3871](https://github.com/withastro/astro/pull/3871) [`1cc5b7890`](https://github.com/withastro/astro/commit/1cc5b78905633608e5b07ad291f916f54e67feb1) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Update supported `node` versions. Minimum versions are now `node@14.20.0` or `node@16.16.0`. + +### Patch Changes + +- [#3886](https://github.com/withastro/astro/pull/3886) [`cb6a97383`](https://github.com/withastro/astro/commit/cb6a973839450dea1705407e1060919c946cca99) Thanks [@QuiiBz](https://github.com/QuiiBz)! - Fix portfolio example JSX error + +## 0.12.5 + +### Patch Changes + +- [#3831](https://github.com/withastro/astro/pull/3831) [`4fb08502`](https://github.com/withastro/astro/commit/4fb08502a99396723b9eb671099482cd619b3564) Thanks [@FredKSchott](https://github.com/FredKSchott)! - Small wording updates + +## 0.12.4 + +### Patch Changes + +- [#3756](https://github.com/withastro/astro/pull/3756) [`507cd5c8`](https://github.com/withastro/astro/commit/507cd5c868448971c6265d97f22e786263dd5a77) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Chore: remove create-astro install step test + +## 0.12.3 + +### Patch Changes + +- [#3748](https://github.com/withastro/astro/pull/3748) [`012f093e`](https://github.com/withastro/astro/commit/012f093eeb771b42b4e9d1e0cbb0d9a9605e0514) Thanks [@delucis](https://github.com/delucis)! - Remove `astro add` step & tweak wording (PR #3715) + ## 0.12.2 ### Patch Changes diff --git a/packages/create-astro/create-astro.mjs b/packages/create-astro/create-astro.mjs index be032f3c2..7f09ba700 100755 --- a/packages/create-astro/create-astro.mjs +++ b/packages/create-astro/create-astro.mjs @@ -3,7 +3,7 @@ const currentVersion = process.versions.node; const requiredMajorVersion = parseInt(currentVersion.split('.')[0], 10); -const minimumMajorVersion = 12; +const minimumMajorVersion = 14; if (requiredMajorVersion < minimumMajorVersion) { console.error(`Node.js v${currentVersion} is out of date and unsupported!`); diff --git a/packages/create-astro/package.json b/packages/create-astro/package.json index a978d8e26..96bd5199b 100644 --- a/packages/create-astro/package.json +++ b/packages/create-astro/package.json @@ -1,6 +1,6 @@ { "name": "create-astro", - "version": "0.12.2", + "version": "0.14.1", "type": "module", "author": "withastro", "license": "MIT", @@ -28,19 +28,21 @@ "create-astro.js" ], "dependencies": { - "@types/degit": "^2.8.3", - "@types/prompts": "^2.0.14", "chalk": "^5.0.1", "degit": "^2.8.4", "execa": "^6.1.0", "kleur": "^4.1.4", "ora": "^6.1.0", "prompts": "^2.4.2", + "which-pm-runs": "^1.1.0", "yargs-parser": "^21.0.1" }, "devDependencies": { "@types/chai": "^4.3.1", + "@types/degit": "^2.8.3", "@types/mocha": "^9.1.1", + "@types/prompts": "^2.0.14", + "@types/which-pm-runs": "^1.0.0", "@types/yargs-parser": "^21.0.0", "astro-scripts": "workspace:*", "chai": "^4.3.6", @@ -48,6 +50,6 @@ "uvu": "^0.5.3" }, "engines": { - "node": "^14.15.0 || >=16.0.0" + "node": "^14.18.0 || >=16.12.0" } } diff --git a/packages/create-astro/src/index.ts b/packages/create-astro/src/index.ts index 4fb6cec28..be6c6a6b9 100644 --- a/packages/create-astro/src/index.ts +++ b/packages/create-astro/src/index.ts @@ -1,15 +1,25 @@ +/* eslint no-console: 'off' */ import degit from 'degit'; import { execa, execaCommand } from 'execa'; import fs from 'fs'; -import { bgCyan, black, bold, cyan, gray, green, red, yellow } from 'kleur/colors'; +import { bgCyan, black, bold, cyan, dim, gray, green, red, reset, yellow } from 'kleur/colors'; import ora from 'ora'; import path from 'path'; import prompts from 'prompts'; +import detectPackageManager from 'which-pm-runs'; import yargs from 'yargs-parser'; import { loadWithRocketGradient, rocketAscii } from './gradient.js'; import { defaultLogLevel, logger } from './logger.js'; import { TEMPLATES } from './templates.js'; +function wait(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +function logAndWait(message: string, ms = 100) { + console.log(message); + return wait(ms); +} // NOTE: In the v7.x version of npm, the default behavior of `npm init` was changed // to no longer require `--` to pass args and instead pass `--` directly to us. This // broke our arg parser, since `--` is a special kind of flag. Filtering for `--` here @@ -37,11 +47,13 @@ const { version } = JSON.parse( const FILES_TO_REMOVE = ['.stackblitzrc', 'sandbox.config.json', 'CHANGELOG.md']; // some files are only needed for online editors when using astro.new. Remove for create-astro installs. +// Please also update the installation instructions in the docs at https://github.com/withastro/docs/blob/main/src/pages/en/install/auto.md if you make any changes to the flow or wording here. export async function main() { - const pkgManager = pkgManagerFromUserAgent(process.env.npm_config_user_agent); + const pkgManager = detectPackageManager()?.name || 'npm'; logger.debug('Verbose logging turned on'); console.log(`\n${bold('Welcome to Astro!')} ${gray(`(create-astro v${version})`)}`); + console.log(`Lets walk through setting up your new Astro project.\n`); let cwd = args['_'][2] as string; @@ -63,7 +75,7 @@ export async function main() { const dirResponse = await prompts({ type: 'text', name: 'directory', - message: 'Where would you like to create your app?', + message: 'Where would you like to create your new project?', initial: './my-astro-site', validate(value) { if (!isEmpty(value)) { @@ -83,7 +95,7 @@ export async function main() { { type: 'select', name: 'template', - message: 'Which app template would you like to use?', + message: 'Which template would you like to use?', choices: TEMPLATES, }, ]); @@ -96,7 +108,10 @@ export async function main() { const hash = args.commit ? `#${args.commit}` : ''; - const templateTarget = `withastro/astro/examples/${options.template}#latest`; + // Don't touch the template name if a GitHub repo was provided, ex: `--template cassidoo/shopify-react-astro` + const templateTarget = options.template.includes('/') + ? options.template + : `withastro/astro/examples/${options.template}#latest`; const emitter = degit(`${templateTarget}${hash}`, { cache: false, @@ -111,7 +126,7 @@ export async function main() { }); // Copy - if (!args.dryrun) { + if (!args.dryRun) { try { emitter.on('info', (info) => { logger.debug(info.message); @@ -170,15 +185,13 @@ export async function main() { const installResponse = await prompts({ type: 'confirm', name: 'install', - message: `Would you like us to run "${pkgManager} install?"`, + message: `Would you like to install ${pkgManager} dependencies? ${reset(dim('(recommended)'))}`, initial: true, }); - if (!installResponse) { - process.exit(0); - } - - if (installResponse.install && !args.dryrun) { + if (args.dryRun) { + ora().info(dim(`--dry-run enabled, skipping.`)); + } else if (installResponse.install) { const installExec = execa(pkgManager, ['install'], { cwd }); const installingPackagesMsg = `Installing packages${emojiWithFallback(' 📦', '...')}`; const installSpinner = await loadWithRocketGradient(installingPackagesMsg); @@ -193,87 +206,51 @@ export async function main() { }); installSpinner.text = green('Packages installed!'); installSpinner.succeed(); - } - - const astroAddCommand = installResponse.install - ? 'astro add --yes' - : `${pkgManagerExecCommand(pkgManager)} astro@latest add --yes`; - - const astroAddResponse = await prompts({ - type: 'confirm', - name: 'astroAdd', - message: `Run "${astroAddCommand}?" This lets you optionally add component frameworks (ex. React), CSS frameworks (ex. Tailwind), and more.`, - initial: true, - }); - - if (!astroAddResponse) { - process.exit(0); - } - - if (!astroAddResponse.astroAdd) { - ora().info( - `No problem. You can always run "${pkgManagerExecCommand(pkgManager)} astro add" later!` - ); - } - - if (astroAddResponse.astroAdd && !args.dryrun) { - await execaCommand( - astroAddCommand, - astroAddCommand === 'astro add --yes' - ? { cwd, stdio: 'inherit', localDir: cwd, preferLocal: true } - : { cwd, stdio: 'inherit' } - ); + } else { + ora().info(dim(`No problem! Remember to install dependencies after setup.`)); } const gitResponse = await prompts({ type: 'confirm', name: 'git', - message: 'Initialize a git repository?', + message: `Would you like to initialize a new git repository? ${reset(dim('(optional)'))}`, initial: true, }); - if (!gitResponse) { - process.exit(0); - } - - if (gitResponse.git && !args.dryrun) { + if (args.dryRun) { + ora().info(dim(`--dry-run enabled, skipping.`)); + } else if (gitResponse.git) { await execaCommand('git init', { cwd }); + } else { + ora().info(dim(`Sounds good! You can come back and run ${cyan(`git init`)} later.`)); } - ora({ text: green('Done. Ready for liftoff!') }).succeed(); + ora().succeed('Setup complete.'); + ora({ text: green('Ready for liftoff!') }).succeed(); + await wait(300); + console.log(`\n${bgCyan(black(' Next steps '))}\n`); - const projectDir = path.relative(process.cwd(), cwd); + let projectDir = path.relative(process.cwd(), cwd); const devCmd = pkgManager === 'npm' ? 'npm run dev' : `${pkgManager} dev`; - console.log( + await logAndWait( `You can now ${bold(cyan('cd'))} into the ${bold(cyan(projectDir))} project directory.` ); - console.log( + await logAndWait( `Run ${bold(cyan(devCmd))} to start the Astro dev server. ${bold(cyan('CTRL-C'))} to close.` ); - if (!installResponse.install) { - console.log(yellow(`Remember to install dependencies first!`)); - } - console.log(`\nStuck? Come join us at ${bold(cyan('https://astro.build/chat'))}`); + await logAndWait( + `Add frameworks like ${bold(cyan('react'))} and ${bold( + cyan('tailwind') + )} to your project using ${bold(cyan('astro add'))}` + ); + await logAndWait(''); + await logAndWait(`Stuck? Come join us at ${bold(cyan('https://astro.build/chat'))}`, 1000); + await logAndWait(dim('Good luck out there, astronaut.')); + await logAndWait('', 300); } function emojiWithFallback(char: string, fallback: string) { return process.platform !== 'win32' ? char : fallback; } - -function pkgManagerFromUserAgent(userAgent?: string) { - if (!userAgent) return 'npm'; - const pkgSpec = userAgent.split(' ')[0]; - const pkgSpecArr = pkgSpec.split('/'); - return pkgSpecArr[0]; -} - -function pkgManagerExecCommand(pkgManager: string) { - if (pkgManager === 'pnpm') { - return 'pnpx'; - } else { - // note: yarn does not have an "npx" equivalent - return 'npx'; - } -} diff --git a/packages/create-astro/src/templates.ts b/packages/create-astro/src/templates.ts index 2e35d4496..d379b5579 100644 --- a/packages/create-astro/src/templates.ts +++ b/packages/create-astro/src/templates.ts @@ -1,22 +1,22 @@ export const TEMPLATES = [ { - title: 'Just the basics', + title: 'Just the basics (recommended)', value: 'basics', }, { title: 'Blog', value: 'blog', }, - { - title: 'Documentation', - value: 'docs', - }, { title: 'Portfolio', value: 'portfolio', }, { - title: 'Completely empty', + title: 'Documentation Site', + value: 'docs', + }, + { + title: 'Empty project', value: 'minimal', }, ]; diff --git a/packages/create-astro/test/astro-add-step.test.js b/packages/create-astro/test/astro-add-step.test.js deleted file mode 100644 index 73d963ed0..000000000 --- a/packages/create-astro/test/astro-add-step.test.js +++ /dev/null @@ -1,69 +0,0 @@ -import { setup, promiseWithTimeout, timeout, PROMPT_MESSAGES } from './utils.js'; -import { sep } from 'path'; -import fs from 'fs'; -import os from 'os'; - -// reset package manager in process.env -// prevents test issues when running with pnpm -const FAKE_PACKAGE_MANAGER = 'npm'; -let initialEnvValue = null; - -describe('[create-astro] astro add', function () { - this.timeout(timeout); - let tempDir = ''; - beforeEach(async () => { - tempDir = await fs.promises.mkdtemp(`${os.tmpdir()}${sep}`); - }); - this.beforeAll(() => { - initialEnvValue = process.env.npm_config_user_agent; - process.env.npm_config_user_agent = FAKE_PACKAGE_MANAGER; - }); - this.afterAll(() => { - process.env.npm_config_user_agent = initialEnvValue; - }); - - it('should use "astro add" when user has installed dependencies', function () { - const { stdout, stdin } = setup([tempDir]); - return promiseWithTimeout((resolve) => { - const seen = new Set(); - const installPrompt = PROMPT_MESSAGES.install('npm'); - stdout.on('data', (chunk) => { - if (!seen.has(PROMPT_MESSAGES.template) && chunk.includes(PROMPT_MESSAGES.template)) { - seen.add(PROMPT_MESSAGES.template); - // respond with "enter key" - stdin.write('\x0D'); - } - if (!seen.has(installPrompt) && chunk.includes(installPrompt)) { - seen.add(installPrompt); - stdin.write('\x0D'); - } - if (chunk.includes(PROMPT_MESSAGES.astroAdd('astro add --yes'))) { - resolve(); - } - }); - }); - }); - - it('should use "npx astro@latest add" when use has NOT installed dependencies', function () { - const { stdout, stdin } = setup([tempDir]); - return promiseWithTimeout((resolve) => { - const seen = new Set(); - const installPrompt = PROMPT_MESSAGES.install('npm'); - stdout.on('data', (chunk) => { - if (!seen.has(PROMPT_MESSAGES.template) && chunk.includes(PROMPT_MESSAGES.template)) { - seen.add(PROMPT_MESSAGES.template); - // respond with "enter key" - stdin.write('\x0D'); - } - if (!seen.has(installPrompt) && chunk.includes(installPrompt)) { - seen.add(installPrompt); - // respond with "no, then enter key" - stdin.write('n\x0D'); - } - if (chunk.includes(PROMPT_MESSAGES.astroAdd('npx astro@latest add --yes'))) { - resolve(); - } - }); - }); - }); -}); diff --git a/packages/create-astro/test/directory-step.test.js b/packages/create-astro/test/directory-step.test.js index 7193fe298..7c629598a 100644 --- a/packages/create-astro/test/directory-step.test.js +++ b/packages/create-astro/test/directory-step.test.js @@ -1,4 +1,4 @@ -import { resolve } from 'path'; +import path from 'path'; import { promises, existsSync } from 'fs'; import { PROMPT_MESSAGES, testDir, setup, promiseWithTimeout, timeout } from './utils.js'; @@ -31,7 +31,7 @@ describe('[create-astro] select directory', function () { }); }); it('should proceed on an empty directory', async function () { - const resolvedEmptyDirPath = resolve(testDir, inputs.emptyDir); + const resolvedEmptyDirPath = path.resolve(testDir, inputs.emptyDir); if (!existsSync(resolvedEmptyDirPath)) { await promises.mkdir(resolvedEmptyDirPath); } diff --git a/packages/create-astro/test/install-step.test.js b/packages/create-astro/test/install-step.test.js deleted file mode 100644 index d8219b520..000000000 --- a/packages/create-astro/test/install-step.test.js +++ /dev/null @@ -1,73 +0,0 @@ -import { setup, promiseWithTimeout, timeout, PROMPT_MESSAGES } from './utils.js'; -import { sep } from 'path'; -import fs from 'fs'; -import os from 'os'; - -const FAKE_PACKAGE_MANAGER = 'banana'; -let initialEnvValue = null; - -describe('[create-astro] install', function () { - this.timeout(timeout); - let tempDir = ''; - beforeEach(async () => { - tempDir = await fs.promises.mkdtemp(`${os.tmpdir()}${sep}`); - }); - this.beforeAll(() => { - initialEnvValue = process.env.npm_config_user_agent; - process.env.npm_config_user_agent = FAKE_PACKAGE_MANAGER; - }); - this.afterAll(() => { - process.env.npm_config_user_agent = initialEnvValue; - }); - - it('should respect package manager in prompt', function () { - const { stdout, stdin } = setup([tempDir]); - return promiseWithTimeout((resolve) => { - const seen = new Set(); - const installPrompt = PROMPT_MESSAGES.install(FAKE_PACKAGE_MANAGER); - stdout.on('data', (chunk) => { - if (!seen.has(PROMPT_MESSAGES.template) && chunk.includes(PROMPT_MESSAGES.template)) { - seen.add(PROMPT_MESSAGES.template); - // respond with "enter key" - stdin.write('\x0D'); - } - if (!seen.has(installPrompt) && chunk.includes(installPrompt)) { - seen.add(installPrompt); - resolve(); - } - }); - }); - }); - - it('should respect package manager in next steps', function () { - const { stdout, stdin } = setup([tempDir]); - return promiseWithTimeout((resolve) => { - const seen = new Set(); - const installPrompt = PROMPT_MESSAGES.install(FAKE_PACKAGE_MANAGER); - const astroAddPrompt = PROMPT_MESSAGES.astroAdd(); - stdout.on('data', (chunk) => { - if (!seen.has(PROMPT_MESSAGES.template) && chunk.includes(PROMPT_MESSAGES.template)) { - seen.add(PROMPT_MESSAGES.template); - // respond with "enter key" - stdin.write('\x0D'); - } - if (!seen.has(installPrompt) && chunk.includes(installPrompt)) { - seen.add(installPrompt); - // respond with "no, then enter key" - stdin.write('n\x0D'); - } - if (!seen.has(astroAddPrompt) && chunk.includes(astroAddPrompt)) { - seen.add(astroAddPrompt); - stdin.write('n\x0D'); - } - if (!seen.has(PROMPT_MESSAGES.git) && chunk.includes(PROMPT_MESSAGES.git)) { - seen.add(PROMPT_MESSAGES.git); - stdin.write('\x0D'); - } - if (chunk.includes('banana dev')) { - resolve(); - } - }); - }); - }); -}); diff --git a/packages/create-astro/test/utils.js b/packages/create-astro/test/utils.js index 964ae6a20..b085ef083 100644 --- a/packages/create-astro/test/utils.js +++ b/packages/create-astro/test/utils.js @@ -24,12 +24,8 @@ export function promiseWithTimeout(testFn) { } export const PROMPT_MESSAGES = { - directory: 'Where would you like to create your app?', - template: 'Which app template would you like to use?', - install: (pkgManager) => `Would you like us to run "${pkgManager} install?"`, - astroAdd: (astroAddCommand = 'npx astro@latest add --yes') => - `Run "${astroAddCommand}?" This lets you optionally add component frameworks (ex. React), CSS frameworks (ex. Tailwind), and more.`, - git: 'Initialize a git repository?', + directory: 'Where would you like to create your new project?', + template: 'Which template would you like to use?', }; export function setup(args = []) { diff --git a/packages/integrations/cloudflare/CHANGELOG.md b/packages/integrations/cloudflare/CHANGELOG.md new file mode 100644 index 000000000..c6eae1744 --- /dev/null +++ b/packages/integrations/cloudflare/CHANGELOG.md @@ -0,0 +1,31 @@ +# @astrojs/cloudflare + +## 0.2.4 + +### Patch Changes + +- [#3885](https://github.com/withastro/astro/pull/3885) [`bf5d1cc1e`](https://github.com/withastro/astro/commit/bf5d1cc1e71da38a14658c615e9481f2145cc6e7) Thanks [@delucis](https://github.com/delucis)! - Integration README fixes + +## 0.2.3 + +### Patch Changes + +- [#3854](https://github.com/withastro/astro/pull/3854) [`b012ee55`](https://github.com/withastro/astro/commit/b012ee55b107dea0730286263b27d83e530fad5d) Thanks [@bholmesdev](https://github.com/bholmesdev)! - [astro add] Support adapters and third party packages + +## 0.2.2 + +### Patch Changes + +- [#3777](https://github.com/withastro/astro/pull/3777) [`976e1f17`](https://github.com/withastro/astro/commit/976e1f175a95ea39f737b8575e4fdf3c3d89e1ee) Thanks [@tony-sull](https://github.com/tony-sull)! - Disables HTTP streaming in Cloudflare Pages deployments + +## 0.2.1 + +### Patch Changes + +- [#3695](https://github.com/withastro/astro/pull/3695) [`0d667d0e`](https://github.com/withastro/astro/commit/0d667d0e572d76d4c819816ddf51ed14b43e2551) Thanks [@nrgnrg](https://github.com/nrgnrg)! - fix custom 404 pages not rendering + +## 0.2.0 + +### Minor Changes + +- [#3600](https://github.com/withastro/astro/pull/3600) [`7f423581`](https://github.com/withastro/astro/commit/7f423581411648c9a69b68918ff930581f12cf16) Thanks [@nrgnrg](https://github.com/nrgnrg)! - add SSR adaptor for Cloudflare Pages functions diff --git a/packages/integrations/cloudflare/README.md b/packages/integrations/cloudflare/README.md new file mode 100644 index 000000000..3417149b8 --- /dev/null +++ b/packages/integrations/cloudflare/README.md @@ -0,0 +1,32 @@ +# @astrojs/cloudflare + +An SSR adapter for use with Cloudflare Pages Functions targets. Write your code in Astro/Node and deploy to Cloudflare Pages. + +In your `astro.config.mjs` use: + +```js +import { defineConfig } from 'astro/config'; +import cloudflare from '@astrojs/cloudflare'; + +export default defineConfig({ + adapter: cloudflare() +}); +``` + +## Enabling Preview + +In order for preview to work you must install `wrangler` + +```sh +$ pnpm install wrangler --save-dev +``` + +It's then possible to update the preview script in your `package.json` to `"preview": "wrangler pages dev ./dist"` + +## Streams + +Some integrations such as [React](https://github.com/withastro/astro/tree/main/packages/integrations/react) rely on web streams. Currently Cloudflare Pages functions are in beta and don't support the `streams_enable_constructors` feature flag. + +In order to work around this: +- install the `"web-streams-polyfill"` package +- add `import "web-streams-polyfill/es2018";` to the top of the front matter of every page which requires streams, such as server rendering a React component. diff --git a/packages/integrations/cloudflare/package.json b/packages/integrations/cloudflare/package.json new file mode 100644 index 000000000..4835549c0 --- /dev/null +++ b/packages/integrations/cloudflare/package.json @@ -0,0 +1,36 @@ +{ + "name": "@astrojs/cloudflare", + "description": "Deploy your site to cloudflare pages functions", + "version": "0.2.4", + "type": "module", + "types": "./dist/index.d.ts", + "author": "withastro", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/withastro/astro.git", + "directory": "packages/integrations/cloudflare" + }, + "keywords": [ + "astro-adapter" + ], + "bugs": "https://github.com/withastro/astro/issues", + "homepage": "https://docs.astro.build/en/guides/integrations-guide/cloudflare/", + "exports": { + ".": "./dist/index.js", + "./server.js": "./dist/server.js", + "./package.json": "./package.json" + }, + "scripts": { + "build": "astro-scripts build \"src/**/*.ts\" && tsc", + "build:ci": "astro-scripts build \"src/**/*.ts\"", + "dev": "astro-scripts dev \"src/**/*.ts\"" + }, + "dependencies": { + "esbuild": "^0.14.42" + }, + "devDependencies": { + "astro": "workspace:*", + "astro-scripts": "workspace:*" + } +} diff --git a/packages/integrations/cloudflare/src/index.ts b/packages/integrations/cloudflare/src/index.ts new file mode 100644 index 000000000..dc65f23ce --- /dev/null +++ b/packages/integrations/cloudflare/src/index.ts @@ -0,0 +1,73 @@ +import type { AstroAdapter, AstroConfig, AstroIntegration, BuildConfig } from 'astro'; +import esbuild from 'esbuild'; +import * as fs from 'fs'; +import { fileURLToPath } from 'url'; + +export function getAdapter(): AstroAdapter { + return { + name: '@astrojs/cloudflare', + serverEntrypoint: '@astrojs/cloudflare/server.js', + exports: ['default'], + }; +} + +export default function createIntegration(): AstroIntegration { + let _config: AstroConfig; + let _buildConfig: BuildConfig; + + return { + name: '@astrojs/cloudflare', + hooks: { + 'astro:config:done': ({ setAdapter, config }) => { + setAdapter(getAdapter()); + _config = config; + }, + 'astro:build:start': ({ buildConfig }) => { + _buildConfig = buildConfig; + buildConfig.serverEntry = '_worker.js'; + buildConfig.client = new URL('./static/', _config.outDir); + buildConfig.server = new URL('./', _config.outDir); + }, + 'astro:build:setup': ({ vite, target }) => { + if (target === 'server') { + vite.resolve = vite.resolve || {}; + vite.resolve.alias = vite.resolve.alias || {}; + + const aliases = [{ find: 'react-dom/server', replacement: 'react-dom/server.browser' }]; + + if (Array.isArray(vite.resolve.alias)) { + vite.resolve.alias = [...vite.resolve.alias, ...aliases]; + } else { + for (const alias of aliases) { + (vite.resolve.alias as Record)[alias.find] = alias.replacement; + } + } + + vite.ssr = { + target: 'webworker', + noExternal: true, + }; + } + }, + 'astro:build:done': async () => { + const entryUrl = new URL(_buildConfig.serverEntry, _buildConfig.server); + const pkg = fileURLToPath(entryUrl); + + await esbuild.build({ + target: 'es2020', + platform: 'browser', + entryPoints: [pkg], + outfile: pkg, + allowOverwrite: true, + format: 'esm', + bundle: true, + minify: true, + }); + + // throw the server folder in the bin + const chunksUrl = new URL('./chunks', _buildConfig.server); + await fs.promises.rm(chunksUrl, { recursive: true, force: true }); + }, + }, + }; +} diff --git a/packages/integrations/cloudflare/src/server.ts b/packages/integrations/cloudflare/src/server.ts new file mode 100644 index 000000000..7b88c7b1e --- /dev/null +++ b/packages/integrations/cloudflare/src/server.ts @@ -0,0 +1,39 @@ +import './shim.js'; + +import type { SSRManifest } from 'astro'; +import { App } from 'astro/app'; + +type Env = { + ASSETS: { fetch: (req: Request) => Promise }; +}; + +export function createExports(manifest: SSRManifest) { + const app = new App(manifest, false); + + const fetch = async (request: Request, env: Env) => { + const { origin, pathname } = new URL(request.url); + + // static assets + if (manifest.assets.has(pathname)) { + const assetRequest = new Request(`${origin}/static${pathname}`, request); + return env.ASSETS.fetch(assetRequest); + } + + let routeData = app.match(request, { matchNotFound: true }); + if (routeData) { + Reflect.set( + request, + Symbol.for('astro.clientAddress'), + request.headers.get('cf-connecting-ip') + ); + return app.render(request, routeData); + } + + return new Response(null, { + status: 404, + statusText: 'Not found', + }); + }; + + return { default: { fetch } }; +} diff --git a/packages/integrations/netlify/src/edge-shim.ts b/packages/integrations/cloudflare/src/shim.ts similarity index 100% rename from packages/integrations/netlify/src/edge-shim.ts rename to packages/integrations/cloudflare/src/shim.ts diff --git a/packages/integrations/cloudflare/tsconfig.json b/packages/integrations/cloudflare/tsconfig.json new file mode 100644 index 000000000..44baf375c --- /dev/null +++ b/packages/integrations/cloudflare/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../../tsconfig.base.json", + "include": ["src"], + "compilerOptions": { + "allowJs": true, + "module": "ES2020", + "outDir": "./dist", + "target": "ES2020" + } +} diff --git a/packages/integrations/deno/CHANGELOG.md b/packages/integrations/deno/CHANGELOG.md index ab7052fe8..60ffb5fcb 100644 --- a/packages/integrations/deno/CHANGELOG.md +++ b/packages/integrations/deno/CHANGELOG.md @@ -1,5 +1,37 @@ # @astrojs/node +## 0.1.10 + +### Patch Changes + +- [#3885](https://github.com/withastro/astro/pull/3885) [`bf5d1cc1e`](https://github.com/withastro/astro/commit/bf5d1cc1e71da38a14658c615e9481f2145cc6e7) Thanks [@delucis](https://github.com/delucis)! - Integration README fixes + +## 0.1.9 + +### Patch Changes + +- [#3865](https://github.com/withastro/astro/pull/3865) [`1f9e4857`](https://github.com/withastro/astro/commit/1f9e4857ff2b2cb7db89d619618cdf546cd3b3dc) Thanks [@delucis](https://github.com/delucis)! - Small README fixes + +* [#3854](https://github.com/withastro/astro/pull/3854) [`b012ee55`](https://github.com/withastro/astro/commit/b012ee55b107dea0730286263b27d83e530fad5d) Thanks [@bholmesdev](https://github.com/bholmesdev)! - [astro add] Support adapters and third party packages + +## 0.1.8 + +### Patch Changes + +- [#3677](https://github.com/withastro/astro/pull/3677) [`8045c8ad`](https://github.com/withastro/astro/commit/8045c8ade16fe4306448b7f98a4560ef0557d378) Thanks [@Jutanium](https://github.com/Jutanium)! - Update READMEs + +## 0.1.7 + +### Patch Changes + +- [#3734](https://github.com/withastro/astro/pull/3734) [`4acd245d`](https://github.com/withastro/astro/commit/4acd245d8f59871eb9c0083ae1a0fe7aa70c84f5) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Fix: append shim to top of built file to avoid "can't read process of undefined" issues + +## 0.1.6 + +### Patch Changes + +- [#3673](https://github.com/withastro/astro/pull/3673) [`ba5ad785`](https://github.com/withastro/astro/commit/ba5ad7855c4252e10e76b41b88fd4c74b4b7295b) Thanks [@hippotastic](https://github.com/hippotastic)! - Fix react dependencies to improve test reliability + ## 0.1.5 ### Patch Changes diff --git a/packages/integrations/deno/README.md b/packages/integrations/deno/README.md new file mode 100644 index 000000000..bc8dfe8f6 --- /dev/null +++ b/packages/integrations/deno/README.md @@ -0,0 +1,144 @@ +# @astrojs/deno 🦖 + +This adapter allows Astro to deploy your SSR site to Deno targets. + +- [Why Astro Deno](#why-astro-deno) +- [Installation](#installation) +- [Usage](#usage) +- [Configuration](#configuration) +- [Examples](#examples) +- [Troubleshooting](#troubleshooting) +- [Contributing](#contributing) +- [Changelog](#changelog) + +## Why Astro Deno + +If you're using Astro as a static site builder—its behavior out of the box—you don't need an adapter. + +If you wish to [use server-side rendering (SSR)](https://docs.astro.build/en/guides/server-side-rendering/), Astro requires an adapter that matches your deployment runtime. + +[Deno](https://deno.land/) is a runtime similar to Node, but with an API that's more similar to the browser's API. This adapter provides access to Deno's API and creates a script to run your project on a Deno server. + +## Installation + +First, install the `@astrojs/deno` package using your package manager. If you're using npm or aren't sure, run this in the terminal: + +```sh +npm install @astrojs/deno +``` + +Then, install this adapter in your `astro.config.*` file using the `adapter` property: + +__`astro.config.mjs`__ + +```js +import { defineConfig } from 'astro/config'; +import deno from '@astrojs/deno'; + +export default defineConfig({ + // ... + adapter: deno() +}); +``` + +## Usage + +After [performing a build](https://docs.astro.build/en/guides/deploy/#building-your-site-locally) there will be a `dist/server/entry.mjs` module. You can start a server by importing this module in your Deno app: + +```js +import './dist/entry.mjs'; +``` + +See the `start` option below for how you can have more control over starting the Astro server. + +You can also run the script directly using deno: + +```sh +deno run --allow-net --allow-read --allow-env ./dist/server/entry.mjs +``` + + +## Configuration + +To configure this adapter, pass an object to the `deno()` function call in `astro.config.mjs`. + +__`astro.config.mjs`__ + +```js +import { defineConfig } from 'astro/config'; +import deno from '@astrojs/deno'; + +export default defineConfig({ + adapter: deno({ + //options go here + }) +}); +``` + +
      + start + + This adapter automatically starts a server when it is imported. You can turn this off with the `start` option: + + ```js + import { defineConfig } from 'astro/config'; + import deno from '@astrojs/deno'; + + export default defineConfig({ + adapter: deno({ + start: false + }) + }); + ``` + + If you disable this, you need to write your own Deno web server. Import and call `handle` from the generated entry script to render requests: + + ```ts + import { serve } from "https://deno.land/std@0.132.0/http/server.ts"; + import { handle } from './dist/entry.mjs'; + + serve((req: Request) => { + // Check the request, maybe do static file handling here. + + return handle(req); + }); + ``` +
      + +
      + port and hostname + + You can set the port (default: `8085`) and hostname (default: `0.0.0.0`) for the deno server to use. If `start` is false, this has no effect; your own server must configure the port and hostname. + + ```js + import { defineConfig } from 'astro/config'; + import deno from '@astrojs/deno'; + + export default defineConfig({ + adapter: deno({ + port: 8081, + hostname: 'myhost' + }) + }); +``` +
      + +## Examples + +The [Astro Deno](https://github.com/withastro/astro/tree/main/examples/deno) example includes a `preview:deno` command that runs the entry script directly. Run `npm run build` then `npm run preview:deno` to run the production deno server. + +## Troubleshooting + +For help, check out the `#support-threads` channel on [Discord](https://astro.build/chat). Our friendly Support Squad members are here to help! + +You can also check our [Astro Integration Documentation][astro-integration] for more on integrations. + +## Contributing + +This package is maintained by Astro's Core team. You're welcome to submit an issue or PR! + +## Changelog + +See [CHANGELOG.md](CHANGELOG.md) for a history of changes to this integration. + +[astro-integration]: https://docs.astro.build/en/guides/integrations-guide/ diff --git a/packages/integrations/deno/package.json b/packages/integrations/deno/package.json index 8392a1469..c20e2d417 100644 --- a/packages/integrations/deno/package.json +++ b/packages/integrations/deno/package.json @@ -1,7 +1,7 @@ { "name": "@astrojs/deno", "description": "Deploy your site to a Deno server", - "version": "0.1.5", + "version": "0.1.10", "type": "module", "types": "./dist/index.d.ts", "author": "withastro", @@ -11,8 +11,11 @@ "url": "https://github.com/withastro/astro.git", "directory": "packages/integrations/deno" }, + "keywords": [ + "astro-adapter" + ], "bugs": "https://github.com/withastro/astro/issues", - "homepage": "https://astro.build", + "homepage": "https://docs.astro.build/en/guides/integrations-guide/deno/", "exports": { ".": "./dist/index.js", "./server.js": "./dist/server.js", @@ -25,7 +28,7 @@ "test": "deno test --allow-run --allow-env --allow-read --allow-net ./test/" }, "dependencies": { - "esbuild": "^0.14.42" + "esbuild": "^0.14.43" }, "devDependencies": { "astro": "workspace:*", diff --git a/packages/integrations/deno/readme.md b/packages/integrations/deno/readme.md deleted file mode 100644 index 4b3dc959f..000000000 --- a/packages/integrations/deno/readme.md +++ /dev/null @@ -1,66 +0,0 @@ -# @astrojs/deno - -A server-side rendering adapter for use with Deno targets. Write your code in Astro/Node and deploy to Deno servers. - -In your astro.config.mjs use: - -```js -import { defineConfig } from 'astro/config'; -import deno from '@astrojs/deno'; - -export default defineConfig({ - adapter: deno() -}); -``` - -After performing a build there will be a `dist/server/entry.mjs` module. You can start a server simply by importing this module: - -```js -import './dist/entry.mjs'; -``` - -## API - -### Adapter options - -This adapter automatically starts a server when it is imported. You can configure this through options: - -```js -import { defineConfig } from 'astro/config'; -import deno from '@astrojs/deno'; - -export default defineConfig({ - adapter: deno({ - start: false - }) -}); -``` - -If disabling start you need to write your own web server and use `handle` to render requests: - -```ts -import { serve } from "https://deno.land/std@0.132.0/http/server.ts"; -import { handle } from './dist/entry.mjs'; - -serve((req: Request) => { - // Check the request, maybe do static file handling here. - - return handle(req); -}); -``` - ----- - -You an also pass in a port/hostname to use: - -```js -import { defineConfig } from 'astro/config'; -import deno from '@astrojs/deno'; - -export default defineConfig({ - adapter: deno({ - port: 8081, - hostname: 'myhost' - }) -}); -``` diff --git a/packages/integrations/deno/src/index.ts b/packages/integrations/deno/src/index.ts index 0dad8e8ef..9a6df4f76 100644 --- a/packages/integrations/deno/src/index.ts +++ b/packages/integrations/deno/src/index.ts @@ -9,6 +9,11 @@ interface Options { hostname?: string; } +const SHIM = `globalThis.process = { + argv: [], + env: Deno.env.toObject(), +};`; + export function getAdapter(args?: Options): AstroAdapter { return { name: '@astrojs/deno', @@ -63,6 +68,9 @@ export default function createIntegration(args?: Options): AstroIntegration { format: 'esm', bundle: true, external: ['@astrojs/markdown-remark'], + banner: { + js: SHIM, + }, }); // Remove chunks, if they exist. Since we have bundled via esbuild these chunks are trash. diff --git a/packages/integrations/deno/src/server.ts b/packages/integrations/deno/src/server.ts index eb83c8eae..b18e6034c 100644 --- a/packages/integrations/deno/src/server.ts +++ b/packages/integrations/deno/src/server.ts @@ -1,8 +1,3 @@ -// NOTE(fks): Side-effect -- shim.js must run first. This isn't guaranteed by -// the language, but it is a Node.js behavior that we rely on here. Keep this -// separate from the other imports so that it doesn't get organized & reordered. -import './shim.js'; - // Normal Imports import type { SSRManifest } from 'astro'; import { App } from 'astro/app'; @@ -27,8 +22,10 @@ export function start(manifest: SSRManifest, options: Options) { const clientRoot = new URL('../client/', import.meta.url); const app = new App(manifest); - const handler = async (request: Request) => { + const handler = async (request: Request, connInfo: any) => { if (app.match(request)) { + let ip = connInfo?.remoteAddr?.hostname; + Reflect.set(request, Symbol.for('astro.clientAddress'), ip); return await app.render(request); } @@ -45,6 +42,7 @@ export function start(manifest: SSRManifest, options: Options) { }); _startPromise = Promise.resolve(_server.listenAndServe()); + // eslint-disable-next-line no-console console.error(`Server running on port ${port}`); } diff --git a/packages/integrations/deno/src/shim.ts b/packages/integrations/deno/src/shim.ts deleted file mode 100644 index 62e82ba30..000000000 --- a/packages/integrations/deno/src/shim.ts +++ /dev/null @@ -1,5 +0,0 @@ -(globalThis as any).process = { - argv: [], - // @ts-ignore - env: Deno.env.toObject(), -}; diff --git a/packages/integrations/deno/test/fixtures/basics/package.json b/packages/integrations/deno/test/fixtures/basics/package.json index 7800873f7..18d1e50e7 100644 --- a/packages/integrations/deno/test/fixtures/basics/package.json +++ b/packages/integrations/deno/test/fixtures/basics/package.json @@ -5,6 +5,8 @@ "dependencies": { "astro": "workspace:*", "@astrojs/deno": "workspace:*", - "@astrojs/react": "workspace:*" + "@astrojs/react": "workspace:*", + "react": "^18.1.0", + "react-dom": "^18.1.0" } } diff --git a/packages/integrations/image/.npmignore b/packages/integrations/image/.npmignore new file mode 100644 index 000000000..65e3ba2ed --- /dev/null +++ b/packages/integrations/image/.npmignore @@ -0,0 +1 @@ +test/ diff --git a/packages/integrations/image/CHANGELOG.md b/packages/integrations/image/CHANGELOG.md new file mode 100644 index 000000000..d39e9a977 --- /dev/null +++ b/packages/integrations/image/CHANGELOG.md @@ -0,0 +1,56 @@ +# @astrojs/image + +## 0.1.3 + +### Patch Changes + +- [#3957](https://github.com/withastro/astro/pull/3957) [`2a7dd040e`](https://github.com/withastro/astro/commit/2a7dd040e8a65d62fbb3bbd7308f523bd48deda5) Thanks [@tony-sull](https://github.com/tony-sull)! - Improves the `astro dev` experience when using a third-party hosted image service + +* [#3965](https://github.com/withastro/astro/pull/3965) [`299b4afca`](https://github.com/withastro/astro/commit/299b4afcab090bbe014d4eaf2a5ea439e8436bcc) Thanks [@tony-sull](https://github.com/tony-sull)! - Adding a unique hash to remote images built for SSG to ensure unique URLs are always de-duplicated + +## 0.1.2 + +### Patch Changes + +- [#3885](https://github.com/withastro/astro/pull/3885) [`bf5d1cc1e`](https://github.com/withastro/astro/commit/bf5d1cc1e71da38a14658c615e9481f2145cc6e7) Thanks [@delucis](https://github.com/delucis)! - Integration README fixes + +## 0.1.1 + +### Patch Changes + +- [#3876](https://github.com/withastro/astro/pull/3876) [`f9614128`](https://github.com/withastro/astro/commit/f9614128622583cba6f65cb4202d56a71b4269a3) Thanks [@tony-sull](https://github.com/tony-sull)! - Bug: Updating the component to default to async image decoding + +## 0.1.0 + +### Minor Changes + +- [#3866](https://github.com/withastro/astro/pull/3866) [`89d76753`](https://github.com/withastro/astro/commit/89d76753a0dc50b2967d1fa9d36e34bde2722b83) Thanks [@tony-sull](https://github.com/tony-sull)! - The new `` component adds art direction support for building responsive images with multiple sizes and file types :tada: + +### Patch Changes + +- [#3865](https://github.com/withastro/astro/pull/3865) [`1f9e4857`](https://github.com/withastro/astro/commit/1f9e4857ff2b2cb7db89d619618cdf546cd3b3dc) Thanks [@delucis](https://github.com/delucis)! - Small README fixes + +* [#3854](https://github.com/withastro/astro/pull/3854) [`b012ee55`](https://github.com/withastro/astro/commit/b012ee55b107dea0730286263b27d83e530fad5d) Thanks [@bholmesdev](https://github.com/bholmesdev)! - [astro add] Support adapters and third party packages + +- [#3848](https://github.com/withastro/astro/pull/3848) [`502f0631`](https://github.com/withastro/astro/commit/502f0631317fe1b23582d4126c44f44cb0b0716f) Thanks [@matthewp](https://github.com/matthewp)! - Allow importing the Image component from @astrojs/image + +* [#3869](https://github.com/withastro/astro/pull/3869) [`0aaef1c4`](https://github.com/withastro/astro/commit/0aaef1c48bacff5a05498af201d456efeac82ac2) Thanks [@tony-sull](https://github.com/tony-sull)! - Bugfix: fixing a bug that broke builds in NPM workspaces + +## 0.0.4 + +### Patch Changes + +- [#3812](https://github.com/withastro/astro/pull/3812) [`5ccccace`](https://github.com/withastro/astro/commit/5ccccace0cc3055117f118a88231999fab585a3b) Thanks [@tony-sull](https://github.com/tony-sull)! - - Updates how the `` component is exported to support older versions of Astro + - Adds an example of using the `` component in markdown pages + +## 0.0.3 + +### Patch Changes + +- [#3795](https://github.com/withastro/astro/pull/3795) [`d143d24c`](https://github.com/withastro/astro/commit/d143d24c7246153e6f66d8e0f3f9c78cadfee258) Thanks [@tony-sull](https://github.com/tony-sull)! - Automatically adds the required `vite.optimizeDeps` config for `sharp`. Also ensures that only whole numbers are passed to sharp's resize transform + +## 0.0.2 + +### Patch Changes + +- [#3788](https://github.com/withastro/astro/pull/3788) [`f4943e0f`](https://github.com/withastro/astro/commit/f4943e0fbced044f0ba4435cb41d77b67c98e69f) Thanks [@tony-sull](https://github.com/tony-sull)! - Initial release! 🎉 diff --git a/packages/integrations/image/README.md b/packages/integrations/image/README.md new file mode 100644 index 000000000..c24a84e17 --- /dev/null +++ b/packages/integrations/image/README.md @@ -0,0 +1,220 @@ +# @astrojs/image 📷 + +> ⚠️ This integration is still experimental! Only node environments are supported currently, stay tuned for Deno support in the future! + +This **[Astro integration][astro-integration]** makes it easy to optimize images in your [Astro project](https://astro.build), with full support for SSG builds and server-side rendering! + +- [Why `@astrojs/image`?](#why-astrojsimage) +- [Installation](#installation) +- [Usage](#usage) +- [Configuration](#configuration) +- [Examples](#examples) +- [Troubleshooting](#troubleshooting) +- [Contributing](#contributing) +- [Changelog](#changelog) + +## Why `@astrojs/image`? + +Images play a big role in overall site performance and usability. Serving properly sized images makes all the difference but is often tricky to automate. + +This integration provides `` and `` components as well as a basic image transformer powered by [sharp](https://sharp.pixelplumbing.com/), with full support for static sites and server-side rendering. The built-in `sharp` transformer is also replacable, opening the door for future integrations that work with your favorite hosted image service. + +## Installation + +
      + Quick Install + +The `astro add` command-line tool automates the installation for you. Run one of the following commands in a new terminal window. (If you aren't sure which package manager you're using, run the first command.) Then, follow the prompts, and type "y" in the terminal (meaning "yes") for each one. + + ```sh + # Using NPM + npx astro add image + # Using Yarn + yarn astro add image + # Using PNPM + pnpx astro add image + ``` + +Then, restart the dev server by typing `CTRL-C` and then `npm run astro dev` in the terminal window that was running Astro. + +Because this command is new, it might not properly set things up. If that happens, [feel free to log an issue on our GitHub](https://github.com/withastro/astro/issues) and try the manual installation steps below. +
      + +
      + Manual Install + +First, install the `@astrojs/image` package using your package manager. If you're using npm or aren't sure, run this in the terminal: +```sh +npm install @astrojs/image +``` +Then, apply this integration to your `astro.config.*` file using the `integrations` property: + +__`astro.config.mjs`__ + +```js +import image from '@astrojs/image'; + +export default { + // ... + integrations: [image()], +} +``` + +Then, restart the dev server. +
      + +## Usage + +The built-in `` component is used to create an optimized `` for both remote images hosted on other domains as well as local images imported from your project's `src` directory. + +The included `sharp` transformer supports resizing images and encoding them to different image formats. Third-party image services will be able to add support for custom transformations as well (ex: `blur`, `filter`, `rotate`, etc). + +## Configuration + +The intergration can be configured to run with a different image service, either a hosted image service or a full image transformer that runs locally in your build or SSR deployment. + +> During development, local images may not have been published yet and would not be available to hosted image services. Local images will always use the built-in `sharp` service when using `astro dev`. + +There are currently no other configuration options for the `@astrojs/image` integration. Please [open an issue](https://github.com/withastro/astro/issues/new/choose) if you have a compelling use case to share. + +
      + config.serviceEntryPoint + + The `serviceEntryPoint` should resolve to the image service installed from NPM. The default entry point is `@astrojs/image/sharp`, which resolves to the entry point exported from this integration's `package.json`. + +```js +// astro.config.mjs +import image from '@astrojs/image'; + +export default { + integrations: [image({ + // Example: The entrypoint for a third-party image service installed from NPM + serviceEntryPoint: 'my-image-service/astro.js' + })], +} +``` +
      + +## Examples + +
      + Local images + + Image files in your project's `src` directory can be imported in frontmatter and passed directly to the `` component. All other properties are optional and will default to the original image file's properties if not provided. + +```html +--- +import { Image } from '@astrojs/image/components'; +import heroImage from '../assets/hero.png'; +--- + +// optimized image, keeping the original width, height, and image format + + +// height will be recalculated to match the original aspect ratio + + +// cropping to a specific width and height + + +// cropping to a specific aspect ratio and converting to an avif format + + +// image imports can also be inlined directly + +``` +
      + +
      + Remote images + + Remote images can be transformed with the `` component. The `` component needs to know the final dimensions for the `` element to avoid content layout shifts. For remote images, this means you must either provide `width` and `height`, or one of the dimensions plus the required `aspectRatio`. + +```html +--- +import { Image } from '@astrojs/image/components'; + +const imageUrl = 'https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png'; +--- + +// cropping to a specific width and height + + +// height will be recalculated to match the aspect ratio + + +// cropping to a specific height and aspect ratio and converting to an avif format + +``` +
      + +
      +Images in markdown + + The `` component can also be used to optimize images in markdown pages. For local images imported from your project's `src` directory, use Astro's the `setup` frontmatter to import the image file. + +```html +--- +setup: | + import { Image } from '@astrojs/image/components' + import hero from '../../assets/blog/introducing-astro.jpg' +title: Hello world! +publishDate: 12 Sep 2021 +name: Nate Moore +value: 128 +description: Just a Hello World Post! +--- + + + +``` +
      + +
      +Responsive pictures + + The `` component can be used to automatically build a `` with multiple sizes and formats. Check out [MDN](https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images#art_direction) for a deep dive into responsive images and art direction. + + By default, the picture will include formats for `avif` and `webp` in addition to the image's original format. + + For remote images, an `aspectRatio` is required to ensure the correct `height` can be calculated at build time. + +```html +--- +import { Picture } from '@astrojs/image/components'; +import hero from '../assets/hero.png'; + +const imageUrl = 'https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png'; +--- + +// Local image with multiple sizes + + +// Remote image (aspect ratio is required) + + +// Inlined imports are supported + +``` + +
      + +## Troubleshooting +- If your installation doesn't seem to be working, make sure to restart the dev server. +- If you edit and save a file and don't see your site update accordingly, try refreshing the page. +- If you edit and save a file and don't see your site update accordingly, try refreshing the page. +- If refreshing the page doesn't update your preview, or if a new installation doesn't seem to be working, then restart the dev server. + +For help, check out the `#support-threads` channel on [Discord](https://astro.build/chat). Our friendly Support Squad members are here to help! + +You can also check our [Astro Integration Documentation][astro-integration] for more on integrations. + +[astro-integration]: https://docs.astro.build/en/guides/integrations-guide/ + +## Contributing + +This package is maintained by Astro's Core team. You're welcome to submit an issue or PR! + +## Changelog + +See [CHANGELOG.md](CHANGELOG.md) for a history of changes to this integration. diff --git a/packages/integrations/image/components/Image.astro b/packages/integrations/image/components/Image.astro new file mode 100644 index 000000000..18e35d1a6 --- /dev/null +++ b/packages/integrations/image/components/Image.astro @@ -0,0 +1,30 @@ +--- +// @ts-ignore +import { getImage } from '../dist/index.js'; +import type { ImageAttributes, ImageMetadata, TransformOptions, OutputFormat } from '../dist/types'; + +export interface LocalImageProps extends Omit, Omit { + src: ImageMetadata | Promise<{ default: ImageMetadata }>; +} + +export interface RemoteImageProps extends TransformOptions, ImageAttributes { + src: string; + format: OutputFormat; + width: number; + height: number; +} + +export type Props = LocalImageProps | RemoteImageProps; + +const { loading = "lazy", decoding = "async", ...props } = Astro.props as Props; + +const attrs = await getImage(props); +--- + + + + diff --git a/packages/integrations/image/components/Picture.astro b/packages/integrations/image/components/Picture.astro new file mode 100644 index 000000000..badfc7f46 --- /dev/null +++ b/packages/integrations/image/components/Picture.astro @@ -0,0 +1,39 @@ +--- +import { getPicture } from '../dist/index.js'; +import type { ImageAttributes, ImageMetadata, OutputFormat, PictureAttributes, TransformOptions } from '../dist/types'; + +export interface LocalImageProps extends Omit, Omit, Pick { + src: ImageMetadata | Promise<{ default: ImageMetadata }>; + alt?: string; + sizes: HTMLImageElement['sizes']; + widths: number[]; + formats?: OutputFormat[]; +} + +export interface RemoteImageProps extends Omit, TransformOptions, Pick { + src: string; + alt?: string; + sizes: HTMLImageElement['sizes']; + widths: number[]; + aspectRatio: TransformOptions['aspectRatio']; + formats?: OutputFormat[]; +} + +export type Props = LocalImageProps | RemoteImageProps; + +const { src, alt, sizes, widths, aspectRatio, formats = ['avif', 'webp'], loading = 'lazy', decoding = 'async', ...attrs } = Astro.props as Props; + +const { image, sources } = await getPicture({ src, widths, formats, aspectRatio }); +--- + + + {sources.map(attrs => ( + ))} + + + + diff --git a/packages/integrations/image/components/index.ts b/packages/integrations/image/components/index.ts new file mode 100644 index 000000000..be0e10130 --- /dev/null +++ b/packages/integrations/image/components/index.ts @@ -0,0 +1,2 @@ +export { default as Image } from './Image.astro'; +export { default as Picture } from './Picture.astro'; diff --git a/packages/integrations/image/package.json b/packages/integrations/image/package.json new file mode 100644 index 000000000..816f08141 --- /dev/null +++ b/packages/integrations/image/package.json @@ -0,0 +1,60 @@ +{ + "name": "@astrojs/image", + "description": "Load and transform images in your Astro site.", + "version": "0.1.3", + "type": "module", + "types": "./dist/types.d.ts", + "author": "withastro", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/withastro/astro.git", + "directory": "packages/integrations/image" + }, + "keywords": [ + "astro-integration", + "astro-component", + "withastro", + "image" + ], + "bugs": "https://github.com/withastro/astro/issues", + "homepage": "https://docs.astro.build/en/guides/integrations-guide/image/", + "exports": { + ".": { + "astro": "./components/index.js", + "import": "./dist/index.js" + }, + "./sharp": "./dist/loaders/sharp.js", + "./endpoints/dev": "./dist/endpoints/dev.js", + "./endpoints/prod": "./dist/endpoints/prod.js", + "./components": "./components/index.js", + "./package.json": "./package.json" + }, + "files": [ + "components", + "dist", + "src", + "types" + ], + "scripts": { + "build": "astro-scripts build \"src/**/*.ts\" && tsc", + "build:ci": "astro-scripts build \"src/**/*.ts\"", + "dev": "astro-scripts dev \"src/**/*.ts\"", + "test": "mocha --exit --timeout 20000 test" + }, + "dependencies": { + "etag": "^1.8.1", + "image-size": "^1.0.1", + "image-type": "^4.1.0", + "mrmime": "^1.0.0", + "sharp": "^0.30.6", + "slash": "^4.0.0" + }, + "devDependencies": { + "@types/etag": "^1.8.1", + "@types/sharp": "^0.30.4", + "astro": "workspace:*", + "astro-scripts": "workspace:*", + "tiny-glob": "^0.2.9" + } +} diff --git a/packages/integrations/image/src/build/ssg.ts b/packages/integrations/image/src/build/ssg.ts new file mode 100644 index 000000000..951f62331 --- /dev/null +++ b/packages/integrations/image/src/build/ssg.ts @@ -0,0 +1,71 @@ +import fs from 'fs/promises'; +import path from 'path'; +import { fileURLToPath } from 'url'; +import { OUTPUT_DIR } from '../constants.js'; +import type { SSRImageService, TransformOptions } from '../types.js'; +import { isRemoteImage, loadLocalImage, loadRemoteImage } from '../utils/images.js'; +import { ensureDir } from '../utils/paths.js'; + +export interface SSGBuildParams { + loader: SSRImageService; + staticImages: Map>; + srcDir: URL; + outDir: URL; +} + +export async function ssgBuild({ loader, staticImages, srcDir, outDir }: SSGBuildParams) { + const inputFiles = new Set(); + + // process transforms one original image file at a time + for await (const [src, transformsMap] of staticImages) { + let inputFile: string | undefined = undefined; + let inputBuffer: Buffer | undefined = undefined; + + if (isRemoteImage(src)) { + // try to load the remote image + inputBuffer = await loadRemoteImage(src); + } else { + const inputFileURL = new URL(`.${src}`, srcDir); + inputFile = fileURLToPath(inputFileURL); + inputBuffer = await loadLocalImage(inputFile); + + // track the local file used so the original can be copied over + inputFiles.add(inputFile); + } + + if (!inputBuffer) { + // eslint-disable-next-line no-console + console.warn(`"${src}" image could not be fetched`); + continue; + } + + const transforms = Array.from(transformsMap.entries()); + + // process each transformed versiono of the + for await (const [filename, transform] of transforms) { + let outputFile: string; + + if (isRemoteImage(src)) { + const outputFileURL = new URL(path.join('./', OUTPUT_DIR, path.basename(filename)), outDir); + outputFile = fileURLToPath(outputFileURL); + } else { + const outputFileURL = new URL(path.join('./', OUTPUT_DIR, filename), outDir); + outputFile = fileURLToPath(outputFileURL); + } + + const { data } = await loader.transform(inputBuffer, transform); + + ensureDir(path.dirname(outputFile)); + + await fs.writeFile(outputFile, data); + } + } + + // copy all original local images to dist + for await (const original of inputFiles) { + const to = original.replace(fileURLToPath(srcDir), fileURLToPath(outDir)); + + await ensureDir(path.dirname(to)); + await fs.copyFile(original, to); + } +} diff --git a/packages/integrations/image/src/build/ssr.ts b/packages/integrations/image/src/build/ssr.ts new file mode 100644 index 000000000..2585868b9 --- /dev/null +++ b/packages/integrations/image/src/build/ssr.ts @@ -0,0 +1,28 @@ +import fs from 'fs/promises'; +import path from 'path'; +import glob from 'tiny-glob'; +import { fileURLToPath } from 'url'; +import { ensureDir } from '../utils/paths.js'; + +async function globImages(dir: URL) { + const srcPath = fileURLToPath(dir); + return await glob(`${srcPath}/**/*.{heic,heif,avif,jpeg,jpg,png,tiff,webp,gif}`, { + absolute: true, + }); +} + +export interface SSRBuildParams { + srcDir: URL; + outDir: URL; +} + +export async function ssrBuild({ srcDir, outDir }: SSRBuildParams) { + const images = await globImages(srcDir); + + for await (const image of images) { + const to = image.replace(fileURLToPath(srcDir), fileURLToPath(outDir)); + + await ensureDir(path.dirname(to)); + await fs.copyFile(image, to); + } +} diff --git a/packages/integrations/image/src/constants.ts b/packages/integrations/image/src/constants.ts new file mode 100644 index 000000000..db52614c5 --- /dev/null +++ b/packages/integrations/image/src/constants.ts @@ -0,0 +1,3 @@ +export const PKG_NAME = '@astrojs/image'; +export const ROUTE_PATTERN = '/_image'; +export const OUTPUT_DIR = '/_image'; diff --git a/packages/integrations/image/src/endpoints/dev.ts b/packages/integrations/image/src/endpoints/dev.ts new file mode 100644 index 000000000..dfa7f4900 --- /dev/null +++ b/packages/integrations/image/src/endpoints/dev.ts @@ -0,0 +1,32 @@ +import type { APIRoute } from 'astro'; +import { lookup } from 'mrmime'; +import loader from '../loaders/sharp.js'; +import { loadImage } from '../utils/images.js'; + +export const get: APIRoute = async ({ request }) => { + try { + const url = new URL(request.url); + const transform = loader.parseTransform(url.searchParams); + + if (!transform) { + return new Response('Bad Request', { status: 400 }); + } + + const inputBuffer = await loadImage(transform.src); + + if (!inputBuffer) { + return new Response(`"${transform.src} not found`, { status: 404 }); + } + + const { data, format } = await loader.transform(inputBuffer, transform); + + return new Response(data, { + status: 200, + headers: { + 'Content-Type': lookup(format) || '', + }, + }); + } catch (err: unknown) { + return new Response(`Server Error: ${err}`, { status: 500 }); + } +}; diff --git a/packages/integrations/image/src/endpoints/prod.ts b/packages/integrations/image/src/endpoints/prod.ts new file mode 100644 index 000000000..8a15c2e88 --- /dev/null +++ b/packages/integrations/image/src/endpoints/prod.ts @@ -0,0 +1,45 @@ +import type { APIRoute } from 'astro'; +import etag from 'etag'; +import { lookup } from 'mrmime'; +import { fileURLToPath } from 'url'; +// @ts-ignore +import loader from 'virtual:image-loader'; +import { isRemoteImage, loadLocalImage, loadRemoteImage } from '../utils/images.js'; + +export const get: APIRoute = async ({ request }) => { + try { + const url = new URL(request.url); + const transform = loader.parseTransform(url.searchParams); + + if (!transform) { + return new Response('Bad Request', { status: 400 }); + } + + let inputBuffer: Buffer | undefined = undefined; + + if (isRemoteImage(transform.src)) { + inputBuffer = await loadRemoteImage(transform.src); + } else { + const pathname = fileURLToPath(new URL(`../client${transform.src}`, import.meta.url)); + inputBuffer = await loadLocalImage(pathname); + } + + if (!inputBuffer) { + return new Response(`"${transform.src} not found`, { status: 404 }); + } + + const { data, format } = await loader.transform(inputBuffer, transform); + + return new Response(data, { + status: 200, + headers: { + 'Content-Type': lookup(format) || '', + 'Cache-Control': 'public, max-age=31536000', + ETag: etag(inputBuffer), + Date: new Date().toUTCString(), + }, + }); + } catch (err: unknown) { + return new Response(`Server Error: ${err}`, { status: 500 }); + } +}; diff --git a/packages/integrations/image/src/index.ts b/packages/integrations/image/src/index.ts new file mode 100644 index 000000000..81ef8c6b9 --- /dev/null +++ b/packages/integrations/image/src/index.ts @@ -0,0 +1,5 @@ +import integration from './integration.js'; +export * from './lib/get-image.js'; +export * from './lib/get-picture.js'; + +export default integration; diff --git a/packages/integrations/image/src/integration.ts b/packages/integrations/image/src/integration.ts new file mode 100644 index 000000000..afbeb00a9 --- /dev/null +++ b/packages/integrations/image/src/integration.ts @@ -0,0 +1,93 @@ +import type { AstroConfig, AstroIntegration } from 'astro'; +import { ssgBuild } from './build/ssg.js'; +import { ssrBuild } from './build/ssr.js'; +import { PKG_NAME, ROUTE_PATTERN } from './constants.js'; +import { IntegrationOptions, TransformOptions } from './types.js'; +import { filenameFormat, propsToFilename } from './utils/paths.js'; +import { createPlugin } from './vite-plugin-astro-image.js'; + +export default function integration(options: IntegrationOptions = {}): AstroIntegration { + const resolvedOptions = { + serviceEntryPoint: '@astrojs/image/sharp', + ...options, + }; + + // During SSG builds, this is used to track all transformed images required. + const staticImages = new Map>(); + + let _config: AstroConfig; + let mode: 'ssr' | 'ssg'; + + function getViteConfiguration() { + return { + plugins: [createPlugin(_config, resolvedOptions)], + optimizeDeps: { + include: ['image-size', 'sharp'], + }, + ssr: { + noExternal: ['@astrojs/image', resolvedOptions.serviceEntryPoint], + }, + }; + } + + return { + name: PKG_NAME, + hooks: { + 'astro:config:setup': ({ command, config, injectRoute, updateConfig }) => { + _config = config; + + // Always treat `astro dev` as SSR mode, even without an adapter + mode = command === 'dev' || config.adapter ? 'ssr' : 'ssg'; + + updateConfig({ vite: getViteConfiguration() }); + + if (mode === 'ssr') { + injectRoute({ + pattern: ROUTE_PATTERN, + entryPoint: + command === 'dev' ? '@astrojs/image/endpoints/dev' : '@astrojs/image/endpoints/prod', + }); + } + }, + 'astro:server:setup': async () => { + globalThis.astroImage = {}; + }, + 'astro:build:setup': () => { + // Used to cache all images rendered to HTML + // Added to globalThis to share the same map in Node and Vite + function addStaticImage(transform: TransformOptions) { + const srcTranforms = staticImages.has(transform.src) + ? staticImages.get(transform.src)! + : new Map(); + + srcTranforms.set(propsToFilename(transform), transform); + + staticImages.set(transform.src, srcTranforms); + } + + // Helpers for building static images should only be available for SSG + globalThis.astroImage = + mode === 'ssg' + ? { + addStaticImage, + filenameFormat, + } + : {}; + }, + 'astro:build:done': async ({ dir }) => { + if (mode === 'ssr') { + // for SSR builds, copy all image files from src to dist + // to make sure they are available for use in production + await ssrBuild({ srcDir: _config.srcDir, outDir: dir }); + } else { + // for SSG builds, build all requested image transforms to dist + const loader = globalThis?.astroImage?.loader; + + if (loader && 'transform' in loader && staticImages.size > 0) { + await ssgBuild({ loader, staticImages, srcDir: _config.srcDir, outDir: dir }); + } + } + }, + }, + }; +} diff --git a/packages/integrations/image/src/lib/get-image.ts b/packages/integrations/image/src/lib/get-image.ts new file mode 100644 index 000000000..e0f57e873 --- /dev/null +++ b/packages/integrations/image/src/lib/get-image.ts @@ -0,0 +1,154 @@ +import slash from 'slash'; +import { ROUTE_PATTERN } from '../constants.js'; +import sharp from '../loaders/sharp.js'; +import { + ImageAttributes, + ImageMetadata, + ImageService, + isSSRService, + OutputFormat, + TransformOptions, +} from '../types.js'; +import { isRemoteImage, parseAspectRatio } from '../utils/images.js'; + +export interface GetImageTransform extends Omit { + src: string | ImageMetadata | Promise<{ default: ImageMetadata }>; +} + +function resolveSize(transform: TransformOptions): TransformOptions { + // keep width & height as provided + if (transform.width && transform.height) { + return transform; + } + + if (!transform.width && !transform.height) { + throw new Error(`"width" and "height" cannot both be undefined`); + } + + if (!transform.aspectRatio) { + throw new Error( + `"aspectRatio" must be included if only "${transform.width ? 'width' : 'height'}" is provided` + ); + } + + let aspectRatio: number; + + // parse aspect ratio strings, if required (ex: "16:9") + if (typeof transform.aspectRatio === 'number') { + aspectRatio = transform.aspectRatio; + } else { + const [width, height] = transform.aspectRatio.split(':'); + aspectRatio = Number.parseInt(width) / Number.parseInt(height); + } + + if (transform.width) { + // only width was provided, calculate height + return { + ...transform, + width: transform.width, + height: Math.round(transform.width / aspectRatio), + } as TransformOptions; + } else if (transform.height) { + // only height was provided, calculate width + return { + ...transform, + width: Math.round(transform.height * aspectRatio), + height: transform.height, + }; + } + + return transform; +} + +async function resolveTransform(input: GetImageTransform): Promise { + // for remote images, only validate the width and height props + if (typeof input.src === 'string') { + return resolveSize(input as TransformOptions); + } + + // resolve the metadata promise, usually when the ESM import is inlined + const metadata = 'then' in input.src ? (await input.src).default : input.src; + + let { width, height, aspectRatio, format = metadata.format, ...rest } = input; + + if (!width && !height) { + // neither dimension was provided, use the file metadata + width = metadata.width; + height = metadata.height; + } else if (width) { + // one dimension was provided, calculate the other + let ratio = parseAspectRatio(aspectRatio) || metadata.width / metadata.height; + height = height || Math.round(width / ratio); + } else if (height) { + // one dimension was provided, calculate the other + let ratio = parseAspectRatio(aspectRatio) || metadata.width / metadata.height; + width = width || Math.round(height * ratio); + } + + return { + ...rest, + src: metadata.src, + width, + height, + aspectRatio, + format: format as OutputFormat, + }; +} + +/** + * Gets the HTML attributes required to build an `` for the transformed image. + * + * @param transform @type {TransformOptions} The transformations requested for the optimized image. + * @returns @type {ImageAttributes} The HTML attributes to be included on the built `` element. + */ +export async function getImage(transform: GetImageTransform): Promise { + if (!transform.src) { + throw new Error('[@astrojs/image] `src` is required'); + } + + let loader = globalThis.astroImage?.loader; + + if (!loader) { + // @ts-ignore + const { default: mod } = await import('virtual:image-loader'); + loader = mod as ImageService; + globalThis.astroImage = globalThis.astroImage || {}; + globalThis.astroImage.loader = loader; + } + + const resolved = await resolveTransform(transform); + + const attributes = await loader.getImageAttributes(resolved); + + // @ts-ignore + const isDev = import.meta.env.DEV; + const isLocalImage = !isRemoteImage(resolved.src); + + const _loader = isDev && isLocalImage ? sharp : loader; + + if (!_loader) { + throw new Error('@astrojs/image: loader not found!'); + } + + // For SSR services, build URLs for the injected route + if (isSSRService(_loader)) { + const { searchParams } = _loader.serializeTransform(resolved); + + // cache all images rendered to HTML + if (globalThis.astroImage?.addStaticImage) { + globalThis.astroImage.addStaticImage(resolved); + } + + const src = globalThis.astroImage?.filenameFormat + ? globalThis.astroImage.filenameFormat(resolved, searchParams) + : `${ROUTE_PATTERN}?${searchParams.toString()}`; + + return { + ...attributes, + src: slash(src), // Windows compat + }; + } + + // For hosted services, return the `` attributes as-is + return attributes; +} diff --git a/packages/integrations/image/src/lib/get-picture.ts b/packages/integrations/image/src/lib/get-picture.ts new file mode 100644 index 000000000..7b7273616 --- /dev/null +++ b/packages/integrations/image/src/lib/get-picture.ts @@ -0,0 +1,93 @@ +import { lookup } from 'mrmime'; +import { extname } from 'path'; +import { ImageAttributes, ImageMetadata, OutputFormat, TransformOptions } from '../types.js'; +import { parseAspectRatio } from '../utils/images.js'; +import { getImage } from './get-image.js'; + +export interface GetPictureParams { + src: string | ImageMetadata | Promise<{ default: ImageMetadata }>; + widths: number[]; + formats: OutputFormat[]; + aspectRatio?: TransformOptions['aspectRatio']; +} + +export interface GetPictureResult { + image: ImageAttributes; + sources: { type: string; srcset: string }[]; +} + +async function resolveAspectRatio({ src, aspectRatio }: GetPictureParams) { + if (typeof src === 'string') { + return parseAspectRatio(aspectRatio); + } else { + const metadata = 'then' in src ? (await src).default : src; + return parseAspectRatio(aspectRatio) || metadata.width / metadata.height; + } +} + +async function resolveFormats({ src, formats }: GetPictureParams) { + const unique = new Set(formats); + + if (typeof src === 'string') { + unique.add(extname(src).replace('.', '') as OutputFormat); + } else { + const metadata = 'then' in src ? (await src).default : src; + unique.add(extname(metadata.src).replace('.', '') as OutputFormat); + } + + return [...unique]; +} + +export async function getPicture(params: GetPictureParams): Promise { + const { src, widths } = params; + + if (!src) { + throw new Error('[@astrojs/image] `src` is required'); + } + + if (!widths || !Array.isArray(widths)) { + throw new Error('[@astrojs/image] at least one `width` is required'); + } + + const aspectRatio = await resolveAspectRatio(params); + + if (!aspectRatio) { + throw new Error('`aspectRatio` must be provided for remote images'); + } + + async function getSource(format: OutputFormat) { + const imgs = await Promise.all( + widths.map(async (width) => { + const img = await getImage({ + src, + format, + width, + height: Math.round(width / aspectRatio!), + }); + return `${img.src} ${width}w`; + }) + ); + + return { + type: lookup(format) || format, + srcset: imgs.join(','), + }; + } + + // always include the original image format + const allFormats = await resolveFormats(params); + + const image = await getImage({ + src, + width: Math.max(...widths), + aspectRatio, + format: allFormats[allFormats.length - 1], + }); + + const sources = await Promise.all(allFormats.map((format) => getSource(format))); + + return { + sources, + image, + }; +} diff --git a/packages/integrations/image/src/loaders/sharp.ts b/packages/integrations/image/src/loaders/sharp.ts new file mode 100644 index 000000000..b4c5e18fd --- /dev/null +++ b/packages/integrations/image/src/loaders/sharp.ts @@ -0,0 +1,111 @@ +import sharp from 'sharp'; +import type { OutputFormat, SSRImageService, TransformOptions } from '../types.js'; +import { isAspectRatioString, isOutputFormat } from '../utils/images.js'; + +class SharpService implements SSRImageService { + async getImageAttributes(transform: TransformOptions) { + // strip off the known attributes + const { width, height, src, format, quality, aspectRatio, ...rest } = transform; + + return { + ...rest, + width: width, + height: height, + }; + } + + serializeTransform(transform: TransformOptions) { + const searchParams = new URLSearchParams(); + + if (transform.quality) { + searchParams.append('q', transform.quality.toString()); + } + + if (transform.format) { + searchParams.append('f', transform.format); + } + + if (transform.width) { + searchParams.append('w', transform.width.toString()); + } + + if (transform.height) { + searchParams.append('h', transform.height.toString()); + } + + if (transform.aspectRatio) { + searchParams.append('ar', transform.aspectRatio.toString()); + } + + searchParams.append('href', transform.src); + + return { searchParams }; + } + + parseTransform(searchParams: URLSearchParams) { + if (!searchParams.has('href')) { + return undefined; + } + + let transform: TransformOptions = { src: searchParams.get('href')! }; + + if (searchParams.has('q')) { + transform.quality = parseInt(searchParams.get('q')!); + } + + if (searchParams.has('f')) { + const format = searchParams.get('f')!; + if (isOutputFormat(format)) { + transform.format = format; + } + } + + if (searchParams.has('w')) { + transform.width = parseInt(searchParams.get('w')!); + } + + if (searchParams.has('h')) { + transform.height = parseInt(searchParams.get('h')!); + } + + if (searchParams.has('ar')) { + const ratio = searchParams.get('ar')!; + + if (isAspectRatioString(ratio)) { + transform.aspectRatio = ratio; + } else { + transform.aspectRatio = parseFloat(ratio); + } + } + + return transform; + } + + async transform(inputBuffer: Buffer, transform: TransformOptions) { + const sharpImage = sharp(inputBuffer, { failOnError: false }); + + // always call rotate to adjust for EXIF data orientation + sharpImage.rotate(); + + if (transform.width || transform.height) { + const width = transform.width && Math.round(transform.width); + const height = transform.height && Math.round(transform.height); + sharpImage.resize(width, height); + } + + if (transform.format) { + sharpImage.toFormat(transform.format, { quality: transform.quality }); + } + + const { data, info } = await sharpImage.toBuffer({ resolveWithObject: true }); + + return { + data, + format: info.format as OutputFormat, + }; + } +} + +const service = new SharpService(); + +export default service; diff --git a/packages/integrations/image/src/types.ts b/packages/integrations/image/src/types.ts new file mode 100644 index 000000000..f7e0c0e5f --- /dev/null +++ b/packages/integrations/image/src/types.ts @@ -0,0 +1,143 @@ +/// +export * from './index.js'; + +interface ImageIntegration { + loader?: ImageService; + addStaticImage?: (transform: TransformOptions) => void; + filenameFormat?: (transform: TransformOptions, searchParams: URLSearchParams) => string; +} + +declare global { + // eslint-disable-next-line no-var + var astroImage: ImageIntegration | undefined; +} + +export type InputFormat = + | 'heic' + | 'heif' + | 'avif' + | 'jpeg' + | 'jpg' + | 'png' + | 'tiff' + | 'webp' + | 'gif'; + +export type OutputFormat = 'avif' | 'jpeg' | 'png' | 'webp'; + +/** + * Converts a set of image transforms to the filename to use when building for static. + * + * This is only used for static production builds and ignored when an SSR adapter is used, + * or in `astro dev` for static builds. + */ +export type FilenameFormatter = (transform: TransformOptions) => string; + +export interface IntegrationOptions { + /** + * Entry point for the @type {HostedImageService} or @type {LocalImageService} to be used. + */ + serviceEntryPoint?: string; +} + +/** + * Defines the original image and transforms that need to be applied to it. + */ +export interface TransformOptions { + /** + * Source for the original image file. + * + * For images in your project's repository, use the `src` relative to the `public` directory. + * For remote images, provide the full URL. + */ + src: string; + /** + * The output format to be used in the optimized image. + * + * @default undefined The original image format will be used. + */ + format?: OutputFormat; + /** + * The compression quality used during optimization. + * + * @default undefined Allows the image service to determine defaults. + */ + quality?: number; + /** + * The desired width of the output image. Combine with `height` to crop the image + * to an exact size, or `aspectRatio` to automatically calculate and crop the height. + */ + width?: number; + /** + * The desired height of the output image. Combine with `height` to crop the image + * to an exact size, or `aspectRatio` to automatically calculate and crop the width. + */ + height?: number; + /** + * The desired aspect ratio of the output image. Combine with either `width` or `height` + * to automatically calculate and crop the other dimension. + * + * @example 1.777 - numbers can be used for computed ratios, useful for doing `{width/height}` + * @example "16:9" - strings can be used in the format of `{ratioWidth}:{ratioHeight}`. + */ + aspectRatio?: number | `${number}:${number}`; +} + +export type ImageAttributes = astroHTML.JSX.ImgHTMLAttributes; +export type PictureAttributes = astroHTML.JSX.HTMLAttributes; + +export interface HostedImageService { + /** + * Gets the HTML attributes needed for the server rendered `` element. + */ + getImageAttributes(transform: T): Promise; +} + +export interface SSRImageService + extends HostedImageService { + /** + * Gets tthe HTML attributes needed for the server rendered `` element. + */ + getImageAttributes(transform: T): Promise>; + /** + * Serializes image transformation properties to URLSearchParams, used to build + * the final `src` that points to the self-hosted SSR endpoint. + * + * @param transform @type {TransformOptions} defining the requested image transformation. + */ + serializeTransform(transform: T): { searchParams: URLSearchParams }; + /** + * The reverse of `serializeTransform(transform)`, this parsed the @type {TransformOptions} back out of a given URL. + * + * @param searchParams @type {URLSearchParams} + * @returns @type {TransformOptions} used to generate the URL, or undefined if the URL isn't valid. + */ + parseTransform(searchParams: URLSearchParams): T | undefined; + /** + * Performs the image transformations on the input image and returns both the binary data and + * final image format of the optimized image. + * + * @param inputBuffer Binary buffer containing the original image. + * @param transform @type {TransformOptions} defining the requested transformations. + */ + transform(inputBuffer: Buffer, transform: T): Promise<{ data: Buffer; format: OutputFormat }>; +} + +export type ImageService = + | HostedImageService + | SSRImageService; + +export function isHostedService(service: ImageService): service is ImageService { + return 'getImageSrc' in service; +} + +export function isSSRService(service: ImageService): service is SSRImageService { + return 'transform' in service; +} + +export interface ImageMetadata { + src: string; + width: number; + height: number; + format: InputFormat; +} diff --git a/packages/integrations/image/src/utils/images.ts b/packages/integrations/image/src/utils/images.ts new file mode 100644 index 000000000..55a45d1ce --- /dev/null +++ b/packages/integrations/image/src/utils/images.ts @@ -0,0 +1,54 @@ +import fs from 'fs/promises'; +import type { OutputFormat, TransformOptions } from '../types.js'; + +export function isOutputFormat(value: string): value is OutputFormat { + return ['avif', 'jpeg', 'png', 'webp'].includes(value); +} + +export function isAspectRatioString(value: string): value is `${number}:${number}` { + return /^\d*:\d*$/.test(value); +} + +export function isRemoteImage(src: string) { + return /^http(s?):\/\//.test(src); +} + +export async function loadLocalImage(src: string) { + try { + return await fs.readFile(src); + } catch { + return undefined; + } +} + +export async function loadRemoteImage(src: string) { + try { + const res = await fetch(src); + + if (!res.ok) { + return undefined; + } + + return Buffer.from(await res.arrayBuffer()); + } catch { + return undefined; + } +} + +export async function loadImage(src: string) { + return isRemoteImage(src) ? await loadRemoteImage(src) : await loadLocalImage(src); +} + +export function parseAspectRatio(aspectRatio: TransformOptions['aspectRatio']) { + if (!aspectRatio) { + return undefined; + } + + // parse aspect ratio strings, if required (ex: "16:9") + if (typeof aspectRatio === 'number') { + return aspectRatio; + } else { + const [width, height] = aspectRatio.split(':'); + return parseInt(width) / parseInt(height); + } +} diff --git a/packages/integrations/image/src/utils/metadata.ts b/packages/integrations/image/src/utils/metadata.ts new file mode 100644 index 000000000..38859b817 --- /dev/null +++ b/packages/integrations/image/src/utils/metadata.ts @@ -0,0 +1,21 @@ +import fs from 'fs/promises'; +import sizeOf from 'image-size'; +import { ImageMetadata, InputFormat } from '../types.js'; + +export async function metadata(src: string): Promise { + const file = await fs.readFile(src); + + const { width, height, type, orientation } = await sizeOf(file); + const isPortrait = (orientation || 0) >= 5; + + if (!width || !height || !type) { + return undefined; + } + + return { + src, + width: isPortrait ? height : width, + height: isPortrait ? width : height, + format: type as InputFormat, + }; +} diff --git a/packages/integrations/image/src/utils/paths.ts b/packages/integrations/image/src/utils/paths.ts new file mode 100644 index 000000000..1ba299526 --- /dev/null +++ b/packages/integrations/image/src/utils/paths.ts @@ -0,0 +1,36 @@ +import fs from 'fs'; +import path from 'path'; +import { OUTPUT_DIR } from '../constants.js'; +import type { TransformOptions } from '../types.js'; +import { isRemoteImage } from './images.js'; +import { shorthash } from './shorthash.js'; + +export function ensureDir(dir: string) { + fs.mkdirSync(dir, { recursive: true }); +} + +export function propsToFilename({ src, width, height, format }: TransformOptions) { + const ext = path.extname(src); + let filename = src.replace(ext, ''); + + // for remote images, add a hash of the full URL to dedupe images with the same filename + if (isRemoteImage(src)) { + filename += `-${shorthash(src)}`; + } + + if (width && height) { + return `${filename}_${width}x${height}.${format}`; + } else if (width) { + return `${filename}_${width}w.${format}`; + } else if (height) { + return `${filename}_${height}h.${format}`; + } + + return format ? src.replace(ext, format) : src; +} + +export function filenameFormat(transform: TransformOptions) { + return isRemoteImage(transform.src) + ? path.join(OUTPUT_DIR, path.basename(propsToFilename(transform))) + : path.join(OUTPUT_DIR, path.dirname(transform.src), path.basename(propsToFilename(transform))); +} diff --git a/packages/integrations/image/src/utils/shorthash.ts b/packages/integrations/image/src/utils/shorthash.ts new file mode 100644 index 000000000..99a691ac4 --- /dev/null +++ b/packages/integrations/image/src/utils/shorthash.ts @@ -0,0 +1,67 @@ +/** + * shortdash - https://github.com/bibig/node-shorthash + * + * @license + * + * (The MIT License) + * + * Copyright (c) 2013 Bibig + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +const dictionary = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXY'; +const binary = dictionary.length; + +// refer to: http://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/ +function bitwise(str: string) { + let hash = 0; + if (str.length === 0) return hash; + for (let i = 0; i < str.length; i++) { + const ch = str.charCodeAt(i); + hash = (hash << 5) - hash + ch; + hash = hash & hash; // Convert to 32bit integer + } + return hash; +} + +export function shorthash(text: string) { + let num: number; + let result = ''; + + let integer = bitwise(text); + const sign = integer < 0 ? 'Z' : ''; // It it's negative, start with Z, which isn't in the dictionary + + integer = Math.abs(integer); + + while (integer >= binary) { + num = integer % binary; + integer = Math.floor(integer / binary); + result = dictionary[num] + result; + } + + if (integer > 0) { + result = dictionary[integer] + result; + } + + return sign + result; +} diff --git a/packages/integrations/image/src/vite-plugin-astro-image.ts b/packages/integrations/image/src/vite-plugin-astro-image.ts new file mode 100644 index 000000000..7a494e989 --- /dev/null +++ b/packages/integrations/image/src/vite-plugin-astro-image.ts @@ -0,0 +1,65 @@ +import type { AstroConfig } from 'astro'; +import type { PluginContext } from 'rollup'; +import slash from 'slash'; +import { pathToFileURL } from 'url'; +import type { Plugin, ResolvedConfig } from 'vite'; +import type { IntegrationOptions } from './types.js'; +import { metadata } from './utils/metadata.js'; + +export function createPlugin(config: AstroConfig, options: Required): Plugin { + const filter = (id: string) => + /^(?!\/_image?).*.(heic|heif|avif|jpeg|jpg|png|tiff|webp|gif)$/.test(id); + + const virtualModuleId = 'virtual:image-loader'; + + let resolvedConfig: ResolvedConfig; + let loaderModuleId: string; + + async function resolveLoader(context: PluginContext) { + if (!loaderModuleId) { + const module = await context.resolve(options.serviceEntryPoint); + if (!module) { + throw new Error(`"${options.serviceEntryPoint}" could not be found`); + } + loaderModuleId = module.id; + } + + return loaderModuleId; + } + + return { + name: '@astrojs/image', + enforce: 'pre', + configResolved(viteConfig) { + resolvedConfig = viteConfig; + }, + async resolveId(id) { + // The virtual model redirects imports to the ImageService being used + // This ensures the module is available in `astro dev` and is included + // in the SSR server bundle. + if (id === virtualModuleId) { + return await resolveLoader(this); + } + }, + async load(id) { + // only claim image ESM imports + if (!filter(id)) { + return null; + } + + const meta = await metadata(id); + + const fileUrl = pathToFileURL(id); + const src = resolvedConfig.isProduction + ? fileUrl.pathname.replace(config.srcDir.pathname, '/') + : id; + + const output = { + ...meta, + src: slash(src), // Windows compat + }; + + return `export default ${JSON.stringify(output)}`; + }, + }; +} diff --git a/packages/integrations/image/test/fixtures/basic-image/astro.config.mjs b/packages/integrations/image/test/fixtures/basic-image/astro.config.mjs new file mode 100644 index 000000000..45a11dc9d --- /dev/null +++ b/packages/integrations/image/test/fixtures/basic-image/astro.config.mjs @@ -0,0 +1,8 @@ +import { defineConfig } from 'astro/config'; +import image from '@astrojs/image'; + +// https://astro.build/config +export default defineConfig({ + site: 'http://localhost:3000', + integrations: [image()] +}); diff --git a/packages/integrations/image/test/fixtures/basic-image/package.json b/packages/integrations/image/test/fixtures/basic-image/package.json new file mode 100644 index 000000000..502e42c96 --- /dev/null +++ b/packages/integrations/image/test/fixtures/basic-image/package.json @@ -0,0 +1,10 @@ +{ + "name": "@test/basic-image", + "version": "0.0.0", + "private": true, + "dependencies": { + "@astrojs/image": "workspace:*", + "@astrojs/node": "workspace:*", + "astro": "workspace:*" + } +} diff --git a/packages/integrations/image/test/fixtures/basic-image/public/favicon.ico b/packages/integrations/image/test/fixtures/basic-image/public/favicon.ico new file mode 100644 index 000000000..578ad458b Binary files /dev/null and b/packages/integrations/image/test/fixtures/basic-image/public/favicon.ico differ diff --git a/packages/integrations/image/test/fixtures/basic-image/server/server.mjs b/packages/integrations/image/test/fixtures/basic-image/server/server.mjs new file mode 100644 index 000000000..d7a0a7a40 --- /dev/null +++ b/packages/integrations/image/test/fixtures/basic-image/server/server.mjs @@ -0,0 +1,44 @@ +import { createServer } from 'http'; +import fs from 'fs'; +import mime from 'mime'; +import { handler as ssrHandler } from '../dist/server/entry.mjs'; + +const clientRoot = new URL('../dist/client/', import.meta.url); + +async function handle(req, res) { + ssrHandler(req, res, async (err) => { + if (err) { + res.writeHead(500); + res.end(err.stack); + return; + } + + let local = new URL('.' + req.url, clientRoot); + try { + const data = await fs.promises.readFile(local); + res.writeHead(200, { + 'Content-Type': mime.getType(req.url), + }); + res.end(data); + } catch { + res.writeHead(404); + res.end(); + } + }); +} + +const server = createServer((req, res) => { + handle(req, res).catch((err) => { + console.error(err); + res.writeHead(500, { + 'Content-Type': 'text/plain', + }); + res.end(err.toString()); + }); +}); + +server.listen(8085); +console.log('Serving at http://localhost:8085'); + +// Silence weird
      diff --git a/packages/markdown/component/test/fixtures/astro-markdown/src/pages/imported-md/with-components.astro b/packages/markdown/component/test/fixtures/astro-markdown/src/pages/imported-md/with-components.astro new file mode 100644 index 000000000..97cd8f211 --- /dev/null +++ b/packages/markdown/component/test/fixtures/astro-markdown/src/pages/imported-md/with-components.astro @@ -0,0 +1,9 @@ +--- +import Layout from '../../layouts/content.astro' + +const posts = await Astro.glob('../../imported-md/*.md') +--- + + + {posts.map(({ Content }) => )} + diff --git a/packages/markdown/component/test/fixtures/astro-markdown/src/pages/jsx-expressions.md b/packages/markdown/component/test/fixtures/astro-markdown/src/pages/jsx-expressions.md new file mode 100644 index 000000000..b87efbb2d --- /dev/null +++ b/packages/markdown/component/test/fixtures/astro-markdown/src/pages/jsx-expressions.md @@ -0,0 +1,13 @@ +--- +title: Blog Post with JSX expressions +paragraph: JSX at the start of the line! +list: ['test-1', 'test-2', 'test-3'] +--- + +## {frontmatter.title} + +{frontmatter.paragraph} + +
        + {frontmatter.list.map(item =>
      • {item}
      • )} +
      diff --git a/packages/markdown/component/test/fixtures/astro-markdown/src/pages/layout-props.md b/packages/markdown/component/test/fixtures/astro-markdown/src/pages/layout-props.md new file mode 100644 index 000000000..0f87c1bd0 --- /dev/null +++ b/packages/markdown/component/test/fixtures/astro-markdown/src/pages/layout-props.md @@ -0,0 +1,4 @@ +--- +title: 'Hello world!' +layout: '../layouts/layout-props.astro' +--- \ No newline at end of file diff --git a/packages/markdown/component/test/fixtures/astro-markdown/src/pages/namespace.md b/packages/markdown/component/test/fixtures/astro-markdown/src/pages/namespace.md new file mode 100644 index 000000000..abbe26a3b --- /dev/null +++ b/packages/markdown/component/test/fixtures/astro-markdown/src/pages/namespace.md @@ -0,0 +1,7 @@ +--- +setup: import ns from '../components/index.js'; +--- + +# Hello Namespace! + +Click me! diff --git a/packages/astro/test/fixtures/astro-markdown/src/pages/nested-list.astro b/packages/markdown/component/test/fixtures/astro-markdown/src/pages/nested-list.astro similarity index 86% rename from packages/astro/test/fixtures/astro-markdown/src/pages/nested-list.astro rename to packages/markdown/component/test/fixtures/astro-markdown/src/pages/nested-list.astro index 32a0f2916..771850bc8 100644 --- a/packages/astro/test/fixtures/astro-markdown/src/pages/nested-list.astro +++ b/packages/markdown/component/test/fixtures/astro-markdown/src/pages/nested-list.astro @@ -1,6 +1,6 @@ --- // Component imports and setup JavaScript go here! -import { Markdown } from 'astro/components'; +import Markdown from '@astrojs/markdown-component'; const content = ` - list 1 - list 2 @@ -20,7 +20,7 @@ const content = `

      Welcome to Astro

      - + - list - nested list diff --git a/packages/markdown/component/test/fixtures/astro-markdown/src/pages/no-elements.astro b/packages/markdown/component/test/fixtures/astro-markdown/src/pages/no-elements.astro new file mode 100644 index 000000000..5671ffaa4 --- /dev/null +++ b/packages/markdown/component/test/fixtures/astro-markdown/src/pages/no-elements.astro @@ -0,0 +1,5 @@ +--- +import Markdown from '@astrojs/markdown-component'; +--- + + diff --git a/packages/astro/test/fixtures/astro-markdown/src/pages/post.astro b/packages/markdown/component/test/fixtures/astro-markdown/src/pages/post.astro similarity index 85% rename from packages/astro/test/fixtures/astro-markdown/src/pages/post.astro rename to packages/markdown/component/test/fixtures/astro-markdown/src/pages/post.astro index 9bfcc847c..2745edae1 100644 --- a/packages/astro/test/fixtures/astro-markdown/src/pages/post.astro +++ b/packages/markdown/component/test/fixtures/astro-markdown/src/pages/post.astro @@ -1,5 +1,5 @@ --- -import { Markdown } from 'astro/components'; +import Markdown from '@astrojs/markdown-component'; import Layout from '../layouts/content.astro'; import Example from '../components/Example.jsx'; diff --git a/packages/markdown/component/test/fixtures/astro-markdown/src/pages/raw-content.json.js b/packages/markdown/component/test/fixtures/astro-markdown/src/pages/raw-content.json.js new file mode 100644 index 000000000..21be533e1 --- /dev/null +++ b/packages/markdown/component/test/fixtures/astro-markdown/src/pages/raw-content.json.js @@ -0,0 +1,10 @@ +import { rawContent, compiledContent } from '../imported-md/with-components.md'; + +export async function get() { + return { + body: JSON.stringify({ + raw: rawContent(), + compiled: await compiledContent(), + }), + } +} diff --git a/packages/astro/test/fixtures/astro-markdown/src/pages/scopedStyles-code.astro b/packages/markdown/component/test/fixtures/astro-markdown/src/pages/scopedStyles-code.astro similarity index 78% rename from packages/astro/test/fixtures/astro-markdown/src/pages/scopedStyles-code.astro rename to packages/markdown/component/test/fixtures/astro-markdown/src/pages/scopedStyles-code.astro index 1de76dfe6..1ee0e357d 100644 --- a/packages/astro/test/fixtures/astro-markdown/src/pages/scopedStyles-code.astro +++ b/packages/markdown/component/test/fixtures/astro-markdown/src/pages/scopedStyles-code.astro @@ -1,5 +1,5 @@ --- -import { Markdown } from 'astro/components'; +import Markdown from '@astrojs/markdown-component'; import Layout from '../layouts/content.astro'; --- @@ -18,4 +18,4 @@ import Layout from '../layouts/content.astro'; ```
      - \ No newline at end of file + diff --git a/packages/markdown/component/test/fixtures/astro-markdown/src/pages/script.md b/packages/markdown/component/test/fixtures/astro-markdown/src/pages/script.md new file mode 100644 index 000000000..f2b8bca88 --- /dev/null +++ b/packages/markdown/component/test/fixtures/astro-markdown/src/pages/script.md @@ -0,0 +1,7 @@ +# Test + +## Let's try a script... + +This should work! + +