mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-11 00:23:53 +00:00
Merge remote-tracking branch 'origin/main' into feat/decorators
This commit is contained in:
commit
7c9d21a406
2
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
2
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
@ -1,6 +1,6 @@
|
||||
name: "\U0001F41E Bug report"
|
||||
description: Create a report to help us improve Nuxt
|
||||
labels: ["pending triage", "3.x"]
|
||||
labels: ["pending triage"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
|
7
.github/ISSUE_TEMPLATE/config.yml
vendored
7
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -1,11 +1,8 @@
|
||||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: 📚 Nuxt 3 Documentation
|
||||
- name: 📚 Nuxt Documentation
|
||||
url: https://nuxt.com/docs
|
||||
about: Check the documentation for usage of Nuxt 3
|
||||
- name: 📚 Nuxt 2 Documentation
|
||||
url: https://v2.nuxt.com
|
||||
about: Check the documentation for usage of Nuxt 2
|
||||
about: Check the documentation for usage of Nuxt
|
||||
- name: 💬 Discussions
|
||||
url: https://github.com/nuxt/nuxt/discussions
|
||||
about: Use discussions if you have another issue, an idea for improvement or for asking questions.
|
||||
|
2
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
2
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
@ -1,6 +1,6 @@
|
||||
name: "🚀 Feature request"
|
||||
description: Suggest a feature that will improve Nuxt
|
||||
labels: ["pending triage", "3.x"]
|
||||
labels: ["pending triage"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
|
49
.github/ISSUE_TEMPLATE/z-bug-report-2.yml
vendored
49
.github/ISSUE_TEMPLATE/z-bug-report-2.yml
vendored
@ -1,49 +0,0 @@
|
||||
name: "\U0001F41E Bug report (Nuxt 2)"
|
||||
description: Create a report to help us improve Nuxt
|
||||
labels: ["pending triage", "2.x"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Please carefully read the contribution docs before creating a bug report
|
||||
👉 https://nuxt.com/docs/community/reporting-bugs
|
||||
|
||||
Please use a template below to create a minimal reproduction
|
||||
👉 https://stackblitz.com/github/nuxt/starter/tree/v2
|
||||
👉 https://codesandbox.io/s/github/nuxt/starter/v2
|
||||
- type: textarea
|
||||
id: bug-env
|
||||
attributes:
|
||||
label: Environment
|
||||
description: You can use `npx envinfo --system --npmPackages '{nuxt,@nuxt/*}' --binaries --browsers` to fill this section
|
||||
placeholder: Environment
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: reproduction
|
||||
attributes:
|
||||
label: Reproduction
|
||||
description: Please provide a link to a repo that can reproduce the problem you ran into. A [**minimal reproduction**](https://nuxt.com/docs/community/reporting-bugs#create-a-minimal-reproduction) is required unless you are absolutely sure that the issue is obvious and the provided information is enough to understand the problem. If a report is vague (e.g. just a generic error message) and has no reproduction, it will receive a "need reproduction" label. If no reproduction is provided we might close it.
|
||||
placeholder: Reproduction
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: bug-description
|
||||
attributes:
|
||||
label: Describe the bug
|
||||
description: A clear and concise description of what the bug is. If you intend to submit a PR for this issue, tell us in the description. Thanks!
|
||||
placeholder: Bug description
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: additonal
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: If applicable, add any other context about the problem here
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Logs
|
||||
description: |
|
||||
Optional if provided reproduction. Please try not to insert an image but copy paste the log text.
|
||||
render: shell-script
|
2
.github/workflows/autofix-docs.yml
vendored
2
.github/workflows/autofix-docs.yml
vendored
@ -30,4 +30,4 @@ jobs:
|
||||
- name: Lint (docs)
|
||||
run: pnpm lint:docs:fix
|
||||
|
||||
- uses: autofix-ci/action@ea32e3a12414e6d3183163c3424a7d7a8631ad84
|
||||
- uses: autofix-ci/action@2891949f3779a1cafafae1523058501de3d4e944
|
||||
|
2
.github/workflows/autofix.yml
vendored
2
.github/workflows/autofix.yml
vendored
@ -52,4 +52,4 @@ jobs:
|
||||
- name: Lint (code)
|
||||
run: pnpm lint:fix
|
||||
|
||||
- uses: autofix-ci/action@ea32e3a12414e6d3183163c3424a7d7a8631ad84
|
||||
- uses: autofix-ci/action@2891949f3779a1cafafae1523058501de3d4e944
|
||||
|
1
.github/workflows/changelog.yml
vendored
1
.github/workflows/changelog.yml
vendored
@ -5,7 +5,6 @@ on:
|
||||
branches:
|
||||
- main
|
||||
- 3.x
|
||||
- 2.x
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
1
.github/workflows/check-links.yml
vendored
1
.github/workflows/check-links.yml
vendored
@ -7,6 +7,7 @@ on:
|
||||
- "*.md"
|
||||
branches:
|
||||
- main
|
||||
- 3.x
|
||||
|
||||
# Remove default permissions of GITHUB_TOKEN for security
|
||||
# https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs
|
||||
|
14
.github/workflows/ci.yml
vendored
14
.github/workflows/ci.yml
vendored
@ -7,12 +7,14 @@ on:
|
||||
- "*.md"
|
||||
branches:
|
||||
- main
|
||||
- 3.x
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "docs/**"
|
||||
- "*.md"
|
||||
branches:
|
||||
- main
|
||||
- 3.x
|
||||
- "!v[0-9]*"
|
||||
|
||||
# https://github.com/vitejs/vite/blob/main/.github/workflows/ci.yml
|
||||
@ -83,7 +85,7 @@ jobs:
|
||||
run: pnpm install
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@23acc5c183826b7a8a97bce3cecc52db901f8251 # v3.25.10
|
||||
uses: github/codeql-action/init@b611370bb5703a7efb587f9d136a52ea24c5c38c # v3.25.11
|
||||
with:
|
||||
languages: javascript
|
||||
queries: +security-and-quality
|
||||
@ -95,7 +97,7 @@ jobs:
|
||||
path: packages
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@23acc5c183826b7a8a97bce3cecc52db901f8251 # v3.25.10
|
||||
uses: github/codeql-action/analyze@b611370bb5703a7efb587f9d136a52ea24c5c38c # v3.25.11
|
||||
with:
|
||||
category: "/language:javascript"
|
||||
|
||||
@ -198,7 +200,6 @@ jobs:
|
||||
builder: ["vite", "webpack"]
|
||||
context: ["async", "default"]
|
||||
manifest: ["manifest-on", "manifest-off"]
|
||||
version: ["v4", "v3"]
|
||||
payload: ["json", "js"]
|
||||
node: [18]
|
||||
exclude:
|
||||
@ -244,7 +245,6 @@ jobs:
|
||||
TEST_BUILDER: ${{ matrix.builder }}
|
||||
TEST_MANIFEST: ${{ matrix.manifest }}
|
||||
TEST_CONTEXT: ${{ matrix.context }}
|
||||
TEST_V4: ${{ matrix.version == 'v4' }}
|
||||
TEST_PAYLOAD: ${{ matrix.payload }}
|
||||
SKIP_BUNDLE_SIZE: ${{ github.event_name != 'push' || matrix.env == 'dev' || matrix.builder == 'webpack' || matrix.context == 'default' || matrix.payload == 'js' || runner.os == 'Windows' }}
|
||||
|
||||
@ -254,6 +254,8 @@ jobs:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
build-release:
|
||||
concurrency:
|
||||
group: release
|
||||
permissions:
|
||||
id-token: write
|
||||
if: |
|
||||
@ -289,12 +291,14 @@ jobs:
|
||||
path: packages
|
||||
|
||||
- name: Release Edge
|
||||
run: ./scripts/release-edge.sh
|
||||
run: ./scripts/release-edge.sh ${{ github.ref == 'refs/heads/main' && 'latest' || '3x' }}
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{secrets.NODE_AUTH_TOKEN}}
|
||||
NPM_CONFIG_PROVENANCE: true
|
||||
|
||||
release-pr:
|
||||
concurrency:
|
||||
group: release
|
||||
permissions:
|
||||
id-token: write
|
||||
pull-requests: write
|
||||
|
1
.github/workflows/docs.yml
vendored
1
.github/workflows/docs.yml
vendored
@ -9,6 +9,7 @@ on:
|
||||
# autofix workflow will be triggered instead for PRs
|
||||
branches:
|
||||
- main
|
||||
- 3.x
|
||||
- "!v[0-9]*"
|
||||
|
||||
# Remove default permissions of GITHUB_TOKEN for security
|
||||
|
2
.github/workflows/introspect.yml
vendored
2
.github/workflows/introspect.yml
vendored
@ -6,11 +6,13 @@ on:
|
||||
- ".github/workflows/**"
|
||||
branches:
|
||||
- main
|
||||
- 3.x
|
||||
pull_request:
|
||||
paths:
|
||||
- ".github/workflows/**"
|
||||
branches:
|
||||
- main
|
||||
- 3.x
|
||||
- "!v[0-9]*"
|
||||
|
||||
permissions:
|
||||
|
1
.github/workflows/label-pr.yml
vendored
1
.github/workflows/label-pr.yml
vendored
@ -6,6 +6,7 @@ on:
|
||||
- opened
|
||||
branches:
|
||||
- main
|
||||
- 3.x
|
||||
|
||||
jobs:
|
||||
add-pr-labels:
|
||||
|
23
.github/workflows/release-pr.yml
vendored
23
.github/workflows/release-pr.yml
vendored
@ -14,6 +14,8 @@ permissions:
|
||||
jobs:
|
||||
release-pr:
|
||||
if: github.repository == 'nuxt/nuxt' && github.event.issue.pull_request && github.event.comment.body == '/trigger release'
|
||||
concurrency:
|
||||
group: release
|
||||
permissions:
|
||||
id-token: write
|
||||
pull-requests: write
|
||||
@ -29,10 +31,27 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Get PR Info
|
||||
id: pr
|
||||
env:
|
||||
PR_NUMBER: ${{ github.event.issue.number }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GH_REPO: ${{ github.repository }}
|
||||
COMMENT_AT: ${{ github.event.comment.created_at }}
|
||||
run: |
|
||||
pr="$(gh api -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" /repos/${GH_REPO}/pulls/${PR_NUMBER})"
|
||||
head_sha="$(echo "$pr" | jq -r .head.sha)"
|
||||
updated_at="$(echo "$pr" | jq -r .updated_at)"
|
||||
|
||||
if [[ $(date -d "$updated_at" +%s) -gt $(date -d "$COMMENT_AT" +%s) ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "head_sha=$head_sha" >> $GITHUB_OUTPUT
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
with:
|
||||
ref: ${{ github.event.issue.pull_request.head.sha }}
|
||||
fetch-depth: 0
|
||||
ref: ${{ steps.pr.outputs.head_sha }}
|
||||
fetch-depth: 1
|
||||
|
||||
- run: corepack enable
|
||||
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||
|
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@ -12,6 +12,8 @@ permissions: {}
|
||||
jobs:
|
||||
release:
|
||||
if: github.repository == 'nuxt/nuxt' && (startsWith(github.event.head_commit.message, 'v3.') || startsWith(github.event.head_commit.message, 'v4.'))
|
||||
concurrency:
|
||||
group: release
|
||||
permissions:
|
||||
id-token: write
|
||||
runs-on: ubuntu-latest
|
||||
|
2
.github/workflows/scorecards.yml
vendored
2
.github/workflows/scorecards.yml
vendored
@ -68,7 +68,7 @@ jobs:
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@23acc5c183826b7a8a97bce3cecc52db901f8251 # v3.25.10
|
||||
uses: github/codeql-action/upload-sarif@b611370bb5703a7efb587f9d136a52ea24c5c38c # v3.25.11
|
||||
if: github.repository == 'nuxt/nuxt' && success()
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
2
.github/workflows/semantic-pull-requests.yml
vendored
2
.github/workflows/semantic-pull-requests.yml
vendored
@ -20,7 +20,7 @@ jobs:
|
||||
name: Semantic pull request
|
||||
steps:
|
||||
- name: Validate PR title
|
||||
uses: amannn/action-semantic-pull-request@cfb60706e18bc85e8aec535e3c577abe8f70378e # v5.5.2
|
||||
uses: amannn/action-semantic-pull-request@0723387faaf9b38adef4775cd42cfd5155ed6017 # v5.5.3
|
||||
with:
|
||||
scopes: |
|
||||
kit
|
||||
|
1
CODEOWNERS
Normal file
1
CODEOWNERS
Normal file
@ -0,0 +1 @@
|
||||
* @danielroe
|
@ -101,12 +101,6 @@ Here are a few ways you can get involved:
|
||||
|
||||
Follow the docs to [Set Up Your Local Development Environment](https://nuxt.com/docs/community/framework-contribution#setup) to contribute to the framework and documentation.
|
||||
|
||||
## <a name="nuxt-2">⛰️ Nuxt 2</a>
|
||||
|
||||
You can find the code for Nuxt 2 on the [`2.x` branch](https://github.com/nuxt/nuxt/tree/2.x) and the documentation at [v2.nuxt.com](https://v2.nuxt.com).
|
||||
|
||||
If you expect to be using Nuxt 2 beyond the EOL (End of Life) date (June 30, 2024), and still need a maintained version that can satisfy security and browser compatibility requirements, make sure to check out [HeroDevs’ NES (Never-Ending Support) Nuxt 2](https://www.herodevs.com/support/nuxt-nes?utm_source=nuxt-github&utm_medium=nuxt-readme).
|
||||
|
||||
## <a name="professional-support">🛟 Professional Support</a>
|
||||
|
||||
- Technical audit & consulting: [Nuxt Experts](https://nuxt.com/enterprise/support)
|
||||
|
@ -76,7 +76,6 @@ Nuxt is composed of different [core packages](https://github.com/nuxt/nuxt/tree/
|
||||
- Command line interface: [nuxi](https://github.com/nuxt/nuxt/tree/main/packages/nuxi)
|
||||
- Server engine: [nitro](https://github.com/unjs/nitro)
|
||||
- Development kit: [@nuxt/kit](https://github.com/nuxt/nuxt/tree/main/packages/kit)
|
||||
- Nuxt 2 Bridge: [@nuxt/bridge](https://github.com/nuxt/bridge)
|
||||
|
||||
We recommend reading each concept to have a full vision of Nuxt capabilities and the scope of each package.
|
||||
|
||||
|
@ -85,13 +85,13 @@ export default defineNuxtConfig({
|
||||
|
||||
## Hosting Providers
|
||||
|
||||
Nuxt 3 can be deployed to several cloud providers with a minimal amount of configuration:
|
||||
Nuxt can be deployed to several cloud providers with a minimal amount of configuration:
|
||||
|
||||
:read-more{to="/deploy"}
|
||||
|
||||
## Presets
|
||||
|
||||
In addition to Node.js servers and static hosting services, a Nuxt 3 project can be deployed with several well-tested presets and minimal amount of configuration.
|
||||
In addition to Node.js servers and static hosting services, a Nuxt project can be deployed with several well-tested presets and minimal amount of configuration.
|
||||
|
||||
You can explicitly set the desired preset in the [`nuxt.config.ts`](/docs/guide/directory-structure/nuxt-config) file:
|
||||
|
||||
@ -125,5 +125,5 @@ Accordingly, you should make sure that the following options are unchecked / dis
|
||||
With these settings, you can be sure that Cloudflare won't inject scripts into your Nuxt application that may cause unwanted side effects.
|
||||
|
||||
::tip
|
||||
Their location on the Cloudfalre dashboard sometimes changes so don't hesitate to look around.
|
||||
Their location on the Cloudflare dashboard sometimes changes so don't hesitate to look around.
|
||||
::
|
||||
|
@ -11,19 +11,41 @@ navigation.icon: i-ph-arrow-circle-up-duotone
|
||||
|
||||
To upgrade Nuxt to the [latest release](https://github.com/nuxt/nuxt/releases), use the `nuxi upgrade` command.
|
||||
|
||||
```bash [Terminal]
|
||||
::code-group
|
||||
|
||||
```bash [npm]
|
||||
npx nuxi upgrade
|
||||
```
|
||||
|
||||
```bash [yarn]
|
||||
yarn dlx nuxi upgrade
|
||||
```
|
||||
|
||||
```bash [pnpm]
|
||||
pnpm dlx nuxi upgrade
|
||||
```
|
||||
|
||||
```bash [bun]
|
||||
bunx nuxi upgrade
|
||||
```
|
||||
|
||||
::
|
||||
|
||||
### Nightly Release Channel
|
||||
|
||||
To use the latest Nuxt build and test features before their release, read about the [nightly release channel](/docs/guide/going-further/nightly-release-channel) guide.
|
||||
|
||||
::alert{type="warning"}
|
||||
The nightly release channel `latest` tag is currently tracking the Nuxt v4 branch, meaning that it is particularly likely to have breaking changes right now - be careful!
|
||||
|
||||
You can opt in to the 3.x branch nightly releases with `"nuxt": "npm:nuxt-nightly@3x"`.
|
||||
::
|
||||
|
||||
## Testing Nuxt 4
|
||||
|
||||
Nuxt 4 is planned to be released **on or before June 14** (though obviously this is dependent on having enough time after Nitro's major release to be properly tested in the community, so be aware that this is not an exact date).
|
||||
|
||||
Until then, it is possible to test many of Nuxt 4's breaking changes from Nuxt version 3.12 or via the nightly release channel.
|
||||
Until then, it is possible to test many of Nuxt 4's breaking changes from Nuxt version 3.12+.
|
||||
|
||||
::tip{icon="i-ph-video-duotone" to="https://www.youtube.com/watch?v=r4wFKlcJK6c" target="_blank"}
|
||||
Watch a video from Alexander Lichter showing how to opt in to Nuxt 4's breaking changes already.
|
||||
@ -31,7 +53,7 @@ Watch a video from Alexander Lichter showing how to opt in to Nuxt 4's breaking
|
||||
|
||||
### Opting in to Nuxt 4
|
||||
|
||||
First, opt in to the nightly release channel [following these steps](/docs/guide/going-further/nightly-release-channel#opting-in).
|
||||
First, upgrade Nuxt to the [latest release](https://github.com/nuxt/nuxt/releases).
|
||||
|
||||
Then you can set your `compatibilityVersion` to match Nuxt 4 behavior:
|
||||
|
||||
@ -87,7 +109,7 @@ Nuxt now defaults to a new directory structure, with backwards compatibility (so
|
||||
|
||||
* the new Nuxt default `srcDir` is `app/` by default, and most things are resolved from there.
|
||||
* `serverDir` now defaults to `<rootDir>/server` rather than `<srcDir>/server`
|
||||
* `modules` and `public` are resolved relative to `<rootDir>` by default
|
||||
* `layers`, `modules` and `public` are resolved relative to `<rootDir>` by default
|
||||
* a new `dir.app` is added, which is the directory we look for `router.options.ts` and `spa-loading-template.html` - this defaults to `<srcDir>/`
|
||||
|
||||
<details>
|
||||
@ -109,6 +131,7 @@ app/
|
||||
app.config.ts
|
||||
app.vue
|
||||
router.options.ts
|
||||
layers/
|
||||
modules/
|
||||
node_modules/
|
||||
public/
|
||||
@ -209,6 +232,7 @@ Previously `data` was initialized to `null` but reset in `clearNuxtData` to `und
|
||||
If you encounter any issues you can revert back to the previous behavior with:
|
||||
|
||||
```ts twoslash [nuxt.config.ts]
|
||||
// @errors: 2353
|
||||
export default defineNuxtConfig({
|
||||
experimental: {
|
||||
defaults: {
|
||||
@ -232,6 +256,7 @@ Please report an issue if you are doing this, as we do not plan to keep this as
|
||||
Previously it was possible to pass `dedupe: boolean` to `refresh`. These were aliases of `cancel` (`true`) and `defer` (`false`).
|
||||
|
||||
```ts twoslash [app.vue]
|
||||
// @errors: 2322
|
||||
const { refresh } = await useAsyncData(async () => ({ message: 'Hello, Nuxt 3!' }))
|
||||
|
||||
async function refreshData () {
|
||||
@ -280,6 +305,7 @@ Often users set an appropriately empty value, such as an empty array, to avoid t
|
||||
If you encounter any issues you can revert back to the previous behavior, for now, with:
|
||||
|
||||
```ts twoslash [nuxt.config.ts]
|
||||
// @errors: 2353
|
||||
export default defineNuxtConfig({
|
||||
experimental: {
|
||||
resetAsyncDataToUndefined: true,
|
||||
@ -352,6 +378,25 @@ However, if you are a module author using the `builder:watch` hook and wishing t
|
||||
})
|
||||
```
|
||||
|
||||
#### Removal of `window.__NUXT__` object
|
||||
|
||||
##### What Changed
|
||||
|
||||
We are removing the global `window.__NUXT__` object after the app finishes hydration.
|
||||
|
||||
##### Reasons for Change
|
||||
|
||||
This opens the way to multi-app patterns ([#21635](https://github.com/nuxt/nuxt/issues/21635)) and enables us to focus on a single way to access Nuxt app data - `useNuxtApp()`.
|
||||
|
||||
##### Migration Steps
|
||||
|
||||
The data is still available, but can be accessed with `useNuxtApp().payload`:
|
||||
|
||||
```diff
|
||||
- console.log(window.__NUXT__)
|
||||
+ console.log(useNuxtApp().payload)
|
||||
```
|
||||
|
||||
#### Directory index scanning
|
||||
|
||||
🚦 **Impact Level**: Medium
|
||||
@ -448,10 +493,11 @@ const importName = genSafeVariableName
|
||||
|
||||
Four experimental features are no longer configurable in Nuxt 4:
|
||||
|
||||
* `treeshakeClientOnly` will be `true` (default since v3.0)
|
||||
* `configSchema` will be `true` (default since v3.3)
|
||||
* `polyfillVueUseHead` will be `false` (default since v3.4)
|
||||
* `respectNoSSRHeader` will be `false` (default since v3.4)
|
||||
* `experimental.treeshakeClientOnly` will be `true` (default since v3.0)
|
||||
* `experimental.configSchema` will be `true` (default since v3.3)
|
||||
* `experimental.polyfillVueUseHead` will be `false` (default since v3.4)
|
||||
* `experimental.respectNoSSRHeader` will be `false` (default since v3.4)
|
||||
* `vite.devBundler` is no longer configurable - it will use `vite-node` by default
|
||||
|
||||
##### Reasons for Change
|
||||
|
||||
@ -463,11 +509,35 @@ These options have been set to their current values for some time and we do not
|
||||
|
||||
* `respectNoSSRHeader`is implementable in user-land with [server middleware](https://github.com/nuxt/nuxt/blob/c660b39447f0d5b8790c0826092638d321cd6821/packages/nuxt/src/core/runtime/nitro/no-ssr.ts#L8-L9)
|
||||
|
||||
## Nuxt 2 vs Nuxt 3
|
||||
#### Removal of Deprecated Internal CJS Utils
|
||||
|
||||
🚦 **Impact Level**: Minimal
|
||||
|
||||
##### What Changed
|
||||
|
||||
We have now removed the following utils exported from `@nuxt/kit`:
|
||||
|
||||
* `resolveModule`
|
||||
* `requireModule`
|
||||
* `importModule`
|
||||
* `tryImportModule`
|
||||
* `tryRequireModule`
|
||||
|
||||
They were previously marked as deprecated and relied on CJS resolutions.
|
||||
|
||||
##### Reasons for Change
|
||||
|
||||
We now use [jiti](https://github.com/unjs/jiti) to resolve modules and other imports internally. It supports native ESM resolution where possible and should be less buggy.
|
||||
|
||||
##### Migration Steps
|
||||
|
||||
You can use [jiti](https://github.com/unjs/jiti) or [mlly](https://github.com/unjs/mlly) to do the same job in your own projects if you were relying on these utilities.
|
||||
|
||||
## Nuxt 2 vs Nuxt 3+
|
||||
|
||||
In the table below, there is a quick comparison between 3 versions of Nuxt:
|
||||
|
||||
Feature / Version | Nuxt 2 | Nuxt Bridge | Nuxt 3
|
||||
Feature / Version | Nuxt 2 | Nuxt Bridge | Nuxt 3+
|
||||
-------------------------|-----------------|------------------|---------
|
||||
Vue | 2 | 2 | 3
|
||||
Stability | 😊 Stable | 😊 Stable | 😊 Stable
|
||||
@ -485,9 +555,9 @@ Vite | ⚠️ Partial | 🚧 Partial | ✅
|
||||
Nuxi CLI | ❌ Old | ✅ nuxi | ✅ nuxi
|
||||
Static sites | ✅ | ✅ | ✅
|
||||
|
||||
## Nuxt 2 to Nuxt 3
|
||||
## Nuxt 2 to Nuxt 3+
|
||||
|
||||
The migration guide provides a step-by-step comparison of Nuxt 2 features to Nuxt 3 features and guidance to adapt your current application.
|
||||
The migration guide provides a step-by-step comparison of Nuxt 2 features to Nuxt 3+ features and guidance to adapt your current application.
|
||||
|
||||
::read-more{to="/docs/migration/overview"}
|
||||
Check out the **guide to migrating from Nuxt 2 to Nuxt 3**.
|
||||
@ -495,7 +565,7 @@ Check out the **guide to migrating from Nuxt 2 to Nuxt 3**.
|
||||
|
||||
## Nuxt 2 to Nuxt Bridge
|
||||
|
||||
If you prefer to progressively migrate your Nuxt 2 application to Nuxt 3, you can use Nuxt Bridge. Nuxt Bridge is a compatibility layer that allows you to use Nuxt 3 features in Nuxt 2 with an opt-in mechanism.
|
||||
If you prefer to progressively migrate your Nuxt 2 application to Nuxt 3, you can use Nuxt Bridge. Nuxt Bridge is a compatibility layer that allows you to use Nuxt 3+ features in Nuxt 2 with an opt-in mechanism.
|
||||
|
||||
::read-more{to="/docs/bridge/overview"}
|
||||
**Migrate from Nuxt 2 to Nuxt Bridge**
|
||||
|
@ -37,10 +37,14 @@ Open a terminal (if you're using [Visual Studio Code](https://code.visualstudio.
|
||||
|
||||
::code-group
|
||||
|
||||
```bash [npx]
|
||||
```bash [npm]
|
||||
npx nuxi@latest init <project-name>
|
||||
```
|
||||
|
||||
```bash [yarn]
|
||||
yarn dlx nuxi@latest init <project-name>
|
||||
```
|
||||
|
||||
```bash [pnpm]
|
||||
pnpm dlx nuxi@latest init <project-name>
|
||||
```
|
||||
@ -96,6 +100,6 @@ Well done! A browser window should automatically open for <http://localhost:3000
|
||||
|
||||
## Next Steps
|
||||
|
||||
Now that you've created your Nuxt 3 project, you are ready to start building your application.
|
||||
Now that you've created your Nuxt project, you are ready to start building your application.
|
||||
|
||||
:read-more{title="Nuxt Concepts" to="/docs/guide/concepts"}
|
||||
|
@ -77,10 +77,26 @@ h1 {
|
||||
|
||||
You can also reference stylesheets that are distributed through npm. Let's use the popular `animate.css` library as an example.
|
||||
|
||||
```bash [Terminal]
|
||||
::code-group
|
||||
|
||||
```bash [npm]
|
||||
npm install animate.css
|
||||
```
|
||||
|
||||
```bash [yarn]
|
||||
yarn add animate.css
|
||||
```
|
||||
|
||||
```bash [pnpm]
|
||||
pnpm install animate.css
|
||||
```
|
||||
|
||||
```bash [bun]
|
||||
bun install animate.css
|
||||
```
|
||||
|
||||
::
|
||||
|
||||
Then you can reference it directly in your pages, layouts and components:
|
||||
|
||||
```vue [app.vue]
|
||||
|
@ -328,7 +328,7 @@ definePageMeta({
|
||||
},
|
||||
middleware (to, from) {
|
||||
if (to.meta.pageTransition && typeof to.meta.pageTransition !== 'boolean')
|
||||
to.meta.pageTransition.name = +to.params.id > +from.params.id ? 'slide-left' : 'slide-right'
|
||||
to.meta.pageTransition.name = +to.params.id! > +from.params.id! ? 'slide-left' : 'slide-right'
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
@ -494,7 +494,7 @@ onMounted(() => console.log(document.cookie))
|
||||
|
||||
## Options API support
|
||||
|
||||
Nuxt 3 provides a way to perform `asyncData` fetching within the Options API. You must wrap your component definition within `defineNuxtComponent` for this to work.
|
||||
Nuxt provides a way to perform `asyncData` fetching within the Options API. You must wrap your component definition within `defineNuxtComponent` for this to work.
|
||||
|
||||
```vue
|
||||
<script>
|
||||
|
@ -4,7 +4,7 @@ description: 'Learn how to catch and handle errors in Nuxt.'
|
||||
navigation.icon: i-ph-bug-beetle-duotone
|
||||
---
|
||||
|
||||
Nuxt 3 is a full-stack framework, which means there are several sources of unpreventable user runtime errors that can happen in different contexts:
|
||||
Nuxt is a full-stack framework, which means there are several sources of unpreventable user runtime errors that can happen in different contexts:
|
||||
|
||||
- Errors during the Vue rendering lifecycle (SSR & CSR)
|
||||
- Server and client startup errors (SSR + CSR)
|
||||
|
@ -4,7 +4,7 @@ description: Nuxt provides a powerful system that allows you to extend the defau
|
||||
navigation.icon: i-ph-stack-duotone
|
||||
---
|
||||
|
||||
One of the core features of Nuxt 3 is the layers and extending support. You can extend a default Nuxt application to reuse components, utils, and configuration. The layers structure is almost identical to a standard Nuxt application which makes them easy to author and maintain.
|
||||
One of the core features of Nuxt is the layers and extending support. You can extend a default Nuxt application to reuse components, utils, and configuration. The layers structure is almost identical to a standard Nuxt application which makes them easy to author and maintain.
|
||||
|
||||
## Use Cases
|
||||
|
||||
|
@ -14,10 +14,26 @@ Use the [`nuxi generate` command](/docs/api/commands/generate) to build and pre-
|
||||
|
||||
This will build your site, stand up a nuxt instance, and, by default, prerender the root page `/` along with any of your site's pages it links to, any of your site's pages they link to, and so on.
|
||||
|
||||
```bash [Terminal]
|
||||
::code-group
|
||||
|
||||
```bash [npm]
|
||||
npx nuxi generate
|
||||
```
|
||||
|
||||
```bash [yarn]
|
||||
yarn dlx nuxi generate
|
||||
```
|
||||
|
||||
```bash [pnpm]
|
||||
pnpm dlx nuxi generate
|
||||
```
|
||||
|
||||
```bash [bun]
|
||||
bunx nuxi generate
|
||||
```
|
||||
|
||||
::
|
||||
|
||||
You can now deploy the `.output/public` directory to any static hosting service or preview it locally with `npx serve .output/public`.
|
||||
|
||||
Working of the Nitro crawler:
|
||||
|
@ -105,6 +105,11 @@ Nuxt directly auto-imports files created in defined directories:
|
||||
|
||||
:link-example{to="/docs/examples/features/auto-imports"}
|
||||
|
||||
::warning
|
||||
**Auto-imported `ref` and `computed` won't be unwrapped in a component `<template>`.** :br
|
||||
This is due to how Vue works with refs that aren't top-level to the template. You can read more about it [in the Vue documentation](https://vuejs.org/guide/essentials/reactivity-fundamentals.html#caveat-when-unwrapping-in-templates).
|
||||
::
|
||||
|
||||
### Explicit Imports
|
||||
|
||||
Nuxt exposes every auto-import with the `#imports` alias that can be used to make the import explicit if needed:
|
||||
|
@ -39,7 +39,7 @@ Most applications need multiple pages and a way to navigate between them. This i
|
||||
|
||||
## Differences with Nuxt 2 / Vue 2
|
||||
|
||||
Nuxt 3 is based on Vue 3. The new major Vue version introduces several changes that Nuxt takes advantage of:
|
||||
Nuxt 3+ is based on Vue 3. The new major Vue version introduces several changes that Nuxt takes advantage of:
|
||||
|
||||
- Better performance
|
||||
- Composition API
|
||||
@ -89,15 +89,15 @@ const increment = () => count.value++
|
||||
</script>
|
||||
```
|
||||
|
||||
The goal of Nuxt 3 is to provide a great developer experience around the Composition API.
|
||||
The goal of Nuxt is to provide a great developer experience around the Composition API.
|
||||
|
||||
- Use auto-imported [Reactivity functions](https://vuejs.org/api/reactivity-core.html) from Vue and Nuxt 3 [built-in composables](/docs/api/composables/use-async-data).
|
||||
- Use auto-imported [Reactivity functions](https://vuejs.org/api/reactivity-core.html) from Vue and Nuxt [built-in composables](/docs/api/composables/use-async-data).
|
||||
- Write your own auto-imported reusable functions in the [`composables/` directory](/docs/guide/directory-structure/composables).
|
||||
|
||||
### TypeScript Support
|
||||
|
||||
Both Vue 3 and Nuxt 3 are written in TypeScript. A fully typed codebase prevents mistakes and documents APIs usage. This doesn’t mean that you have to write your application in TypeScript to take advantage of it. With Nuxt 3, you can opt-in by renaming your file from `.js` to `.ts` , or add `<script setup lang="ts">` in a component.
|
||||
Both Vue 3 and Nuxt 3+ are written in TypeScript. A fully typed codebase prevents mistakes and documents APIs usage. This doesn’t mean that you have to write your application in TypeScript to take advantage of it. With Nuxt 3, you can opt-in by renaming your file from `.js` to `.ts` , or add `<script setup lang="ts">` in a component.
|
||||
|
||||
::read-more{to="/docs/guide/concepts/typescript"}
|
||||
Read the details about TypeScript in Nuxt 3
|
||||
Read the details about TypeScript in Nuxt
|
||||
::
|
||||
|
@ -105,7 +105,7 @@ Hybrid rendering allows different caching rules per route using **Route Rules**
|
||||
|
||||
Previously every route/page of a Nuxt application and server must use the same rendering mode, universal or client-side. In various cases, some pages could be generated at build time, while others should be client-side rendered. For example, think of a content website with an admin section. Every content page should be primarily static and generated once, but the admin section requires registration and behaves more like a dynamic application.
|
||||
|
||||
Nuxt 3 includes route rules and hybrid rendering support. Using route rules you can define rules for a group of nuxt routes, change rendering mode or assign a cache strategy based on route!
|
||||
Nuxt includes route rules and hybrid rendering support. Using route rules you can define rules for a group of nuxt routes, change rendering mode or assign a cache strategy based on route!
|
||||
|
||||
Nuxt server will automatically register corresponding middleware and wrap routes with cache handlers using [Nitro caching layer](https://nitro.unjs.io/guide/cache).
|
||||
|
||||
@ -168,7 +168,7 @@ Note that Hybrid Rendering is not available when using [`nuxt generate`](/docs/a
|
||||
|
||||
## Edge-Side Rendering
|
||||
|
||||
Edge-Side Rendering (ESR) is a powerful feature introduced in Nuxt 3 that allows the rendering of your Nuxt application closer to your users via edge servers of a Content Delivery Network (CDN). By leveraging ESR, you can ensure improved performance and reduced latency, thereby providing an enhanced user experience.
|
||||
Edge-Side Rendering (ESR) is a powerful feature introduced in Nuxt that allows the rendering of your Nuxt application closer to your users via edge servers of a Content Delivery Network (CDN). By leveraging ESR, you can ensure improved performance and reduced latency, thereby providing an enhanced user experience.
|
||||
|
||||
With ESR, the rendering process is pushed to the 'edge' of the network - the CDN's edge servers. Note that ESR is more a deployment target than an actual rendering mode.
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Server Engine
|
||||
description: 'Nuxt 3 is powered by a new server engine: Nitro.'
|
||||
description: 'Nuxt is powered by a new server engine: Nitro.'
|
||||
---
|
||||
|
||||
While building Nuxt 3, we created a new server engine: [Nitro](https://nitro.unjs.io).
|
||||
@ -53,7 +53,7 @@ Nitro produces a standalone server dist that is independent of `node_modules`.
|
||||
|
||||
The server in Nuxt 2 is not standalone and requires part of Nuxt core to be involved by running `nuxt start` (with the [`nuxt-start`](https://www.npmjs.com/package/nuxt-start) or [`nuxt`](https://www.npmjs.com/package/nuxt) distributions) or custom programmatic usage, which is fragile and prone to breakage and not suitable for serverless and service-worker environments.
|
||||
|
||||
Nuxt 3 generates this dist when running `nuxt build` into a [`.output`](/docs/guide/directory-structure/output) directory.
|
||||
Nuxt generates this dist when running `nuxt build` into a [`.output`](/docs/guide/directory-structure/output) directory.
|
||||
|
||||
The output contains runtime code to run your Nuxt server in any environment (including experimental browser service workers!) and serve your static files, making it a true hybrid framework for the JAMstack. In addition, Nuxt implements a native storage layer, supporting multi-source drivers and local assets.
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
title: 'ES Modules'
|
||||
description: "Nuxt 3 (and Bridge) uses Native ES Modules."
|
||||
description: "Nuxt uses native ES modules."
|
||||
---
|
||||
|
||||
This guide helps explain what ES Modules are and how to make a Nuxt app (or upstream library) compatible with ESM.
|
||||
@ -190,7 +190,7 @@ import { default as pkg } from 'cjs-pkg'
|
||||
import('cjs-pkg').then(m => m.default || m).then(console.log)
|
||||
```
|
||||
|
||||
For handling more complex situations and more safety, we recommend and internally use [mlly](https://github.com/unjs/mlly) in Nuxt 3 that can preserve named exports.
|
||||
For handling more complex situations and more safety, we recommend and internally use [mlly](https://github.com/unjs/mlly) in Nuxt that can preserve named exports.
|
||||
|
||||
```js
|
||||
import { interopDefault } from 'mlly'
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
title: 'TypeScript'
|
||||
description: "Nuxt 3 is fully typed and provides helpful shortcuts to ensure you have access to accurate type information when you are coding."
|
||||
description: "Nuxt is fully typed and provides helpful shortcuts to ensure you have access to accurate type information when you are coding."
|
||||
---
|
||||
|
||||
## Type-checking
|
||||
@ -9,10 +9,6 @@ By default, Nuxt doesn't check types when you run [`nuxi dev`](/docs/api/command
|
||||
|
||||
To enable type-checking at build or development time, install `vue-tsc` and `typescript` as development dependency:
|
||||
|
||||
::alert{type="warning"}
|
||||
You may experience issues with the latest `vue-tsc` and `vite-plugin-checker`, used internally when type checking. For now, you may need to stay on v1 of `vue-tsc`, and follow these upstream issues for updates: [fi3ework/vite-plugin-checker#306](https://github.com/fi3ework/vite-plugin-checker/issues/306) and [vuejs/language-tools#3969](https://github.com/vuejs/language-tools/issues/3969).
|
||||
::
|
||||
|
||||
::code-group
|
||||
|
||||
```bash [yarn]
|
||||
@ -55,7 +51,7 @@ When you run `nuxi dev` or `nuxi build`, Nuxt generates the following files for
|
||||
|
||||
### `.nuxt/nuxt.d.ts`
|
||||
|
||||
This file contains the types of any modules you are using, as well as the key types that Nuxt 3 requires. Your IDE should recognize these types automatically.
|
||||
This file contains the types of any modules you are using, as well as the key types that Nuxt requires. Your IDE should recognize these types automatically.
|
||||
|
||||
Some of the references in the file are to files that are only generated within your `buildDir` (`.nuxt`) and therefore for full typings, you will need to run `nuxi dev` or `nuxi build`.
|
||||
|
||||
@ -84,7 +80,7 @@ In case you need to extend options provided by `./.nuxt/tsconfig.json` further,
|
||||
|
||||
TypeScript comes with certain checks to give you more safety and analysis of your program.
|
||||
|
||||
[Strict checks](https://www.typescriptlang.org/docs/handbook/migrating-from-javascript.html#getting-stricter-checks) are enabled by default in Nuxt 3 to give you greater type safety.
|
||||
[Strict checks](https://www.typescriptlang.org/docs/handbook/migrating-from-javascript.html#getting-stricter-checks) are enabled by default in Nuxt to give you greater type safety.
|
||||
|
||||
If you are currently converting your codebase to TypeScript, you may want to temporarily disable strict checks by setting `strict` to `false` in your `nuxt.config`:
|
||||
|
||||
|
@ -342,7 +342,7 @@ Learn more about `<NuxtLink>` usage.
|
||||
|
||||
## Programmatic Navigation
|
||||
|
||||
Nuxt 3 allows programmatic navigation through the `navigateTo()` utility method. Using this utility method, you will be able to programmatically navigate the user in your app. This is great for taking input from the user and navigating them dynamically throughout your application. In this example, we have a simple method called `navigate()` that gets called when the user submits a search form.
|
||||
Nuxt allows programmatic navigation through the `navigateTo()` utility method. Using this utility method, you will be able to programmatically navigate the user in your app. This is great for taking input from the user and navigating them dynamically throughout your application. In this example, we have a simple method called `navigate()` that gets called when the user submits a search form.
|
||||
|
||||
::note
|
||||
Ensure to always `await` on `navigateTo` or chain its result by returning from functions.
|
||||
|
@ -33,6 +33,10 @@ npx nuxi dev --dotenv .env.local
|
||||
|
||||
When updating `.env` in development mode, the Nuxt instance is automatically restarted to apply new values to the `process.env`.
|
||||
|
||||
::important
|
||||
In your application code, you should use [Runtime Config](/docs/guide/going-further/runtime-config) instead of plain env variables.
|
||||
::
|
||||
|
||||
## Production
|
||||
|
||||
**After your server is built**, you are responsible for setting environment variables when you run the server.
|
||||
|
@ -5,7 +5,7 @@ description: Expose reactive configuration within your application with the App
|
||||
navigation.icon: i-ph-file-duotone
|
||||
---
|
||||
|
||||
Nuxt 3 provides an `app.config` config file to expose reactive configuration within your application with the ability to update it at runtime within lifecycle or using a nuxt plugin and editing it with HMR (hot-module-replacement).
|
||||
Nuxt provides an `app.config` config file to expose reactive configuration within your application with the ability to update it at runtime within lifecycle or using a nuxt plugin and editing it with HMR (hot-module-replacement).
|
||||
|
||||
You can easily provide runtime app configuration using `app.config.ts` file. It can have either of `.ts`, `.js`, or `.mjs` extensions.
|
||||
|
||||
|
@ -57,20 +57,6 @@ export default defineNuxtConfig({
|
||||
This feature will likely be removed in a near future.
|
||||
::
|
||||
|
||||
## treeshakeClientOnly
|
||||
|
||||
Tree shakes contents of client-only components from server bundle.
|
||||
|
||||
*Enabled by default.*
|
||||
|
||||
```ts twoslash [nuxt.config.ts]
|
||||
export default defineNuxtConfig({
|
||||
experimental: {
|
||||
treeshakeClientOnly: true
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## emitRouteChunkError
|
||||
|
||||
Emits `app:chunkError` hook when there is an error loading vite/webpack chunks. Default behavior is to perform a hard reload of the new route when a chunk fails to load.
|
||||
@ -238,44 +224,6 @@ export default defineNuxtConfig({
|
||||
You can follow the server components roadmap on GitHub.
|
||||
::
|
||||
|
||||
## configSchema
|
||||
|
||||
Enables config schema support.
|
||||
|
||||
*Enabled by default.*
|
||||
|
||||
```ts twoslash [nuxt.config.ts]
|
||||
export default defineNuxtConfig({
|
||||
experimental: {
|
||||
configSchema: true
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## polyfillVueUseHead
|
||||
|
||||
Adds a compatibility layer for modules, plugins, or user code relying on the old `@vueuse/head` API.
|
||||
|
||||
```ts twoslash [nuxt.config.ts]
|
||||
export default defineNuxtConfig({
|
||||
experimental: {
|
||||
polyfillVueUseHead: false
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## respectNoSSRHeader
|
||||
|
||||
Allow disabling Nuxt SSR responses by setting the `x-nuxt-no-ssr` header.
|
||||
|
||||
```ts twoslash [nuxt.config.ts]
|
||||
export default defineNuxtConfig({
|
||||
experimental: {
|
||||
respectNoSSRHeader: false
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## localLayerAliases
|
||||
|
||||
Resolve `~`, `~~`, `@` and `@@` aliases located within layers with respect to their layer source and root directories.
|
||||
|
@ -94,7 +94,7 @@ The behavior is different between the client-side and server-side:
|
||||
|
||||
- On client-side, only keys in `runtimeConfig.public` are available, and the object is both writable and reactive.
|
||||
|
||||
- On server-side, the entire runtime config is available on the server-side, but it is read-only to avoid context sharing.
|
||||
- On server-side, the entire runtime config is available, but it is read-only to avoid context sharing.
|
||||
::
|
||||
|
||||
```vue [pages/index.vue]
|
||||
|
@ -15,6 +15,12 @@ The build and publishing method and quality of these 'nightly' releases are the
|
||||
Features that are only available on the nightly release channel are marked with an alert in the documentation.
|
||||
::
|
||||
|
||||
::alert{type="warning"}
|
||||
The `latest` nightly release channel is currently tracking the Nuxt v4 branch, meaning that it is particularly likely to have breaking changes right now - be careful!
|
||||
|
||||
You can opt in to the 3.x branch nightly releases with `"nuxt": "npm:nuxt-nightly@3x"`.
|
||||
::
|
||||
|
||||
## Opting In
|
||||
|
||||
Update `nuxt` dependency inside `package.json`:
|
||||
|
@ -90,7 +90,7 @@ declare module '#app' {
|
||||
}
|
||||
}
|
||||
|
||||
declare module 'nitropack' {
|
||||
declare module 'nitro/types' {
|
||||
interface NitroRuntimeHooks {
|
||||
'your-nitro-hook': () => void;
|
||||
}
|
||||
|
@ -583,7 +583,7 @@ export default defineNuxtModule({
|
||||
interface MyModuleNitroRules {
|
||||
myModule?: { foo: 'bar' }
|
||||
}
|
||||
declare module 'nitropack' {
|
||||
declare module 'nitro/types' {
|
||||
interface NitroRouteRules extends MyModuleNitroRules {}
|
||||
interface NitroRouteConfig extends MyModuleNitroRules {}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ Let's pretend here that:
|
||||
- If the API responds with a `401` status code, we redirect the user to the `/login` page
|
||||
|
||||
```ts [plugins/api.ts]
|
||||
export default defineNuxtPlugin(() => {
|
||||
export default defineNuxtPlugin((nuxtApp) => {
|
||||
const { session } = useUserSession()
|
||||
|
||||
const api = $fetch.create({
|
||||
@ -43,7 +43,7 @@ export default defineNuxtPlugin(() => {
|
||||
},
|
||||
async onResponseError({ response }) {
|
||||
if (response.status === 401) {
|
||||
await navigateTo('/login')
|
||||
await nuxtApp.runWithContext(() => navigateTo('/login'))
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -70,7 +70,7 @@ const { data: modules } = await useAsyncData('modules', () => $api('/modules'))
|
||||
Wrapping with [`useAsyncData`](/docs/api/composables/use-async-data) **avoid double data fetching when doing server-side rendering** (server & client on hydration).
|
||||
::
|
||||
|
||||
## Custom `useFetch`
|
||||
## Custom `useFetch`/`useAsyncData`
|
||||
|
||||
Now that `$api` has the logic we want, let's create a `useAPI` composable to replace the usage of `useAsyncData` + `$api`:
|
||||
|
||||
@ -96,6 +96,10 @@ const { data: modules } = await useAPI('/modules')
|
||||
</script>
|
||||
```
|
||||
|
||||
::note
|
||||
This example demonstrates how to use a custom `useFetch`, but the same structure is identical for a custom `useAsyncData`.
|
||||
::
|
||||
|
||||
::callout{icon="i-simple-icons-youtube" color="red" to="https://www.youtube.com/watch?v=jXH8Tr-exhI"}
|
||||
Watch a video about custom `$fetch` and Repository Pattern in Nuxt.
|
||||
::
|
||||
|
@ -111,7 +111,7 @@ When you need to overwrite this behavior you can use the `rel` and `noRel` props
|
||||
|
||||
When not using `external`, `<NuxtLink>` supports all Vue Router's [`RouterLink` props](https://router.vuejs.org/api/interfaces/RouterLinkProps.html)
|
||||
|
||||
- `to`: Any URL or a [route location object](https://router.vuejs.org/api/interfaces/RouteLocation.html) from Vue Router
|
||||
- `to`: Any URL or a [route location object](https://router.vuejs.org/api/#RouteLocation) from Vue Router
|
||||
- `custom`: Whether `<NuxtLink>` should wrap its content in an `<a>` element. It allows taking full control of how a link is rendered and how navigation works when it is clicked. Works the same as [Vue Router's `custom` prop](https://router.vuejs.org/api/interfaces/RouterLinkProps.html#Properties-custom)
|
||||
- `exactActiveClass`: A class to apply on exact active links. Works the same as [Vue Router's `exact-active-class` prop](https://router.vuejs.org/api/interfaces/RouterLinkProps.html#Properties-exactActiveClass) on internal links. Defaults to Vue Router's default `"router-link-exact-active"`)
|
||||
- `replace`: Works the same as [Vue Router's `replace` prop](https://router.vuejs.org/api/interfaces/RouteLocationOptions.html#Properties-replace) on internal links
|
||||
@ -140,7 +140,7 @@ Defaults can be overwritten, see [overwriting defaults](#overwriting-defaults) i
|
||||
|
||||
### In Nuxt Config
|
||||
|
||||
You can overwrite some `<NuxtLink>` defaults in your [`nuxt.config`](https://nuxt.com/docs/api/nuxt-config#defaults)
|
||||
You can overwrite some `<NuxtLink>` defaults in your [`nuxt.config`](/docs/api/nuxt-config#defaults)
|
||||
|
||||
::important
|
||||
These options will likely be moved elsewhere in the future, such as into `app.config` or into the `app/` directory.
|
||||
|
@ -25,6 +25,10 @@ const { data, pending, error, refresh, clear } = await useAsyncData(
|
||||
</script>
|
||||
```
|
||||
|
||||
::warning
|
||||
If you're using a custom useAsyncData wrapper, do not await it in the composable, as that can cause unexpected behavior. Please follow [this recipe](/docs/guide/recipes/custom-usefetch#custom-usefetch) for more information on how to make a custom async data fetcher.
|
||||
::
|
||||
|
||||
::note
|
||||
`data`, `pending`, `status` and `error` are Vue refs and they should be accessed with `.value` when used within the `<script setup>`, while `refresh`/`execute` and `clear` are plain functions.
|
||||
::
|
||||
|
@ -45,6 +45,10 @@ counter.value = counter.value || Math.round(Math.random() * 1000)
|
||||
|
||||
:link-example{to="/docs/examples/advanced/use-cookie"}
|
||||
|
||||
::note
|
||||
Refresh `useCookie` values manually when a cookie has changed with [`refreshCookie`](/docs/api/utils/refresh-cookie).
|
||||
::
|
||||
|
||||
## Options
|
||||
|
||||
Cookie composable accepts several options which let you modify the behavior of cookies.
|
||||
@ -148,6 +152,10 @@ Specifies the `boolean` or `string` value for [watch](https://vuejs.org/api/reac
|
||||
- `shallow` - Will watch cookie ref data changes for only top level properties
|
||||
- `false` - Will not watch cookie ref data changes.
|
||||
|
||||
::note
|
||||
Refresh `useCookie` values manually when a cookie has changed with [`refreshCookie`](/docs/api/utils/refresh-cookie).
|
||||
::
|
||||
|
||||
**Example 1:**
|
||||
|
||||
```vue
|
||||
|
@ -25,6 +25,10 @@ const { data, pending, error, refresh, clear } = await useFetch('/api/modules',
|
||||
</script>
|
||||
```
|
||||
|
||||
::warning
|
||||
If you're using a custom useFetch wrapper, do not await it in the composable, as that can cause unexpected behavior. Please follow [this recipe](/docs/guide/recipes/custom-usefetch#custom-usefetch) for more information on how to make a custom async data fetcher.
|
||||
::
|
||||
|
||||
::note
|
||||
`data`, `pending`, `status` and `error` are Vue refs and they should be accessed with `.value` when used within the `<script setup>`, while `refresh`/`execute` and `clear` are plain functions..
|
||||
::
|
||||
|
@ -252,7 +252,7 @@ For a better description of what Vue actually does, see [unjs/unctx#2 (comment)]
|
||||
|
||||
This is where `runWithContext` can be used to restore context, similarly to how `<script setup>` works.
|
||||
|
||||
Nuxt 3 internally uses [unjs/unctx](https://github.com/unjs/unctx) to support composables similar to Vue for plugins and middleware. This enables composables like `navigateTo()` to work without directly passing `nuxtApp` to them - bringing the DX and performance benefits of Composition API to the whole Nuxt framework.
|
||||
Nuxt internally uses [unjs/unctx](https://github.com/unjs/unctx) to support composables similar to Vue for plugins and middleware. This enables composables like `navigateTo()` to work without directly passing `nuxtApp` to them - bringing the DX and performance benefits of Composition API to the whole Nuxt framework.
|
||||
|
||||
Nuxt composables have the same design as the Vue Composition API and therefore need a similar solution to magically do this transform. Check out [unjs/unctx#2](https://github.com/unjs/unctx/issues/2) (proposal), [unjs/unctx#4](https://github.com/unjs/unctx/pull/4) (transform implementation), and [nuxt/framework#3884](https://github.com/nuxt/framework/pull/3884) (Integration to Nuxt).
|
||||
|
||||
|
@ -48,4 +48,4 @@ Apart from dynamic parameters and query parameters, `useRoute()` also provides t
|
||||
Browsers don't send [URL fragments](https://url.spec.whatwg.org/#concept-url-fragment) (for example `#foo`) when making requests. So using `route.fullPath` in your template can trigger hydration issues because this will include the fragment on client but not the server.
|
||||
::
|
||||
|
||||
:read-more{icon="i-simple-icons-vuedotjs" to="https://router.vuejs.org/api/interfaces/RouteLocationNormalizedLoaded.html"}
|
||||
:read-more{icon="i-simple-icons-vuedotjs" to="https://router.vuejs.org/api/#RouteLocationNormalizedLoaded"}
|
||||
|
@ -28,7 +28,7 @@ interface RouteMiddleware {
|
||||
|
||||
A function that takes two Vue Router's route location objects as parameters: the next route `to` as the first, and the current route `from` as the second.
|
||||
|
||||
Learn more about available properties of `RouteLocationNormalized` in the **[Vue Router docs](https://router.vuejs.org/api/interfaces/RouteLocationNormalized.html)**.
|
||||
Learn more about available properties of `RouteLocationNormalized` in the **[Vue Router docs](https://router.vuejs.org/api/#RouteLocationNormalized)**.
|
||||
|
||||
## Examples
|
||||
|
||||
|
@ -115,7 +115,7 @@ Make sure to always use `await` or `return` on result of `navigateTo` when calli
|
||||
|
||||
### `to`
|
||||
|
||||
**Type**: [`RouteLocationRaw`](https://router.vuejs.org/api/interfaces/RouteLocation.html) | `undefined` | `null`
|
||||
**Type**: [`RouteLocationRaw`](https://router.vuejs.org/api/interfaces/RouteLocationOptions.html#Interface-RouteLocationOptions) | `undefined` | `null`
|
||||
|
||||
**Default**: `'/'`
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
title: "nuxi upgrade"
|
||||
description: The upgrade command upgrades Nuxt 3 to the latest version.
|
||||
description: The upgrade command upgrades Nuxt to the latest version.
|
||||
links:
|
||||
- label: Source
|
||||
icon: i-simple-icons-github
|
||||
@ -12,7 +12,7 @@ links:
|
||||
npx nuxi upgrade [--force|-f]
|
||||
```
|
||||
|
||||
The `upgrade` command upgrades Nuxt 3 to the latest version.
|
||||
The `upgrade` command upgrades Nuxt to the latest version.
|
||||
|
||||
Option | Default | Description
|
||||
-------------------------|-----------------|------------------
|
||||
|
@ -8,7 +8,7 @@ links:
|
||||
size: xs
|
||||
---
|
||||
|
||||
Nitro is an open source TypeScript framework to build ultra-fast web servers. Nuxt 3 (and, optionally, Nuxt Bridge) uses Nitro as its server engine. You can use `useNitro` to access the Nitro instance, `addServerHandler` to add a server handler, `addDevServerHandler` to add a server handler to be used only in development mode, `addServerPlugin` to add a plugin to extend Nitro's runtime behavior, and `addPrerenderRoutes` to add routes to be prerendered by Nitro.
|
||||
Nitro is an open source TypeScript framework to build ultra-fast web servers. Nuxt uses Nitro as its server engine. You can use `useNitro` to access the Nitro instance, `addServerHandler` to add a server handler, `addDevServerHandler` to add a server handler to be used only in development mode, `addServerPlugin` to add a plugin to extend Nitro's runtime behavior, and `addPrerenderRoutes` to add routes to be prerendered by Nitro.
|
||||
|
||||
## `addServerHandler`
|
||||
|
||||
|
@ -10,7 +10,7 @@ links:
|
||||
|
||||
## `extendPages`
|
||||
|
||||
In Nuxt 3, routes are automatically generated based on the structure of the files in the `pages` directory. However, there may be scenarios where you'd want to customize these routes. For instance, you might need to add a route for a dynamic page not generated by Nuxt, remove an existing route, or modify the configuration of a route. For such customizations, Nuxt 3 offers the `extendPages` feature, which allows you to extend and alter the pages configuration.
|
||||
In Nuxt 3, routes are automatically generated based on the structure of the files in the `pages` directory. However, there may be scenarios where you'd want to customize these routes. For instance, you might need to add a route for a dynamic page not generated by Nuxt, remove an existing route, or modify the configuration of a route. For such customizations, Nuxt offers the `extendPages` feature, which allows you to extend and alter the pages configuration.
|
||||
|
||||
::tip{icon="i-ph-video-duotone" to="https://vueschool.io/lessons/extend-and-alter-nuxt-pages?friend=nuxt" target="_blank"}
|
||||
Watch Vue School video about extendPages.
|
||||
|
@ -15,7 +15,7 @@ Layouts is used to be a wrapper around your pages. It can be used to wrap your p
|
||||
Register template as layout and add it to the layouts.
|
||||
|
||||
::note
|
||||
In Nuxt 2 `error` layout can also be registered using this utility. In Nuxt 3 `error` layout [replaced](/docs/getting-started/error-handling#rendering-an-error-page) with `error.vue` page in project root.
|
||||
In Nuxt 2 `error` layout can also be registered using this utility. In Nuxt 3+ `error` layout [replaced](/docs/getting-started/error-handling#rendering-an-error-page) with `error.vue` page in project root.
|
||||
::
|
||||
|
||||
### Type
|
||||
|
@ -30,7 +30,7 @@ Hook | Arguments | Environment | Description
|
||||
`page:loading:end` | - | Client | Called after `page:finish`
|
||||
`page:transition:finish`| `pageComponent?` | Client | After page transition [onAfterLeave](https://vuejs.org/guide/built-ins/transition.html#javascript-hooks) event.
|
||||
`dev:ssr-logs` | `logs` | Client | Called with an array of server-side logs that have been passed to the client (if `features.devLogs` is enabled).
|
||||
`page:view-transition:start` | `transition` | Client | Called after `document.startViewTransition` is called when [experimental viewTransition support is enabled](https://nuxt.com/docs/getting-started/transitions#view-transitions-api-experimental).
|
||||
`page:view-transition:start` | `transition` | Client | Called after `document.startViewTransition` is called when [experimental viewTransition support is enabled](/docs/getting-started/transitions#view-transitions-api-experimental).
|
||||
|
||||
## Nuxt Hooks (build time)
|
||||
|
||||
|
@ -30,4 +30,4 @@ And finally, just ask the question! There's no need to [ask permission to ask a
|
||||
|
||||
Something isn't working the way that the docs say that it should. You're not sure if it's a bug. You've searched through the [open issues](https://github.com/nuxt/nuxt/issues) and [discussions](https://github.com/nuxt/nuxt/discussions) but you can't find anything. (if there is a closed issue, please create a new one)
|
||||
|
||||
We recommend taking a look at [how to report bugs](/docs/community/reporting-bugs). Nuxt 3 is still in active development, and every issue helps make it better.
|
||||
We recommend taking a look at [how to report bugs](/docs/community/reporting-bugs). Nuxt is still in active development, and every issue helps make it better.
|
||||
|
@ -22,31 +22,25 @@ Search through the [open issues](https://github.com/nuxt/nuxt/issues) and [discu
|
||||
|
||||
It's important to be able to reproduce the bug reliably - in a minimal way and apart from the rest of your project. This narrows down what could be causing the issue and makes it possible for someone not only to find the cause, but also to test a potential solution.
|
||||
|
||||
Start with the Nuxt 3 or Nuxt Bridge sandbox and add the **minimum** amount of code necessary to reproduce the bug you're experiencing.
|
||||
Start with the Nuxt sandbox and add the **minimum** amount of code necessary to reproduce the bug you're experiencing.
|
||||
|
||||
::note
|
||||
If your issue concerns Vue 3 or Vite, please try to reproduce it first with the Vue 3 SSR starter.
|
||||
If your issue concerns Vue or Vite, please try to reproduce it first with the Vue SSR starter.
|
||||
::
|
||||
|
||||
**Nuxt 3**:
|
||||
**Nuxt**:
|
||||
|
||||
::card-group
|
||||
:card{title="Nuxt 3 on StackBlitz" icon="i-simple-icons-stackblitz" to="https://nuxt.new/s/v3" target="_blank"}
|
||||
:card{title="Nuxt 3 on CodeSandbox" icon="i-simple-icons-codesandbox" to="https://nuxt.new/c/v3" target="_blank"}
|
||||
:card{title="Nuxt on StackBlitz" icon="i-simple-icons-stackblitz" to="https://nuxt.new/s/v3" target="_blank"}
|
||||
:card{title="Nuxt on CodeSandbox" icon="i-simple-icons-codesandbox" to="https://nuxt.new/c/v3" target="_blank"}
|
||||
::
|
||||
|
||||
**Nuxt Bridge**:
|
||||
**Vue**:
|
||||
|
||||
::card-group
|
||||
:card{title="Nuxt Bridge on CodeSandbox" icon="i-simple-icons-codesandbox" to="https://codesandbox.io/s/github/nuxt/starter/v2-bridge-codesandbox" target="_blank"}
|
||||
::
|
||||
|
||||
**Vue 3**:
|
||||
|
||||
::card-group
|
||||
:card{title="Vue 3 SSR on StackBlitz" icon="i-simple-icons-stackblitz" to="https://stackblitz.com/github/nuxt-contrib/vue3-ssr-starter/tree/main?terminal=dev" target="_blank"}
|
||||
:card{title="Vue 3 SSR on CodeSandbox" icon="i-simple-icons-codesandbox" to="https://codesandbox.io/s/github/nuxt-contrib/vue3-ssr-starter/main" target="_blank"}
|
||||
:card{title="Vue 3 SSR Template on GitHub" icon="i-simple-icons-github" to="https://github.com/nuxt-contrib/vue3-ssr-starter/generate" target="_blank"}
|
||||
:card{title="Vue SSR on StackBlitz" icon="i-simple-icons-stackblitz" to="https://stackblitz.com/github/nuxt-contrib/vue3-ssr-starter/tree/main?terminal=dev" target="_blank"}
|
||||
:card{title="Vue SSR on CodeSandbox" icon="i-simple-icons-codesandbox" to="https://codesandbox.io/s/github/nuxt-contrib/vue3-ssr-starter/main" target="_blank"}
|
||||
:card{title="Vue SSR Template on GitHub" icon="i-simple-icons-github" to="https://github.com/nuxt-contrib/vue3-ssr-starter/generate" target="_blank"}
|
||||
::
|
||||
|
||||
Once you've reproduced the issue, remove as much code from your reproduction as you can (while still recreating the bug). The time spent making the reproduction as minimal as possible will make a huge difference to whoever sets out to fix the issue.
|
||||
|
@ -32,10 +32,6 @@ We'll do our best to follow our [internal issue decision making flowchart](https
|
||||
|
||||
### Send a Pull Request
|
||||
|
||||
::Tip
|
||||
On windows, you need to clone the repository with `git clone -c core.symlinks=true https://github.com/nuxt/nuxt.git` to make symlinks work.
|
||||
::
|
||||
|
||||
We always welcome pull requests! ❤️
|
||||
|
||||
#### Before You Start
|
||||
|
@ -32,7 +32,7 @@ Milestone | Expected date | Notes
|
||||
-------------|---------------|------------------------------------------------------------------------|-----------------------
|
||||
SEO & PWA | 2024 | [nuxt/nuxt#18395](https://github.com/nuxt/nuxt/discussions/18395) | Migrating from [nuxt-community/pwa-module](https://github.com/nuxt-community/pwa-module) for built-in SEO utils and service worker support
|
||||
Assets | 2024 | [nuxt/nuxt#22012](https://github.com/nuxt/nuxt/discussions/22012) | Allow developers and modules to handle loading third-party assets.
|
||||
Translations | - | [nuxt/translations#4](https://github.com/nuxt/translations/discussions/4) ([request access](https://github.com/nuxt/nuxt/discussions/16054)) | A collaborative project for a stable translation process for Nuxt 3 docs. Currently pending for ideas and documentation tooling support (content v2 with remote sources).
|
||||
Translations | - | [nuxt/translations#4](https://github.com/nuxt/translations/discussions/4) ([request access](https://github.com/nuxt/nuxt/discussions/16054)) | A collaborative project for a stable translation process for Nuxt docs. Currently pending for ideas and documentation tooling support (content v2 with remote sources).
|
||||
|
||||
## Core Modules Roadmap
|
||||
|
||||
@ -42,7 +42,7 @@ Module | Status | Nuxt Support | Repos
|
||||
------------------------------------|---------------------|--------------|------------|-------------------
|
||||
[Scripts](https://scripts.nuxt.com) | Public Preview | 3.x | [nuxt/scripts](https://github.com/nuxt/scripts) | Easy 3rd party script management.
|
||||
A11y | Planned | 3.x | `nuxt/a11y` to be announced | Accessibility hinting and utilities [nuxt/nuxt#23255](https://github.com/nuxt/nuxt/issues/23255)
|
||||
Auth | Planned | 3.x | `nuxt/auth` to be announced | Nuxt 3 support is planned after session support.
|
||||
Auth | Planned | 3.x | `nuxt/auth` to be announced | Support is planned after session support.
|
||||
Hints | Planned | 3.x | `nuxt/hints` to be announced | Guidance and suggestions for enhancing development practices.
|
||||
|
||||
## Release Cycle
|
||||
@ -59,13 +59,13 @@ The current active version of [Nuxt](https://nuxt.com) is **v3** which is availa
|
||||
|
||||
Nuxt 2 is in maintenance mode and is available on npm with the `2x` tag. It will reach End of Life (EOL) on June 30, 2024.
|
||||
|
||||
Each active version has its own nightly releases which are generated automatically. For more about enabling the Nuxt 3 nightly release channel, see [the nightly release channel docs](/docs/guide/going-further/nightly-release-channel).
|
||||
Each active version has its own nightly releases which are generated automatically. For more about enabling the Nuxt nightly release channel, see [the nightly release channel docs](/docs/guide/going-further/nightly-release-channel).
|
||||
|
||||
Release | | Initial release | End Of Life | Docs
|
||||
----------------------------------------|---------------------------------------------------------------------------------------------------|-----------------|--------------|-------
|
||||
**4.x** (scheduled) | | 2024 Q2 | |
|
||||
**4.x** (scheduled) | | 2024 Q3 | |
|
||||
**3.x** (stable) | <a href="https://npmjs.com/package/nuxt"><img alt="Nuxt latest 3.x version" src="https://flat.badgen.net/npm/v/nuxt?label=" class="not-prose"></a> | 2022-11-16 | TBA | [nuxt.com](/docs)
|
||||
**2.x** (maintenance) | <a href="https://www.npmjs.com/package/nuxt?activeTab=versions"><img alt="Nuxt 2.x version" src="https://flat.badgen.net/npm/v/nuxt/2x?label=" class="not-prose"></a> | 2018-09-21 | 2024-06-30 | [v2.nuxt.com](https://v2.nuxt.com/docs)
|
||||
**2.x** (unsupported) | <a href="https://www.npmjs.com/package/nuxt?activeTab=versions"><img alt="Nuxt 2.x version" src="https://flat.badgen.net/npm/v/nuxt/2x?label=" class="not-prose"></a> | 2018-09-21 | 2024-06-30 | [v2.nuxt.com](https://v2.nuxt.com/docs)
|
||||
**1.x** (unsupported) | <a href="https://www.npmjs.com/package/nuxt?activeTab=versions"><img alt="Nuxt 1.x version" src="https://flat.badgen.net/npm/v/nuxt/1x?label=" class="not-prose"></a> | 2018-01-08 | 2019-09-21 |
|
||||
|
||||
### Support Status
|
||||
|
@ -44,7 +44,7 @@ Use of `defineNuxtRouteMiddleware` is not supported outside of the middleware di
|
||||
|
||||
## definePageMeta
|
||||
|
||||
You can also use [`definePageMeta`](https://nuxt.com/docs/api/utils/define-page-meta) in Nuxt Bridge.
|
||||
You can also use [`definePageMeta`](/docs/api/utils/define-page-meta) in Nuxt Bridge.
|
||||
|
||||
You can be enabled with the `macros.pageMeta` option in your configuration file
|
||||
|
||||
|
@ -148,17 +148,6 @@ export default createConfigForNuxt({
|
||||
],
|
||||
},
|
||||
],
|
||||
'import/order': [
|
||||
'error',
|
||||
{
|
||||
pathGroups: [
|
||||
{
|
||||
group: 'external',
|
||||
pattern: '#vue-router',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
'jsdoc/check-tag-names': [
|
||||
'error',
|
||||
{
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Nuxt 3 Examples
|
||||
# Nuxt Examples
|
||||
|
||||
- 👉 See examples in your browser at https://nuxt.com/docs/examples
|
||||
- 👉 View on GitHub at https://github.com/nuxt/examples
|
||||
|
55
package.json
55
package.json
@ -34,6 +34,12 @@
|
||||
"typecheck:docs": "DOCS_TYPECHECK=true pnpm nuxi prepare && nuxt-content-twoslash verify --content-dir docs"
|
||||
},
|
||||
"resolutions": {
|
||||
"nitro": "npm:nitro-nightly@3.0.0-beta-28659787.859de2d6",
|
||||
"typescript": "5.5.3",
|
||||
"h3": "npm:h3-nightly@2.0.0-1718872656.6765a6e",
|
||||
"c12": "2.0.0-beta.1",
|
||||
"jiti": "2.0.0-beta.3",
|
||||
"unbuild": "3.0.0-rc.6",
|
||||
"@nuxt/kit": "workspace:*",
|
||||
"@nuxt/schema": "workspace:*",
|
||||
"@nuxt/ui-templates": "workspace:*",
|
||||
@ -42,60 +48,65 @@
|
||||
"magic-string": "^0.30.10",
|
||||
"nuxt": "workspace:*",
|
||||
"rollup": "^4.18.0",
|
||||
"vite": "5.3.1",
|
||||
"vue": "3.4.29"
|
||||
"vite": "5.3.3",
|
||||
"vue": "3.4.31"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "9.5.0",
|
||||
"@eslint/js": "9.6.0",
|
||||
"@nuxt/eslint-config": "0.3.13",
|
||||
"@nuxt/kit": "workspace:*",
|
||||
"@nuxt/test-utils": "3.13.1",
|
||||
"@nuxt/webpack-builder": "workspace:*",
|
||||
"@testing-library/vue": "8.1.0",
|
||||
"@types/eslint__js": "8.42.3",
|
||||
"@types/fs-extra": "11.0.4",
|
||||
"@types/node": "20.14.5",
|
||||
"@types/node": "20.14.9",
|
||||
"@types/semver": "7.5.8",
|
||||
"@unhead/schema": "1.9.13",
|
||||
"@vitejs/plugin-vue": "5.0.4",
|
||||
"@unhead/schema": "1.9.14",
|
||||
"@vitejs/plugin-vue": "5.0.5",
|
||||
"@vitest/coverage-v8": "1.6.0",
|
||||
"@vue/test-utils": "2.4.6",
|
||||
"autoprefixer": "10.4.19",
|
||||
"case-police": "0.6.1",
|
||||
"changelogen": "0.5.5",
|
||||
"consola": "3.2.3",
|
||||
"cssnano": "7.0.3",
|
||||
"devalue": "5.0.0",
|
||||
"eslint": "9.5.0",
|
||||
"eslint": "9.6.0",
|
||||
"eslint-plugin-no-only-tests": "3.1.0",
|
||||
"eslint-plugin-perfectionist": "2.11.0",
|
||||
"eslint-typegen": "0.2.4",
|
||||
"execa": "9.2.0",
|
||||
"fs-extra": "11.2.0",
|
||||
"globby": "14.0.1",
|
||||
"h3": "1.11.1",
|
||||
"happy-dom": "14.12.0",
|
||||
"jiti": "1.21.6",
|
||||
"execa": "9.3.0",
|
||||
"globby": "14.0.2",
|
||||
"h3": "npm:h3-nightly@2.0.0-1718872656.6765a6e",
|
||||
"happy-dom": "14.12.3",
|
||||
"jiti": "2.0.0-beta.3",
|
||||
"markdownlint-cli": "0.41.0",
|
||||
"nitropack": "2.9.6",
|
||||
"nitro": "npm:nitro-nightly@3.0.0-beta-28659787.859de2d6",
|
||||
"nuxi": "3.12.0",
|
||||
"nuxt": "workspace:*",
|
||||
"nuxt-content-twoslash": "0.0.10",
|
||||
"nuxt-content-twoslash": "0.1.0",
|
||||
"ofetch": "1.3.4",
|
||||
"pathe": "1.1.2",
|
||||
"playwright-core": "1.44.1",
|
||||
"playwright-core": "1.45.1",
|
||||
"rimraf": "5.0.7",
|
||||
"semver": "7.6.2",
|
||||
"std-env": "3.7.0",
|
||||
"typescript": "5.4.5",
|
||||
"typescript": "5.5.3",
|
||||
"ufo": "1.5.3",
|
||||
"vitest": "1.6.0",
|
||||
"vitest-environment-nuxt": "1.0.0",
|
||||
"vue": "3.4.29",
|
||||
"vue-router": "4.3.3",
|
||||
"vue-tsc": "2.0.21"
|
||||
"vue": "3.4.31",
|
||||
"vue-router": "4.4.0",
|
||||
"vue-tsc": "2.0.24"
|
||||
},
|
||||
"packageManager": "pnpm@9.4.0",
|
||||
"engines": {
|
||||
"node": "^16.10.0 || >=18.0.0"
|
||||
},
|
||||
"version": ""
|
||||
"version": "",
|
||||
"pnpm": {
|
||||
"patchedDependencies": {
|
||||
"ofetch@1.3.4": "patches/ofetch@1.3.4.patch"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,9 +8,9 @@ export default defineBuildConfig({
|
||||
externals: [
|
||||
'@nuxt/schema',
|
||||
'nitropack',
|
||||
'nitro',
|
||||
'webpack',
|
||||
'vite',
|
||||
'h3',
|
||||
],
|
||||
failOnWarn: false,
|
||||
})
|
||||
|
7
packages/kit/index.d.ts
vendored
7
packages/kit/index.d.ts
vendored
@ -1,7 +0,0 @@
|
||||
/* eslint-disable no-var */
|
||||
declare global {
|
||||
var __NUXT_PREPATHS__: string[] | string | undefined
|
||||
var __NUXT_PATHS__: string[] | string | undefined
|
||||
}
|
||||
|
||||
export {}
|
@ -27,19 +27,18 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@nuxt/schema": "workspace:*",
|
||||
"c12": "^1.11.1",
|
||||
"c12": "^2.0.0-beta.1",
|
||||
"consola": "^3.2.3",
|
||||
"defu": "^6.1.4",
|
||||
"destr": "^2.0.3",
|
||||
"globby": "^14.0.1",
|
||||
"globby": "^14.0.2",
|
||||
"hash-sum": "^2.0.0",
|
||||
"ignore": "^5.3.1",
|
||||
"jiti": "^1.21.6",
|
||||
"jiti": "^2.0.0-beta.3",
|
||||
"klona": "^2.0.6",
|
||||
"knitwork": "^1.1.0",
|
||||
"mlly": "^1.7.1",
|
||||
"pathe": "^1.1.2",
|
||||
"pkg-types": "^1.1.1",
|
||||
"pkg-types": "^1.1.3",
|
||||
"scule": "^1.3.0",
|
||||
"semver": "^7.6.2",
|
||||
"ufo": "^1.5.3",
|
||||
@ -49,14 +48,12 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/hash-sum": "1.0.2",
|
||||
"@types/lodash-es": "4.17.12",
|
||||
"@types/semver": "7.5.8",
|
||||
"lodash-es": "4.17.21",
|
||||
"nitropack": "2.9.6",
|
||||
"unbuild": "latest",
|
||||
"vite": "5.3.1",
|
||||
"nitro": "npm:nitro-nightly@3.0.0-beta-28659787.859de2d6",
|
||||
"unbuild": "3.0.0-rc.6",
|
||||
"vite": "5.3.3",
|
||||
"vitest": "1.6.0",
|
||||
"webpack": "5.92.0"
|
||||
"webpack": "5.92.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.18.0 || >=16.10.0"
|
||||
|
@ -29,23 +29,6 @@ export async function checkNuxtCompatibility (constraints: NuxtCompatibility, nu
|
||||
}
|
||||
}
|
||||
|
||||
// Bridge compatibility check
|
||||
if (isNuxt2(nuxt)) {
|
||||
const bridgeRequirement = constraints.bridge
|
||||
const hasBridge = !!(nuxt.options as any).bridge
|
||||
if (bridgeRequirement === true && !hasBridge) {
|
||||
issues.push({
|
||||
name: 'bridge',
|
||||
message: 'Nuxt bridge is required',
|
||||
})
|
||||
} else if (bridgeRequirement === false && hasBridge) {
|
||||
issues.push({
|
||||
name: 'bridge',
|
||||
message: 'Nuxt bridge is not supported',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Builder compatibility check
|
||||
if (constraints.builder && typeof nuxt.options.builder === 'string') {
|
||||
const currentBuilder = builderMap[nuxt.options.builder] || nuxt.options.builder
|
||||
@ -98,19 +81,26 @@ export async function hasNuxtCompatibility (constraints: NuxtCompatibility, nuxt
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if current nuxt instance is version 2 legacy
|
||||
* Check if current Nuxt instance is of specified major version
|
||||
*/
|
||||
export function isNuxt2 (nuxt: Nuxt = useNuxt()) {
|
||||
export function isNuxtMajorVersion (majorVersion: 2 | 3 | 4, nuxt: Nuxt = useNuxt()) {
|
||||
const version = getNuxtVersion(nuxt)
|
||||
return version[0] === '2' && version[1] === '.'
|
||||
|
||||
return version[0] === majorVersion.toString() && version[1] === '.'
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if current nuxt instance is version 3
|
||||
* @deprecated Use `isNuxtMajorVersion(2, nuxt)` instead. This may be removed in \@nuxt/kit v5 or a future major version.
|
||||
*/
|
||||
export function isNuxt2 (nuxt: Nuxt = useNuxt()) {
|
||||
return isNuxtMajorVersion(2, nuxt)
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use `isNuxtMajorVersion(3, nuxt)` instead. This may be removed in \@nuxt/kit v5 or a future major version.
|
||||
*/
|
||||
export function isNuxt3 (nuxt: Nuxt = useNuxt()) {
|
||||
const version = getNuxtVersion(nuxt)
|
||||
return version[0] === '3' && version[1] === '.'
|
||||
return isNuxtMajorVersion(3, nuxt)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -55,7 +55,7 @@ export async function addComponent (opts: AddComponentOptions) {
|
||||
nuxt.hook('components:extend', (components: Component[]) => {
|
||||
const existingComponentIndex = components.findIndex(c => (c.pascalName === component.pascalName || c.kebabName === component.kebabName) && c.mode === component.mode)
|
||||
if (existingComponentIndex !== -1) {
|
||||
const existingComponent = components[existingComponentIndex]
|
||||
const existingComponent = components[existingComponentIndex]!
|
||||
const existingPriority = existingComponent.priority ?? 0
|
||||
const newPriority = component.priority ?? 0
|
||||
|
||||
|
@ -50,7 +50,7 @@ export function resolveIgnorePatterns (relativePath?: string): string[] {
|
||||
// Map ignore patterns based on if they start with * or !*
|
||||
return ignorePatterns.map((p) => {
|
||||
const [_, negation = '', pattern] = p.match(NEGATION_RE) || []
|
||||
if (pattern[0] === '*') {
|
||||
if (pattern && pattern[0] === '*') {
|
||||
return p
|
||||
}
|
||||
return negation + relative(relativePath, resolve(nuxt.options.rootDir, pattern || p))
|
||||
@ -73,7 +73,7 @@ export function resolveGroupSyntax (group: string): string[] {
|
||||
groups = groups.flatMap((group) => {
|
||||
const [head, ...tail] = group.split('{')
|
||||
if (tail.length) {
|
||||
const [body, ...rest] = tail.join('{').split('}')
|
||||
const [body = '', ...rest] = tail.join('{').split('}')
|
||||
return body.split(',').map(part => `${head}${part}${rest.join('')}`)
|
||||
}
|
||||
|
||||
|
@ -1,38 +1,35 @@
|
||||
// Module
|
||||
export * from './module/define'
|
||||
export * from './module/install'
|
||||
export * from './module/compatibility'
|
||||
export { defineNuxtModule } from './module/define'
|
||||
export { getDirectory, installModule, loadNuxtModuleInstance, normalizeModuleTranspilePath } from './module/install'
|
||||
export { getNuxtModuleVersion, hasNuxtModule, hasNuxtModuleCompatibility } from './module/compatibility'
|
||||
|
||||
// Loader
|
||||
export * from './loader/config'
|
||||
export * from './loader/schema'
|
||||
export * from './loader/nuxt'
|
||||
export { loadNuxtConfig } from './loader/config'
|
||||
export type { LoadNuxtConfigOptions } from './loader/config'
|
||||
export { extendNuxtSchema } from './loader/schema'
|
||||
export { buildNuxt, loadNuxt } from './loader/nuxt'
|
||||
export type { LoadNuxtOptions } from './loader/nuxt'
|
||||
|
||||
// Utils
|
||||
export * from './imports'
|
||||
export { addImports, addImportsDir, addImportsSources } from './imports'
|
||||
export { updateRuntimeConfig, useRuntimeConfig } from './runtime-config'
|
||||
export * from './build'
|
||||
export * from './compatibility'
|
||||
export * from './components'
|
||||
export * from './context'
|
||||
export { addBuildPlugin, addVitePlugin, addWebpackPlugin, extendViteConfig, extendWebpackConfig } from './build'
|
||||
export type { ExtendConfigOptions, ExtendViteConfigOptions, ExtendWebpackConfigOptions } from './build'
|
||||
export { assertNuxtCompatibility, checkNuxtCompatibility, getNuxtVersion, hasNuxtCompatibility, isNuxtMajorVersion, normalizeSemanticVersion, isNuxt2, isNuxt3 } from './compatibility'
|
||||
export { addComponent, addComponentsDir } from './components'
|
||||
export type { AddComponentOptions } from './components'
|
||||
export { nuxtCtx, tryUseNuxt, useNuxt } from './context'
|
||||
export { isIgnored, resolveIgnorePatterns } from './ignore'
|
||||
export * from './layout'
|
||||
export * from './pages'
|
||||
export * from './plugin'
|
||||
export * from './resolve'
|
||||
export * from './nitro'
|
||||
export { addLayout } from './layout'
|
||||
export { addRouteMiddleware, extendPages, extendRouteRules } from './pages'
|
||||
export type { AddRouteMiddlewareOptions, ExtendRouteRulesOptions } from './pages'
|
||||
export { addPlugin, addPluginTemplate, normalizePlugin } from './plugin'
|
||||
export type { AddPluginOptions } from './plugin'
|
||||
export { createResolver, findPath, resolveAlias, resolveFiles, resolveNuxtModule, resolvePath } from './resolve'
|
||||
export type { ResolvePathOptions, Resolver } from './resolve'
|
||||
export { addServerHandler, addDevServerHandler, addServerPlugin, addPrerenderRoutes, useNitro, addServerImports, addServerImportsDir, addServerScanDir } from './nitro'
|
||||
export { addTemplate, addTypeTemplate, normalizeTemplate, updateTemplates, writeTypes } from './template'
|
||||
export * from './logger'
|
||||
export { logger, useLogger } from './logger'
|
||||
|
||||
// Internal Utils
|
||||
// TODO
|
||||
export {
|
||||
resolveModule,
|
||||
requireModule,
|
||||
importModule,
|
||||
tryImportModule,
|
||||
tryRequireModule,
|
||||
} from './internal/cjs'
|
||||
export type { ResolveModuleOptions, RequireModuleOptions } from './internal/cjs'
|
||||
export { tryResolveModule } from './internal/esm'
|
||||
export * from './internal/template'
|
||||
|
@ -1,121 +0,0 @@
|
||||
import { pathToFileURL } from 'node:url'
|
||||
import { normalize } from 'pathe'
|
||||
import { interopDefault } from 'mlly'
|
||||
import jiti from 'jiti'
|
||||
|
||||
// TODO: use create-require for jest environment
|
||||
const _require = jiti(process.cwd(), { interopDefault: true, esmResolve: true })
|
||||
|
||||
/** @deprecated Do not use CJS utils */
|
||||
export interface ResolveModuleOptions {
|
||||
paths?: string | string[]
|
||||
}
|
||||
|
||||
/** @deprecated Do not use CJS utils */
|
||||
export interface RequireModuleOptions extends ResolveModuleOptions {
|
||||
// TODO: use create-require for jest environment
|
||||
// native?: boolean
|
||||
/** Clear the require cache (force fresh require) but only if not within `node_modules` */
|
||||
clearCache?: boolean
|
||||
|
||||
/** Automatically de-default the result of requiring the module. */
|
||||
interopDefault?: boolean
|
||||
}
|
||||
|
||||
/** @deprecated Do not use CJS utils */
|
||||
function isNodeModules (id: string) {
|
||||
// TODO: Follow symlinks
|
||||
return /[/\\]node_modules[/\\]/.test(id)
|
||||
}
|
||||
|
||||
/** @deprecated Do not use CJS utils */
|
||||
function clearRequireCache (id: string) {
|
||||
if (isNodeModules(id)) {
|
||||
return
|
||||
}
|
||||
|
||||
const entry = getRequireCacheItem(id)
|
||||
|
||||
if (!entry) {
|
||||
delete _require.cache[id]
|
||||
return
|
||||
}
|
||||
|
||||
if (entry.parent) {
|
||||
entry.parent.children = entry.parent.children.filter(e => e.id !== id)
|
||||
}
|
||||
|
||||
for (const child of entry.children) {
|
||||
clearRequireCache(child.id)
|
||||
}
|
||||
|
||||
delete _require.cache[id]
|
||||
}
|
||||
|
||||
/** @deprecated Do not use CJS utils */
|
||||
function getRequireCacheItem (id: string) {
|
||||
try {
|
||||
return _require.cache[id]
|
||||
} catch (e) {
|
||||
// ignore issues accessing require.cache
|
||||
}
|
||||
}
|
||||
|
||||
export function getNodeModulesPaths (paths?: string[] | string) {
|
||||
return ([] as Array<string | undefined>).concat(
|
||||
global.__NUXT_PREPATHS__,
|
||||
paths || [],
|
||||
process.cwd(),
|
||||
global.__NUXT_PATHS__,
|
||||
).filter(Boolean) as string[]
|
||||
}
|
||||
|
||||
/** @deprecated Do not use CJS utils */
|
||||
export function resolveModule (id: string, opts: ResolveModuleOptions = {}) {
|
||||
return normalize(_require.resolve(id, {
|
||||
paths: getNodeModulesPaths(opts.paths),
|
||||
}))
|
||||
}
|
||||
|
||||
/** @deprecated Do not use CJS utils */
|
||||
export function requireModule (id: string, opts: RequireModuleOptions = {}) {
|
||||
// Resolve id
|
||||
const resolvedPath = resolveModule(id, opts)
|
||||
|
||||
// Clear require cache if necessary
|
||||
if (opts.clearCache && !isNodeModules(id)) {
|
||||
clearRequireCache(resolvedPath)
|
||||
}
|
||||
|
||||
// Try to require
|
||||
const requiredModule = _require(resolvedPath)
|
||||
|
||||
return requiredModule
|
||||
}
|
||||
|
||||
/** @deprecated Do not use CJS utils */
|
||||
export function importModule (id: string, opts: RequireModuleOptions = {}) {
|
||||
const resolvedPath = resolveModule(id, opts)
|
||||
if (opts.interopDefault !== false) {
|
||||
return import(pathToFileURL(resolvedPath).href).then(interopDefault)
|
||||
}
|
||||
return import(pathToFileURL(resolvedPath).href)
|
||||
}
|
||||
|
||||
/** @deprecated Do not use CJS utils */
|
||||
export function tryImportModule (id: string, opts: RequireModuleOptions = {}) {
|
||||
try {
|
||||
return importModule(id, opts).catch(() => undefined)
|
||||
} catch {
|
||||
// intentionally empty as this is a `try-` function
|
||||
}
|
||||
}
|
||||
|
||||
/** @deprecated Do not use CJS utils */
|
||||
export function tryRequireModule (id: string, opts: RequireModuleOptions = {}) {
|
||||
try {
|
||||
return requireModule(id, opts)
|
||||
} catch {
|
||||
// intentionally empty as this is a `try-` function
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
import { promises as fsp } from 'node:fs'
|
||||
// TODO: swap out when https://github.com/lodash/lodash/pull/5649 is merged
|
||||
import { template as lodashTemplate } from 'lodash-es'
|
||||
import { genDynamicImport, genImport, genSafeVariableName } from 'knitwork'
|
||||
|
||||
import type { NuxtTemplate } from '@nuxt/schema'
|
||||
import { logger } from '../logger'
|
||||
import { toArray } from '../utils'
|
||||
|
||||
/** @deprecated */
|
||||
// TODO: Remove support for compiling ejs templates in v4
|
||||
export async function compileTemplate<T> (template: NuxtTemplate<T>, ctx: any) {
|
||||
const data = { ...ctx, options: template.options }
|
||||
if (template.src) {
|
||||
try {
|
||||
const srcContents = await fsp.readFile(template.src, 'utf-8')
|
||||
return lodashTemplate(srcContents, {})(data)
|
||||
} catch (err) {
|
||||
logger.error('Error compiling template: ', template)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
if (template.getContents) {
|
||||
return template.getContents(data)
|
||||
}
|
||||
throw new Error('Invalid template: ' + JSON.stringify(template))
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
const serialize = (data: any) => JSON.stringify(data, null, 2).replace(/"\{(.+)\}"(?=,?$)/gm, r => JSON.parse(r).replace(/^\{(.*)\}$/, '$1'))
|
||||
|
||||
/** @deprecated */
|
||||
const importSources = (sources: string | string[], { lazy = false } = {}) => {
|
||||
return toArray(sources).map((src) => {
|
||||
const safeVariableName = genSafeVariableName(src)
|
||||
if (lazy) {
|
||||
return `const ${safeVariableName} = ${genDynamicImport(src, { comment: `webpackChunkName: ${JSON.stringify(src)}` })}`
|
||||
}
|
||||
return genImport(src, safeVariableName)
|
||||
}).join('\n')
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
const importName = genSafeVariableName
|
||||
|
||||
/** @deprecated */
|
||||
export const templateUtils = { serialize, importName, importSources }
|
@ -1,7 +1,6 @@
|
||||
import type { NuxtTemplate } from '@nuxt/schema'
|
||||
import { join, parse, relative } from 'pathe'
|
||||
import { kebabCase } from 'scule'
|
||||
import { isNuxt2 } from './compatibility'
|
||||
import { useNuxt } from './context'
|
||||
import { logger } from './logger'
|
||||
import { addTemplate } from './template'
|
||||
@ -11,25 +10,10 @@ export function addLayout (this: any, template: NuxtTemplate | string, name?: st
|
||||
const { filename, src } = addTemplate(template)
|
||||
const layoutName = kebabCase(name || parse(filename).name).replace(/["']/g, '')
|
||||
|
||||
if (isNuxt2(nuxt)) {
|
||||
// Nuxt 2 adds layouts in options
|
||||
const layout = (nuxt.options as any).layouts[layoutName]
|
||||
if (layout) {
|
||||
return logger.warn(
|
||||
`Not overriding \`${layoutName}\` (provided by \`${layout}\`) with \`${src || filename}\`.`,
|
||||
)
|
||||
}
|
||||
(nuxt.options as any).layouts[layoutName] = `./${filename}`
|
||||
if (name === 'error') {
|
||||
this.addErrorLayout(filename)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Nuxt 3 adds layouts on app
|
||||
nuxt.hook('app:templates', (app) => {
|
||||
if (layoutName in app.layouts) {
|
||||
const relativePath = relative(nuxt.options.srcDir, app.layouts[layoutName].file)
|
||||
const relativePath = relative(nuxt.options.srcDir, app.layouts[layoutName]!.file)
|
||||
return logger.warn(
|
||||
`Not overriding \`${layoutName}\` (provided by \`~/${relativePath}\`) with \`${src || filename}\`.`,
|
||||
)
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { pathToFileURL } from 'node:url'
|
||||
import { readPackageJSON, resolvePackageJSON } from 'pkg-types'
|
||||
import type { Nuxt } from '@nuxt/schema'
|
||||
import { resolve } from 'pathe'
|
||||
import { importModule, tryImportModule } from '../internal/esm'
|
||||
import type { LoadNuxtConfigOptions } from './config'
|
||||
|
||||
@ -10,76 +11,34 @@ export interface LoadNuxtOptions extends LoadNuxtConfigOptions {
|
||||
|
||||
/** Use lazy initialization of nuxt if set to false */
|
||||
ready?: boolean
|
||||
|
||||
/** @deprecated Use cwd option */
|
||||
rootDir?: LoadNuxtConfigOptions['cwd']
|
||||
|
||||
/** @deprecated use overrides option */
|
||||
config?: LoadNuxtConfigOptions['overrides']
|
||||
}
|
||||
|
||||
export async function loadNuxt (opts: LoadNuxtOptions): Promise<Nuxt> {
|
||||
// Backward compatibility
|
||||
opts.cwd = opts.cwd || opts.rootDir
|
||||
opts.overrides = opts.overrides || opts.config || {}
|
||||
opts.cwd = resolve(opts.cwd || (opts as any).rootDir /* backwards compat */ || '.')
|
||||
opts.overrides = opts.overrides || (opts as any).config as {} /* backwards compat */ || {}
|
||||
|
||||
// Apply dev as config override
|
||||
opts.overrides.dev = !!opts.dev
|
||||
|
||||
const nearestNuxtPkg = await Promise.all(['nuxt-nightly', 'nuxt3', 'nuxt', 'nuxt-edge']
|
||||
const nearestNuxtPkg = await Promise.all(['nuxt-nightly', 'nuxt']
|
||||
.map(pkg => resolvePackageJSON(pkg, { url: opts.cwd }).catch(() => null)))
|
||||
.then(r => (r.filter(Boolean) as string[]).sort((a, b) => b.length - a.length)[0])
|
||||
if (!nearestNuxtPkg) {
|
||||
throw new Error(`Cannot find any nuxt version from ${opts.cwd}`)
|
||||
}
|
||||
const pkg = await readPackageJSON(nearestNuxtPkg)
|
||||
const majorVersion = pkg.version ? Number.parseInt(pkg.version.split('.')[0]) : ''
|
||||
|
||||
const rootDir = pathToFileURL(opts.cwd || process.cwd()).href
|
||||
const rootDir = pathToFileURL(opts.cwd!).href
|
||||
|
||||
// Nuxt 3
|
||||
if (majorVersion === 3) {
|
||||
const { loadNuxt } = await importModule((pkg as any)._name || pkg.name, rootDir)
|
||||
const nuxt = await loadNuxt(opts)
|
||||
return nuxt
|
||||
}
|
||||
|
||||
// Nuxt 2
|
||||
const { loadNuxt } = await tryImportModule('nuxt-edge', rootDir) || await importModule('nuxt', rootDir)
|
||||
const nuxt = await loadNuxt({
|
||||
rootDir: opts.cwd,
|
||||
for: opts.dev ? 'dev' : 'build',
|
||||
configOverrides: opts.overrides,
|
||||
ready: opts.ready,
|
||||
envConfig: opts.dotenv, // TODO: Backward format conversion
|
||||
})
|
||||
|
||||
// Mock new hookable methods
|
||||
nuxt.removeHook ||= nuxt.clearHook.bind(nuxt)
|
||||
nuxt.removeAllHooks ||= nuxt.clearHooks.bind(nuxt)
|
||||
nuxt.hookOnce ||= (name: string, fn: (...args: any[]) => any, ...hookArgs: any[]) => {
|
||||
const unsub = nuxt.hook(name, (...args: any[]) => {
|
||||
unsub()
|
||||
return fn(...args)
|
||||
}, ...hookArgs)
|
||||
return unsub
|
||||
}
|
||||
// https://github.com/nuxt/nuxt/tree/main/packages/kit/src/module/define.ts#L111-L113
|
||||
nuxt.hooks ||= nuxt
|
||||
|
||||
return nuxt as Nuxt
|
||||
}
|
||||
|
||||
export async function buildNuxt (nuxt: Nuxt): Promise<any> {
|
||||
const rootDir = pathToFileURL(nuxt.options.rootDir).href
|
||||
|
||||
// Nuxt 3
|
||||
if (nuxt.options._majorVersion === 3) {
|
||||
const { build } = await tryImportModule('nuxt-nightly', rootDir) || await tryImportModule('nuxt3', rootDir) || await importModule('nuxt', rootDir)
|
||||
return build(nuxt)
|
||||
}
|
||||
|
||||
// Nuxt 2
|
||||
const { build } = await tryImportModule('nuxt-edge', rootDir) || await importModule('nuxt', rootDir)
|
||||
const { build } = await tryImportModule('nuxt-nightly', rootDir) || await importModule('nuxt', rootDir)
|
||||
return build(nuxt)
|
||||
}
|
||||
|
@ -1,40 +1,85 @@
|
||||
import { promises as fsp } from 'node:fs'
|
||||
import { performance } from 'node:perf_hooks'
|
||||
import { defu } from 'defu'
|
||||
import { applyDefaults } from 'untyped'
|
||||
import { dirname } from 'pathe'
|
||||
import type { ModuleDefinition, ModuleOptions, ModuleSetupReturn, Nuxt, NuxtModule, NuxtOptions, ResolvedNuxtTemplate } from '@nuxt/schema'
|
||||
import type { ModuleDefinition, ModuleOptions, ModuleSetupInstallResult, ModuleSetupReturn, Nuxt, NuxtModule, NuxtOptions, ResolvedModuleOptions } from '@nuxt/schema'
|
||||
import { logger } from '../logger'
|
||||
import { nuxtCtx, tryUseNuxt, useNuxt } from '../context'
|
||||
import { checkNuxtCompatibility, isNuxt2 } from '../compatibility'
|
||||
import { compileTemplate, templateUtils } from '../internal/template'
|
||||
import { tryUseNuxt, useNuxt } from '../context'
|
||||
import { checkNuxtCompatibility } from '../compatibility'
|
||||
|
||||
/**
|
||||
* Define a Nuxt module, automatically merging defaults with user provided options, installing
|
||||
* any hooks that are provided, and calling an optional setup function for full control.
|
||||
*/
|
||||
export function defineNuxtModule<OptionsT extends ModuleOptions> (definition: ModuleDefinition<OptionsT> | NuxtModule<OptionsT>): NuxtModule<OptionsT> {
|
||||
if (typeof definition === 'function') { return defineNuxtModule({ setup: definition }) }
|
||||
export function defineNuxtModule<TOptions extends ModuleOptions> (
|
||||
definition: ModuleDefinition<TOptions, Partial<TOptions>, false> | NuxtModule<TOptions, Partial<TOptions>, false>
|
||||
): NuxtModule<TOptions, TOptions, false>
|
||||
|
||||
export function defineNuxtModule<TOptions extends ModuleOptions> (): {
|
||||
with: <TOptionsDefaults extends Partial<TOptions>> (
|
||||
definition: ModuleDefinition<TOptions, TOptionsDefaults, true> | NuxtModule<TOptions, TOptionsDefaults, true>
|
||||
) => NuxtModule<TOptions, TOptionsDefaults, true>
|
||||
}
|
||||
|
||||
export function defineNuxtModule<TOptions extends ModuleOptions> (
|
||||
definition?: ModuleDefinition<TOptions, Partial<TOptions>, false> | NuxtModule<TOptions, Partial<TOptions>, false>,
|
||||
) {
|
||||
if (definition) {
|
||||
return _defineNuxtModule(definition)
|
||||
}
|
||||
|
||||
return {
|
||||
with: <TOptionsDefaults extends Partial<TOptions>>(
|
||||
definition: ModuleDefinition<TOptions, TOptionsDefaults, true> | NuxtModule<TOptions, TOptionsDefaults, true>,
|
||||
) => _defineNuxtModule(definition),
|
||||
}
|
||||
}
|
||||
|
||||
function _defineNuxtModule<
|
||||
TOptions extends ModuleOptions,
|
||||
TOptionsDefaults extends Partial<TOptions>,
|
||||
TWith extends boolean,
|
||||
> (
|
||||
definition: ModuleDefinition<TOptions, TOptionsDefaults, TWith> | NuxtModule<TOptions, TOptionsDefaults, TWith>,
|
||||
): NuxtModule<TOptions, TOptionsDefaults, TWith> {
|
||||
if (typeof definition === 'function') {
|
||||
return _defineNuxtModule<TOptions, TOptionsDefaults, TWith>({ setup: definition })
|
||||
}
|
||||
|
||||
// Normalize definition and meta
|
||||
const module: ModuleDefinition<OptionsT> & Required<Pick<ModuleDefinition<OptionsT>, 'meta'>> = defu(definition, { meta: {} })
|
||||
if (module.meta.configKey === undefined) {
|
||||
module.meta.configKey = module.meta.name
|
||||
}
|
||||
const module: ModuleDefinition<TOptions, TOptionsDefaults, TWith> & Required<Pick<ModuleDefinition<TOptions, TOptionsDefaults, TWith>, 'meta'>> = defu(definition, { meta: {} })
|
||||
|
||||
module.meta.configKey ||= module.meta.name
|
||||
|
||||
// Resolves module options from inline options, [configKey] in nuxt.config, defaults and schema
|
||||
async function getOptions (inlineOptions?: OptionsT, nuxt: Nuxt = useNuxt()) {
|
||||
const configKey = module.meta.configKey || module.meta.name!
|
||||
const _defaults = module.defaults instanceof Function ? module.defaults(nuxt) : module.defaults
|
||||
let _options = defu(inlineOptions, nuxt.options[configKey as keyof NuxtOptions], _defaults) as OptionsT
|
||||
async function getOptions (
|
||||
inlineOptions?: Partial<TOptions>,
|
||||
nuxt: Nuxt = useNuxt(),
|
||||
): Promise<
|
||||
TWith extends true
|
||||
? ResolvedModuleOptions<TOptions, TOptionsDefaults>
|
||||
: TOptions
|
||||
> {
|
||||
const nuxtConfigOptionsKey = module.meta.configKey || module.meta.name
|
||||
|
||||
const nuxtConfigOptions: Partial<TOptions> = nuxtConfigOptionsKey && nuxtConfigOptionsKey in nuxt.options ? nuxt.options[<keyof NuxtOptions> nuxtConfigOptionsKey] : {}
|
||||
|
||||
const optionsDefaults: TOptionsDefaults =
|
||||
module.defaults instanceof Function
|
||||
? module.defaults(nuxt)
|
||||
: module.defaults ?? <TOptionsDefaults> {}
|
||||
|
||||
let options = defu(inlineOptions, nuxtConfigOptions, optionsDefaults)
|
||||
|
||||
if (module.schema) {
|
||||
_options = await applyDefaults(module.schema, _options) as OptionsT
|
||||
options = await applyDefaults(module.schema, options) as any
|
||||
}
|
||||
return Promise.resolve(_options)
|
||||
|
||||
// @ts-expect-error ignore type mismatch when calling `defineNuxtModule` without `.with()`
|
||||
return Promise.resolve(options)
|
||||
}
|
||||
|
||||
// Module format is always a simple function
|
||||
async function normalizedModule (this: any, inlineOptions: OptionsT, nuxt: Nuxt) {
|
||||
async function normalizedModule (this: any, inlineOptions: Partial<TOptions>, nuxt: Nuxt): Promise<ModuleSetupReturn> {
|
||||
if (!nuxt) {
|
||||
nuxt = tryUseNuxt() || this.nuxt /* invoked by nuxt 2 */
|
||||
}
|
||||
@ -58,9 +103,6 @@ export function defineNuxtModule<OptionsT extends ModuleOptions> (definition: Mo
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare
|
||||
nuxt2Shims(nuxt)
|
||||
|
||||
// Resolve module and options
|
||||
const _options = await getOptions(inlineOptions, nuxt)
|
||||
|
||||
@ -70,11 +112,10 @@ export function defineNuxtModule<OptionsT extends ModuleOptions> (definition: Mo
|
||||
}
|
||||
|
||||
// Call setup
|
||||
const key = `nuxt:module:${uniqueKey || (Math.round(Math.random() * 10000))}`
|
||||
const mark = performance.mark(key)
|
||||
const start = performance.now()
|
||||
const res = await module.setup?.call(null as any, _options, nuxt) ?? {}
|
||||
const perf = performance.measure(key, mark.name)
|
||||
const setupTime = Math.round((perf.duration * 100)) / 100
|
||||
const perf = performance.now() - start
|
||||
const setupTime = Math.round((perf * 100)) / 100
|
||||
|
||||
// Measure setup time
|
||||
if (setupTime > 5000 && uniqueKey !== '@nuxt/telemetry') {
|
||||
@ -87,7 +128,7 @@ export function defineNuxtModule<OptionsT extends ModuleOptions> (definition: Mo
|
||||
if (res === false) { return false }
|
||||
|
||||
// Return module install result
|
||||
return defu(res, <ModuleSetupReturn> {
|
||||
return defu(res, <ModuleSetupInstallResult> {
|
||||
timings: {
|
||||
setup: setupTime,
|
||||
},
|
||||
@ -98,55 +139,5 @@ export function defineNuxtModule<OptionsT extends ModuleOptions> (definition: Mo
|
||||
normalizedModule.getMeta = () => Promise.resolve(module.meta)
|
||||
normalizedModule.getOptions = getOptions
|
||||
|
||||
return normalizedModule as NuxtModule<OptionsT>
|
||||
}
|
||||
|
||||
// -- Nuxt 2 compatibility shims --
|
||||
const NUXT2_SHIMS_KEY = '__nuxt2_shims_key__'
|
||||
function nuxt2Shims (nuxt: Nuxt) {
|
||||
// Avoid duplicate install and only apply to Nuxt2
|
||||
if (!isNuxt2(nuxt) || nuxt[NUXT2_SHIMS_KEY as keyof Nuxt]) { return }
|
||||
nuxt[NUXT2_SHIMS_KEY as keyof Nuxt] = true
|
||||
|
||||
// Allow using nuxt.hooks
|
||||
// @ts-expect-error Nuxt 2 extends hookable
|
||||
nuxt.hooks = nuxt
|
||||
|
||||
// Allow using useNuxt()
|
||||
if (!nuxtCtx.tryUse()) {
|
||||
nuxtCtx.set(nuxt)
|
||||
nuxt.hook('close', () => nuxtCtx.unset())
|
||||
}
|
||||
|
||||
// Support virtual templates with getContents() by writing them to .nuxt directory
|
||||
let virtualTemplates: ResolvedNuxtTemplate[]
|
||||
// @ts-expect-error Nuxt 2 hook
|
||||
nuxt.hook('builder:prepared', (_builder, buildOptions) => {
|
||||
virtualTemplates = buildOptions.templates.filter((t: any) => t.getContents)
|
||||
for (const template of virtualTemplates) {
|
||||
buildOptions.templates.splice(buildOptions.templates.indexOf(template), 1)
|
||||
}
|
||||
})
|
||||
// @ts-expect-error Nuxt 2 hook
|
||||
nuxt.hook('build:templates', async (templates) => {
|
||||
const context = {
|
||||
nuxt,
|
||||
utils: templateUtils,
|
||||
app: {
|
||||
dir: nuxt.options.srcDir,
|
||||
extensions: nuxt.options.extensions,
|
||||
plugins: nuxt.options.plugins,
|
||||
templates: [
|
||||
...templates.templatesFiles,
|
||||
...virtualTemplates,
|
||||
],
|
||||
templateVars: templates.templateVars,
|
||||
},
|
||||
}
|
||||
for await (const template of virtualTemplates) {
|
||||
const contents = await compileTemplate({ ...template, src: '' }, context)
|
||||
await fsp.mkdir(dirname(template.dst), { recursive: true })
|
||||
await fsp.writeFile(template.dst, contents)
|
||||
}
|
||||
})
|
||||
return <NuxtModule<TOptions, TOptionsDefaults, TWith>> normalizedModule
|
||||
}
|
||||
|
@ -2,11 +2,9 @@ import { existsSync, promises as fsp, lstatSync } from 'node:fs'
|
||||
import type { ModuleMeta, Nuxt, NuxtConfig, NuxtModule } from '@nuxt/schema'
|
||||
import { dirname, isAbsolute, join, resolve } from 'pathe'
|
||||
import { defu } from 'defu'
|
||||
import { isNuxt2 } from '../compatibility'
|
||||
import { createJiti } from 'jiti'
|
||||
import { useNuxt } from '../context'
|
||||
import { requireModule } from '../internal/cjs'
|
||||
import { importModule } from '../internal/esm'
|
||||
import { resolveAlias, resolvePath } from '../resolve'
|
||||
import { resolveAlias } from '../resolve'
|
||||
import { logger } from '../logger'
|
||||
|
||||
const NODE_MODULES_RE = /[/\\]node_modules[/\\]/
|
||||
@ -27,12 +25,7 @@ export async function installModule<
|
||||
}
|
||||
|
||||
// Call module
|
||||
const res = (
|
||||
isNuxt2()
|
||||
// @ts-expect-error Nuxt 2 `moduleContainer` is not typed
|
||||
? await nuxtModule.call(nuxt.moduleContainer, inlineOptions, nuxt)
|
||||
: await nuxtModule(inlineOptions, nuxt)
|
||||
) ?? {}
|
||||
const res = await nuxtModule(inlineOptions || {}, nuxt) ?? {}
|
||||
if (res === false /* setup aborted */) {
|
||||
return
|
||||
}
|
||||
@ -78,15 +71,20 @@ export const normalizeModuleTranspilePath = (p: string) => {
|
||||
|
||||
export async function loadNuxtModuleInstance (nuxtModule: string | NuxtModule, nuxt: Nuxt = useNuxt()) {
|
||||
let buildTimeModuleMeta: ModuleMeta = {}
|
||||
|
||||
const jiti = createJiti(nuxt.options.rootDir, {
|
||||
interopDefault: true,
|
||||
alias: nuxt.options.alias,
|
||||
})
|
||||
|
||||
// Import if input is string
|
||||
if (typeof nuxtModule === 'string') {
|
||||
const paths = [join(nuxtModule, 'nuxt'), join(nuxtModule, 'module'), nuxtModule]
|
||||
let error: unknown
|
||||
for (const path of paths) {
|
||||
try {
|
||||
const src = await resolvePath(path, { fallbackToOriginal: true })
|
||||
// Prefer ESM resolution if possible
|
||||
nuxtModule = await importModule(src, nuxt.options.modulesDir).catch(() => null) ?? requireModule(src, { paths: nuxt.options.modulesDir })
|
||||
const src = jiti.esmResolve(path)
|
||||
nuxtModule = await jiti.import(src) as NuxtModule
|
||||
|
||||
// nuxt-module-builder generates a module.json with metadata including the version
|
||||
const moduleMetadataPath = join(dirname(src), 'module.json')
|
||||
@ -100,7 +98,7 @@ export async function loadNuxtModuleInstance (nuxtModule: string | NuxtModule, n
|
||||
}
|
||||
}
|
||||
if (typeof nuxtModule !== 'function' && error) {
|
||||
logger.error(`Error while requiring module \`${nuxtModule}\`: ${error}`)
|
||||
logger.error(`Error while importing module \`${nuxtModule}\`: ${error}`)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import type { Nitro, NitroDevEventHandler, NitroEventHandler } from 'nitropack'
|
||||
import type { Nitro, NitroDevEventHandler, NitroEventHandler } from 'nitro/types'
|
||||
import type { Import } from 'unimport'
|
||||
import { normalize } from 'pathe'
|
||||
import { useNuxt } from './context'
|
||||
@ -12,7 +12,7 @@ function normalizeHandlerMethod (handler: NitroEventHandler) {
|
||||
// retrieve method from handler file name
|
||||
const [, method = undefined] = handler.handler.match(/\.(get|head|patch|post|put|delete|connect|options|trace)(\.\w+)*$/) || []
|
||||
return {
|
||||
method,
|
||||
method: method as 'get' | 'head' | 'patch' | 'post' | 'put' | 'delete' | 'connect' | 'options' | 'trace' | undefined,
|
||||
...handler,
|
||||
handler: normalize(handler.handler),
|
||||
}
|
||||
|
@ -1,19 +1,12 @@
|
||||
import type { NuxtHooks, NuxtMiddleware } from '@nuxt/schema'
|
||||
import type { NitroRouteConfig } from 'nitropack'
|
||||
import type { NitroRouteConfig } from 'nitro/types'
|
||||
import { defu } from 'defu'
|
||||
import { useNuxt } from './context'
|
||||
import { isNuxt2 } from './compatibility'
|
||||
import { logger } from './logger'
|
||||
import { toArray } from './utils'
|
||||
|
||||
export function extendPages (cb: NuxtHooks['pages:extend']) {
|
||||
const nuxt = useNuxt()
|
||||
if (isNuxt2(nuxt)) {
|
||||
// @ts-expect-error TODO: Nuxt 2 hook
|
||||
nuxt.hook('build:extendRoutes', cb)
|
||||
} else {
|
||||
nuxt.hook('pages:extend', cb)
|
||||
}
|
||||
useNuxt().hook('pages:extend', cb)
|
||||
}
|
||||
|
||||
export interface ExtendRouteRulesOptions {
|
||||
@ -51,7 +44,7 @@ export function addRouteMiddleware (input: NuxtMiddleware | NuxtMiddleware[], op
|
||||
for (const middleware of middlewares) {
|
||||
const find = app.middleware.findIndex(item => item.name === middleware.name)
|
||||
if (find >= 0) {
|
||||
const foundPath = app.middleware[find].path
|
||||
const foundPath = app.middleware[find]!.path
|
||||
if (foundPath === middleware.path) { continue }
|
||||
if (options.override === true) {
|
||||
app.middleware[find] = { ...middleware }
|
||||
|
@ -174,7 +174,7 @@ export async function resolveNuxtModule (base: string, paths: string[]): Promise
|
||||
|
||||
for (const path of paths) {
|
||||
if (path.startsWith(base)) {
|
||||
resolved.push(path.split('/index.ts')[0])
|
||||
resolved.push(path.split('/index.ts')[0]!)
|
||||
} else {
|
||||
const resolvedPath = await resolver.resolvePath(path)
|
||||
resolved.push(resolvedPath.slice(0, resolvedPath.lastIndexOf(path) + path.length))
|
||||
|
@ -11,7 +11,6 @@ import { readPackageJSON } from 'pkg-types'
|
||||
import { tryResolveModule } from './internal/esm'
|
||||
import { getDirectory } from './module/install'
|
||||
import { tryUseNuxt, useNuxt } from './context'
|
||||
import { getNodeModulesPaths } from './internal/cjs'
|
||||
import { resolveNuxtModule } from './resolve'
|
||||
|
||||
/**
|
||||
@ -191,6 +190,7 @@ export async function _generateTypes (nuxt: Nuxt) {
|
||||
'ESNext',
|
||||
'dom',
|
||||
'dom.iterable',
|
||||
'webworker',
|
||||
],
|
||||
/* JSX support for Vue */
|
||||
jsx: 'preserve',
|
||||
@ -228,10 +228,10 @@ export async function _generateTypes (nuxt: Nuxt) {
|
||||
if (excludedAlias.some(re => re.test(alias))) {
|
||||
continue
|
||||
}
|
||||
let absolutePath = resolve(basePath, aliases[alias])
|
||||
let absolutePath = resolve(basePath, aliases[alias]!)
|
||||
let stats = await fsp.stat(absolutePath).catch(() => null /* file does not exist */)
|
||||
if (!stats) {
|
||||
const resolvedModule = await tryResolveModule(aliases[alias], nuxt.options.modulesDir)
|
||||
const resolvedModule = await tryResolveModule(aliases[alias]!, nuxt.options.modulesDir)
|
||||
if (resolvedModule) {
|
||||
absolutePath = resolvedModule
|
||||
stats = await fsp.stat(resolvedModule).catch(() => null)
|
||||
@ -251,7 +251,7 @@ export async function _generateTypes (nuxt: Nuxt) {
|
||||
// remove extension
|
||||
? relativePath.replace(/\b\.\w+$/g, '')
|
||||
// non-existent file probably shouldn't be resolved
|
||||
: aliases[alias]
|
||||
: aliases[alias]!
|
||||
|
||||
tsConfig.compilerOptions.paths[alias] = [path]
|
||||
|
||||
@ -265,7 +265,7 @@ export async function _generateTypes (nuxt: Nuxt) {
|
||||
await Promise.all([...nuxt.options.modules, ...nuxt.options._modules].map(async (id) => {
|
||||
if (typeof id !== 'string') { return }
|
||||
|
||||
const pkg = await readPackageJSON(id, { url: getNodeModulesPaths(nuxt.options.modulesDir) }).catch(() => null)
|
||||
const pkg = await readPackageJSON(id, { url: nuxt.options.modulesDir }).catch(() => null)
|
||||
references.push(({ types: pkg?.name || id }))
|
||||
}))
|
||||
|
||||
@ -334,7 +334,7 @@ function renderAttrs (obj: Record<string, string>) {
|
||||
return attrs.join(' ')
|
||||
}
|
||||
|
||||
function renderAttr (key: string, value: string) {
|
||||
function renderAttr (key: string, value?: string) {
|
||||
return value ? `${key}="${value}"` : ''
|
||||
}
|
||||
|
||||
|
2
packages/nuxt/index.d.ts
vendored
2
packages/nuxt/index.d.ts
vendored
@ -2,8 +2,6 @@
|
||||
declare global {
|
||||
var __NUXT_VERSION__: string
|
||||
var __NUXT_ASYNC_CONTEXT__: boolean
|
||||
var __NUXT_PREPATHS__: string[] | string | undefined
|
||||
var __NUXT_PATHS__: string[] | string | undefined
|
||||
|
||||
interface Navigator {
|
||||
connection?: {
|
||||
|
@ -60,43 +60,44 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@nuxt/devalue": "^2.0.2",
|
||||
"@nuxt/devtools": "^1.3.3",
|
||||
"@nuxt/devtools": "^1.3.9",
|
||||
"@nuxt/kit": "workspace:*",
|
||||
"@nuxt/schema": "workspace:*",
|
||||
"@nuxt/telemetry": "^2.5.4",
|
||||
"@nuxt/vite-builder": "workspace:*",
|
||||
"@unhead/dom": "^1.9.13",
|
||||
"@unhead/ssr": "^1.9.13",
|
||||
"@unhead/vue": "^1.9.13",
|
||||
"@vue/shared": "^3.4.29",
|
||||
"acorn": "8.12.0",
|
||||
"c12": "^1.11.1",
|
||||
"@unhead/dom": "^1.9.14",
|
||||
"@unhead/ssr": "^1.9.14",
|
||||
"@unhead/vue": "^1.9.14",
|
||||
"@vue/shared": "^3.4.31",
|
||||
"acorn": "8.12.1",
|
||||
"c12": "^2.0.0-beta.1",
|
||||
"chokidar": "^3.6.0",
|
||||
"compatx": "^0.1.8",
|
||||
"consola": "^3.2.3",
|
||||
"cookie-es": "^1.1.0",
|
||||
"defu": "^6.1.4",
|
||||
"destr": "^2.0.3",
|
||||
"devalue": "^5.0.0",
|
||||
"esbuild": "^0.21.5",
|
||||
"esbuild": "^0.23.0",
|
||||
"escape-string-regexp": "^5.0.0",
|
||||
"estree-walker": "^3.0.3",
|
||||
"fs-extra": "^11.2.0",
|
||||
"globby": "^14.0.1",
|
||||
"h3": "^1.11.1",
|
||||
"globby": "^14.0.2",
|
||||
"h3": "npm:h3-nightly@2.0.0-1718872656.6765a6e",
|
||||
"hookable": "^5.5.3",
|
||||
"ignore": "^5.3.1",
|
||||
"jiti": "^1.21.6",
|
||||
"jiti": "^2.0.0-beta.3",
|
||||
"klona": "^2.0.6",
|
||||
"knitwork": "^1.1.0",
|
||||
"magic-string": "^0.30.10",
|
||||
"mlly": "^1.7.1",
|
||||
"nitropack": "^2.9.6",
|
||||
"nitro": "npm:nitro-nightly@3.0.0-beta-28659787.859de2d6",
|
||||
"nuxi": "^3.12.0",
|
||||
"nypm": "^0.3.8",
|
||||
"nypm": "^0.3.9",
|
||||
"ofetch": "^1.3.4",
|
||||
"ohash": "^1.1.3",
|
||||
"pathe": "^1.1.2",
|
||||
"perfect-debounce": "^1.0.0",
|
||||
"pkg-types": "^1.1.1",
|
||||
"pkg-types": "^1.1.3",
|
||||
"radix3": "^1.1.2",
|
||||
"scule": "^1.3.0",
|
||||
"semver": "^7.6.2",
|
||||
@ -108,25 +109,24 @@
|
||||
"unctx": "^2.3.1",
|
||||
"unenv": "^1.9.0",
|
||||
"unimport": "^3.7.2",
|
||||
"unplugin": "^1.10.1",
|
||||
"unplugin-vue-router": "^0.7.0",
|
||||
"unplugin": "^1.11.0",
|
||||
"unplugin-vue-router": "^0.10.0",
|
||||
"unstorage": "^1.10.2",
|
||||
"untyped": "^1.4.2",
|
||||
"vue": "^3.4.29",
|
||||
"vue": "^3.4.31",
|
||||
"vue-bundle-renderer": "^2.1.0",
|
||||
"vue-devtools-stub": "^0.1.0",
|
||||
"vue-router": "^4.3.3"
|
||||
"vue-router": "^4.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxt/scripts": "0.5.1",
|
||||
"@nuxt/ui-templates": "1.3.4",
|
||||
"@parcel/watcher": "2.4.1",
|
||||
"@types/estree": "1.0.5",
|
||||
"@types/fs-extra": "11.0.4",
|
||||
"@vitejs/plugin-vue": "5.0.4",
|
||||
"@vue/compiler-sfc": "3.4.29",
|
||||
"unbuild": "latest",
|
||||
"vite": "5.3.1",
|
||||
"@vitejs/plugin-vue": "5.0.5",
|
||||
"@vue/compiler-sfc": "3.4.31",
|
||||
"unbuild": "3.0.0-rc.6",
|
||||
"vite": "5.3.3",
|
||||
"vitest": "1.6.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
@ -1,2 +0,0 @@
|
||||
// TODO: remove in 4.x
|
||||
export { default } from './nuxt-layout'
|
@ -7,11 +7,11 @@ import type {
|
||||
VNodeProps,
|
||||
} from 'vue'
|
||||
import { computed, defineComponent, h, inject, onBeforeUnmount, onMounted, provide, ref, resolveComponent } from 'vue'
|
||||
import type { RouteLocation, RouteLocationRaw, Router, RouterLink, RouterLinkProps, useLink } from '#vue-router'
|
||||
import { hasProtocol, joinURL, parseQuery, withQuery, withTrailingSlash, withoutTrailingSlash } from 'ufo'
|
||||
import type { RouteLocation, RouteLocationRaw, Router, RouterLink, RouterLinkProps, useLink } from 'vue-router'
|
||||
import { hasProtocol, joinURL, parseQuery, withTrailingSlash, withoutTrailingSlash } from 'ufo'
|
||||
import { preloadRouteComponents } from '../composables/preload'
|
||||
import { onNuxtReady } from '../composables/ready'
|
||||
import { navigateTo, useRouter } from '../composables/router'
|
||||
import { navigateTo, resolveRouteObject, useRouter } from '../composables/router'
|
||||
import { useNuxtApp, useRuntimeConfig } from '../nuxt'
|
||||
import { cancelIdleCallback, requestIdleCallback } from '../compat/idle-callback'
|
||||
|
||||
@ -167,8 +167,10 @@ export function defineNuxtLink (options: NuxtLinkOptions) {
|
||||
if (!to.value || isAbsoluteUrl.value) { return to.value as string }
|
||||
|
||||
if (isExternal.value) {
|
||||
const path = typeof to.value === 'object' ? resolveRouteObject(to.value) : to.value
|
||||
return resolveTrailingSlashBehavior(path, router.resolve /* will not be called */) as string
|
||||
const path = typeof to.value === 'object' && 'path' in to.value ? resolveRouteObject(to.value) : to.value
|
||||
// separately resolve route objects with a 'name' property and without 'path'
|
||||
const href = typeof path === 'object' ? router.resolve(path).href : path
|
||||
return resolveTrailingSlashBehavior(href, router.resolve /* will not be called */) as string
|
||||
}
|
||||
|
||||
if (typeof to.value === 'object') {
|
||||
@ -495,7 +497,3 @@ function isSlowConnection () {
|
||||
if (cn && (cn.saveData || /2g/.test(cn.effectiveType))) { return true }
|
||||
return false
|
||||
}
|
||||
|
||||
function resolveRouteObject (to: Exclude<RouteLocationRaw, string>) {
|
||||
return withQuery(to.path || '', to.query || {}) + (to.hash ? '#' + to.hash : '')
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { defineComponent, h, nextTick, onMounted, provide, shallowReactive } from 'vue'
|
||||
import type { Ref, VNode } from 'vue'
|
||||
import type { RouteLocation, RouteLocationNormalizedLoaded } from '#vue-router'
|
||||
import type { RouteLocationNormalizedLoaded } from 'vue-router'
|
||||
import { PageRouteSymbol } from './injections'
|
||||
|
||||
export const RouteProvider = defineComponent({
|
||||
@ -23,7 +23,7 @@ export const RouteProvider = defineComponent({
|
||||
const previousRoute = props.route
|
||||
|
||||
// Provide a reactive route within the page
|
||||
const route = {} as RouteLocation
|
||||
const route = {} as RouteLocationNormalizedLoaded
|
||||
for (const key in props.route) {
|
||||
Object.defineProperty(route, key, {
|
||||
get: () => previousKey === props.renderKey ? props.route[key as keyof RouteLocationNormalizedLoaded] : previousRoute[key as keyof RouteLocationNormalizedLoaded],
|
||||
|
@ -2,7 +2,7 @@ import { h } from 'vue'
|
||||
import type { Component, RendererNode } from 'vue'
|
||||
// eslint-disable-next-line
|
||||
import { isString, isPromise, isArray, isObject } from '@vue/shared'
|
||||
import type { RouteLocationNormalized } from '#vue-router'
|
||||
import type { RouteLocationNormalized } from 'vue-router'
|
||||
// @ts-expect-error virtual file
|
||||
import { START_LOCATION } from '#build/pages'
|
||||
|
||||
|
@ -8,10 +8,7 @@ import { createError } from './error'
|
||||
import { onNuxtReady } from './ready'
|
||||
|
||||
// @ts-expect-error virtual file
|
||||
import { asyncDataDefaults, resetAsyncDataToUndefined } from '#build/nuxt.config.mjs'
|
||||
|
||||
// TODO: temporary module for backwards compatibility
|
||||
import type { DedupeOption, DefaultAsyncDataErrorValue, DefaultAsyncDataValue } from '#app/defaults'
|
||||
import { asyncDataDefaults } from '#build/nuxt.config.mjs'
|
||||
|
||||
export type AsyncDataRequestStatus = 'idle' | 'pending' | 'success' | 'error'
|
||||
|
||||
@ -45,7 +42,7 @@ export interface AsyncDataOptions<
|
||||
ResT,
|
||||
DataT = ResT,
|
||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||
DefaultT = DefaultAsyncDataValue,
|
||||
DefaultT = undefined,
|
||||
> {
|
||||
/**
|
||||
* Whether to fetch on the server side.
|
||||
@ -107,7 +104,7 @@ export interface AsyncDataExecuteOptions {
|
||||
* Instead of using `boolean` values, use `cancel` for `true` and `defer` for `false`.
|
||||
* Boolean values will be removed in a future release.
|
||||
*/
|
||||
dedupe?: DedupeOption
|
||||
dedupe?: 'cancel' | 'defer'
|
||||
}
|
||||
|
||||
export interface _AsyncData<DataT, ErrorT> {
|
||||
@ -119,7 +116,7 @@ export interface _AsyncData<DataT, ErrorT> {
|
||||
refresh: (opts?: AsyncDataExecuteOptions) => Promise<void>
|
||||
execute: (opts?: AsyncDataExecuteOptions) => Promise<void>
|
||||
clear: () => void
|
||||
error: Ref<ErrorT | DefaultAsyncDataErrorValue>
|
||||
error: Ref<ErrorT | undefined>
|
||||
status: Ref<AsyncDataRequestStatus>
|
||||
}
|
||||
|
||||
@ -140,11 +137,11 @@ export function useAsyncData<
|
||||
NuxtErrorDataT = unknown,
|
||||
DataT = ResT,
|
||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||
DefaultT = DefaultAsyncDataValue,
|
||||
DefaultT = undefined,
|
||||
> (
|
||||
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
||||
options?: AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>) | DefaultAsyncDataErrorValue>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>) | undefined>
|
||||
/**
|
||||
* Provides access to data that resolves asynchronously in an SSR-friendly composable.
|
||||
* See {@link https://nuxt.com/docs/api/composables/use-async-data}
|
||||
@ -160,7 +157,7 @@ export function useAsyncData<
|
||||
> (
|
||||
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
||||
options?: AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>) | DefaultAsyncDataErrorValue>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>) | undefined>
|
||||
/**
|
||||
* Provides access to data that resolves asynchronously in an SSR-friendly composable.
|
||||
* See {@link https://nuxt.com/docs/api/composables/use-async-data}
|
||||
@ -173,12 +170,12 @@ export function useAsyncData<
|
||||
NuxtErrorDataT = unknown,
|
||||
DataT = ResT,
|
||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||
DefaultT = DefaultAsyncDataValue,
|
||||
DefaultT = undefined,
|
||||
> (
|
||||
key: string,
|
||||
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
||||
options?: AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>) | DefaultAsyncDataErrorValue>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>) | undefined>
|
||||
/**
|
||||
* Provides access to data that resolves asynchronously in an SSR-friendly composable.
|
||||
* See {@link https://nuxt.com/docs/api/composables/use-async-data}
|
||||
@ -196,14 +193,14 @@ export function useAsyncData<
|
||||
key: string,
|
||||
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
||||
options?: AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>) | DefaultAsyncDataErrorValue>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>) | undefined>
|
||||
export function useAsyncData<
|
||||
ResT,
|
||||
NuxtErrorDataT = unknown,
|
||||
DataT = ResT,
|
||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||
DefaultT = DefaultAsyncDataValue,
|
||||
> (...args: any[]): AsyncData<PickFrom<DataT, PickKeys>, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>) | DefaultAsyncDataErrorValue> {
|
||||
DefaultT = undefined,
|
||||
> (...args: any[]): AsyncData<PickFrom<DataT, PickKeys>, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>) | undefined> {
|
||||
const autoKey = typeof args[args.length - 1] === 'string' ? args.pop() : undefined
|
||||
if (typeof args[0] !== 'string') { args.unshift(autoKey) }
|
||||
|
||||
@ -235,7 +232,7 @@ export function useAsyncData<
|
||||
}
|
||||
|
||||
// Used to get default values
|
||||
const getDefault = () => asyncDataDefaults.value
|
||||
const getDefault = () => undefined
|
||||
const getDefaultCachedData = () => nuxtApp.isHydrating ? nuxtApp.payload.data[key] : nuxtApp.static.data[key]
|
||||
|
||||
// Apply defaults
|
||||
@ -257,7 +254,7 @@ export function useAsyncData<
|
||||
|
||||
// Create or use a shared asyncData entity
|
||||
if (!nuxtApp._asyncData[key] || !options.immediate) {
|
||||
nuxtApp.payload._errors[key] ??= asyncDataDefaults.errorValue
|
||||
nuxtApp.payload._errors[key] ??= undefined
|
||||
|
||||
const _ref = options.deep ? ref : shallowRef
|
||||
|
||||
@ -313,13 +310,13 @@ export function useAsyncData<
|
||||
|
||||
if (import.meta.dev && import.meta.server && !result) {
|
||||
// @ts-expect-error private property
|
||||
console.warn(`[nuxt] \`${options._functionName || 'useAsyncData'}\` should return a value that is not \`null\` or \`undefined\` or the request may be duplicated on the client side.`)
|
||||
console.warn(`[nuxt] \`${options._functionName || 'useAsyncData'}\` must return a truthy value (for example, it should not be \`undefined\`, \`null\` or empty string) or the request may be duplicated on the client side.`)
|
||||
}
|
||||
|
||||
nuxtApp.payload.data[key] = result
|
||||
|
||||
asyncData.data.value = result
|
||||
asyncData.error.value = asyncDataDefaults.errorValue
|
||||
asyncData.error.value = undefined
|
||||
asyncData.status.value = 'success'
|
||||
})
|
||||
.catch((error: any) => {
|
||||
@ -416,11 +413,11 @@ export function useLazyAsyncData<
|
||||
DataE = Error,
|
||||
DataT = ResT,
|
||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||
DefaultT = DefaultAsyncDataValue,
|
||||
DefaultT = undefined,
|
||||
> (
|
||||
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
||||
options?: Omit<AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>, 'lazy'>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | DefaultAsyncDataValue>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | undefined>
|
||||
export function useLazyAsyncData<
|
||||
ResT,
|
||||
DataE = Error,
|
||||
@ -430,18 +427,18 @@ export function useLazyAsyncData<
|
||||
> (
|
||||
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
||||
options?: Omit<AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>, 'lazy'>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | DefaultAsyncDataValue>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | undefined>
|
||||
export function useLazyAsyncData<
|
||||
ResT,
|
||||
DataE = Error,
|
||||
DataT = ResT,
|
||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||
DefaultT = DefaultAsyncDataValue,
|
||||
DefaultT = undefined,
|
||||
> (
|
||||
key: string,
|
||||
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
||||
options?: Omit<AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>, 'lazy'>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | DefaultAsyncDataValue>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | undefined>
|
||||
export function useLazyAsyncData<
|
||||
ResT,
|
||||
DataE = Error,
|
||||
@ -452,15 +449,15 @@ export function useLazyAsyncData<
|
||||
key: string,
|
||||
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
||||
options?: Omit<AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>, 'lazy'>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | DefaultAsyncDataValue>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | undefined>
|
||||
|
||||
export function useLazyAsyncData<
|
||||
ResT,
|
||||
DataE = Error,
|
||||
DataT = ResT,
|
||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||
DefaultT = DefaultAsyncDataValue,
|
||||
> (...args: any[]): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | DefaultAsyncDataValue> {
|
||||
DefaultT = undefined,
|
||||
> (...args: any[]): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | undefined> {
|
||||
const autoKey = typeof args[args.length - 1] === 'string' ? args.pop() : undefined
|
||||
if (typeof args[0] !== 'string') { args.unshift(autoKey) }
|
||||
const [key, handler, options = {}] = args as [string, (ctx?: NuxtApp) => Promise<ResT>, AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>]
|
||||
@ -475,12 +472,12 @@ export function useLazyAsyncData<
|
||||
}
|
||||
|
||||
/** @since 3.1.0 */
|
||||
export function useNuxtData<DataT = any> (key: string): { data: Ref<DataT | DefaultAsyncDataValue> } {
|
||||
export function useNuxtData<DataT = any> (key: string): { data: Ref<DataT | undefined> } {
|
||||
const nuxtApp = useNuxtApp()
|
||||
|
||||
// Initialize value when key is not already set
|
||||
if (!(key in nuxtApp.payload.data)) {
|
||||
nuxtApp.payload.data[key] = asyncDataDefaults.value
|
||||
nuxtApp.payload.data[key] = undefined
|
||||
}
|
||||
|
||||
return {
|
||||
@ -532,12 +529,12 @@ function clearNuxtDataByKey (nuxtApp: NuxtApp, key: string): void {
|
||||
}
|
||||
|
||||
if (key in nuxtApp.payload._errors) {
|
||||
nuxtApp.payload._errors[key] = asyncDataDefaults.errorValue
|
||||
nuxtApp.payload._errors[key] = undefined
|
||||
}
|
||||
|
||||
if (nuxtApp._asyncData[key]) {
|
||||
nuxtApp._asyncData[key]!.data.value = resetAsyncDataToUndefined ? undefined : nuxtApp._asyncData[key]!._default()
|
||||
nuxtApp._asyncData[key]!.error.value = asyncDataDefaults.errorValue
|
||||
nuxtApp._asyncData[key]!.data.value = nuxtApp._asyncData[key]!._default()
|
||||
nuxtApp._asyncData[key]!.error.value = undefined
|
||||
nuxtApp._asyncData[key]!.pending.value = false
|
||||
nuxtApp._asyncData[key]!.status.value = 'idle'
|
||||
}
|
||||
|
@ -4,9 +4,6 @@ import { toRef } from 'vue'
|
||||
import { useNuxtApp } from '../nuxt'
|
||||
import { useRouter } from './router'
|
||||
|
||||
// @ts-expect-error virtual file
|
||||
import { nuxtDefaultErrorValue } from '#build/nuxt.config.mjs'
|
||||
|
||||
export const NUXT_ERROR_SIGNATURE = '__nuxt_error'
|
||||
|
||||
/** @since 3.0.0 */
|
||||
@ -50,7 +47,7 @@ export const clearError = async (options: { redirect?: string } = {}) => {
|
||||
await useRouter().replace(options.redirect)
|
||||
}
|
||||
|
||||
error.value = nuxtDefaultErrorValue
|
||||
error.value = undefined
|
||||
}
|
||||
|
||||
/** @since 3.0.0 */
|
||||
|
@ -1,5 +1,5 @@
|
||||
import type { FetchError, FetchOptions } from 'ofetch'
|
||||
import type { NitroFetchRequest, TypedInternalResponse, AvailableRouterMethod as _AvailableRouterMethod } from 'nitropack'
|
||||
import type { NitroFetchRequest, TypedInternalResponse, AvailableRouterMethod as _AvailableRouterMethod } from 'nitro/types'
|
||||
import type { MaybeRef, Ref } from 'vue'
|
||||
import { computed, reactive, toValue } from 'vue'
|
||||
import { hash } from 'ohash'
|
||||
@ -8,9 +8,6 @@ import { useRequestFetch } from './ssr'
|
||||
import type { AsyncData, AsyncDataOptions, KeysOf, MultiWatchSources, PickFrom } from './asyncData'
|
||||
import { useAsyncData } from './asyncData'
|
||||
|
||||
// TODO: temporary module for backwards compatibility
|
||||
import type { DefaultAsyncDataErrorValue, DefaultAsyncDataValue } from '#app/defaults'
|
||||
|
||||
// @ts-expect-error virtual file
|
||||
import { fetchDefaults } from '#build/nuxt.config.mjs'
|
||||
|
||||
@ -33,7 +30,7 @@ export interface UseFetchOptions<
|
||||
ResT,
|
||||
DataT = ResT,
|
||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||
DefaultT = DefaultAsyncDataValue,
|
||||
DefaultT = undefined,
|
||||
R extends NitroFetchRequest = string & {},
|
||||
M extends AvailableRouterMethod<R> = AvailableRouterMethod<R>,
|
||||
> extends Omit<AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>, 'watch'>, ComputedFetchOptions<R, M> {
|
||||
@ -57,11 +54,11 @@ export function useFetch<
|
||||
_ResT = ResT extends void ? FetchResult<ReqT, Method> : ResT,
|
||||
DataT = _ResT,
|
||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||
DefaultT = DefaultAsyncDataValue,
|
||||
DefaultT = undefined,
|
||||
> (
|
||||
request: Ref<ReqT> | ReqT | (() => ReqT),
|
||||
opts?: UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, ErrorT | DefaultAsyncDataErrorValue>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, ErrorT | undefined>
|
||||
/**
|
||||
* Fetch data from an API endpoint with an SSR-friendly composable.
|
||||
* See {@link https://nuxt.com/docs/api/composables/use-fetch}
|
||||
@ -80,7 +77,7 @@ export function useFetch<
|
||||
> (
|
||||
request: Ref<ReqT> | ReqT | (() => ReqT),
|
||||
opts?: UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, ErrorT | DefaultAsyncDataErrorValue>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, ErrorT | undefined>
|
||||
export function useFetch<
|
||||
ResT = void,
|
||||
ErrorT = FetchError,
|
||||
@ -89,7 +86,7 @@ export function useFetch<
|
||||
_ResT = ResT extends void ? FetchResult<ReqT, Method> : ResT,
|
||||
DataT = _ResT,
|
||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||
DefaultT = DefaultAsyncDataValue,
|
||||
DefaultT = undefined,
|
||||
> (
|
||||
request: Ref<ReqT> | ReqT | (() => ReqT),
|
||||
arg1?: string | UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>,
|
||||
@ -195,11 +192,11 @@ export function useLazyFetch<
|
||||
_ResT = ResT extends void ? FetchResult<ReqT, Method> : ResT,
|
||||
DataT = _ResT,
|
||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||
DefaultT = DefaultAsyncDataValue,
|
||||
DefaultT = undefined,
|
||||
> (
|
||||
request: Ref<ReqT> | ReqT | (() => ReqT),
|
||||
opts?: Omit<UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>, 'lazy'>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, ErrorT | DefaultAsyncDataErrorValue>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, ErrorT | undefined>
|
||||
export function useLazyFetch<
|
||||
ResT = void,
|
||||
ErrorT = FetchError,
|
||||
@ -212,7 +209,7 @@ export function useLazyFetch<
|
||||
> (
|
||||
request: Ref<ReqT> | ReqT | (() => ReqT),
|
||||
opts?: Omit<UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>, 'lazy'>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, ErrorT | DefaultAsyncDataErrorValue>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, ErrorT | undefined>
|
||||
export function useLazyFetch<
|
||||
ResT = void,
|
||||
ErrorT = FetchError,
|
||||
@ -221,7 +218,7 @@ export function useLazyFetch<
|
||||
_ResT = ResT extends void ? FetchResult<ReqT, Method> : ResT,
|
||||
DataT = _ResT,
|
||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||
DefaultT = DefaultAsyncDataValue,
|
||||
DefaultT = undefined,
|
||||
> (
|
||||
request: Ref<ReqT> | ReqT | (() => ReqT),
|
||||
arg1?: string | Omit<UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>, 'lazy'>,
|
||||
|
@ -1,5 +1,5 @@
|
||||
import type { Component } from 'vue'
|
||||
import type { RouteLocationRaw, Router } from '#vue-router'
|
||||
import type { RouteLocationRaw, Router } from 'vue-router'
|
||||
import { useNuxtApp } from '../nuxt'
|
||||
import { toArray } from '../utils'
|
||||
import { useRouter } from './router'
|
||||
@ -23,6 +23,8 @@ export const preloadComponents = async (components: string | string[]) => {
|
||||
* @since 3.0.0
|
||||
*/
|
||||
export const prefetchComponents = (components: string | string[]) => {
|
||||
if (import.meta.server) { return }
|
||||
|
||||
// TODO
|
||||
return preloadComponents(components)
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import type { Ref } from 'vue'
|
||||
import { getCurrentScope, onScopeDispose, ref } from 'vue'
|
||||
import { injectHead } from '@unhead/vue'
|
||||
import { useNuxtApp } from '#app'
|
||||
import { useNuxtApp } from '../nuxt'
|
||||
|
||||
export type Politeness = 'assertive' | 'polite' | 'off'
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { getCurrentInstance, hasInjectionContext, inject, onScopeDispose } from 'vue'
|
||||
import type { Ref } from 'vue'
|
||||
import type { NavigationFailure, NavigationGuard, RouteLocationNormalized, RouteLocationPathRaw, RouteLocationRaw, Router, useRoute as _useRoute, useRouter as _useRouter } from '#vue-router'
|
||||
import type { NavigationFailure, NavigationGuard, RouteLocationNormalized, RouteLocationRaw, Router, useRoute as _useRoute, useRouter as _useRouter } from 'vue-router'
|
||||
import { sanitizeStatusCode } from 'h3'
|
||||
import { hasProtocol, isScriptProtocol, joinURL, withQuery } from 'ufo'
|
||||
|
||||
@ -120,7 +120,7 @@ export const navigateTo = (to: RouteLocationRaw | undefined | null, options?: Na
|
||||
to = '/'
|
||||
}
|
||||
|
||||
const toPath = typeof to === 'string' ? to : (withQuery((to as RouteLocationPathRaw).path || '/', to.query || {}) + (to.hash || ''))
|
||||
const toPath = typeof to === 'string' ? to : 'path' in to ? resolveRouteObject(to) : useRouter().resolve(to).href
|
||||
|
||||
// Early open handler
|
||||
if (import.meta.client && options?.open) {
|
||||
@ -135,7 +135,8 @@ export const navigateTo = (to: RouteLocationRaw | undefined | null, options?: Na
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
const isExternal = options?.external || hasProtocol(toPath, { acceptRelative: true })
|
||||
const isExternalHost = hasProtocol(toPath, { acceptRelative: true })
|
||||
const isExternal = options?.external || isExternalHost
|
||||
if (isExternal) {
|
||||
if (!options?.external) {
|
||||
throw new Error('Navigating to an external URL is not allowed by default. Use `navigateTo(url, { external: true })`.')
|
||||
@ -166,10 +167,12 @@ export const navigateTo = (to: RouteLocationRaw | undefined | null, options?: Na
|
||||
// TODO: consider deprecating in favour of `app:rendered` and removing
|
||||
await nuxtApp.callHook('app:redirected')
|
||||
const encodedLoc = location.replace(/"/g, '%22')
|
||||
const encodedHeader = encodeURL(location, isExternalHost)
|
||||
|
||||
nuxtApp.ssrContext!._renderResponse = {
|
||||
statusCode: sanitizeStatusCode(options?.redirectCode || 302, 302),
|
||||
body: `<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0; url=${encodedLoc}"></head></html>`,
|
||||
headers: { location: encodeURI(location) },
|
||||
headers: { location: encodedHeader },
|
||||
}
|
||||
return response
|
||||
}
|
||||
@ -252,3 +255,24 @@ export const setPageLayout = (layout: unknown extends PageMeta['layout'] ? strin
|
||||
useRoute().meta.layout = layout as Exclude<PageMeta['layout'], Ref | false>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export function resolveRouteObject (to: Exclude<RouteLocationRaw, string>) {
|
||||
return withQuery(to.path || '', to.query || {}) + (to.hash || '')
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export function encodeURL (location: string, isExternalHost = false) {
|
||||
const url = new URL(location, 'http://localhost')
|
||||
if (!isExternalHost) {
|
||||
return url.pathname + url.search + url.hash
|
||||
}
|
||||
if (location.startsWith('//')) {
|
||||
return url.toString().replace(url.protocol, '')
|
||||
}
|
||||
return url.toString()
|
||||
}
|
||||
|
@ -1,8 +0,0 @@
|
||||
// TODO: temporary module for backwards compatibility
|
||||
|
||||
export type DefaultAsyncDataErrorValue = null
|
||||
export type DefaultAsyncDataValue = null
|
||||
export type DefaultErrorValue = null
|
||||
export type DedupeOption = boolean | 'cancel' | 'defer'
|
||||
|
||||
export {}
|
@ -1,13 +1,14 @@
|
||||
/// <reference path="types/augments.d.ts" />
|
||||
export { applyPlugin, applyPlugins, callWithNuxt, createNuxtApp, defineAppConfig, defineNuxtPlugin, definePayloadPlugin, isNuxtPlugin, registerPluginHooks, tryUseNuxtApp, useNuxtApp, useRuntimeConfig } from './nuxt'
|
||||
export type { CreateOptions, NuxtApp, NuxtPayload, NuxtPluginIndicator, NuxtSSRContext, ObjectPlugin, Plugin, PluginEnvContext, PluginMeta, ResolvedPluginMeta, RuntimeNuxtHooks } from './nuxt'
|
||||
|
||||
export * from './nuxt'
|
||||
export { defineNuxtComponent, useAsyncData, useLazyAsyncData, useNuxtData, refreshNuxtData, clearNuxtData, useHydration, callOnce, useState, clearNuxtState, clearError, createError, isNuxtError, showError, useError, useFetch, useLazyFetch, useCookie, refreshCookie, onPrehydrate, prerenderRoutes, useRequestHeaders, useRequestEvent, useRequestFetch, setResponseStatus, onNuxtReady, abortNavigation, addRouteMiddleware, defineNuxtRouteMiddleware, onBeforeRouteLeave, onBeforeRouteUpdate, setPageLayout, navigateTo, useRoute, useRouter, preloadComponents, prefetchComponents, preloadRouteComponents, isPrerendered, loadPayload, preloadPayload, definePayloadReducer, definePayloadReviver, getAppManifest, getRouteRules, reloadNuxtApp, useRequestURL, usePreviewMode, useId, useRouteAnnouncer, useHead, useSeoMeta, useServerSeoMeta } from './composables/index'
|
||||
export type { AddRouteMiddlewareOptions, AsyncData, AsyncDataOptions, AsyncDataRequestStatus, CookieOptions, CookieRef, FetchResult, NuxtAppManifest, NuxtAppManifestMeta, NuxtError, ReloadNuxtAppOptions, RouteMiddleware, UseFetchOptions } from './composables/index'
|
||||
|
||||
export * from './composables/index'
|
||||
|
||||
export * from './components/index'
|
||||
export * from './config'
|
||||
export * from './compat/idle-callback'
|
||||
export * from './types'
|
||||
export { defineNuxtLink } from './components/index'
|
||||
export type { NuxtLinkOptions, NuxtLinkProps } from './components/index'
|
||||
export { _getAppConfig, updateAppConfig, useAppConfig } from './config'
|
||||
export { cancelIdleCallback, requestIdleCallback } from './compat/idle-callback'
|
||||
export type { NuxtAppLiterals, NuxtIslandContext, NuxtIslandResponse, NuxtRenderHTMLContext, PageMeta } from './types'
|
||||
|
||||
export const isVue2 = false
|
||||
export const isVue3 = true
|
||||
|
@ -1,13 +1,13 @@
|
||||
import { effectScope, getCurrentInstance, getCurrentScope, hasInjectionContext, reactive, shallowReactive } from 'vue'
|
||||
import type { App, EffectScope, Ref, VNode, onErrorCaptured } from 'vue'
|
||||
import type { RouteLocationNormalizedLoaded } from '#vue-router'
|
||||
import type { RouteLocationNormalizedLoaded } from 'vue-router'
|
||||
import type { HookCallback, Hookable } from 'hookable'
|
||||
import { createHooks } from 'hookable'
|
||||
import { getContext } from 'unctx'
|
||||
import type { SSRContext, createRenderer } from 'vue-bundle-renderer/runtime'
|
||||
import type { EventHandlerRequest, H3Event } from 'h3'
|
||||
import type { AppConfig, AppConfigInput, RuntimeConfig } from 'nuxt/schema'
|
||||
import type { RenderResponse } from 'nitropack'
|
||||
import type { RenderResponse } from 'nitro/types'
|
||||
import type { LogObject } from 'consola'
|
||||
import type { MergeHead, VueHeadClient } from '@unhead/vue'
|
||||
|
||||
@ -23,8 +23,6 @@ import type { ViewTransition } from './plugins/view-transitions.client'
|
||||
// @ts-expect-error virtual file
|
||||
import { appId } from '#build/nuxt.config.mjs'
|
||||
|
||||
// TODO: temporary module for backwards compatibility
|
||||
import type { DefaultAsyncDataErrorValue, DefaultErrorValue } from '#app/defaults'
|
||||
import type { NuxtAppLiterals } from '#app'
|
||||
|
||||
function getNuxtAppCtx (appName = appId || 'nuxt-app') {
|
||||
@ -94,8 +92,8 @@ export interface NuxtPayload {
|
||||
state: Record<string, any>
|
||||
once: Set<string>
|
||||
config?: Pick<RuntimeConfig, 'public' | 'app'>
|
||||
error?: NuxtError | DefaultErrorValue
|
||||
_errors: Record<string, NuxtError | DefaultAsyncDataErrorValue>
|
||||
error?: NuxtError | undefined
|
||||
_errors: Record<string, NuxtError | undefined>
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
@ -124,7 +122,7 @@ interface _NuxtApp {
|
||||
_asyncData: Record<string, {
|
||||
data: Ref<unknown>
|
||||
pending: Ref<boolean>
|
||||
error: Ref<Error | DefaultAsyncDataErrorValue>
|
||||
error: Ref<Error | undefined>
|
||||
status: Ref<AsyncDataRequestStatus>
|
||||
/** @internal */
|
||||
_default: () => unknown
|
||||
|
23
packages/nuxt/src/app/plugins/navigation-repaint.client.ts
Normal file
23
packages/nuxt/src/app/plugins/navigation-repaint.client.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { defineNuxtPlugin } from '../nuxt'
|
||||
import { onNuxtReady } from '../composables/ready'
|
||||
import { useRouter } from '../composables/router'
|
||||
|
||||
export default defineNuxtPlugin(() => {
|
||||
const router = useRouter()
|
||||
onNuxtReady(() => {
|
||||
router.beforeResolve(async () => {
|
||||
/**
|
||||
* This gives an opportunity for the browser to repaint, acknowledging user interaction.
|
||||
* It can reduce INP when navigating on prerendered routes.
|
||||
*
|
||||
* @see https://github.com/nuxt/nuxt/issues/26271#issuecomment-2178582037
|
||||
* @see https://vercel.com/blog/demystifying-inp-new-tools-and-actionable-insights
|
||||
*/
|
||||
await new Promise((resolve) => {
|
||||
// Ensure we always resolve, even if the animation frame never fires
|
||||
setTimeout(resolve, 100)
|
||||
requestAnimationFrame(() => { setTimeout(resolve, 0) })
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
@ -5,9 +5,9 @@ export default defineNuxtPlugin({
|
||||
setup (nuxtApp) {
|
||||
nuxtApp.vueApp.mixin({
|
||||
beforeCreate () {
|
||||
const { _registeredComponents } = this.$nuxt.ssrContext
|
||||
const { modules } = this.$nuxt.ssrContext
|
||||
const { __moduleIdentifier } = this.$options
|
||||
_registeredComponents.add(__moduleIdentifier)
|
||||
modules.add(__moduleIdentifier)
|
||||
},
|
||||
})
|
||||
},
|
||||
|
@ -49,7 +49,6 @@ export default defineNuxtPlugin({
|
||||
definePayloadReviver(reviver, revivers[reviver as keyof typeof revivers])
|
||||
}
|
||||
Object.assign(nuxtApp.payload, await nuxtApp.runWithContext(getNuxtClientPayload))
|
||||
// For backwards compatibility - TODO: remove later
|
||||
window.__NUXT__ = nuxtApp.payload
|
||||
delete window.__NUXT__
|
||||
},
|
||||
})
|
||||
|
@ -226,6 +226,7 @@ export default defineNuxtPlugin<{ route: Route, router: Router }>({
|
||||
})
|
||||
}
|
||||
|
||||
// @ts-expect-error vue-router types diverge from our Route type above
|
||||
nuxtApp._route = route
|
||||
|
||||
// Handle middleware
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user