mirror of
https://github.com/nuxt/nuxt.git
synced 2025-02-22 00:19:45 +00:00
Merge branch 'main' into docs/new-structure
This commit is contained in:
commit
0cfde6e382
30
.github/workflows/autofix-docs.yml
vendored
Normal file
30
.github/workflows/autofix-docs.yml
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
name: autofix.ci # needed to securely identify the workflow
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "docs/**"
|
||||
- ".github/workflows/docs.yml"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
docs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- run: corepack enable
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
cache: "pnpm"
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Lint (docs)
|
||||
run: pnpm lint:docs:fix
|
||||
|
||||
- uses: autofix-ci/action@8bc06253bec489732e5f9c52884c7cace15c0160
|
42
.github/workflows/autofix.yml
vendored
Normal file
42
.github/workflows/autofix.yml
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
name: autofix.ci # needed to securely identify the workflow
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "docs/**"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
code:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- run: corepack enable
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
cache: "pnpm"
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Dedupe dependencies
|
||||
if: ${{ contains(github.ref_name, 'renovate') }}
|
||||
run: pnpm dedupe
|
||||
|
||||
- name: Build (stub)
|
||||
run: pnpm build:stub
|
||||
|
||||
- name: Lint (code)
|
||||
run: pnpm lint:fix
|
||||
|
||||
- name: Test (unit)
|
||||
run: pnpm test:unit -u
|
||||
|
||||
- name: Update bundle size
|
||||
run: pnpm vitest run bundle -u
|
||||
|
||||
- uses: autofix-ci/action@8bc06253bec489732e5f9c52884c7cace15c0160
|
5
.github/workflows/ci.yml
vendored
5
.github/workflows/ci.yml
vendored
@ -88,6 +88,8 @@ jobs:
|
||||
run: pnpm test:types
|
||||
|
||||
lint:
|
||||
# autofix workflow will be triggered instead for PRs
|
||||
if: github.event_name == 'push'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
|
||||
@ -169,9 +171,6 @@ jobs:
|
||||
|
||||
- name: Test (unit)
|
||||
run: pnpm test:unit
|
||||
env:
|
||||
TEST_ENV: ${{ matrix.env }}
|
||||
TEST_BUILDER: ${{ matrix.builder }}
|
||||
|
||||
- name: Test (fixtures)
|
||||
run: pnpm test:fixtures
|
||||
|
20
.github/workflows/docs.yml
vendored
20
.github/workflows/docs.yml
vendored
@ -5,30 +5,24 @@ on:
|
||||
paths:
|
||||
- "docs/**"
|
||||
- ".github/workflows/docs.yml"
|
||||
# autofix workflow will be triggered instead for PRs
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
paths:
|
||||
- "docs/**"
|
||||
- ".github/workflows/docs.yml"
|
||||
branches:
|
||||
- main
|
||||
|
||||
# Remove default permissions of GITHUB_TOKEN for security
|
||||
# https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
lint-docs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
node: [14]
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- run: corepack enable
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
node-version: 18
|
||||
cache: "pnpm"
|
||||
|
||||
- name: Install dependencies
|
||||
|
2
.github/workflows/introspect.yml
vendored
2
.github/workflows/introspect.yml
vendored
@ -1,4 +1,4 @@
|
||||
name: Docs
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
|
@ -12,3 +12,5 @@ MD025: false
|
||||
MD033: false
|
||||
# Allow non blank lines around list
|
||||
MD032: false
|
||||
MD046:
|
||||
style: fenced
|
||||
|
@ -1,5 +1,5 @@
|
||||
**/node_modules
|
||||
|
||||
docs/content/index.md
|
||||
docs/content/**/*.nuxt.config.md
|
||||
docs/content/changelog.md
|
||||
docs/0.index.md
|
||||
docs/1.getting-started/1.introduction.md
|
||||
docs/**/*.nuxt.config.md
|
||||
|
@ -17,6 +17,10 @@ You can find a reference for auto-imported [composables](/docs/api/composables/u
|
||||
In the [server directory](/docs/guide/directory-structure/server), we auto import exported functions and variables from `server/utils/`.
|
||||
::
|
||||
|
||||
::alert
|
||||
You can also auto-import functions exported from custom folders or third-party packages by configuring the [`imports` section](/docs/api/configuration/nuxt-config#imports) of your `nuxt.config` file.
|
||||
::
|
||||
|
||||
## Built-in Auto-imports
|
||||
|
||||
### Nuxt Auto-imports
|
||||
@ -46,7 +50,7 @@ Vue 3 exposes Reactivity APIs like `ref` or `computed`, as well as lifecycle hoo
|
||||
|
||||
<!-- TODO: move to separate page with https://github.com/nuxt/nuxt/issues/14723 and add more information -->
|
||||
|
||||
When you are using the built-in composition API composables provided by Vue and Nuxt, be aware that many of them rely on being called in the right _context_.
|
||||
When you are using the built-in Composition API composables provided by Vue and Nuxt, be aware that many of them rely on being called in the right _context_.
|
||||
|
||||
During a component lifecycle, Vue tracks the temporary instance of the current component (and similarly, Nuxt tracks a temporary instance of `nuxtApp`) via a global variable, and then unsets it in same tick. This is essential when server rendering, both to avoid cross-request state pollution (leaking a shared reference between two users) and to avoid leakage between different components.
|
||||
|
||||
|
@ -141,7 +141,7 @@ Nuxt 3 can be deployed to several cloud providers with a minimal amount of confi
|
||||
- :icon{name="logos:microsoft-azure" class="h-5 w-4 inline mb-2"} [Azure](https://nitro.unjs.io/deploy/providers/azure)
|
||||
- :icon{name="ph:cloud-duotone" class="h-5 w-4 inline mb-2"} [Cleavr](https://nitro.unjs.io/deploy/providers/cleavr)
|
||||
- :icon{name="logos:cloudflare" class="h-5 w-4 inline mb-2"} [CloudFlare](https://nitro.unjs.io/deploy/providers/cloudflare)
|
||||
- :icon{name="logos:digital-ocean" class="h-5 w-4 inline mb-2"} [Digital Ocean](https://nitro.unjs.io/deploy/providers/digitalocean)
|
||||
- :icon{name="logos:digital-ocean" class="h-5 w-4 inline mb-2"} [DigitalOcean](https://nitro.unjs.io/deploy/providers/digitalocean)
|
||||
- :icon{name="logos:firebase" class="h-5 w-4 inline mb-2"} [Firebase](https://nitro.unjs.io/deploy/providers/firebase)
|
||||
- :icon{name="logos:heroku-icon" class="h-5 w-4 inline mb-2"} [heroku](https://nitro.unjs.io/deploy/providers/heroku)
|
||||
- :icon{name="ph:cloud-duotone" class="h-5 w-4 inline mb-2"} [Edgio](https://nitro.unjs.io/deploy/providers/edgio)
|
||||
|
@ -19,28 +19,32 @@ Start with one of our starters and themes directly by opening [nuxt.new](https:/
|
||||
|
||||
## New Project
|
||||
|
||||
<!-- TODO: need to fix upstream in nuxt/nuxt.com -->
|
||||
<!-- markdownlint-disable-next-line MD001 -->
|
||||
#### Prerequisites
|
||||
|
||||
- **Node.js** - [`v16.10.0`](https://nodejs.org/en/) or newer
|
||||
- **Text editor** - We recommend [Visual Studio Code]() with the [Volar Extension](https://marketplace.visualstudio.com/items?itemName=Vue.volar)
|
||||
- **Text editor** - We recommend [Visual Studio Code](https://code.visualstudio.com/) with the [Volar Extension](https://marketplace.visualstudio.com/items?itemName=Vue.volar)
|
||||
- **Terminal** - In order to run Nuxt commands
|
||||
|
||||
::alert
|
||||
::details
|
||||
:summary[Additional notes for an optimal setup:]
|
||||
- **Node.js**: Make sure to use an even numbered version (16, 18, etc)
|
||||
::details
|
||||
:summary[Additional notes for an optimal setup:]
|
||||
- **Node.js**: Make sure to use an even numbered version (16, 18, etc)
|
||||
|
||||
- **Volar**: Either enable [**Take Over Mode**](https://vuejs.org/guide/typescript/overview.html#volar-takeover-mode) (recommended) or add the [TypeScript Vue Plugin](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin)
|
||||
- **Volar**: Either enable [**Take Over Mode**](https://vuejs.org/guide/typescript/overview.html#volar-takeover-mode) (recommended) or add the [TypeScript Vue Plugin](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin)
|
||||
|
||||
If you have enabled **Take Over Mode** or installed the **TypeScript Vue Plugin (Volar)**, you can disable generating the shim for `*.vue` files in your `nuxt.config.ts` file:
|
||||
If you have enabled **Take Over Mode** or installed the **TypeScript Vue Plugin (Volar)**, you can disable generating the shim for `*.vue` files in your `nuxt.config.ts` file:
|
||||
|
||||
```ts [nuxt.config.ts]
|
||||
export default defineNuxtConfig({
|
||||
typescript: {
|
||||
shim: false
|
||||
}
|
||||
})
|
||||
```
|
||||
::
|
||||
```ts [nuxt.config.ts]
|
||||
export default defineNuxtConfig({
|
||||
typescript: {
|
||||
shim: false
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
::
|
||||
::
|
||||
|
||||
Open a terminal (if you're using [Visual Studio Code](https://code.visualstudio.com/), you can open an [integrated terminal](https://code.visualstudio.com/docs/editor/integrated-terminal)) and use the following command to create a new starter project:
|
||||
@ -110,4 +114,4 @@ Well done! A browser window should automatically open for <http://localhost:3000
|
||||
|
||||
Now that you've created your Nuxt 3 project, you are ready to start building your application.
|
||||
|
||||
* Learn about the framework [concepts](/docs/guide/concepts/auto-imports)
|
||||
- Learn about the framework [concepts](/docs/guide/concepts/auto-imports)
|
||||
|
@ -48,7 +48,6 @@ This includes:
|
||||
|
||||
You cannot currently define a server-side handler for these errors, but can render an error page (see the next section).
|
||||
|
||||
|
||||
### Errors downloading JS chunks
|
||||
|
||||
You might encounter chunk loading errors due to a network connectivity failure or a new deployment (which invalidates your old, hashed JS chunk URLs). Nuxt provides built-in support for handling chunk loading errors by performing a hard reload when a chunk fails to load during route navigation.
|
||||
|
@ -57,6 +57,59 @@ Unlike navigation guards in [the vue-router docs](https://router.vuejs.org/guide
|
||||
We recommend using the helper functions above for performing redirects or stopping navigation. Other possible return values described in [the vue-router docs](https://router.vuejs.org/guide/advanced/navigation-guards.html#global-before-guards) may work but there may be breaking changes in future.
|
||||
::
|
||||
|
||||
## What Order Middleware Runs In
|
||||
|
||||
Middleware runs in the following order:
|
||||
|
||||
1. Global Middleware
|
||||
2. Page defined middleware order (if there are multiple middleware declared with the array syntax)
|
||||
|
||||
For example, assuming you have the following middleware and component:
|
||||
|
||||
```text [middleware/ directory]
|
||||
middleware/
|
||||
--| analytics.global.ts
|
||||
--| setup.global.ts
|
||||
--| auth.ts
|
||||
```
|
||||
|
||||
```vue [pages/profile.vue]
|
||||
<script setup>
|
||||
definePageMeta({
|
||||
middleware: [
|
||||
function (to, from) {
|
||||
// Custom inline middleware
|
||||
},
|
||||
'auth',
|
||||
],
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
You can expect the middleware to be run in the following order:
|
||||
|
||||
1. `analytics.global.ts`
|
||||
2. `setup.global.ts`
|
||||
3. Custom inline middleware
|
||||
4. `auth.ts`
|
||||
|
||||
### Ordering Global Middleware
|
||||
|
||||
By default, global middleware is executed alphabetically based on the filename.
|
||||
|
||||
However, there may be times you want to define a specific order. For example, in the last scenario, `setup.global.ts` may need to run before `analytics.global.ts`. In that case, we recommend prefixing global middleware with 'alphabetical' numbering.
|
||||
|
||||
```text [middleware/ directory]
|
||||
middleware/
|
||||
--| 01.setup.global.ts
|
||||
--| 02.analytics.global.ts
|
||||
--| auth.ts
|
||||
```
|
||||
|
||||
::alert{type=info icon=💡}
|
||||
In case you're new to 'alphabetical' numbering, remember that filenames are sorted as strings, not as numeric values. For example, `10.new.global.ts` would come before `2.new.global.ts`. This is why the example prefixes single digit numbers with `0`.
|
||||
::
|
||||
|
||||
## When Middleware Runs
|
||||
|
||||
If your site is server-rendered or generated, middleware for the initial page will be executed both when the page is rendered and then again on the client. This might be needed if your middleware needs a browser environment, such as if you have a generated site, aggressively cache responses, or want to read a value from local storage.
|
||||
|
@ -15,6 +15,7 @@ The auto-registered files patterns are:
|
||||
You don't need to add those local modules to your [`nuxt.config.ts`](/docs/guide/directory-structure/nuxt.config) separately.
|
||||
|
||||
::code-group
|
||||
|
||||
```ts [modules/hello/index.ts]
|
||||
// `nuxt/kit` is a helper subpath import you can use when defining local modules
|
||||
// that means you do not need to add `@nuxt/kit` to your project's dependencies
|
||||
@ -35,11 +36,13 @@ export default defineNuxtModule({
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
```ts [modules/hello/runtime/api-route.ts]
|
||||
export default defineEventHandler(() => {
|
||||
return { hello: 'world' }
|
||||
}
|
||||
```
|
||||
|
||||
::
|
||||
|
||||
When starting Nuxt, the `hello` module will be registered and the `/api/hello` route will be available.
|
||||
|
@ -340,7 +340,6 @@ Nuxt 3 allows programmatic navigation through the `navigateTo()` utility method.
|
||||
|
||||
```vue
|
||||
<script setup>
|
||||
const router = useRouter();
|
||||
const name = ref('');
|
||||
const type = ref(1);
|
||||
|
||||
|
@ -133,7 +133,7 @@ export { }
|
||||
```
|
||||
|
||||
::alert{type=warning}
|
||||
If you are using WebStorm, you may need to augment `@vue/runtime-core` until [this issue](https://youtrack.jetbrains.com/issue/WEB-59818/VUE-Typescript-WS-PS-does-not-correctly-display-type-of-globally-injected-properties) is resolved.
|
||||
If you are using WebStorm, you may need to augment `@vue/runtime-core` until [this issue](https://youtrack.jetbrains.com/issue/WEB-59818/VUE-TypeScript-WS-PS-does-not-correctly-display-type-of-globally-injected-properties) is resolved.
|
||||
::
|
||||
|
||||
## Vue Plugins
|
||||
|
@ -90,4 +90,3 @@ declare module 'nuxt/schema' {
|
||||
// It is always important to ensure you import/export something when augmenting a type
|
||||
export {}
|
||||
```
|
||||
|
||||
|
@ -58,7 +58,7 @@ All fetch options can be given a `computed` or `ref` value. These will be watche
|
||||
* `server`: Whether to fetch the data on the server (defaults to `true`).
|
||||
* `default`: A factory function to set the default value of the data, before the async function resolves - particularly useful with the `lazy: true` option.
|
||||
* `pick`: Only pick specified keys in this array from the `handler` function result.
|
||||
* `watch`: watch reactive sources to auto-refresh.
|
||||
* `watch`: Watch an array of reactive sources and auto-refresh the fetch result when they change. Fetch options and URL are watched by default. You can completely ignore reactive sources by using `watch: false`. Together with `immediate: false`, this allows for a fully-manual `useFetch`.
|
||||
* `transform`: A function that can be used to alter `handler` function result after resolving.
|
||||
* `immediate`: When set to `false`, will prevent the request from firing immediately. (defaults to `true`)
|
||||
|
||||
|
@ -9,6 +9,7 @@ The `useHeadSafe` composable is a wrapper around the [`useHead`](/docs/api/compo
|
||||
## Usage
|
||||
|
||||
You can pass all the same values as `useHead`
|
||||
|
||||
```ts
|
||||
useHeadSafe({
|
||||
script: [
|
||||
|
@ -10,11 +10,13 @@ Nuxt provides composables and utilities for first-class server-side-rendering su
|
||||
`setResponseStatus` can only be called within component setup functions, plugins, and route middleware.
|
||||
|
||||
```js
|
||||
const event = useRequestEvent()
|
||||
|
||||
// Set the status code to 404 for a custom 404 page
|
||||
setResponseStatus(404)
|
||||
setResponseStatus(event, 404)
|
||||
|
||||
// Set the status message as well
|
||||
setResponseStatus(404, 'Page Not Found')
|
||||
setResponseStatus(event, 404, 'Page Not Found')
|
||||
```
|
||||
|
||||
::alert{icon=👉}
|
||||
|
@ -46,7 +46,7 @@ Hook | Arguments | Description
|
||||
`app:templatesGenerated` | `app` | Called after templates are compiled into the [virtual file system](https://nuxt.com/docs/guide/directory-structure/nuxt#virtual-file-system) (vfs).
|
||||
`build:before` | - | Called before Nuxt bundle builder.
|
||||
`build:done` | - | Called after Nuxt bundle builder is complete.
|
||||
`build:manifest` | `manifest` | Called during the manifest build by Vite and Webpack. This allows customizing the manifest that Nitro will use to render `<script>` and `<link>` tags in the final HTML.
|
||||
`build:manifest` | `manifest` | Called during the manifest build by Vite and webpack. This allows customizing the manifest that Nitro will use to render `<script>` and `<link>` tags in the final HTML.
|
||||
`builder:generateApp` | `options` | Called before generating the app.
|
||||
`builder:watch` | `event, path` | Called at build time in development when the watcher spots a change to a file or directory in the project.
|
||||
`pages:extend` | `pages` | Called after pages routes are resolved.
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
title: "nuxi devtools"
|
||||
description: The devtools command allows you to enable or disable Nuxt Devtools on a per-project basis.
|
||||
description: The devtools command allows you to enable or disable Nuxt DevTools on a per-project basis.
|
||||
---
|
||||
|
||||
# `nuxi devtools`
|
||||
|
@ -424,6 +424,7 @@ export default defineNuxtModule({
|
||||
|
||||
:ReadMore{link="/docs/api/advanced/hooks" title="API > Advanced > Hooks"}
|
||||
|
||||
::alert{type=info}
|
||||
**Module cleanup**
|
||||
|
||||
If your module opens, handles, or starts a watcher, you should close it when the Nuxt lifecycle is done. The `close` hook is available for this.
|
||||
@ -440,6 +441,8 @@ export default defineNuxtModule({
|
||||
})
|
||||
```
|
||||
|
||||
::
|
||||
|
||||
#### Augmenting Types
|
||||
|
||||
If your module should augment types handled by Nuxt, you can use the `prepare:types` hook to perform this operation.
|
||||
@ -589,9 +592,9 @@ Consider documenting module usage in the readme file:
|
||||
|
||||
Linking to the integration website and documentation is always a good idea.
|
||||
|
||||
#### Provide a Stackblitz Demo or Boilerplate
|
||||
#### Provide a StackBlitz Demo or Boilerplate
|
||||
|
||||
It's a good practice to make a minimal reproduction with your module and [StackBlitz](https://nuxt.new/s/v3) that you add to your module readme.
|
||||
It's a good practice to make a minimal reproduction with your module and [StackBlitz](https://nuxt.new/s/v3) that you add to your module readme.
|
||||
|
||||
This not only provides potential users of your module a quick and easy way to experiment with the module but also an easy way for them to build minimal reproductions they can send you when they encounter issues.
|
||||
|
||||
|
@ -22,7 +22,7 @@ export default <RouterConfig> {
|
||||
{
|
||||
name: 'home',
|
||||
path: '/',
|
||||
component: () => import('~/pages/home.vue')
|
||||
component: () => import('~/pages/home.vue').then(r => r.default || r)
|
||||
}
|
||||
],
|
||||
}
|
||||
@ -44,7 +44,7 @@ export default defineNuxtConfig({
|
||||
pages.push({
|
||||
name: 'profile',
|
||||
path: '/profile',
|
||||
component: () => import('~/pages/profile.vue')
|
||||
file: '~/extra-pages/profile.vue'
|
||||
})
|
||||
|
||||
// remove routes
|
||||
|
@ -134,11 +134,18 @@ git checkout -b my-new-branch
|
||||
|
||||
### Set Up Documentation Website in Local Environment
|
||||
|
||||
We are using [Docus](https://docus.dev) for documentation.
|
||||
The Nuxt documentation is currently deployed within [nuxt/nuxt.com](https://github.com/nuxt/nuxt.com) as a layer.
|
||||
|
||||
- Run `pnpm build:stub` once in the root directory
|
||||
- Go into the docs directory: `cd docs`
|
||||
- Install docs dependencies using `yarn install`
|
||||
- Run `yarn dev` to start docs in development mode
|
||||
<!-- - Go into the docs directory: `cd docs` -->
|
||||
<!-- - Install docs dependencies using `yarn install` -->
|
||||
<!-- - Run `yarn dev` to start docs in development mode -->
|
||||
- Before opening a PR, run `pnpm docs:lint:fix` to highlight and resolve any lint issues
|
||||
|
||||
::alert
|
||||
🚧 This repository will be open-sourced shortly. Until then, you will need to open a pull request to see a preview of your changes.
|
||||
::
|
||||
|
||||
::alert
|
||||
We recommend that you install the [MDC extension](https://marketplace.visualstudio.com/items?itemName=Nuxt.mdc) for VS Code.
|
||||
::
|
||||
|
@ -88,7 +88,6 @@ Nuxt and Nuxt Modules are now build-time-only.
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
::alert
|
||||
If you are a module author, you can check out [more information about module compatibility](/docs/migration/module-authors) and [our module author guide](/docs/guide/going-further/modules).
|
||||
::
|
||||
|
23
package.json
23
package.json
@ -12,8 +12,9 @@
|
||||
"example": "./scripts/example.sh dev",
|
||||
"example:build": "./scripts/example.sh build",
|
||||
"lint": "eslint --ext .vue,.ts,.js,.mjs .",
|
||||
"lint:docs": "markdownlint ./docs/content/1.docs && case-police 'docs/content/1.docs/**/*.md'",
|
||||
"lint:docs:fix": "markdownlint ./docs/content/1.docs --fix && case-police 'docs/content/1.docs/**/*.md' --fix",
|
||||
"lint:fix": "eslint --ext .vue,.ts,.js,.mjs . --fix",
|
||||
"lint:docs": "markdownlint ./docs && case-police 'docs/**/*.md'",
|
||||
"lint:docs:fix": "markdownlint ./docs --fix && case-police 'docs/**/*.md' --fix",
|
||||
"nuxi": "JITI_ESM_RESOLVE=1 nuxi",
|
||||
"nuxt": "JITI_ESM_RESOLVE=1 nuxi",
|
||||
"play": "pnpm nuxi dev playground",
|
||||
@ -35,7 +36,7 @@
|
||||
"nuxi": "workspace:*",
|
||||
"nuxt": "workspace:*",
|
||||
"nuxt3": "workspace:nuxt@*",
|
||||
"unbuild": "^1.1.2",
|
||||
"unbuild": "^1.2.0",
|
||||
"vite": "^4.2.1",
|
||||
"vue": "3.2.47",
|
||||
"magic-string": "^0.30.0"
|
||||
@ -49,15 +50,15 @@
|
||||
"@nuxt/webpack-builder": "workspace:*",
|
||||
"@nuxtjs/eslint-config-typescript": "^12.0.0",
|
||||
"@types/crawler": "^1.2.2",
|
||||
"@types/node": "^18.15.8",
|
||||
"@types/node": "^18.15.11",
|
||||
"@types/rimraf": "^3.0.2",
|
||||
"@types/semver": "^7.3.13",
|
||||
"@unocss/reset": "^0.50.6",
|
||||
"case-police": "^0.5.14",
|
||||
"changelogen": "^0.5.1",
|
||||
"changelogen": "^0.5.2",
|
||||
"crawler": "^1.4.0",
|
||||
"eslint": "^8.36.0",
|
||||
"eslint-plugin-jsdoc": "^40.1.0",
|
||||
"eslint": "^8.37.0",
|
||||
"eslint-plugin-jsdoc": "^40.1.1",
|
||||
"execa": "^7.1.1",
|
||||
"expect-type": "^0.15.0",
|
||||
"globby": "^13.1.3",
|
||||
@ -70,14 +71,14 @@
|
||||
"rimraf": "^4.4.1",
|
||||
"semver": "^7.3.8",
|
||||
"std-env": "^3.3.2",
|
||||
"typescript": "^5.0.2",
|
||||
"typescript": "^5.0.3",
|
||||
"ufo": "^1.1.1",
|
||||
"unbuild": "^1.1.2",
|
||||
"unbuild": "^1.2.0",
|
||||
"vite": "^4.2.1",
|
||||
"vitest": "^0.29.7",
|
||||
"vitest": "^0.29.8",
|
||||
"vue-tsc": "^1.2.0"
|
||||
},
|
||||
"packageManager": "pnpm@7.30.3",
|
||||
"packageManager": "pnpm@8.1.1",
|
||||
"engines": {
|
||||
"node": "^14.18.0 || ^16.10.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nuxt/kit",
|
||||
"version": "3.3.2",
|
||||
"version": "3.3.3",
|
||||
"repository": "nuxt/nuxt",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
@ -20,7 +20,7 @@
|
||||
"prepack": "unbuild"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nuxt/schema": "3.3.2",
|
||||
"@nuxt/schema": "workspace:../schema",
|
||||
"c12": "^1.2.0",
|
||||
"consola": "^2.15.3",
|
||||
"defu": "^6.1.2",
|
||||
@ -36,8 +36,8 @@
|
||||
"scule": "^1.0.0",
|
||||
"semver": "^7.3.8",
|
||||
"unctx": "^2.1.2",
|
||||
"unimport": "^3.0.4",
|
||||
"untyped": "^1.2.2"
|
||||
"unimport": "^3.0.5",
|
||||
"untyped": "^1.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/lodash.template": "^4.5.1",
|
||||
|
@ -8,13 +8,13 @@ export interface ExtendConfigOptions {
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
dev?: boolean
|
||||
/**
|
||||
* Install plugin on build
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
build?: boolean
|
||||
dev?: boolean
|
||||
/**
|
||||
* Install plugin on build
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
build?: boolean
|
||||
/**
|
||||
* Install plugin on server side
|
||||
*
|
||||
@ -41,7 +41,7 @@ export interface ExtendViteConfigOptions extends ExtendConfigOptions {}
|
||||
* when applying to both client and server builds.
|
||||
*/
|
||||
export function extendWebpackConfig (
|
||||
fn: ((config: WebpackConfig)=> void),
|
||||
fn: ((config: WebpackConfig) => void),
|
||||
options: ExtendWebpackConfigOptions = {}
|
||||
) {
|
||||
const nuxt = useNuxt()
|
||||
|
@ -1,4 +1,5 @@
|
||||
import type { Nuxt, NuxtModule } from '@nuxt/schema'
|
||||
import { isNuxt2 } from '../compatibility'
|
||||
import { useNuxt } from '../context'
|
||||
import { resolveModule, requireModule } from '../internal/cjs'
|
||||
import { importModule } from '../internal/esm'
|
||||
@ -10,7 +11,12 @@ export async function installModule (moduleToInstall: string | NuxtModule, _inli
|
||||
const { nuxtModule, inlineOptions } = await normalizeModule(moduleToInstall, _inlineOptions)
|
||||
|
||||
// Call module
|
||||
const res = await nuxtModule(inlineOptions, nuxt) ?? {}
|
||||
const res = (
|
||||
isNuxt2()
|
||||
// @ts-expect-error Nuxt 2 `moduleContainer` is not typed
|
||||
? await nuxtModule.call(nuxt.moduleContainer, inlineOptions, nuxt)
|
||||
: await nuxtModule(inlineOptions, nuxt)
|
||||
) ?? {}
|
||||
if (res === false /* setup aborted */) {
|
||||
return
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "nuxi",
|
||||
"version": "3.3.2",
|
||||
"version": "3.3.3",
|
||||
"repository": "nuxt/nuxt",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
@ -18,8 +18,8 @@
|
||||
"prepack": "unbuild"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxt/kit": "3.3.2",
|
||||
"@nuxt/schema": "3.3.2",
|
||||
"@nuxt/kit": "workspace:../kit",
|
||||
"@nuxt/schema": "workspace:../schema",
|
||||
"@types/clear": "^0.1.2",
|
||||
"@types/flat": "^5.0.2",
|
||||
"@types/mri": "^1.1.1",
|
||||
@ -35,7 +35,7 @@
|
||||
"execa": "^7.1.1",
|
||||
"flat": "^5.0.2",
|
||||
"giget": "^1.1.2",
|
||||
"h3": "^1.6.2",
|
||||
"h3": "^1.6.4",
|
||||
"jiti": "^1.18.2",
|
||||
"listhen": "^1.0.4",
|
||||
"mlly": "^1.2.0",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "nuxt",
|
||||
"version": "3.3.2",
|
||||
"version": "3.3.3",
|
||||
"repository": "nuxt/nuxt",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
@ -61,11 +61,11 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@nuxt/devalue": "^2.0.0",
|
||||
"@nuxt/kit": "3.3.2",
|
||||
"@nuxt/schema": "3.3.2",
|
||||
"@nuxt/kit": "workspace:../kit",
|
||||
"@nuxt/schema": "workspace:../schema",
|
||||
"@nuxt/telemetry": "^2.1.10",
|
||||
"@nuxt/ui-templates": "^1.1.1",
|
||||
"@nuxt/vite-builder": "3.3.2",
|
||||
"@nuxt/vite-builder": "workspace:../vite",
|
||||
"@unhead/ssr": "^1.1.25",
|
||||
"@unhead/vue": "^1.1.25",
|
||||
"@vue/reactivity": "^3.2.47",
|
||||
@ -78,15 +78,15 @@
|
||||
"estree-walker": "^3.0.3",
|
||||
"fs-extra": "^11.1.1",
|
||||
"globby": "^13.1.3",
|
||||
"h3": "^1.6.2",
|
||||
"h3": "^1.6.4",
|
||||
"hash-sum": "^2.0.0",
|
||||
"hookable": "^5.5.0",
|
||||
"hookable": "^5.5.3",
|
||||
"jiti": "^1.18.2",
|
||||
"knitwork": "^1.0.0",
|
||||
"magic-string": "^0.30.0",
|
||||
"mlly": "^1.2.0",
|
||||
"nitropack": "~2.3.2",
|
||||
"nuxi": "3.3.2",
|
||||
"nitropack": "^2.3.2",
|
||||
"nuxi": "workspace:../nuxi",
|
||||
"ofetch": "^1.0.1",
|
||||
"ohash": "^1.0.0",
|
||||
"pathe": "^1.1.0",
|
||||
@ -96,9 +96,9 @@
|
||||
"ufo": "^1.1.1",
|
||||
"unctx": "^2.1.2",
|
||||
"unenv": "^1.2.2",
|
||||
"unimport": "^3.0.4",
|
||||
"unimport": "^3.0.5",
|
||||
"unplugin": "^1.3.1",
|
||||
"untyped": "^1.2.2",
|
||||
"untyped": "^1.3.2",
|
||||
"vue": "^3.2.47",
|
||||
"vue-bundle-renderer": "^1.0.3",
|
||||
"vue-devtools-stub": "^0.1.0",
|
||||
|
@ -265,7 +265,7 @@ export function defineNuxtLink (options: NuxtLinkOptions) {
|
||||
}
|
||||
|
||||
// Resolves `to` value if it's a route location object
|
||||
// converts `'''` to `null` to prevent the attribute from being added as empty (`href=""`)
|
||||
// converts `""` to `null` to prevent the attribute from being added as empty (`href=""`)
|
||||
const href = typeof to.value === 'object' ? router.resolve(to.value)?.href ?? null : to.value || null
|
||||
|
||||
// Resolves `target` value
|
||||
|
@ -37,6 +37,7 @@ onErrorCaptured((err, target, info) => {
|
||||
if (process.server || (isNuxtError(err) && (err.fatal || err.unhandled))) {
|
||||
const p = callWithNuxt(nuxtApp, showError, [err])
|
||||
onServerPrefetch(() => p)
|
||||
return false // suppress error from breaking render
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -24,7 +24,7 @@ export type KeysOf<T> = Array<
|
||||
|
||||
export type KeyOfRes<Transform extends _Transform> = KeysOf<ReturnType<Transform>>
|
||||
|
||||
type MultiWatchSources = (WatchSource<unknown> | object)[]
|
||||
export type MultiWatchSources = (WatchSource<unknown> | object)[]
|
||||
|
||||
export interface AsyncDataOptions<
|
||||
ResT,
|
||||
|
@ -4,7 +4,7 @@ import type { Ref } from 'vue'
|
||||
import { computed, unref, reactive } from 'vue'
|
||||
import { hash } from 'ohash'
|
||||
import { useRequestFetch } from './ssr'
|
||||
import type { AsyncDataOptions, _Transform, KeysOf, AsyncData, PickFrom } from './asyncData'
|
||||
import type { AsyncDataOptions, _Transform, KeysOf, AsyncData, PickFrom, MultiWatchSources } from './asyncData'
|
||||
import { useAsyncData } from './asyncData'
|
||||
|
||||
export type FetchResult<ReqT extends NitroFetchRequest, M extends AvailableRouterMethod<ReqT>> = TypedInternalResponse<ReqT, unknown, M>
|
||||
@ -21,9 +21,10 @@ export interface UseFetchOptions<
|
||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||
R extends NitroFetchRequest = string & {},
|
||||
M extends AvailableRouterMethod<R> = AvailableRouterMethod<R>
|
||||
> extends AsyncDataOptions<ResT, DataT, PickKeys>, ComputedFetchOptions<R, M> {
|
||||
> extends Omit<AsyncDataOptions<ResT, DataT, PickKeys>, 'watch'>, ComputedFetchOptions<R, M> {
|
||||
key?: string
|
||||
$fetch?: typeof globalThis.$fetch
|
||||
watch?: MultiWatchSources | false
|
||||
}
|
||||
|
||||
export function useFetch<
|
||||
@ -59,6 +60,7 @@ export function useFetch<
|
||||
if (!request) {
|
||||
throw new Error('[nuxt] [useFetch] request is missing.')
|
||||
}
|
||||
|
||||
const key = _key === autoKey ? '$f' + _key : _key
|
||||
|
||||
const _request = computed(() => {
|
||||
@ -69,6 +71,10 @@ export function useFetch<
|
||||
return unref(r)
|
||||
})
|
||||
|
||||
if (!opts.baseURL && typeof _request.value === 'string' && _request.value.startsWith('//')) {
|
||||
throw new Error('[nuxt] [useFetch] the request URL must not start with "//".')
|
||||
}
|
||||
|
||||
const {
|
||||
server,
|
||||
lazy,
|
||||
@ -92,11 +98,7 @@ export function useFetch<
|
||||
transform,
|
||||
pick,
|
||||
immediate,
|
||||
watch: [
|
||||
_fetchOptions,
|
||||
_request,
|
||||
...(watch || [])
|
||||
]
|
||||
watch: watch === false ? [] : [_fetchOptions, _request, ...(watch || [])]
|
||||
}
|
||||
|
||||
let controller: AbortController
|
||||
|
@ -17,6 +17,9 @@ export const useRouter = () => {
|
||||
}
|
||||
|
||||
export const useRoute = (): RouteLocationNormalizedLoaded => {
|
||||
if (process.dev && isProcessingMiddleware()) {
|
||||
console.warn('[nuxt] Calling `useRoute` within middleware may lead to misleading results. Instead, use the (to, from) arguments passed to the middleware to access the new and old routes.')
|
||||
}
|
||||
if (getCurrentInstance()) {
|
||||
return inject('_route', useNuxtApp()._route)
|
||||
}
|
||||
@ -111,7 +114,7 @@ export const navigateTo = (to: RouteLocationRaw | undefined | null, options?: Na
|
||||
// Let vue-router handle internal redirects within middleware
|
||||
// to prevent the navigation happening after response is sent
|
||||
if (isProcessingMiddleware() && !isExternal) {
|
||||
setResponseStatus(options?.redirectCode || 302)
|
||||
setResponseStatus(nuxtApp.ssrContext.event, options?.redirectCode || 302)
|
||||
return to
|
||||
}
|
||||
const redirectLocation = isExternal ? toPath : joinURL(useRuntimeConfig().app.baseURL, router.resolve(to).fullPath || '/')
|
||||
|
@ -25,7 +25,13 @@ export function useRequestFetch (): typeof global.$fetch {
|
||||
return event?.$fetch as typeof globalThis.$fetch || globalThis.$fetch
|
||||
}
|
||||
|
||||
export function setResponseStatus (code: number, message?: string) {
|
||||
export function setResponseStatus (event: H3Event, code?: number, message?: string): void
|
||||
/** @deprecated Pass `event` as first option. */
|
||||
export function setResponseStatus (code: number, message?: string): void
|
||||
export function setResponseStatus (arg1: H3Event | number | undefined, arg2?: number | string, arg3?: string) {
|
||||
if (process.client) { return }
|
||||
_setResponseStatus(useRequestEvent(), code, message)
|
||||
if (arg1 && typeof arg1 !== 'number') {
|
||||
return _setResponseStatus(arg1, arg2 as number | undefined, arg3)
|
||||
}
|
||||
return _setResponseStatus(useRequestEvent(), arg1, arg2 as string | undefined)
|
||||
}
|
||||
|
@ -238,8 +238,9 @@ export function createNuxtApp (options: CreateOptions) {
|
||||
})
|
||||
|
||||
// Log errors captured when running plugins, in the `app:created` and `app:beforeMount` hooks
|
||||
// as well as when mounting the app and in the `app:mounted` hook
|
||||
nuxtApp.hook('app:error', (...args) => { console.error('[nuxt] error caught during app initialization', ...args) })
|
||||
// as well as when mounting the app.
|
||||
const unreg = nuxtApp.hook('app:error', (...args) => { console.error('[nuxt] error caught during app initialization', ...args) })
|
||||
nuxtApp.hook('app:mounted', unreg)
|
||||
}
|
||||
|
||||
// Expose runtime config
|
||||
|
@ -189,6 +189,15 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
|
||||
}
|
||||
}
|
||||
|
||||
// Add backward-compatible middleware to respect `x-nuxt-no-ssr` header
|
||||
if (nuxt.options.experimental.respectNoSSRHeader) {
|
||||
nitroConfig.handlers = nitroConfig.handlers || []
|
||||
nitroConfig.handlers.push({
|
||||
handler: resolve(distDir, 'core/runtime/nitro/no-ssr'),
|
||||
middleware: true
|
||||
})
|
||||
}
|
||||
|
||||
// Register nuxt protection patterns
|
||||
nitroConfig.rollupConfig!.plugins = await nitroConfig.rollupConfig!.plugins || []
|
||||
nitroConfig.rollupConfig!.plugins = Array.isArray(nitroConfig.rollupConfig!.plugins) ? nitroConfig.rollupConfig!.plugins : [nitroConfig.rollupConfig!.plugins]
|
||||
|
@ -20,6 +20,7 @@ import { UnctxTransformPlugin } from './plugins/unctx'
|
||||
import type { TreeShakeComposablesPluginOptions } from './plugins/tree-shake'
|
||||
import { TreeShakeComposablesPlugin } from './plugins/tree-shake'
|
||||
import { DevOnlyPlugin } from './plugins/dev-only'
|
||||
import { LayerAliasingPlugin } from './plugins/layer-aliasing'
|
||||
import { addModuleTranspiles } from './modules'
|
||||
import { initNitro } from './nitro'
|
||||
import schemaModule from './schema'
|
||||
@ -80,13 +81,28 @@ async function initNuxt (nuxt: Nuxt) {
|
||||
addVitePlugin(ImportProtectionPlugin.vite(config))
|
||||
addWebpackPlugin(ImportProtectionPlugin.webpack(config))
|
||||
|
||||
if (nuxt.options.experimental.localLayerAliases) {
|
||||
// Add layer aliasing support for ~, ~~, @ and @@ aliases
|
||||
addVitePlugin(LayerAliasingPlugin.vite({
|
||||
sourcemap: nuxt.options.sourcemap.server || nuxt.options.sourcemap.client,
|
||||
// skip top-level layer (user's project) as the aliases will already be correctly resolved
|
||||
layers: nuxt.options._layers.slice(1)
|
||||
}))
|
||||
addWebpackPlugin(LayerAliasingPlugin.webpack({
|
||||
sourcemap: nuxt.options.sourcemap.server || nuxt.options.sourcemap.client,
|
||||
// skip top-level layer (user's project) as the aliases will already be correctly resolved
|
||||
layers: nuxt.options._layers.slice(1),
|
||||
transform: true
|
||||
}))
|
||||
}
|
||||
|
||||
nuxt.hook('modules:done', () => {
|
||||
// Add unctx transform
|
||||
addVitePlugin(UnctxTransformPlugin(nuxt).vite({ sourcemap: nuxt.options.sourcemap.server || nuxt.options.sourcemap.client }))
|
||||
addWebpackPlugin(UnctxTransformPlugin(nuxt).webpack({ sourcemap: nuxt.options.sourcemap.server || nuxt.options.sourcemap.client }))
|
||||
|
||||
// Add composable tree-shaking optimisations
|
||||
const serverTreeShakeOptions : TreeShakeComposablesPluginOptions = {
|
||||
const serverTreeShakeOptions: TreeShakeComposablesPluginOptions = {
|
||||
sourcemap: nuxt.options.sourcemap.server,
|
||||
composables: nuxt.options.optimization.treeShake.composables.server
|
||||
}
|
||||
@ -94,7 +110,7 @@ async function initNuxt (nuxt: Nuxt) {
|
||||
addVitePlugin(TreeShakeComposablesPlugin.vite(serverTreeShakeOptions), { client: false })
|
||||
addWebpackPlugin(TreeShakeComposablesPlugin.webpack(serverTreeShakeOptions), { client: false })
|
||||
}
|
||||
const clientTreeShakeOptions : TreeShakeComposablesPluginOptions = {
|
||||
const clientTreeShakeOptions: TreeShakeComposablesPluginOptions = {
|
||||
sourcemap: nuxt.options.sourcemap.client,
|
||||
composables: nuxt.options.optimization.treeShake.composables.client
|
||||
}
|
||||
|
68
packages/nuxt/src/core/plugins/layer-aliasing.ts
Normal file
68
packages/nuxt/src/core/plugins/layer-aliasing.ts
Normal file
@ -0,0 +1,68 @@
|
||||
import { createUnplugin } from 'unplugin'
|
||||
import type { NuxtConfigLayer } from 'nuxt/schema'
|
||||
import { resolveAlias } from '@nuxt/kit'
|
||||
import { normalize } from 'pathe'
|
||||
import MagicString from 'magic-string'
|
||||
|
||||
interface LayerAliasingOptions {
|
||||
sourcemap?: boolean
|
||||
transform?: boolean
|
||||
layers: NuxtConfigLayer[]
|
||||
}
|
||||
|
||||
const ALIAS_RE = /(?<=['"])[~@]{1,2}(?=\/)/g
|
||||
|
||||
export const LayerAliasingPlugin = createUnplugin((options: LayerAliasingOptions) => {
|
||||
const aliases = Object.fromEntries(options.layers.map(l => [l.config.srcDir || l.cwd, {
|
||||
'~': l.config?.alias?.['~'] || l.config.srcDir || l.cwd,
|
||||
'@': l.config?.alias?.['@'] || l.config.srcDir || l.cwd,
|
||||
'~~': l.config?.alias?.['~~'] || l.config.rootDir || l.cwd,
|
||||
'@@': l.config?.alias?.['@@'] || l.config.rootDir || l.cwd
|
||||
}]))
|
||||
const layers = Object.keys(aliases).sort((a, b) => b.length - a.length)
|
||||
|
||||
return {
|
||||
name: 'nuxt:layer-aliasing',
|
||||
enforce: 'pre',
|
||||
vite: {
|
||||
resolveId: {
|
||||
order: 'pre',
|
||||
async handler (id, importer) {
|
||||
if (!importer) { return }
|
||||
|
||||
const layer = layers.find(l => importer.startsWith(l))
|
||||
if (!layer) { return }
|
||||
|
||||
const resolvedId = resolveAlias(id, aliases[layer])
|
||||
if (resolvedId !== id) {
|
||||
return await this.resolve(resolvedId, importer, { skipSelf: true })
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// webpack-only transform
|
||||
transformInclude: (id) => {
|
||||
if (!options.transform) { return false }
|
||||
const _id = normalize(id)
|
||||
return layers.some(dir => _id.startsWith(dir))
|
||||
},
|
||||
transform (code, id) {
|
||||
if (!options.transform) { return }
|
||||
|
||||
const _id = normalize(id)
|
||||
const layer = layers.find(l => _id.startsWith(l))
|
||||
if (!layer || !code.match(ALIAS_RE)) { return }
|
||||
|
||||
const s = new MagicString(code)
|
||||
s.replace(ALIAS_RE, r => aliases[layer][r as '~'] || r)
|
||||
|
||||
if (s.hasChanged()) {
|
||||
return {
|
||||
code: s.toString(),
|
||||
map: options.sourcemap ? s.generateMap({ source: id, includeContent: true }) : undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
8
packages/nuxt/src/core/runtime/nitro/no-ssr.ts
Normal file
8
packages/nuxt/src/core/runtime/nitro/no-ssr.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { defineEventHandler, getRequestHeader } from 'h3'
|
||||
|
||||
export default defineEventHandler((event) => {
|
||||
if (getRequestHeader(event, 'x-nuxt-no-ssr')) {
|
||||
event.context.nuxt = event.context.nuxt || {}
|
||||
event.context.nuxt.noSSR = true
|
||||
}
|
||||
})
|
@ -5,7 +5,7 @@ import type { H3Event } from 'h3'
|
||||
import { appendHeader, getQuery, writeEarlyHints, readBody, createError } from 'h3'
|
||||
import devalue from '@nuxt/devalue'
|
||||
import destr from 'destr'
|
||||
import { joinURL } from 'ufo'
|
||||
import { joinURL, withoutTrailingSlash } from 'ufo'
|
||||
import { renderToString as _renderToString } from 'vue/server-renderer'
|
||||
import { hash } from 'ohash'
|
||||
|
||||
@ -213,7 +213,7 @@ export default defineRenderHandler(async (event) => {
|
||||
runtimeConfig: useRuntimeConfig() as NuxtSSRContext['runtimeConfig'],
|
||||
noSSR:
|
||||
!!(process.env.NUXT_NO_SSR) ||
|
||||
!!(event.node.req.headers['x-nuxt-no-ssr']) ||
|
||||
event.context.nuxt?.noSSR ||
|
||||
routeOptions.ssr === false ||
|
||||
(process.env.prerender ? PRERENDER_NO_SSR_ROUTES.has(url) : false),
|
||||
error: !!ssrError,
|
||||
@ -262,7 +262,7 @@ export default defineRenderHandler(async (event) => {
|
||||
// Hint nitro to prerender payload for this route
|
||||
appendHeader(event, 'x-nitro-prerender', joinURL(url, '_payload.js'))
|
||||
// Use same ssr context to generate payload for this route
|
||||
PAYLOAD_CACHE!.set(url, renderPayloadResponse(ssrContext))
|
||||
PAYLOAD_CACHE!.set(withoutTrailingSlash(url), renderPayloadResponse(ssrContext))
|
||||
}
|
||||
|
||||
// Render meta
|
||||
|
@ -129,7 +129,8 @@ export default defineNuxtModule({
|
||||
const _types = generateTypes(schema, {
|
||||
addExport: true,
|
||||
interfaceName: 'NuxtCustomSchema',
|
||||
partial: true
|
||||
partial: true,
|
||||
allowExtraKeys: false
|
||||
})
|
||||
const types =
|
||||
_types +
|
||||
|
@ -130,7 +130,7 @@ export const schemaTemplate: NuxtTemplate<TemplateContext> = {
|
||||
const modules = moduleInfo.map(meta => [genString(meta.configKey), getImportName(meta.importName)])
|
||||
|
||||
return [
|
||||
"import { NuxtModule } from 'nuxt/schema'",
|
||||
"import { NuxtModule, RuntimeConfig } from 'nuxt/schema'",
|
||||
"declare module 'nuxt/schema' {",
|
||||
' interface NuxtConfig {',
|
||||
...modules.map(([configKey, importName]) =>
|
||||
@ -154,7 +154,18 @@ export const schemaTemplate: NuxtTemplate<TemplateContext> = {
|
||||
allowExtraKeys: false,
|
||||
indentation: 2
|
||||
}),
|
||||
'}'
|
||||
'}',
|
||||
`declare module 'vue' {
|
||||
interface ComponentCustomProperties {
|
||||
$config: RuntimeConfig
|
||||
}
|
||||
}`,
|
||||
// TODO: remove when webstorm has support for augumenting 'vue' directly
|
||||
`declare module '@vue/runtime-dom' {
|
||||
interface ComponentCustomProperties {
|
||||
$config: RuntimeConfig
|
||||
}
|
||||
}`
|
||||
].join('\n')
|
||||
}
|
||||
}
|
||||
@ -278,7 +289,10 @@ export const publicPathTemplate: NuxtTemplate = {
|
||||
export const nuxtConfigTemplate = {
|
||||
filename: 'nuxt.config.mjs',
|
||||
getContents: (ctx: TemplateContext) => {
|
||||
return Object.entries(ctx.nuxt.options.app).map(([k, v]) => `export const ${camelCase('app-' + k)} = ${JSON.stringify(v)}`).join('\n\n')
|
||||
return [
|
||||
...Object.entries(ctx.nuxt.options.app).map(([k, v]) => `export const ${camelCase('app-' + k)} = ${JSON.stringify(v)}`),
|
||||
`export const devPagesDir = ${ctx.nuxt.options.dev ? JSON.stringify(ctx.nuxt.options.dir.pages) : 'null'}`
|
||||
].join('\n\n')
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,12 @@
|
||||
import { defineComponent } from 'vue'
|
||||
// @ts-expect-error virtual file
|
||||
import { devPagesDir } from '#build/nuxt.config.mjs'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'NuxtPage',
|
||||
setup (_, props) {
|
||||
if (process.dev) {
|
||||
console.warn('Create a Vue component in the `pages/` directory to enable `<NuxtPage>`')
|
||||
console.warn(`Create a Vue component in the \`${devPagesDir}/\` directory to enable \`<NuxtPage>\``)
|
||||
}
|
||||
return () => props.slots.default?.()
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ function getRoutePath (tokens: SegmentToken[]): string {
|
||||
(token.type === SegmentTokenType.optional
|
||||
? `:${token.value}?`
|
||||
: token.type === SegmentTokenType.dynamic
|
||||
? `:${token.value}`
|
||||
? `:${token.value}()`
|
||||
: token.type === SegmentTokenType.catchall
|
||||
? `:${token.value}(.*)*`
|
||||
: encodePath(token.value))
|
||||
|
@ -64,13 +64,13 @@ describe('pages:generateRoutesFromFiles', () => {
|
||||
output: [
|
||||
{
|
||||
name: 'parent-child',
|
||||
path: '/parent/:child',
|
||||
path: '/parent/:child()',
|
||||
file: `${pagesDir}/parent/[child].vue`,
|
||||
children: []
|
||||
},
|
||||
{
|
||||
name: 'parent-child',
|
||||
path: '/parent-:child',
|
||||
path: '/parent-:child()',
|
||||
file: `${pagesDir}/parent-[child].vue`,
|
||||
children: []
|
||||
}
|
||||
@ -91,7 +91,7 @@ describe('pages:generateRoutesFromFiles', () => {
|
||||
},
|
||||
{
|
||||
name: 'stories-id',
|
||||
path: '/stories/:id',
|
||||
path: '/stories/:id()',
|
||||
file: `${pagesDir}/stories/[id].vue`,
|
||||
children: []
|
||||
}
|
||||
@ -106,7 +106,7 @@ describe('pages:generateRoutesFromFiles', () => {
|
||||
output: [
|
||||
{
|
||||
name: 'stories-id',
|
||||
path: '/stories/:id',
|
||||
path: '/stories/:id()',
|
||||
file: `${pagesDir}/stories/[id].vue`,
|
||||
children: []
|
||||
},
|
||||
@ -167,7 +167,7 @@ describe('pages:generateRoutesFromFiles', () => {
|
||||
children: [],
|
||||
name: 'slug',
|
||||
file: 'pages/[slug].vue',
|
||||
path: '/:slug'
|
||||
path: '/:slug()'
|
||||
},
|
||||
{
|
||||
children: [
|
||||
@ -186,11 +186,11 @@ describe('pages:generateRoutesFromFiles', () => {
|
||||
children: [],
|
||||
name: 'bar',
|
||||
file: 'pages/[bar]/index.vue',
|
||||
path: '/:bar'
|
||||
path: '/:bar()'
|
||||
},
|
||||
{
|
||||
name: 'nonopt-slug',
|
||||
path: '/nonopt/:slug',
|
||||
path: '/nonopt/:slug()',
|
||||
file: `${pagesDir}/nonopt/[slug].vue`,
|
||||
children: []
|
||||
},
|
||||
@ -202,7 +202,7 @@ describe('pages:generateRoutesFromFiles', () => {
|
||||
},
|
||||
{
|
||||
name: 'sub-route-slug',
|
||||
path: '/:sub?/route-:slug',
|
||||
path: '/:sub?/route-:slug()',
|
||||
file: `${pagesDir}/[[sub]]/route-[slug].vue`,
|
||||
children: []
|
||||
}
|
||||
@ -243,22 +243,29 @@ describe('pages:generateRoutesFromFiles', () => {
|
||||
files: [
|
||||
`${pagesDir}/[a1_1a].vue`,
|
||||
`${pagesDir}/[b2.2b].vue`,
|
||||
`${pagesDir}/[b2]_[2b].vue`,
|
||||
`${pagesDir}/[[c3@3c]].vue`,
|
||||
`${pagesDir}/[[d4-4d]].vue`
|
||||
],
|
||||
output: [
|
||||
{
|
||||
name: 'a1_1a',
|
||||
path: '/:a1_1a',
|
||||
path: '/:a1_1a()',
|
||||
file: `${pagesDir}/[a1_1a].vue`,
|
||||
children: []
|
||||
},
|
||||
{
|
||||
name: 'b2.2b',
|
||||
path: '/:b2.2b',
|
||||
path: '/:b2.2b()',
|
||||
file: `${pagesDir}/[b2.2b].vue`,
|
||||
children: []
|
||||
},
|
||||
{
|
||||
name: 'b2_2b',
|
||||
path: '/:b2()_:2b()',
|
||||
file: `${pagesDir}/[b2]_[2b].vue`,
|
||||
children: []
|
||||
},
|
||||
{
|
||||
name: 'c33c',
|
||||
path: '/:c33c?',
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nuxt/schema",
|
||||
"version": "3.3.2",
|
||||
"version": "3.3.3",
|
||||
"repository": "nuxt/nuxt",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
@ -8,7 +8,8 @@
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.mjs"
|
||||
"import": "./dist/index.mjs",
|
||||
"require": "./dist/index.mjs"
|
||||
},
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
@ -25,7 +26,7 @@
|
||||
"@unhead/schema": "^1.1.25",
|
||||
"@vitejs/plugin-vue": "^4.1.0",
|
||||
"@vitejs/plugin-vue-jsx": "^3.0.1",
|
||||
"nitropack": "~2.3.2",
|
||||
"nitropack": "^2.3.2",
|
||||
"unbuild": "latest",
|
||||
"vite": "~4.2.1"
|
||||
},
|
||||
@ -33,7 +34,7 @@
|
||||
"c12": "^1.2.0",
|
||||
"create-require": "^1.1.1",
|
||||
"defu": "^6.1.2",
|
||||
"hookable": "^5.5.0",
|
||||
"hookable": "^5.5.3",
|
||||
"jiti": "^1.18.2",
|
||||
"pathe": "^1.1.0",
|
||||
"pkg-types": "^1.0.2",
|
||||
@ -41,8 +42,8 @@
|
||||
"scule": "^1.0.0",
|
||||
"std-env": "^3.3.2",
|
||||
"ufo": "^1.1.1",
|
||||
"unimport": "^3.0.4",
|
||||
"untyped": "^1.2.2"
|
||||
"unimport": "^3.0.5",
|
||||
"untyped": "^1.3.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.18.0 || ^16.10.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
|
@ -303,10 +303,10 @@ export default defineUntypedSchema({
|
||||
*/
|
||||
alias: {
|
||||
$resolve: async (val, get) => ({
|
||||
'~~': await get('rootDir'),
|
||||
'@@': await get('rootDir'),
|
||||
'~': await get('srcDir'),
|
||||
'@': await get('srcDir'),
|
||||
'~~': await get('rootDir'),
|
||||
'@@': await get('rootDir'),
|
||||
[await get('dir.assets')]: join(await get('srcDir'), await get('dir.assets')),
|
||||
[await get('dir.public')]: join(await get('srcDir'), await get('dir.public')),
|
||||
...val
|
||||
|
@ -158,6 +158,12 @@ export default defineUntypedSchema({
|
||||
*
|
||||
* This can be disabled for most Nuxt sites to reduce the client-side bundle by ~0.5kb.
|
||||
*/
|
||||
polyfillVueUseHead: true
|
||||
polyfillVueUseHead: true,
|
||||
|
||||
/** Allow disabling Nuxt SSR responses by setting the `x-nuxt-no-ssr` header. */
|
||||
respectNoSSRHeader: false,
|
||||
|
||||
/** Resolve `~`, `~~`, `@` and `@@` aliases located within layers with respect to their layer source and root directories. */
|
||||
localLayerAliases: true,
|
||||
}
|
||||
})
|
||||
|
@ -94,14 +94,16 @@ export interface NuxtOptions extends Omit<ConfigSchema, 'builder'> {
|
||||
}
|
||||
|
||||
export interface ViteConfig extends ViteUserConfig {
|
||||
/** The path to the entrypoint for the Vite build. */
|
||||
entry?: string
|
||||
/**
|
||||
* Options passed to @vitejs/plugin-vue
|
||||
* Options passed to @vitejs/plugin-vue.
|
||||
* @see https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue
|
||||
*/
|
||||
vue?: VuePluginOptions
|
||||
|
||||
/**
|
||||
* Options passed to @vitejs/plugin-vue-jsx
|
||||
* Options passed to @vitejs/plugin-vue-jsx.
|
||||
* @see https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue-jsx
|
||||
*/
|
||||
vueJsx?: VueJsxPluginOptions
|
||||
|
@ -1,7 +1,7 @@
|
||||
import type { TSConfig } from 'pkg-types'
|
||||
import type { Server as HttpServer } from 'node:http'
|
||||
import type { Server as HttpsServer } from 'node:https'
|
||||
import type { InlineConfig as ViteInlineConfig, ViteDevServer } from 'vite'
|
||||
import type { ViteDevServer } from 'vite'
|
||||
import type { Manifest } from 'vue-bundle-renderer'
|
||||
import type { EventHandler } from 'h3'
|
||||
import type { Import, InlinePreset, Unimport } from 'unimport'
|
||||
@ -9,7 +9,7 @@ import type { Compiler, Configuration, Stats } from 'webpack'
|
||||
import type { Nuxt, NuxtApp, ResolvedNuxtTemplate } from './nuxt'
|
||||
import type { Nitro, NitroConfig } from 'nitropack'
|
||||
import type { Component, ComponentsOptions } from './components'
|
||||
import type { NuxtCompatibility, NuxtCompatibilityIssues } from '..'
|
||||
import type { NuxtCompatibility, NuxtCompatibilityIssues, ViteConfig } from '..'
|
||||
import type { Schema, SchemaDefinition } from 'untyped'
|
||||
|
||||
export type HookResult = Promise<void> | void
|
||||
@ -282,14 +282,14 @@ export interface NuxtHooks {
|
||||
* @param viteBuildContext The vite build context object
|
||||
* @returns Promise
|
||||
*/
|
||||
'vite:extend': (viteBuildContext: { nuxt: Nuxt, config: ViteInlineConfig }) => HookResult
|
||||
'vite:extend': (viteBuildContext: { nuxt: Nuxt, config: ViteConfig }) => HookResult
|
||||
/**
|
||||
* Allows to extend Vite default config.
|
||||
* @param viteInlineConfig The vite inline config object
|
||||
* @param env Server or client
|
||||
* @returns Promise
|
||||
*/
|
||||
'vite:extendConfig': (viteInlineConfig: ViteInlineConfig, env: { isClient: boolean, isServer: boolean }) => HookResult
|
||||
'vite:extendConfig': (viteInlineConfig: ViteConfig, env: { isClient: boolean, isServer: boolean }) => HookResult
|
||||
/**
|
||||
* Called when the Vite server is created.
|
||||
* @param viteServer Vite development server
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nuxt/test-utils",
|
||||
"version": "3.3.2",
|
||||
"version": "3.3.3",
|
||||
"repository": "nuxt/nuxt",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
@ -18,8 +18,8 @@
|
||||
"prepack": "unbuild"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nuxt/kit": "3.3.2",
|
||||
"@nuxt/schema": "3.3.2",
|
||||
"@nuxt/kit": "workspace:../kit",
|
||||
"@nuxt/schema": "workspace:../schema",
|
||||
"consola": "^2.15.3",
|
||||
"defu": "^6.1.2",
|
||||
"execa": "^7.1.1",
|
||||
@ -29,9 +29,9 @@
|
||||
"pathe": "^1.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"playwright": "^1.32.0",
|
||||
"playwright": "^1.32.2",
|
||||
"unbuild": "latest",
|
||||
"vitest": "^0.29.7"
|
||||
"vitest": "^0.29.8"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "^3.2.47"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nuxt/vite-builder",
|
||||
"version": "3.3.2",
|
||||
"version": "3.3.3",
|
||||
"repository": "nuxt/nuxt",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
@ -18,28 +18,27 @@
|
||||
"prepack": "unbuild"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxt/schema": "3.3.2",
|
||||
"@types/cssnano": "^5.1.0",
|
||||
"@nuxt/schema": "workspace:../schema",
|
||||
"unbuild": "latest",
|
||||
"vue": "3.2.47"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nuxt/kit": "3.3.2",
|
||||
"@nuxt/kit": "workspace:../kit",
|
||||
"@rollup/plugin-replace": "^5.0.2",
|
||||
"@vitejs/plugin-vue": "^4.1.0",
|
||||
"@vitejs/plugin-vue-jsx": "^3.0.1",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"chokidar": "^3.5.3",
|
||||
"clear": "^0.1.0",
|
||||
"cssnano": "^5.1.15",
|
||||
"cssnano": "^6.0.0",
|
||||
"defu": "^6.1.2",
|
||||
"esbuild": "^0.17.13",
|
||||
"esbuild": "^0.17.15",
|
||||
"escape-string-regexp": "^5.0.0",
|
||||
"estree-walker": "^3.0.3",
|
||||
"externality": "^1.0.0",
|
||||
"fs-extra": "^11.1.1",
|
||||
"get-port-please": "^3.0.1",
|
||||
"h3": "^1.6.2",
|
||||
"h3": "^1.6.4",
|
||||
"knitwork": "^1.0.0",
|
||||
"magic-string": "^0.30.0",
|
||||
"mlly": "^1.2.0",
|
||||
@ -50,14 +49,13 @@
|
||||
"postcss": "^8.4.21",
|
||||
"postcss-import": "^15.1.0",
|
||||
"postcss-url": "^10.1.3",
|
||||
"rollup": "^3.20.2",
|
||||
"rollup-plugin-visualizer": "^5.9.0",
|
||||
"std-env": "^3.3.2",
|
||||
"strip-literal": "^1.0.1",
|
||||
"ufo": "^1.1.1",
|
||||
"unplugin": "^1.3.1",
|
||||
"vite": "~4.2.1",
|
||||
"vite-node": "^0.29.7",
|
||||
"vite-node": "^0.29.8",
|
||||
"vite-plugin-checker": "^0.5.6",
|
||||
"vue-bundle-renderer": "^1.0.3"
|
||||
},
|
||||
|
@ -3,16 +3,16 @@ import { join, resolve } from 'pathe'
|
||||
import * as vite from 'vite'
|
||||
import vuePlugin from '@vitejs/plugin-vue'
|
||||
import viteJsxPlugin from '@vitejs/plugin-vue-jsx'
|
||||
import type { ServerOptions } from 'vite'
|
||||
import type { ServerOptions, BuildOptions } from 'vite'
|
||||
import { logger } from '@nuxt/kit'
|
||||
import { getPort } from 'get-port-please'
|
||||
import { joinURL, withoutLeadingSlash } from 'ufo'
|
||||
import { defu } from 'defu'
|
||||
import type { OutputOptions } from 'rollup'
|
||||
import { defineEventHandler } from 'h3'
|
||||
import type { ViteConfig } from '@nuxt/schema'
|
||||
import { cacheDirPlugin } from './plugins/cache-dir'
|
||||
import { chunkErrorPlugin } from './plugins/chunk-error'
|
||||
import type { ViteBuildContext, ViteOptions } from './vite'
|
||||
import type { ViteBuildContext } from './vite'
|
||||
import { devStyleSSRPlugin } from './plugins/dev-ssr-css'
|
||||
import { runtimePathsPlugin } from './plugins/paths'
|
||||
import { pureAnnotationsPlugin } from './plugins/pure-annotations'
|
||||
@ -20,8 +20,7 @@ import { viteNodePlugin } from './vite-node'
|
||||
import { createViteLogger } from './utils/logger'
|
||||
|
||||
export async function buildClient (ctx: ViteBuildContext) {
|
||||
const clientConfig: vite.InlineConfig = vite.mergeConfig(ctx.config, {
|
||||
entry: ctx.entry,
|
||||
const clientConfig: ViteConfig = vite.mergeConfig(ctx.config, {
|
||||
base: ctx.nuxt.options.dev
|
||||
? joinURL(ctx.nuxt.options.app.baseURL.replace(/^\.\//, '/') || '/', ctx.nuxt.options.app.buildAssetsDir)
|
||||
: './',
|
||||
@ -62,8 +61,6 @@ export async function buildClient (ctx: ViteBuildContext) {
|
||||
},
|
||||
plugins: [
|
||||
cacheDirPlugin(ctx.nuxt.options.rootDir, 'client'),
|
||||
vuePlugin(ctx.config.vue),
|
||||
viteJsxPlugin(ctx.config.vueJsx),
|
||||
devStyleSSRPlugin({
|
||||
srcDir: ctx.nuxt.options.srcDir,
|
||||
buildAssetsURL: joinURL(ctx.nuxt.options.app.baseURL, ctx.nuxt.options.app.buildAssetsDir)
|
||||
@ -81,7 +78,7 @@ export async function buildClient (ctx: ViteBuildContext) {
|
||||
server: {
|
||||
middlewareMode: true
|
||||
}
|
||||
} as ViteOptions)
|
||||
} satisfies vite.InlineConfig)
|
||||
|
||||
clientConfig.customLogger = createViteLogger(clientConfig)
|
||||
|
||||
@ -101,7 +98,7 @@ export async function buildClient (ctx: ViteBuildContext) {
|
||||
output: {
|
||||
chunkFileNames: ctx.nuxt.options.dev ? undefined : withoutLeadingSlash(join(ctx.nuxt.options.app.buildAssetsDir, '[name].[hash].js')),
|
||||
entryFileNames: ctx.nuxt.options.dev ? 'entry.js' : withoutLeadingSlash(join(ctx.nuxt.options.app.buildAssetsDir, '[name].[hash].js'))
|
||||
} as OutputOptions
|
||||
} satisfies NonNullable<BuildOptions['rollupOptions']>['output']
|
||||
}) as any
|
||||
|
||||
if (clientConfig.server && clientConfig.server.hmr !== false) {
|
||||
@ -126,6 +123,11 @@ export async function buildClient (ctx: ViteBuildContext) {
|
||||
|
||||
await ctx.nuxt.callHook('vite:extendConfig', clientConfig, { isClient: true, isServer: false })
|
||||
|
||||
clientConfig.plugins!.unshift(
|
||||
vuePlugin(clientConfig.vue),
|
||||
viteJsxPlugin(clientConfig.vueJsx)
|
||||
)
|
||||
|
||||
if (ctx.nuxt.options.dev) {
|
||||
// Dev
|
||||
const viteServer = await vite.createServer(clientConfig)
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { requireModule } from '@nuxt/kit'
|
||||
import type { Nuxt } from '@nuxt/schema'
|
||||
import type { ViteOptions } from './vite'
|
||||
import type { InlineConfig as ViteConfig } from 'vite'
|
||||
import { distDir } from './dirs'
|
||||
|
||||
export function resolveCSSOptions (nuxt: Nuxt): ViteOptions['css'] {
|
||||
const css: ViteOptions['css'] & { postcss: NonNullable<Exclude<NonNullable<ViteOptions['css']>['postcss'], string>> } = {
|
||||
export function resolveCSSOptions (nuxt: Nuxt): ViteConfig['css'] {
|
||||
const css: ViteConfig['css'] & { postcss: NonNullable<Exclude<NonNullable<ViteConfig['css']>['postcss'], string>> } = {
|
||||
postcss: {
|
||||
plugins: []
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { dirname, isAbsolute, join, resolve } from 'pathe'
|
||||
import type { Plugin } from 'rollup'
|
||||
import type { Plugin } from 'vite'
|
||||
|
||||
const PREFIX = 'virtual:nuxt:'
|
||||
|
||||
|
@ -4,7 +4,8 @@ import vuePlugin from '@vitejs/plugin-vue'
|
||||
import viteJsxPlugin from '@vitejs/plugin-vue-jsx'
|
||||
import { logger, resolveModule, resolvePath } from '@nuxt/kit'
|
||||
import { joinURL, withoutLeadingSlash, withTrailingSlash } from 'ufo'
|
||||
import type { ViteBuildContext, ViteOptions } from './vite'
|
||||
import type { ViteConfig } from '@nuxt/schema'
|
||||
import type { ViteBuildContext } from './vite'
|
||||
import { createViteLogger } from './utils/logger'
|
||||
import { cacheDirPlugin } from './plugins/cache-dir'
|
||||
import { initViteNodeServer } from './vite-node'
|
||||
@ -17,8 +18,7 @@ export async function buildServer (ctx: ViteBuildContext) {
|
||||
const _resolve = (id: string) => resolveModule(id, { paths: ctx.nuxt.options.modulesDir })
|
||||
const helper = ctx.nuxt.options.nitro.imports !== false ? '' : 'globalThis.'
|
||||
const entry = ctx.nuxt.options.ssr ? ctx.entry : await resolvePath(resolve(ctx.nuxt.options.appDir, 'entry-spa'))
|
||||
const serverConfig: vite.InlineConfig = vite.mergeConfig(ctx.config, {
|
||||
entry,
|
||||
const serverConfig: ViteConfig = vite.mergeConfig(ctx.config, {
|
||||
base: ctx.nuxt.options.dev
|
||||
? joinURL(ctx.nuxt.options.app.baseURL.replace(/^\.\//, '/') || '/', ctx.nuxt.options.app.buildAssetsDir)
|
||||
: undefined,
|
||||
@ -111,14 +111,12 @@ export async function buildServer (ctx: ViteBuildContext) {
|
||||
},
|
||||
plugins: [
|
||||
cacheDirPlugin(ctx.nuxt.options.rootDir, 'server'),
|
||||
vuePlugin(ctx.config.vue),
|
||||
viteJsxPlugin(ctx.config.vueJsx),
|
||||
pureAnnotationsPlugin.vite({
|
||||
sourcemap: ctx.nuxt.options.sourcemap.server,
|
||||
functions: ['defineComponent', 'defineAsyncComponent', 'defineNuxtLink', 'createClientOnly', 'defineNuxtPlugin', 'defineNuxtRouteMiddleware', 'defineNuxtComponent', 'useRuntimeConfig']
|
||||
})
|
||||
]
|
||||
} as ViteOptions)
|
||||
} satisfies vite.InlineConfig)
|
||||
|
||||
serverConfig.customLogger = createViteLogger(serverConfig)
|
||||
|
||||
@ -146,6 +144,11 @@ export async function buildServer (ctx: ViteBuildContext) {
|
||||
|
||||
await ctx.nuxt.callHook('vite:extendConfig', serverConfig, { isClient: false, isServer: true })
|
||||
|
||||
serverConfig.plugins!.unshift(
|
||||
vuePlugin(serverConfig.vue),
|
||||
viteJsxPlugin(serverConfig.vueJsx)
|
||||
)
|
||||
|
||||
const onBuild = () => ctx.nuxt.callHook('vite:compiled')
|
||||
|
||||
// Production build
|
||||
|
@ -1,10 +1,7 @@
|
||||
import * as vite from 'vite'
|
||||
import { join, resolve } from 'pathe'
|
||||
import type { Nuxt } from '@nuxt/schema'
|
||||
import type { InlineConfig, SSROptions } from 'vite'
|
||||
import type { Nuxt, ViteConfig } from '@nuxt/schema'
|
||||
import { logger, isIgnored, resolvePath, addVitePlugin } from '@nuxt/kit'
|
||||
import type { Options as VueOptions } from '@vitejs/plugin-vue'
|
||||
import type { Options as VueJsxOptions } from '@vitejs/plugin-vue-jsx'
|
||||
import replace from '@rollup/plugin-replace'
|
||||
import { sanitizeFilePath } from 'mlly'
|
||||
import { withoutLeadingSlash } from 'ufo'
|
||||
@ -18,16 +15,9 @@ import { resolveCSSOptions } from './css'
|
||||
import { composableKeysPlugin } from './plugins/composable-keys'
|
||||
import { logLevelMap } from './utils/logger'
|
||||
|
||||
export interface ViteOptions extends InlineConfig {
|
||||
vue?: VueOptions
|
||||
vueJsx?: VueJsxOptions
|
||||
ssr?: SSROptions
|
||||
devBundler?: 'vite-node' | 'legacy'
|
||||
}
|
||||
|
||||
export interface ViteBuildContext {
|
||||
nuxt: Nuxt
|
||||
config: ViteOptions
|
||||
config: ViteConfig
|
||||
entry: string
|
||||
clientServer?: vite.ViteDevServer
|
||||
ssrServer?: vite.ViteDevServer
|
||||
@ -104,7 +94,7 @@ export async function bundle (nuxt: Nuxt) {
|
||||
]
|
||||
}
|
||||
}
|
||||
} as ViteOptions,
|
||||
} satisfies ViteConfig,
|
||||
nuxt.options.vite
|
||||
)
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nuxt/webpack-builder",
|
||||
"version": "3.3.2",
|
||||
"version": "3.3.3",
|
||||
"repository": "nuxt/nuxt",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
@ -19,13 +19,13 @@
|
||||
"prepack": "unbuild"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.21.3",
|
||||
"@babel/core": "^7.21.4",
|
||||
"@nuxt/friendly-errors-webpack-plugin": "^2.5.2",
|
||||
"@nuxt/kit": "3.3.2",
|
||||
"@nuxt/kit": "workspace:../kit",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"css-loader": "^6.7.3",
|
||||
"css-minimizer-webpack-plugin": "^4.2.2",
|
||||
"cssnano": "^5.1.15",
|
||||
"css-minimizer-webpack-plugin": "^5.0.0",
|
||||
"cssnano": "^6.0.0",
|
||||
"esbuild-loader": "^3.0.1",
|
||||
"escape-string-regexp": "^5.0.0",
|
||||
"estree-walker": "^3.0.3",
|
||||
@ -43,7 +43,7 @@
|
||||
"pify": "^6.1.0",
|
||||
"postcss": "^8.4.21",
|
||||
"postcss-import": "^15.1.0",
|
||||
"postcss-loader": "^7.1.0",
|
||||
"postcss-loader": "^7.2.4",
|
||||
"postcss-url": "^10.1.3",
|
||||
"style-resources-loader": "^1.5.0",
|
||||
"time-fix-plugin": "^2.0.7",
|
||||
@ -52,7 +52,7 @@
|
||||
"url-loader": "^4.1.1",
|
||||
"vue-bundle-renderer": "^1.0.3",
|
||||
"vue-loader": "^17.0.1",
|
||||
"webpack": "^5.76.3",
|
||||
"webpack": "^5.77.0",
|
||||
"webpack-bundle-analyzer": "^4.8.0",
|
||||
"webpack-dev-middleware": "^6.0.2",
|
||||
"webpack-hot-middleware": "^2.25.3",
|
||||
@ -60,11 +60,10 @@
|
||||
"webpackbar": "^5.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxt/schema": "3.3.2",
|
||||
"@nuxt/schema": "workspace:../schema",
|
||||
"@types/lodash-es": "^4.17.7",
|
||||
"@types/pify": "^5.0.1",
|
||||
"@types/webpack-bundle-analyzer": "^4.6.0",
|
||||
"@types/webpack-dev-middleware": "^5.3.0",
|
||||
"@types/webpack-hot-middleware": "^2.25.6",
|
||||
"@types/webpack-virtual-modules": "^0.1.1",
|
||||
"unbuild": "latest",
|
||||
|
@ -159,7 +159,7 @@ export function baseTranspile (ctx: WebpackConfigContext) {
|
||||
/\.vue\.js/i, // include SFCs in node_modules
|
||||
/consola\/src/,
|
||||
/vue-demi/,
|
||||
/(^|\/)nuxt\/(dist\/)?app($|\/)/
|
||||
/(^|\/)nuxt\/(dist\/)?(app|[^/]+\/runtime)($|\/)/
|
||||
]
|
||||
|
||||
for (let pattern of options.build.transpile) {
|
||||
|
6064
pnpm-lock.yaml
6064
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
@ -69,8 +69,10 @@ export async function loadWorkspace (dir: string) {
|
||||
}
|
||||
}
|
||||
|
||||
const setVersion = (name: string, newVersion: string) => {
|
||||
const setVersion = (name: string, newVersion: string, opts: { updateDeps?: boolean } = {}) => {
|
||||
find(name).data.version = newVersion
|
||||
if (!opts.updateDeps) { return }
|
||||
|
||||
for (const pkg of packages) {
|
||||
pkg.updateDeps((dep) => {
|
||||
if (dep.name === name) {
|
||||
|
@ -26,7 +26,9 @@ async function main () {
|
||||
|
||||
for (const pkg of workspace.packages.filter(p => !p.data.private)) {
|
||||
const newVersion = inc(pkg.data.version, bumpType || 'patch')
|
||||
workspace.setVersion(pkg.data.name, `${newVersion}-${date}.${commit}`)
|
||||
workspace.setVersion(pkg.data.name, `${newVersion}-${date}.${commit}`, {
|
||||
updateDeps: true
|
||||
})
|
||||
const newname = pkg.data.name === 'nuxt' ? 'nuxt3' : (pkg.data.name + '-edge')
|
||||
workspace.rename(pkg.data.name, newname)
|
||||
}
|
||||
|
@ -707,6 +707,10 @@ describe('extends support', () => {
|
||||
})
|
||||
|
||||
describe('middlewares', () => {
|
||||
it('works with layer aliases', async () => {
|
||||
const html = await $fetch('/foo')
|
||||
expect(html).toContain('from layer alias')
|
||||
})
|
||||
it('extends foo/middleware/foo', async () => {
|
||||
const html = await $fetch('/foo')
|
||||
expect(html).toContain('Middleware | foo: Injected by extended middleware from foo')
|
||||
|
@ -6,7 +6,7 @@ import { globby } from 'globby'
|
||||
import { join } from 'pathe'
|
||||
import { isWindows } from 'std-env'
|
||||
|
||||
describe.skipIf(isWindows)('minimal nuxt application', () => {
|
||||
describe.skipIf(isWindows || process.env.ECOSYSTEM_CI)('minimal nuxt application', () => {
|
||||
const rootDir = fileURLToPath(new URL('./fixtures/minimal', import.meta.url))
|
||||
const publicDir = join(rootDir, '.output/public')
|
||||
const serverDir = join(rootDir, '.output/server')
|
||||
@ -26,7 +26,7 @@ describe.skipIf(isWindows)('minimal nuxt application', () => {
|
||||
|
||||
it('default client bundle size', async () => {
|
||||
stats.client = await analyzeSizes('**/*.js', publicDir)
|
||||
expect(stats.client.totalBytes).toBeLessThan(106650)
|
||||
expect(roundToKilobytes(stats.client.totalBytes)).toMatchInlineSnapshot('"104k"')
|
||||
expect(stats.client.files.map(f => f.replace(/\..*\.js/, '.js'))).toMatchInlineSnapshot(`
|
||||
[
|
||||
"_nuxt/_plugin-vue_export-helper.js",
|
||||
@ -40,10 +40,10 @@ describe.skipIf(isWindows)('minimal nuxt application', () => {
|
||||
|
||||
it('default server bundle size', async () => {
|
||||
stats.server = await analyzeSizes(['**/*.mjs', '!node_modules'], serverDir)
|
||||
expect(stats.server.totalBytes).toBeLessThan(93900)
|
||||
expect(roundToKilobytes(stats.server.totalBytes)).toMatchInlineSnapshot('"91k"')
|
||||
|
||||
const modules = await analyzeSizes('node_modules/**/*', serverDir)
|
||||
expect(modules.totalBytes).toBeLessThan(2694400)
|
||||
expect(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot('"2632k"')
|
||||
|
||||
const packages = modules.files
|
||||
.filter(m => m.endsWith('package.json'))
|
||||
@ -104,3 +104,7 @@ async function analyzeSizes (pattern: string | string[], rootDir: string) {
|
||||
}
|
||||
return { files, totalBytes }
|
||||
}
|
||||
|
||||
function roundToKilobytes (bytes: number) {
|
||||
return (Math.round(bytes / 1024) + 'k')
|
||||
}
|
||||
|
1
test/fixtures/basic/extends/node_modules/foo/alias/test.ts
generated
vendored
Normal file
1
test/fixtures/basic/extends/node_modules/foo/alias/test.ts
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
export const test = 'from layer alias'
|
2
test/fixtures/basic/extends/node_modules/foo/pages/foo.vue
generated
vendored
2
test/fixtures/basic/extends/node_modules/foo/pages/foo.vue
generated
vendored
@ -1,4 +1,5 @@
|
||||
<script setup>
|
||||
import { test } from '~/alias/test'
|
||||
definePageMeta({
|
||||
middleware: 'foo'
|
||||
})
|
||||
@ -8,6 +9,7 @@ const foo = useExtendsFoo()
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div>{{ test }}</div>
|
||||
<div>Extended page from foo</div>
|
||||
<div>Middleware | foo: {{ $route.meta.foo }}</div>
|
||||
<div>Composable | useExtendsFoo: {{ foo }}</div>
|
||||
|
1
test/fixtures/basic/nuxt.config.ts
vendored
1
test/fixtures/basic/nuxt.config.ts
vendored
@ -184,6 +184,7 @@ export default defineNuxtConfig({
|
||||
}
|
||||
},
|
||||
experimental: {
|
||||
respectNoSSRHeader: true,
|
||||
clientFallback: true,
|
||||
restoreState: true,
|
||||
inlineSSRStyles: id => !!id && !id.includes('assets.vue'),
|
||||
|
4
test/fixtures/basic/package.json
vendored
4
test/fixtures/basic/package.json
vendored
@ -1,10 +1,10 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "fixture-bridge",
|
||||
"name": "fixture-basic",
|
||||
"scripts": {
|
||||
"build": "nuxi build"
|
||||
},
|
||||
"dependencies": {
|
||||
"nuxt": "workspace:*"
|
||||
"nuxt": "latest"
|
||||
}
|
||||
}
|
||||
|
7
test/fixtures/basic/types.ts
vendored
7
test/fixtures/basic/types.ts
vendored
@ -146,6 +146,13 @@ describe('runtimeConfig', () => {
|
||||
expectTypeOf(runtimeConfig.privateConfig).toEqualTypeOf<string>()
|
||||
expectTypeOf(runtimeConfig.public.ids).toEqualTypeOf<number[]>()
|
||||
expectTypeOf(runtimeConfig.unknown).toEqualTypeOf<any>()
|
||||
|
||||
const injectedConfig = useNuxtApp().$config
|
||||
expectTypeOf(injectedConfig.public.testConfig).toEqualTypeOf<number>()
|
||||
expectTypeOf(injectedConfig.public.needsFallback).toEqualTypeOf<string>()
|
||||
expectTypeOf(injectedConfig.privateConfig).toEqualTypeOf<string>()
|
||||
expectTypeOf(injectedConfig.public.ids).toEqualTypeOf<number[]>()
|
||||
expectTypeOf(injectedConfig.unknown).toEqualTypeOf<any>()
|
||||
})
|
||||
it('provides hints on overriding these values', () => {
|
||||
const val = defineNuxtConfig({
|
||||
|
10
test/fixtures/minimal/package.json
vendored
Normal file
10
test/fixtures/minimal/package.json
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "fixture-minimal",
|
||||
"scripts": {
|
||||
"build": "nuxi build"
|
||||
},
|
||||
"dependencies": {
|
||||
"nuxt": "latest"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user