mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-11 00:23:53 +00:00
Merge branch 'main' into docs/new-structure
This commit is contained in:
commit
1fc0d09721
10
.eslintrc
10
.eslintrc
@ -12,6 +12,12 @@
|
||||
"plugin:import/typescript"
|
||||
],
|
||||
"rules": {
|
||||
"sort-imports": [
|
||||
"error",
|
||||
{
|
||||
"ignoreDeclarationSort": true
|
||||
}
|
||||
],
|
||||
"unicorn/prefer-node-protocol": "error",
|
||||
"no-console": "off",
|
||||
"vue/multi-word-component-names": "off",
|
||||
@ -28,6 +34,10 @@
|
||||
"error",
|
||||
{
|
||||
"pathGroups": [
|
||||
{
|
||||
"pattern": "@nuxt/test-utils/experimental",
|
||||
"group": "external"
|
||||
},
|
||||
{
|
||||
"pattern": "@nuxt/test-utils",
|
||||
"group": "external"
|
||||
|
2
.github/workflows/autofix.yml
vendored
2
.github/workflows/autofix.yml
vendored
@ -24,7 +24,7 @@ jobs:
|
||||
run: pnpm install
|
||||
|
||||
- name: Dedupe dependencies
|
||||
if: ${{ contains(github.ref_name, 'renovate') }}
|
||||
if: ${{ contains(github.head_ref, 'renovate') }}
|
||||
run: pnpm dedupe
|
||||
|
||||
- name: Build (stub)
|
||||
|
5
.github/workflows/ci.yml
vendored
5
.github/workflows/ci.yml
vendored
@ -104,6 +104,9 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Build (stub)
|
||||
run: pnpm build:stub
|
||||
|
||||
- name: Lint
|
||||
run: pnpm lint
|
||||
|
||||
@ -118,6 +121,7 @@ jobs:
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
env: ['dev', 'built']
|
||||
builder: ['vite', 'webpack']
|
||||
payload: ['json', 'js']
|
||||
node: [16]
|
||||
exclude:
|
||||
- env: 'dev'
|
||||
@ -177,6 +181,7 @@ jobs:
|
||||
env:
|
||||
TEST_ENV: ${{ matrix.env }}
|
||||
TEST_BUILDER: ${{ matrix.builder }}
|
||||
TEST_PAYLOAD: ${{ matrix.payload }}
|
||||
|
||||
build-release:
|
||||
if: |
|
||||
|
@ -54,7 +54,7 @@ When you are using the built-in Composition API composables provided by Vue and
|
||||
|
||||
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.
|
||||
|
||||
That means that (with very few exceptions) you cannot use them outside a Nuxt plugin, Nuxt route middleware or Vue setup function. On top of that, you must use them synchronously - that is, you cannot use `await` before calling a composable, except within `<script setup>` blocks, in `defineNuxtPlugin` or in `defineNuxtRouteMiddleware`, where we perform a transform to keep the synchronous context even after the `await`.
|
||||
That means that (with very few exceptions) you cannot use them outside a Nuxt plugin, Nuxt route middleware or Vue setup function. On top of that, you must use them synchronously - that is, you cannot use `await` before calling a composable, except within `<script setup>` blocks, within the setup function of a component declared with `defineNuxtComponent`, in `defineNuxtPlugin` or in `defineNuxtRouteMiddleware`, where we perform a transform to keep the synchronous context even after the `await`.
|
||||
|
||||
If you get an error message like `Nuxt instance is unavailable` then it probably means you are calling a Nuxt composable in the wrong place in the Vue or Nuxt lifecycle.
|
||||
|
||||
|
@ -100,6 +100,7 @@ Nuxt 3 includes route rules and hybrid rendering support. Using route rules you
|
||||
- `swr` - Add cache headers to the server response and cache it in the server or reverse proxy for a configurable TTL. The `node-server` preset of Nitro is able to cache the full response. For Netlify and Vercel, the response is also added to the CDN layer.
|
||||
- `static` - The behavior is the same as `swr` except that there is no TTL; the response is cached until the next deployment. On Netlify and Vercel, it enables full incremental static generation.
|
||||
- `prerender` - Prerenders routes at build time and includes them in your build as static assets
|
||||
- `experimentalNoScripts` - Disables rendering of Nuxt scripts and JS resource hints for sections of your site.
|
||||
|
||||
**Examples:**
|
||||
|
||||
|
@ -8,7 +8,7 @@ Nuxt 3 is fully typed and provides helpful shortcuts to ensure you have access t
|
||||
|
||||
## Type-checking
|
||||
|
||||
By default, Nuxt doesn't check types when you run `nuxi dev` or `nuxi build`, for performance reasons. However, you can enable type-checking at build or development time by installing `@types/node`, `vue-tsc` and `typescript` as devDependencies and either enabling [the `typescript.typeCheck` option in your `nuxt.config` file](/docs/api/configuration/nuxt-config#typescript) or [manually checking your types with nuxi](/docs/api/commands/typecheck).
|
||||
By default, Nuxt doesn't check types when you run `nuxi dev` or `nuxi build`, for performance reasons. However, you can enable type-checking at build or development time by installing `vue-tsc` and `typescript` as devDependencies and either enabling [the `typescript.typeCheck` option in your `nuxt.config` file](/docs/api/configuration/nuxt-config#typescript) or [manually checking your types with nuxi](/docs/api/commands/typecheck).
|
||||
|
||||
```bash
|
||||
yarn nuxi typecheck
|
||||
|
@ -408,3 +408,35 @@ When `<NuxtPage />` is used in `app.vue`, transition-props can be passed directl
|
||||
::alert{type="warning"}
|
||||
Remember, this page transition cannot be overridden with `definePageMeta` on individual pages.
|
||||
::
|
||||
|
||||
## View Transitions API (experimental)
|
||||
|
||||
Nuxt ships with an experimental implementation of the [**View Transitions API**](https://developer.chrome.com/docs/web-platform/view-transitions/) (see [MDN](https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API)). This is an exciting new way to implement native browser transitions which (among other things) have the ability to transition between unrelated elements on different pages.
|
||||
|
||||
The Nuxt integration is under active development, but can be enabled with the `experimental.viewTransition` option in your configuration file:
|
||||
|
||||
```ts [nuxt.config.ts]
|
||||
export default defineNuxtConfig({
|
||||
experimental: {
|
||||
viewTransition: true
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
If you are also using Vue transitions like `pageTransition` and `layoutTransition` (see above) to achieve the same result as the new View Transitions API, then you may wish to _disable_ Vue transitions if the user's browser supports the newer, native web API. You can do this by creating `~/middleware/disable-vue-transitions.global.ts` with the following contents:
|
||||
|
||||
```js
|
||||
export default defineNuxtRouteMiddleware(to => {
|
||||
if (!document.startViewTransition) { return }
|
||||
|
||||
// Disable built-in Vue transitions
|
||||
to.meta.pageTransition = false
|
||||
to.meta.layoutTransition = false
|
||||
})
|
||||
```
|
||||
|
||||
### Known issues
|
||||
|
||||
- View transitions may not work as expected with nested pages/layouts/async components owing to this upstream Vue bug: <https://github.com/vuejs/core/issues/5513>. If you make use of this pattern, you may need to delay adopting this experimental feature or implement it yourself. Feedback is very welcome.
|
||||
|
||||
- If you perform data fetching within your page setup functions, that you may wish to reconsider using this feature for the moment. (By design, View Transitions completely freeze DOM updates whilst they are taking place.) We're looking at restrict the View Transition to the final moments before `<Suspense>` resolves, but in the interim you may want to consider carefully whether to adopt this feature if this describes you.
|
||||
|
@ -263,6 +263,8 @@ Be very careful before proxying headers to an external API and just include head
|
||||
If you want to pass on/proxy cookies in the other direction, from an internal request back to the client, you will need to handle this yourself.
|
||||
|
||||
```ts [composables/fetch.ts]
|
||||
import { appendHeader, H3Event } from 'h3'
|
||||
|
||||
export const fetchWithCookie = async (event: H3Event, url: string) => {
|
||||
const res = await $fetch.raw(url)
|
||||
const cookies = (res.headers.get('set-cookie') || '').split(',')
|
||||
@ -356,7 +358,7 @@ const { data } = await useFetch('/api/price')
|
||||
|
||||
## Using Async Setup
|
||||
|
||||
If you are using `async setup()`, the current component instance will be lost after the first `await`. (This is a Vue 3 limitation.) If you want to use multiple async operations, such as multiple calls to `useFetch`, you will need to use `<script setup>` or await them together at the end of setup.
|
||||
If you are using `async setup()`, the current component instance will be lost after the first `await`. (This is a Vue 3 limitation.) If you want to use multiple async operations, such as multiple calls to `useFetch`, you will need to use `<script setup>`, await them together at the end of setup, or alternatively use `defineNuxtComponent` (which applies a custom transform to the setup function).
|
||||
|
||||
::alert{icon=👉}
|
||||
Using `<script setup>` is recommended, as it removes the limitation of using top-level await. [Read more](https://vuejs.org/api/sfc-script-setup.html#top-level-await)
|
||||
|
@ -39,6 +39,31 @@ export default defineNuxtPlugin(nuxtApp => {
|
||||
})
|
||||
```
|
||||
|
||||
### Object Syntax Plugins
|
||||
|
||||
It is also possible to define a plugin using an object syntax, for more advanced use cases. For example:
|
||||
|
||||
```ts
|
||||
export default defineNuxtPlugin({
|
||||
name: 'my-plugin',
|
||||
enforce: 'pre', // or 'post'
|
||||
async setup (nuxtApp) {
|
||||
// this is the equivalent of a normal functional plugin
|
||||
},
|
||||
hooks: {
|
||||
// You can directly register Nuxt app hooks here
|
||||
'app:created'() {
|
||||
const nuxtApp = useNuxtApp()
|
||||
//
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
::alert
|
||||
If you are using an object-syntax plugin, the properties may be statically analyzed in future to produce a more optimized build. So you should not define them at runtime. For example, setting `enforce: process.server ? 'pre' : 'post'` would defeat any future optimization Nuxt is able to do for your plugins.
|
||||
::
|
||||
|
||||
## Plugin Registration Order
|
||||
|
||||
You can control the order in which plugins are registered by prefixing a number to the file names.
|
||||
|
@ -18,7 +18,7 @@ type UseFetchOptions = {
|
||||
query?: SearchParams
|
||||
params?: SearchParams
|
||||
body?: RequestInit['body'] | Record<string, any>
|
||||
headers?: { key: string, value: string }[]
|
||||
headers?: Record<string, string> | [key: string, value: string][] | Headers
|
||||
baseURL?: string
|
||||
server?: boolean
|
||||
lazy?: boolean
|
||||
|
@ -84,9 +84,7 @@ await nuxtApp.callHook('my-plugin:init')
|
||||
|
||||
### `payload`
|
||||
|
||||
`payload` exposes data and state variables from server side to client side and makes them available in the `window.__NUXT__` object that is accessible from the browser.
|
||||
|
||||
`payload` exposes the following keys on the client side after they are stringified and passed from the server side:
|
||||
`payload` exposes data and state variables from server side to client side. The following keys will be available on the client after they have been passed from the server side:
|
||||
|
||||
- **serverRendered** (boolean) - Indicates if response is server-side-rendered.
|
||||
- **data** (object) - When you fetch the data from an API endpoint using either `useFetch` or `useAsyncData`, resulting payload can be accessed from the `payload.data`. This data is cached and helps you prevent fetching the same data in case an identical request is made more than once.
|
||||
@ -115,6 +113,24 @@ export default defineNuxtPlugin((nuxtApp) => {
|
||||
})
|
||||
```
|
||||
|
||||
::alert
|
||||
Normally `payload` must contain only plain JavaScript objects. But by setting `experimental.renderJsonPayloads`, it is possible to use more advanced types, such as `ref`, `reactive`, `shallowRef`, `shallowReactive` and `NuxtError`.
|
||||
|
||||
You can also add your own types, with a special plugin helper:
|
||||
|
||||
```ts [plugins/custom-payload.ts]
|
||||
/**
|
||||
* This kind of plugin runs very early in the Nuxt lifecycle, before we revive the payload.
|
||||
* You will not have access to the router or other Nuxt-injected properties.
|
||||
*/
|
||||
export default definePayloadPlugin((nuxtApp) => {
|
||||
definePayloadReducer('BlinkingText', data => data === '<blink>' && '_')
|
||||
definePayloadReviver('BlinkingText', () => '<blink>')
|
||||
})
|
||||
```
|
||||
|
||||
::
|
||||
|
||||
### `isHydrating`
|
||||
|
||||
Use `nuxtApp.isHydrating` (boolean) to check if the Nuxt app is hydrating on the client side.
|
||||
|
@ -18,5 +18,5 @@ Option | Default | Description
|
||||
This command sets `process.env.NODE_ENV` to `production`. To override, define `NODE_ENV` in a `.env` file or as a command-line argument.
|
||||
|
||||
::alert
|
||||
You can also enable type-checking at build or development time by installing `@types/node`, `typescript` and `vue-tsc` as devDependencies and enabling [the `typescript.typeCheck` option in your `nuxt.config` file](/docs/api/configuration/nuxt-config#typescript).
|
||||
You can also enable type-checking at build or development time by installing `typescript` and `vue-tsc` as devDependencies and enabling [the `typescript.typeCheck` option in your `nuxt.config` file](/docs/api/configuration/nuxt-config#typescript).
|
||||
::
|
||||
|
@ -136,7 +136,7 @@ Nuxt no longer provides a Vuex integration. Instead, the official Vue recommenda
|
||||
|
||||
A simple way to provide global state management with pinia would be:
|
||||
|
||||
Install the [@nuxt/pinia](https://nuxt.com/modules/pinia) module:
|
||||
Install the [@pinia/nuxt](https://nuxt.com/modules/pinia) module:
|
||||
|
||||
```bash
|
||||
yarn add pinia @pinia/nuxt
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { getQuery, defineEventHandler } from 'h3'
|
||||
import { defineEventHandler, getQuery } from 'h3'
|
||||
|
||||
export default defineEventHandler((event) => {
|
||||
if ('api' in getQuery(event)) {
|
||||
|
37
package.json
37
package.json
@ -15,19 +15,19 @@
|
||||
"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",
|
||||
"play:build": "pnpm nuxi build playground",
|
||||
"play:preview": "pnpm nuxi preview playground",
|
||||
"test:fixtures": "pnpm nuxi prepare test/fixtures/basic && JITI_ESM_RESOLVE=1 vitest run --dir test",
|
||||
"play": "nuxi dev playground",
|
||||
"play:build": "nuxi build playground",
|
||||
"play:preview": "nuxi preview playground",
|
||||
"test:fixtures": "nuxi prepare test/fixtures/basic && nuxi prepare test/fixtures/runtime-compiler && vitest run --dir test",
|
||||
"text:fixtures:payload": "TEST_PAYLOAD=js pnpm test:fixtures",
|
||||
"test:fixtures:dev": "TEST_ENV=dev pnpm test:fixtures",
|
||||
"test:fixtures:webpack": "TEST_BUILDER=webpack pnpm test:fixtures",
|
||||
"test:types": "pnpm nuxi prepare test/fixtures/basic && cd test/fixtures/basic && npx vue-tsc --noEmit",
|
||||
"test:unit": "JITI_ESM_RESOLVE=1 vitest run --dir packages",
|
||||
"test:types": "nuxi prepare test/fixtures/basic && cd test/fixtures/basic && npx vue-tsc --noEmit",
|
||||
"test:unit": "vitest run --dir packages",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"resolutions": {
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"@nuxt/kit": "workspace:*",
|
||||
"@nuxt/schema": "workspace:*",
|
||||
"@nuxt/test-utils": "workspace:*",
|
||||
@ -40,6 +40,7 @@
|
||||
"vite": "^4.2.1",
|
||||
"vue": "3.2.47",
|
||||
"magic-string": "^0.30.0"
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@actions/core": "^1.10.0",
|
||||
@ -53,32 +54,32 @@
|
||||
"@types/node": "^18.15.11",
|
||||
"@types/rimraf": "^3.0.2",
|
||||
"@types/semver": "^7.3.13",
|
||||
"@unocss/reset": "^0.50.6",
|
||||
"@unocss/reset": "^0.51.4",
|
||||
"case-police": "^0.5.14",
|
||||
"changelogen": "^0.5.2",
|
||||
"crawler": "^1.4.0",
|
||||
"eslint": "^8.37.0",
|
||||
"eslint-plugin-jsdoc": "^40.1.1",
|
||||
"eslint": "^8.38.0",
|
||||
"eslint-plugin-jsdoc": "^41.1.0",
|
||||
"execa": "^7.1.1",
|
||||
"expect-type": "^0.15.0",
|
||||
"globby": "^13.1.3",
|
||||
"globby": "^13.1.4",
|
||||
"jiti": "^1.18.2",
|
||||
"markdownlint-cli": "^0.33.0",
|
||||
"nuxi": "workspace:*",
|
||||
"nuxt": "workspace:*",
|
||||
"ofetch": "^1.0.1",
|
||||
"pathe": "^1.1.0",
|
||||
"rimraf": "^4.4.1",
|
||||
"semver": "^7.3.8",
|
||||
"rimraf": "^5.0.0",
|
||||
"semver": "^7.4.0",
|
||||
"std-env": "^3.3.2",
|
||||
"typescript": "^5.0.3",
|
||||
"typescript": "^5.0.4",
|
||||
"ufo": "^1.1.1",
|
||||
"unbuild": "^1.2.0",
|
||||
"vite": "^4.2.1",
|
||||
"vitest": "^0.29.8",
|
||||
"vitest": "^0.30.1",
|
||||
"vue-tsc": "^1.2.0"
|
||||
},
|
||||
"packageManager": "pnpm@8.1.1",
|
||||
"packageManager": "pnpm@8.2.0",
|
||||
"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.3",
|
||||
"version": "3.4.0",
|
||||
"repository": "nuxt/nuxt",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
@ -22,9 +22,9 @@
|
||||
"dependencies": {
|
||||
"@nuxt/schema": "workspace:../schema",
|
||||
"c12": "^1.2.0",
|
||||
"consola": "^2.15.3",
|
||||
"consola": "^3.0.1",
|
||||
"defu": "^6.1.2",
|
||||
"globby": "^13.1.3",
|
||||
"globby": "^13.1.4",
|
||||
"hash-sum": "^2.0.0",
|
||||
"ignore": "^5.2.4",
|
||||
"jiti": "^1.18.2",
|
||||
@ -34,9 +34,9 @@
|
||||
"pathe": "^1.1.0",
|
||||
"pkg-types": "^1.0.2",
|
||||
"scule": "^1.0.0",
|
||||
"semver": "^7.3.8",
|
||||
"unctx": "^2.1.2",
|
||||
"unimport": "^3.0.5",
|
||||
"semver": "^7.4.0",
|
||||
"unctx": "^2.2.0",
|
||||
"unimport": "^3.0.6",
|
||||
"untyped": "^1.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import type { WebpackPluginInstance, Configuration as WebpackConfig } from 'webpack'
|
||||
import type { Plugin as VitePlugin, UserConfig as ViteConfig } from 'vite'
|
||||
import type { Configuration as WebpackConfig, WebpackPluginInstance } from 'webpack'
|
||||
import type { UserConfig as ViteConfig, Plugin as VitePlugin } from 'vite'
|
||||
import { useNuxt } from './context'
|
||||
|
||||
export interface ExtendConfigOptions {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { pascalCase, kebabCase } from 'scule'
|
||||
import type { ComponentsDir, Component } from '@nuxt/schema'
|
||||
import { kebabCase, pascalCase } from 'scule'
|
||||
import type { Component, ComponentsDir } from '@nuxt/schema'
|
||||
import { useNuxt } from './context'
|
||||
import { assertNuxtCompatibility } from './compatibility'
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { expect, it, describe } from 'vitest'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { resolveGroupSyntax } from './ignore.js'
|
||||
|
||||
describe('resolveGroupSyntax', () => {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { promises as fsp } from 'node:fs'
|
||||
import lodashTemplate from 'lodash.template'
|
||||
import { genSafeVariableName, genDynamicImport, genImport } from 'knitwork'
|
||||
import { genDynamicImport, genImport, genSafeVariableName } from 'knitwork'
|
||||
|
||||
import type { NuxtTemplate } from '@nuxt/schema'
|
||||
|
||||
|
@ -2,7 +2,7 @@ import { resolve } from 'pathe'
|
||||
import { applyDefaults } from 'untyped'
|
||||
import type { LoadConfigOptions } from 'c12'
|
||||
import { loadConfig } from 'c12'
|
||||
import type { NuxtOptions, NuxtConfig } from '@nuxt/schema'
|
||||
import type { NuxtConfig, NuxtOptions } from '@nuxt/schema'
|
||||
import { NuxtConfigSchema } from '@nuxt/schema'
|
||||
|
||||
export interface LoadNuxtConfigOptions extends LoadConfigOptions<NuxtConfig> {}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import consola from 'consola'
|
||||
import { consola } from 'consola'
|
||||
|
||||
export const logger = consola
|
||||
|
||||
export function useLogger (scope?: string) {
|
||||
return scope ? logger.withScope(scope) : logger
|
||||
export function useLogger (tag?: string) {
|
||||
return tag ? logger.withTag(tag) : logger
|
||||
}
|
||||
|
@ -3,11 +3,11 @@ import { performance } from 'node:perf_hooks'
|
||||
import { defu } from 'defu'
|
||||
import { applyDefaults } from 'untyped'
|
||||
import { dirname } from 'pathe'
|
||||
import type { Nuxt, NuxtModule, ModuleOptions, ModuleSetupReturn, ModuleDefinition, NuxtOptions, ResolvedNuxtTemplate } from '@nuxt/schema'
|
||||
import type { ModuleDefinition, ModuleOptions, ModuleSetupReturn, Nuxt, NuxtModule, NuxtOptions, ResolvedNuxtTemplate } from '@nuxt/schema'
|
||||
import { logger } from '../logger'
|
||||
import { useNuxt, nuxtCtx, tryUseNuxt } from '../context'
|
||||
import { isNuxt2, checkNuxtCompatibility } from '../compatibility'
|
||||
import { templateUtils, compileTemplate } from '../internal/template'
|
||||
import { nuxtCtx, tryUseNuxt, useNuxt } from '../context'
|
||||
import { checkNuxtCompatibility, isNuxt2 } from '../compatibility'
|
||||
import { compileTemplate, templateUtils } from '../internal/template'
|
||||
|
||||
/**
|
||||
* Define a Nuxt module, automatically merging defaults with user provided options, installing
|
||||
|
@ -1,7 +1,7 @@
|
||||
import type { Nuxt, NuxtModule } from '@nuxt/schema'
|
||||
import { isNuxt2 } from '../compatibility'
|
||||
import { useNuxt } from '../context'
|
||||
import { resolveModule, requireModule } from '../internal/cjs'
|
||||
import { requireModule, resolveModule } from '../internal/cjs'
|
||||
import { importModule } from '../internal/esm'
|
||||
import { resolveAlias } from '../resolve'
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import type { NitroEventHandler, NitroDevEventHandler, Nitro } from 'nitropack'
|
||||
import type { Nitro, NitroDevEventHandler, NitroEventHandler } from 'nitropack'
|
||||
import { normalize } from 'pathe'
|
||||
import { useNuxt } from './context'
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { promises as fsp, existsSync } from 'node:fs'
|
||||
import { existsSync, promises as fsp } from 'node:fs'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { basename, dirname, resolve, join, normalize, isAbsolute } from 'pathe'
|
||||
import { basename, dirname, isAbsolute, join, normalize, resolve } from 'pathe'
|
||||
import { globby } from 'globby'
|
||||
import { resolveAlias as _resolveAlias } from 'pathe/utils'
|
||||
import { tryUseNuxt } from './context'
|
||||
|
@ -2,7 +2,7 @@ import { existsSync } from 'node:fs'
|
||||
import { basename, parse, resolve } from 'pathe'
|
||||
import hash from 'hash-sum'
|
||||
import type { NuxtTemplate, ResolvedNuxtTemplate } from '@nuxt/schema'
|
||||
import { useNuxt, tryUseNuxt } from './context'
|
||||
import { tryUseNuxt, useNuxt } from './context'
|
||||
|
||||
/**
|
||||
* Renders given template using lodash template during build into the project buildDir
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "nuxi",
|
||||
"version": "3.3.3",
|
||||
"version": "3.4.0",
|
||||
"repository": "nuxt/nuxt",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
@ -29,7 +29,7 @@
|
||||
"clear": "^0.1.0",
|
||||
"clipboardy": "^3.0.0",
|
||||
"colorette": "^2.0.19",
|
||||
"consola": "^2.15.3",
|
||||
"consola": "^3.0.1",
|
||||
"deep-object-diff": "^1.1.9",
|
||||
"destr": "^1.2.2",
|
||||
"execa": "^7.1.1",
|
||||
@ -44,7 +44,7 @@
|
||||
"perfect-debounce": "^0.1.3",
|
||||
"pkg-types": "^1.0.2",
|
||||
"scule": "^1.0.0",
|
||||
"semver": "^7.3.8",
|
||||
"semver": "^7.4.0",
|
||||
"unbuild": "latest"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import mri from 'mri'
|
||||
import { red } from 'colorette'
|
||||
import type { ConsolaReporter } from 'consola'
|
||||
import consola from 'consola'
|
||||
import { consola } from 'consola'
|
||||
import { checkEngines } from './utils/engines'
|
||||
import type { Command, NuxtCommand } from './commands'
|
||||
import { commands } from './commands'
|
||||
@ -45,7 +45,7 @@ consola.wrapAll()
|
||||
|
||||
// Filter out unwanted logs
|
||||
// TODO: Use better API from consola for intercepting logs
|
||||
const wrapReporter = (reporter: ConsolaReporter) => <ConsolaReporter> {
|
||||
const wrapReporter = (reporter: ConsolaReporter) => ({
|
||||
log (logObj, ctx) {
|
||||
if (!logObj.args || !logObj.args.length) { return }
|
||||
const msg = logObj.args[0]
|
||||
@ -54,6 +54,11 @@ const wrapReporter = (reporter: ConsolaReporter) => <ConsolaReporter> {
|
||||
if (msg.startsWith('[Vue Router warn]: No match found for location with path')) {
|
||||
return
|
||||
}
|
||||
// Suppress warning about native Node.js fetch
|
||||
if (msg.includes('ExperimentalWarning: The Fetch API is an experimental feature')) {
|
||||
return
|
||||
}
|
||||
// TODO: resolve upstream in Vite
|
||||
// Hide sourcemap warnings related to node_modules
|
||||
if (msg.startsWith('Sourcemap') && msg.includes('node_modules')) {
|
||||
return
|
||||
@ -61,9 +66,9 @@ const wrapReporter = (reporter: ConsolaReporter) => <ConsolaReporter> {
|
||||
}
|
||||
return reporter.log(logObj, ctx)
|
||||
}
|
||||
}
|
||||
// @ts-expect-error
|
||||
consola._reporters = consola._reporters.map(wrapReporter)
|
||||
}) satisfies ConsolaReporter
|
||||
|
||||
consola.options.reporters = consola.options.reporters.map(wrapReporter)
|
||||
|
||||
process.on('unhandledRejection', err => consola.error('[unhandledRejection]', err))
|
||||
process.on('uncaughtException', err => consola.error('[uncaughtException]', err))
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { existsSync, promises as fsp } from 'node:fs'
|
||||
import { resolve, dirname } from 'pathe'
|
||||
import consola from 'consola'
|
||||
import { dirname, resolve } from 'pathe'
|
||||
import { consola } from 'consola'
|
||||
import { loadKit } from '../utils/kit'
|
||||
import { templates } from '../utils/templates'
|
||||
import { defineNuxtCommand } from './index'
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { execa } from 'execa'
|
||||
import consola from 'consola'
|
||||
import { consola } from 'consola'
|
||||
import { resolve } from 'pathe'
|
||||
import { tryResolveModule } from '../utils/esm'
|
||||
import { defineNuxtCommand } from './index'
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { relative, resolve } from 'pathe'
|
||||
import consola from 'consola'
|
||||
import { consola } from 'consola'
|
||||
import { writeTypes } from '../utils/prepare'
|
||||
import { loadKit } from '../utils/kit'
|
||||
import { clearDir } from '../utils/fs'
|
||||
|
@ -1,10 +1,10 @@
|
||||
import type { AddressInfo } from 'node:net'
|
||||
import type { RequestListener } from 'node:http'
|
||||
import { resolve, relative } from 'pathe'
|
||||
import { relative, resolve } from 'pathe'
|
||||
import chokidar from 'chokidar'
|
||||
import { debounce } from 'perfect-debounce'
|
||||
import type { Nuxt } from '@nuxt/schema'
|
||||
import consola from 'consola'
|
||||
import { consola } from 'consola'
|
||||
import { withTrailingSlash } from 'ufo'
|
||||
import { setupDotenv } from 'c12'
|
||||
import { showBanner, showVersions } from '../utils/banner'
|
||||
@ -12,7 +12,7 @@ import { writeTypes } from '../utils/prepare'
|
||||
import { loadKit } from '../utils/kit'
|
||||
import { importModule } from '../utils/esm'
|
||||
import { overrideEnv } from '../utils/env'
|
||||
import { writeNuxtManifest, loadNuxtManifest, cleanupNuxtDirs } from '../utils/nuxt'
|
||||
import { cleanupNuxtDirs, loadNuxtManifest, writeNuxtManifest } from '../utils/nuxt'
|
||||
import { defineNuxtCommand } from './index'
|
||||
|
||||
export default defineNuxtCommand({
|
||||
|
@ -19,7 +19,6 @@ export default defineNuxtCommand({
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// Defer to feature setup
|
||||
await execa('npx', ['@nuxt/devtools@latest', command, rootDir], { stdio: 'inherit', cwd: rootDir })
|
||||
await execa('npx', ['@nuxt/devtools-wizard', command, rootDir], { stdio: 'inherit', cwd: rootDir })
|
||||
}
|
||||
})
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { writeFile } from 'node:fs/promises'
|
||||
import { downloadTemplate, startShell } from 'giget'
|
||||
import { relative } from 'pathe'
|
||||
import consola from 'consola'
|
||||
import { consola } from 'consola'
|
||||
import { defineNuxtCommand } from './index'
|
||||
|
||||
const rpath = (p: string) => relative(process.cwd(), p)
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { buildNuxt } from '@nuxt/kit'
|
||||
import { relative, resolve } from 'pathe'
|
||||
import consola from 'consola'
|
||||
import { consola } from 'consola'
|
||||
import { clearDir } from '../utils/fs'
|
||||
import { loadKit } from '../utils/kit'
|
||||
import { writeTypes } from '../utils/prepare'
|
||||
|
@ -3,7 +3,8 @@ import { dirname, relative } from 'node:path'
|
||||
import { execa } from 'execa'
|
||||
import { setupDotenv } from 'c12'
|
||||
import { resolve } from 'pathe'
|
||||
import consola from 'consola'
|
||||
import { consola } from 'consola'
|
||||
import { loadKit } from '../utils/kit'
|
||||
|
||||
import { defineNuxtCommand } from './index'
|
||||
|
||||
@ -16,8 +17,13 @@ export default defineNuxtCommand({
|
||||
async invoke (args) {
|
||||
process.env.NODE_ENV = process.env.NODE_ENV || 'production'
|
||||
const rootDir = resolve(args._[0] || '.')
|
||||
const { loadNuxtConfig } = await loadKit(rootDir)
|
||||
const config = await loadNuxtConfig({ cwd: rootDir })
|
||||
|
||||
const nitroJSONPaths = ['.output/nitro.json', 'nitro.json'].map(p => resolve(rootDir, p))
|
||||
const resolvedOutputDir = resolve(config.srcDir || rootDir, config.nitro.srcDir || 'server', config.nitro.output?.dir || '.output', 'nitro.json')
|
||||
const defaultOutput = resolve(rootDir, '.output', 'nitro.json') // for backwards compatibility
|
||||
|
||||
const nitroJSONPaths = [resolvedOutputDir, defaultOutput]
|
||||
const nitroJSONPath = nitroJSONPaths.find(p => existsSync(p))
|
||||
if (!nitroJSONPath) {
|
||||
consola.error('Cannot find `nitro.json`. Did you run `nuxi build` first? Search path:\n', nitroJSONPaths)
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { execSync } from 'node:child_process'
|
||||
import consola from 'consola'
|
||||
import { consola } from 'consola'
|
||||
import { resolve } from 'pathe'
|
||||
import { readPackageJSON } from 'pkg-types'
|
||||
import { getPackageManager, packageManagerLocks } from '../utils/packageManagers'
|
||||
@ -7,7 +7,7 @@ import { rmRecursive, touchFile } from '../utils/fs'
|
||||
import { cleanupNuxtDirs, nuxtVersionToGitIdentifier } from '../utils/nuxt'
|
||||
import { defineNuxtCommand } from './index'
|
||||
|
||||
async function getNuxtVersion (path: string): Promise<string|null> {
|
||||
async function getNuxtVersion (path: string): Promise<string | null> {
|
||||
try {
|
||||
const pkg = await readPackageJSON('nuxt', { url: path })
|
||||
if (!pkg.version) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { createRequire } from 'node:module'
|
||||
import { normalize, dirname } from 'pathe'
|
||||
import { dirname, normalize } from 'pathe'
|
||||
|
||||
export function getModulePaths (paths?: string | string[]): string[] {
|
||||
return ([] as Array<string | undefined>)
|
||||
|
@ -1,6 +1,6 @@
|
||||
import flatten from 'flat'
|
||||
import { detailedDiff } from 'deep-object-diff'
|
||||
import { green, red, blue, cyan } from 'colorette'
|
||||
import { blue, cyan, green, red } from 'colorette'
|
||||
|
||||
function normalizeDiff (diffObj: any, type: 'added' | 'deleted' | 'updated', ignore: string[]) {
|
||||
return Object.entries(flatten(diffObj) as Record<string, any>)
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { promises as fsp } from 'node:fs'
|
||||
import { dirname } from 'pathe'
|
||||
import consola from 'consola'
|
||||
import { consola } from 'consola'
|
||||
|
||||
// Check if a file exists
|
||||
export async function exists (path: string) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { promises as fsp } from 'node:fs'
|
||||
import { resolve, dirname } from 'pathe'
|
||||
import consola from 'consola'
|
||||
import { dirname, resolve } from 'pathe'
|
||||
import { consola } from 'consola'
|
||||
import { hash } from 'ohash'
|
||||
import type { Nuxt } from '@nuxt/schema'
|
||||
import { rmRecursive } from './fs'
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "nuxt",
|
||||
"version": "3.3.3",
|
||||
"version": "3.4.0",
|
||||
"repository": "nuxt/nuxt",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
@ -38,10 +38,6 @@
|
||||
"types": "./dist/app/index.d.ts",
|
||||
"import": "./dist/app/index.js"
|
||||
},
|
||||
"#head": {
|
||||
"types": "./dist/head/runtime/index.d.ts",
|
||||
"import": "./dist/head/runtime/index.js"
|
||||
},
|
||||
"#pages": {
|
||||
"types": "./dist/pages/runtime/index.d.ts",
|
||||
"import": "./dist/pages/runtime/index.js"
|
||||
@ -63,7 +59,7 @@
|
||||
"@nuxt/devalue": "^2.0.0",
|
||||
"@nuxt/kit": "workspace:../kit",
|
||||
"@nuxt/schema": "workspace:../schema",
|
||||
"@nuxt/telemetry": "^2.1.10",
|
||||
"@nuxt/telemetry": "^2.2.0",
|
||||
"@nuxt/ui-templates": "^1.1.1",
|
||||
"@nuxt/vite-builder": "workspace:../vite",
|
||||
"@unhead/ssr": "^1.1.25",
|
||||
@ -74,29 +70,33 @@
|
||||
"cookie-es": "^0.5.0",
|
||||
"defu": "^6.1.2",
|
||||
"destr": "^1.2.2",
|
||||
"devalue": "^4.3.0",
|
||||
"escape-string-regexp": "^5.0.0",
|
||||
"estree-walker": "^3.0.3",
|
||||
"fs-extra": "^11.1.1",
|
||||
"globby": "^13.1.3",
|
||||
"globby": "^13.1.4",
|
||||
"h3": "^1.6.4",
|
||||
"hash-sum": "^2.0.0",
|
||||
"hookable": "^5.5.3",
|
||||
"jiti": "^1.18.2",
|
||||
"knitwork": "^1.0.0",
|
||||
"local-pkg": "^0.4.3",
|
||||
"magic-string": "^0.30.0",
|
||||
"mlly": "^1.2.0",
|
||||
"nitropack": "^2.3.2",
|
||||
"nitropack": "^2.3.3",
|
||||
"nuxi": "workspace:../nuxi",
|
||||
"nypm": "^0.1.0",
|
||||
"ofetch": "^1.0.1",
|
||||
"ohash": "^1.0.0",
|
||||
"pathe": "^1.1.0",
|
||||
"perfect-debounce": "^0.1.3",
|
||||
"prompts": "^2.4.2",
|
||||
"scule": "^1.0.0",
|
||||
"strip-literal": "^1.0.1",
|
||||
"ufo": "^1.1.1",
|
||||
"unctx": "^2.1.2",
|
||||
"unenv": "^1.2.2",
|
||||
"unimport": "^3.0.5",
|
||||
"unctx": "^2.2.0",
|
||||
"unenv": "^1.3.1",
|
||||
"unimport": "^3.0.6",
|
||||
"unplugin": "^1.3.1",
|
||||
"untyped": "^1.3.2",
|
||||
"vue": "^3.2.47",
|
||||
@ -107,8 +107,12 @@
|
||||
"devDependencies": {
|
||||
"@types/fs-extra": "^11.0.1",
|
||||
"@types/hash-sum": "^1.0.0",
|
||||
"@types/prompts": "^2.4.4",
|
||||
"unbuild": "latest"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": "^14.18.0 || ^16.10.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.18.0 || ^16.10.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { defineComponent, createElementBlock } from 'vue'
|
||||
import { createElementBlock, defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'NuxtClientFallback',
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { defineComponent, getCurrentInstance, onErrorCaptured } from 'vue'
|
||||
import { ssrRenderVNode, ssrRenderAttrs, ssrRenderSlot } from 'vue/server-renderer'
|
||||
import { ssrRenderAttrs, ssrRenderSlot, ssrRenderVNode } from 'vue/server-renderer'
|
||||
import { createBuffer } from './utils'
|
||||
|
||||
const NuxtClientFallbackServer = defineComponent({
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { ref, onMounted, defineComponent, createElementBlock, h, createElementVNode } from 'vue'
|
||||
import { createElementBlock, createElementVNode, defineComponent, h, mergeProps, onMounted, ref } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ClientOnly',
|
||||
@ -37,7 +37,7 @@ export function createClientOnly (component) {
|
||||
? createElementVNode(res.type, res.props, res.children, res.patchFlag, res.dynamicProps, res.shapeFlag)
|
||||
: h(res)
|
||||
} else {
|
||||
return h('div', ctx.$attrs ?? ctx._.attrs)
|
||||
return h('div', mergeProps(ctx.$attrs ?? ctx._.attrs, { key: 'placeholder-key' }))
|
||||
}
|
||||
}
|
||||
} else if (clone.template) {
|
||||
@ -63,7 +63,7 @@ export function createClientOnly (component) {
|
||||
? createElementVNode(res.type, res.props, res.children, res.patchFlag, res.dynamicProps, res.shapeFlag)
|
||||
: h(res)
|
||||
} else {
|
||||
return h('div', ctx.attrs)
|
||||
return h('div', mergeProps(ctx.attrs, { key: 'placeholder-key' }))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -1,5 +1,5 @@
|
||||
import type { defineAsyncComponent } from 'vue'
|
||||
import { defineComponent, createVNode } from 'vue'
|
||||
import { createVNode, defineComponent } from 'vue'
|
||||
|
||||
// @ts-ignore
|
||||
import * as islandComponents from '#build/components.islands.mjs'
|
||||
|
@ -1,5 +1,5 @@
|
||||
import type { Ref, VNode } from 'vue'
|
||||
import { computed, defineComponent, h, inject, nextTick, onMounted, Transition, unref } from 'vue'
|
||||
import { Transition, computed, defineComponent, h, inject, nextTick, onMounted, unref } from 'vue'
|
||||
import type { RouteLocationNormalizedLoaded } from 'vue-router'
|
||||
import { _wrapIf } from './utils'
|
||||
import { useRoute } from '#app/composables/router'
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { defineComponent, ref, onErrorCaptured } from 'vue'
|
||||
import { defineComponent, onErrorCaptured, ref } from 'vue'
|
||||
import { useNuxtApp } from '#app/nuxt'
|
||||
|
||||
export default defineComponent({
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { defineComponent, createStaticVNode, computed, ref, watch, getCurrentInstance } from 'vue'
|
||||
import { computed, createStaticVNode, defineComponent, getCurrentInstance, ref, watch } from 'vue'
|
||||
import { debounce } from 'perfect-debounce'
|
||||
import { hash } from 'ohash'
|
||||
import { appendHeader } from 'h3'
|
||||
|
@ -1,7 +1,7 @@
|
||||
import type { PropType, DefineComponent, ComputedRef } from 'vue'
|
||||
import { defineComponent, h, ref, resolveComponent, computed, onMounted, onBeforeUnmount } from 'vue'
|
||||
import type { ComputedRef, DefineComponent, PropType } from 'vue'
|
||||
import { computed, defineComponent, h, onBeforeUnmount, onMounted, ref, resolveComponent } from 'vue'
|
||||
import type { RouteLocation, RouteLocationRaw } from 'vue-router'
|
||||
import { hasProtocol, parseQuery, parseURL, withoutTrailingSlash, withTrailingSlash } from 'ufo'
|
||||
import { hasProtocol, parseQuery, parseURL, withTrailingSlash, withoutTrailingSlash } from 'ufo'
|
||||
|
||||
import { preloadRouteComponents } from '../composables/preload'
|
||||
import { onNuxtReady } from '../composables/ready'
|
||||
|
@ -2,6 +2,7 @@
|
||||
<Suspense @resolve="onResolve">
|
||||
<ErrorComponent v-if="error" :error="error" />
|
||||
<IslandRenderer v-else-if="islandContext" :context="islandContext" />
|
||||
<component :is="SingleRenderer" v-else-if="SingleRenderer" />
|
||||
<AppComponent v-else />
|
||||
</Suspense>
|
||||
</template>
|
||||
@ -21,6 +22,10 @@ const IslandRenderer = process.server
|
||||
const nuxtApp = useNuxtApp()
|
||||
const onResolve = nuxtApp.deferHydration()
|
||||
|
||||
const url = process.server ? nuxtApp.ssrContext.url : window.location.pathname
|
||||
const SingleRenderer = process.dev && process.server && url.startsWith('/__nuxt_component_test__/') && defineAsyncComponent(() => import('#build/test-component-wrapper.mjs')
|
||||
.then(r => r.default(process.server ? url : window.location.href)))
|
||||
|
||||
// Inject default route (outside of pages) as active route
|
||||
provide('_route', useRoute())
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { defineComponent, createElementBlock } from 'vue'
|
||||
import { createElementBlock, defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ServerPlaceholder',
|
||||
|
19
packages/nuxt/src/app/components/test-component-wrapper.ts
Normal file
19
packages/nuxt/src/app/components/test-component-wrapper.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { parseURL } from 'ufo'
|
||||
import { defineComponent, h } from 'vue'
|
||||
import { parseQuery } from 'vue-router'
|
||||
|
||||
export default (url:string) => defineComponent({
|
||||
name: 'NuxtTestComponentWrapper',
|
||||
|
||||
async setup (props, { attrs }) {
|
||||
const query = parseQuery(parseURL(url).search)
|
||||
const urlProps = query.props ? JSON.parse(query.props as string) : {}
|
||||
const comp = await import(/* @vite-ignore */ query.path as string).then(r => r.default)
|
||||
return () => [
|
||||
h('div', 'Component Test Wrapper for ' + query.path),
|
||||
h('div', { id: 'nuxt-component-root' }, [
|
||||
h(comp, { ...attrs, ...props, ...urlProps })
|
||||
])
|
||||
]
|
||||
}
|
||||
})
|
@ -1,4 +1,4 @@
|
||||
import { onBeforeMount, onServerPrefetch, onUnmounted, ref, getCurrentInstance, watch, unref, toRef } from 'vue'
|
||||
import { getCurrentInstance, onBeforeMount, onServerPrefetch, onUnmounted, ref, toRef, unref, watch } from 'vue'
|
||||
import type { Ref, WatchSource } from 'vue'
|
||||
import type { NuxtApp } from '../nuxt'
|
||||
import { useNuxtApp } from '../nuxt'
|
||||
@ -118,7 +118,7 @@ export function useAsyncData<
|
||||
nuxt._asyncData[key] = {
|
||||
data: ref(getCachedData() ?? options.default?.() ?? null),
|
||||
pending: ref(!hasCachedData()),
|
||||
error: ref(nuxt.payload._errors[key] ? createError(nuxt.payload._errors[key]) : null)
|
||||
error: toRef(nuxt.payload._errors, key)
|
||||
}
|
||||
}
|
||||
// TODO: Else, somehow check for conflicting keys with different defaults or fetcher
|
||||
|
@ -2,7 +2,7 @@ import { getCurrentInstance, reactive, toRefs } from 'vue'
|
||||
import type { DefineComponent, defineComponent } from 'vue'
|
||||
import { useHead } from '@unhead/vue'
|
||||
import type { NuxtApp } from '../nuxt'
|
||||
import { useNuxtApp } from '../nuxt'
|
||||
import { callWithNuxt, useNuxtApp } from '../nuxt'
|
||||
import { useAsyncData } from './asyncData'
|
||||
import { useRoute } from './router'
|
||||
|
||||
@ -14,7 +14,7 @@ async function runLegacyAsyncData (res: Record<string, any> | Promise<Record<str
|
||||
const vm = getCurrentInstance()!
|
||||
const { fetchKey } = vm.proxy!.$options
|
||||
const key = typeof fetchKey === 'function' ? fetchKey(() => '') : fetchKey || route.fullPath
|
||||
const { data } = await useAsyncData(`options:asyncdata:${key}`, () => fn(nuxt))
|
||||
const { data } = await useAsyncData(`options:asyncdata:${key}`, () => callWithNuxt(nuxt, fn, [nuxt]))
|
||||
if (data.value && typeof data.value === 'object') {
|
||||
Object.assign(await res, toRefs(reactive(data.value)))
|
||||
} else if (process.dev) {
|
||||
@ -38,7 +38,8 @@ export const defineNuxtComponent: typeof defineComponent =
|
||||
[NuxtComponentIndicator]: true,
|
||||
...options,
|
||||
setup (props, ctx) {
|
||||
const res = setup?.(props, ctx) || {}
|
||||
const nuxtApp = useNuxtApp()
|
||||
const res = setup ? Promise.resolve(callWithNuxt(nuxtApp, setup, [props, ctx])).then(r => r || {}) : {}
|
||||
|
||||
const promises: Promise<any>[] = []
|
||||
if (options.asyncData) {
|
||||
|
@ -27,7 +27,7 @@ const CookieDefaults: CookieOptions<any> = {
|
||||
encode: val => encodeURIComponent(typeof val === 'string' ? val : JSON.stringify(val))
|
||||
}
|
||||
|
||||
export function useCookie <T = string | null> (name: string, _opts?: CookieOptions<T>): CookieRef<T> {
|
||||
export function useCookie <T = string | null | undefined> (name: string, _opts?: CookieOptions<T>): CookieRef<T> {
|
||||
const opts = { ...CookieDefaults, ..._opts }
|
||||
const cookies = readRawCookies(opts) || {}
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
import type { FetchError } from 'ofetch'
|
||||
import type { TypedInternalResponse, NitroFetchOptions, NitroFetchRequest, AvailableRouterMethod } from 'nitropack'
|
||||
import type { AvailableRouterMethod, NitroFetchOptions, NitroFetchRequest, TypedInternalResponse } from 'nitropack'
|
||||
import type { Ref } from 'vue'
|
||||
import { computed, unref, reactive } from 'vue'
|
||||
import { computed, reactive, unref } from 'vue'
|
||||
import { hash } from 'ohash'
|
||||
import { useRequestFetch } from './ssr'
|
||||
import type { AsyncDataOptions, _Transform, KeysOf, AsyncData, PickFrom, MultiWatchSources } from './asyncData'
|
||||
import type { AsyncData, AsyncDataOptions, KeysOf, MultiWatchSources, PickFrom, _Transform } from './asyncData'
|
||||
import { useAsyncData } from './asyncData'
|
||||
|
||||
export type FetchResult<ReqT extends NitroFetchRequest, M extends AvailableRouterMethod<ReqT>> = TypedInternalResponse<ReqT, unknown, M>
|
||||
|
@ -28,6 +28,6 @@ export { onNuxtReady } from './ready'
|
||||
export { abortNavigation, addRouteMiddleware, defineNuxtRouteMiddleware, onBeforeRouteLeave, onBeforeRouteUpdate, setPageLayout, navigateTo, useRoute, useRouter } from './router'
|
||||
export type { AddRouteMiddlewareOptions, RouteMiddleware } from './router'
|
||||
export { preloadComponents, prefetchComponents, preloadRouteComponents } from './preload'
|
||||
export { isPrerendered, loadPayload, preloadPayload } from './payload'
|
||||
export { isPrerendered, loadPayload, preloadPayload, definePayloadReducer, definePayloadReviver } from './payload'
|
||||
export type { ReloadNuxtAppOptions } from './chunk'
|
||||
export { reloadNuxtApp } from './chunk'
|
||||
|
@ -1,7 +1,12 @@
|
||||
import { joinURL, hasProtocol } from 'ufo'
|
||||
import { hasProtocol, joinURL } from 'ufo'
|
||||
import { parse } from 'devalue'
|
||||
import { useHead } from '@unhead/vue'
|
||||
import { getCurrentInstance } from 'vue'
|
||||
import { useNuxtApp, useRuntimeConfig } from '../nuxt'
|
||||
|
||||
// @ts-expect-error virtual import
|
||||
import { renderJsonPayloads } from '#build/nuxt.config.mjs'
|
||||
|
||||
interface LoadPayloadOptions {
|
||||
fresh?: boolean
|
||||
hash?: string
|
||||
@ -36,6 +41,7 @@ export function preloadPayload (url: string, opts: LoadPayloadOptions = {}) {
|
||||
|
||||
// --- Internal ---
|
||||
|
||||
const extension = renderJsonPayloads ? 'json' : 'js'
|
||||
function _getPayloadURL (url: string, opts: LoadPayloadOptions = {}) {
|
||||
const u = new URL(url, 'http://localhost')
|
||||
if (u.search) {
|
||||
@ -45,15 +51,19 @@ function _getPayloadURL (url: string, opts: LoadPayloadOptions = {}) {
|
||||
throw new Error('Payload URL must not include hostname: ' + url)
|
||||
}
|
||||
const hash = opts.hash || (opts.fresh ? Date.now() : '')
|
||||
return joinURL(useRuntimeConfig().app.baseURL, u.pathname, hash ? `_payload.${hash}.js` : '_payload.js')
|
||||
return joinURL(useRuntimeConfig().app.baseURL, u.pathname, hash ? `_payload.${hash}.${extension}` : `_payload.${extension}`)
|
||||
}
|
||||
|
||||
async function _importPayload (payloadURL: string) {
|
||||
if (process.server) { return null }
|
||||
const res = await import(/* webpackIgnore: true */ /* @vite-ignore */ payloadURL).catch((err) => {
|
||||
try {
|
||||
return renderJsonPayloads
|
||||
? parsePayload(await fetch(payloadURL).then(res => res.text()))
|
||||
: await import(/* webpackIgnore: true */ /* @vite-ignore */ payloadURL).then(r => r.default || r)
|
||||
} catch (err) {
|
||||
console.warn('[nuxt] Cannot load payload ', payloadURL, err)
|
||||
})
|
||||
return res?.default || null
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
export function isPrerendered () {
|
||||
@ -61,3 +71,63 @@ export function isPrerendered () {
|
||||
const nuxtApp = useNuxtApp()
|
||||
return !!nuxtApp.payload.prerenderedAt
|
||||
}
|
||||
|
||||
let payloadCache: any = null
|
||||
export async function getNuxtClientPayload () {
|
||||
if (process.server) {
|
||||
return
|
||||
}
|
||||
if (payloadCache) {
|
||||
return payloadCache
|
||||
}
|
||||
|
||||
const el = document.getElementById('__NUXT_DATA__')
|
||||
if (!el) {
|
||||
return {}
|
||||
}
|
||||
|
||||
const inlineData = parsePayload(el.textContent || '')
|
||||
|
||||
const externalData = el.dataset.src ? await _importPayload(el.dataset.src) : undefined
|
||||
|
||||
payloadCache = {
|
||||
...inlineData,
|
||||
...externalData,
|
||||
...window.__NUXT__
|
||||
}
|
||||
|
||||
return payloadCache
|
||||
}
|
||||
|
||||
export function parsePayload (payload: string) {
|
||||
return parse(payload, useNuxtApp()._payloadRevivers)
|
||||
}
|
||||
|
||||
/**
|
||||
* This is an experimental function for configuring passing rich data from server -> client.
|
||||
*/
|
||||
export function definePayloadReducer (
|
||||
name: string,
|
||||
reduce: (data: any) => any
|
||||
) {
|
||||
if (process.server) {
|
||||
useNuxtApp().ssrContext!._payloadReducers[name] = reduce
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is an experimental function for configuring passing rich data from server -> client.
|
||||
*
|
||||
* This function _must_ be called in a Nuxt plugin that is `unshift`ed to the beginning of the Nuxt plugins array.
|
||||
*/
|
||||
export function definePayloadReviver (
|
||||
name: string,
|
||||
revive: (data: string) => any | undefined
|
||||
) {
|
||||
if (process.dev && getCurrentInstance()) {
|
||||
console.warn('[nuxt] [definePayloadReviver] This function must be called in a Nuxt plugin that is `unshift`ed to the beginning of the Nuxt plugins array.')
|
||||
}
|
||||
if (process.client) {
|
||||
useNuxtApp()._payloadRevivers[name] = revive
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { getCurrentInstance, inject, onUnmounted } from 'vue'
|
||||
import type { Ref } from 'vue'
|
||||
import type { Router, RouteLocationNormalizedLoaded, NavigationGuard, RouteLocationNormalized, RouteLocationRaw, NavigationFailure, RouteLocationPathRaw } from 'vue-router'
|
||||
import type { NavigationFailure, NavigationGuard, RouteLocationNormalized, RouteLocationNormalizedLoaded, RouteLocationPathRaw, RouteLocationRaw, Router } from 'vue-router'
|
||||
import { sendRedirect } from 'h3'
|
||||
import { hasProtocol, joinURL, parseURL } from 'ufo'
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
// We set __webpack_public_path via this import with webpack builder
|
||||
import { createSSRApp, createApp, nextTick } from 'vue'
|
||||
import { createApp, createSSRApp, nextTick } from 'vue'
|
||||
import { $fetch } from 'ofetch'
|
||||
// @ts-ignore
|
||||
import { baseURL } from '#build/paths.mjs'
|
||||
import type { CreateOptions } from '#app'
|
||||
import { createNuxtApp, applyPlugins, normalizePlugins } from '#app/nuxt'
|
||||
import { applyPlugins, createNuxtApp, normalizePlugins } from '#app/nuxt'
|
||||
import '#build/css'
|
||||
// @ts-ignore
|
||||
import _plugins from '#build/plugins'
|
||||
@ -52,7 +52,10 @@ if (process.client) {
|
||||
}
|
||||
|
||||
entry = async function initApp () {
|
||||
const isSSR = Boolean(window.__NUXT__?.serverRendered)
|
||||
const isSSR = Boolean(
|
||||
window.__NUXT__?.serverRendered ||
|
||||
document.getElementById('__NUXT_DATA__')?.dataset.ssr === 'true'
|
||||
)
|
||||
const vueApp = isSSR ? createSSRApp(RootComponent) : createApp(RootComponent)
|
||||
|
||||
const nuxt = createNuxtApp({ vueApp })
|
||||
|
@ -1,17 +1,18 @@
|
||||
/* eslint-disable no-use-before-define */
|
||||
import { getCurrentInstance, reactive } from 'vue'
|
||||
import type { App, onErrorCaptured, VNode, Ref } from 'vue'
|
||||
import type { App, Ref, VNode, onErrorCaptured } from 'vue'
|
||||
import type { RouteLocationNormalizedLoaded } from 'vue-router'
|
||||
import type { Hookable, HookCallback } from 'hookable'
|
||||
import type { HookCallback, Hookable } from 'hookable'
|
||||
import { createHooks } from 'hookable'
|
||||
import { getContext } from 'unctx'
|
||||
import type { SSRContext } from 'vue-bundle-renderer/runtime'
|
||||
import type { H3Event } from 'h3'
|
||||
import type { RuntimeConfig, AppConfigInput, AppConfig } from 'nuxt/schema'
|
||||
import type { AppConfig, AppConfigInput, RuntimeConfig } from 'nuxt/schema'
|
||||
|
||||
// eslint-disable-next-line import/no-restricted-paths
|
||||
import type { NuxtIslandContext } from '../core/runtime/nitro/renderer'
|
||||
import type { RouteMiddleware } from '../../app'
|
||||
import type { NuxtError } from '../app/composables/error'
|
||||
|
||||
const nuxtAppCtx = /* #__PURE__ */ getContext<NuxtApp>('nuxt-app')
|
||||
|
||||
@ -41,6 +42,7 @@ export interface RuntimeNuxtHooks {
|
||||
'link:prefetch': (link: string) => HookResult
|
||||
'page:start': (Component?: VNode) => HookResult
|
||||
'page:finish': (Component?: VNode) => HookResult
|
||||
'page:transition:start': () => HookResult
|
||||
'page:transition:finish': (Component?: VNode) => HookResult
|
||||
'vue:setup': () => void
|
||||
'vue:error': (...args: Parameters<Parameters<typeof onErrorCaptured>[0]>) => HookResult
|
||||
@ -58,6 +60,8 @@ export interface NuxtSSRContext extends SSRContext {
|
||||
teleports?: Record<string, string>
|
||||
renderMeta?: () => Promise<NuxtMeta> | NuxtMeta
|
||||
islandContext?: NuxtIslandContext
|
||||
/** @internal */
|
||||
_payloadReducers: Record<string, (data: any) => any>
|
||||
}
|
||||
|
||||
interface _NuxtApp {
|
||||
@ -99,6 +103,9 @@ interface _NuxtApp {
|
||||
/** @internal */
|
||||
_islandPromises?: Record<string, Promise<any>>
|
||||
|
||||
/** @internal */
|
||||
_payloadRevivers: Record<string, (data: any) => any>
|
||||
|
||||
// Nuxt injections
|
||||
$config: RuntimeConfig
|
||||
|
||||
@ -111,7 +118,6 @@ interface _NuxtApp {
|
||||
prerenderedAt?: number
|
||||
data: Record<string, any>
|
||||
state: Record<string, any>
|
||||
rendered?: Function
|
||||
error?: Error | {
|
||||
url: string
|
||||
statusCode: number
|
||||
@ -120,6 +126,7 @@ interface _NuxtApp {
|
||||
description: string
|
||||
data?: any
|
||||
} | null
|
||||
_errors: Record<string, NuxtError | undefined>
|
||||
[key: string]: any
|
||||
}
|
||||
static: {
|
||||
@ -132,9 +139,31 @@ interface _NuxtApp {
|
||||
export interface NuxtApp extends _NuxtApp {}
|
||||
|
||||
export const NuxtPluginIndicator = '__nuxt_plugin'
|
||||
|
||||
export interface PluginMeta {
|
||||
name?: string
|
||||
enforce?: 'pre' | 'default' | 'post'
|
||||
/**
|
||||
* This allows more granular control over plugin order and should only be used by advanced users.
|
||||
* It overrides the value of `enforce` and is used to sort plugins.
|
||||
*/
|
||||
order?: number
|
||||
}
|
||||
|
||||
export interface ResolvedPluginMeta {
|
||||
name?: string
|
||||
order: number
|
||||
}
|
||||
|
||||
export interface Plugin<Injections extends Record<string, unknown> = Record<string, unknown>> {
|
||||
(nuxt: _NuxtApp): Promise<void> | Promise<{ provide?: Injections }> | void | { provide?: Injections }
|
||||
[NuxtPluginIndicator]?: true
|
||||
meta?: ResolvedPluginMeta
|
||||
}
|
||||
|
||||
export interface ObjectPluginInput<Injections extends Record<string, unknown> = Record<string, unknown>> extends PluginMeta {
|
||||
hooks?: Partial<RuntimeNuxtHooks>
|
||||
setup?: Plugin<Injections>
|
||||
}
|
||||
|
||||
export interface CreateOptions {
|
||||
@ -156,7 +185,7 @@ export function createNuxtApp (options: CreateOptions) {
|
||||
data: {},
|
||||
state: {},
|
||||
_errors: {},
|
||||
...(process.client ? window.__NUXT__ : { serverRendered: true })
|
||||
...(process.client ? window.__NUXT__ ?? {} : { serverRendered: true })
|
||||
}),
|
||||
static: {
|
||||
data: {}
|
||||
@ -182,6 +211,7 @@ export function createNuxtApp (options: CreateOptions) {
|
||||
},
|
||||
_asyncDataPromises: {},
|
||||
_asyncData: {},
|
||||
_payloadRevivers: {},
|
||||
...options
|
||||
} as any as NuxtApp
|
||||
|
||||
@ -217,7 +247,11 @@ export function createNuxtApp (options: CreateOptions) {
|
||||
if (nuxtApp.ssrContext) {
|
||||
nuxtApp.ssrContext.nuxt = nuxtApp
|
||||
}
|
||||
// Expose to server renderer to create window.__NUXT__
|
||||
// Expose payload types
|
||||
if (nuxtApp.ssrContext) {
|
||||
nuxtApp.ssrContext._payloadReducers = {}
|
||||
}
|
||||
// Expose to server renderer to create payload
|
||||
nuxtApp.ssrContext = nuxtApp.ssrContext || {} as any
|
||||
if (nuxtApp.ssrContext!.payload) {
|
||||
Object.assign(nuxtApp.payload, nuxtApp.ssrContext!.payload)
|
||||
@ -225,7 +259,7 @@ export function createNuxtApp (options: CreateOptions) {
|
||||
nuxtApp.ssrContext!.payload = nuxtApp.payload
|
||||
|
||||
// Expose client runtime-config to the payload
|
||||
nuxtApp.payload.config = {
|
||||
nuxtApp.ssrContext!.config = {
|
||||
public: options.ssrContext!.runtimeConfig.public,
|
||||
app: options.ssrContext!.runtimeConfig.app
|
||||
}
|
||||
@ -244,17 +278,19 @@ export function createNuxtApp (options: CreateOptions) {
|
||||
}
|
||||
|
||||
// Expose runtime config
|
||||
const runtimeConfig = process.server
|
||||
? options.ssrContext!.runtimeConfig
|
||||
: reactive(nuxtApp.payload.config)
|
||||
const runtimeConfig = process.server ? options.ssrContext!.runtimeConfig : reactive(nuxtApp.payload.config)
|
||||
|
||||
// TODO: remove in v3.5
|
||||
// Backward compatibility following #4254
|
||||
const compatibilityConfig = new Proxy(runtimeConfig, {
|
||||
get (target, prop) {
|
||||
if (prop === 'public') {
|
||||
return target.public
|
||||
get (target, prop: string) {
|
||||
if (prop in target) {
|
||||
return target[prop]
|
||||
}
|
||||
return target[prop] ?? target.public[prop]
|
||||
if (process.dev && prop in target.public) {
|
||||
console.warn(`[nuxt] [runtimeConfig] You are trying to access a public runtime config value (\`${prop}\`) directly from the top level. This currently works (for backward compatibility with Nuxt 2) but this compatibility layer will be removed in v3.5. Instead, you can update \`config['${prop}']\` to \`config.public['${prop}']\`.`)
|
||||
}
|
||||
return target.public[prop]
|
||||
},
|
||||
set (target, prop, value) {
|
||||
if (process.server || prop === 'public' || prop === 'app') {
|
||||
@ -292,25 +328,30 @@ export function normalizePlugins (_plugins: Plugin[]) {
|
||||
const legacyInjectPlugins: Plugin[] = []
|
||||
const invalidPlugins: Plugin[] = []
|
||||
|
||||
const plugins = _plugins.map((plugin) => {
|
||||
const plugins: Plugin[] = []
|
||||
|
||||
for (const plugin of _plugins) {
|
||||
if (typeof plugin !== 'function') {
|
||||
invalidPlugins.push(plugin)
|
||||
return null
|
||||
if (process.dev) { invalidPlugins.push(plugin) }
|
||||
continue
|
||||
}
|
||||
|
||||
// TODO: Skip invalid plugins in next releases
|
||||
let _plugin = plugin
|
||||
if (plugin.length > 1) {
|
||||
legacyInjectPlugins.push(plugin)
|
||||
// Allow usage without wrapper but warn
|
||||
// TODO: Skip invalid in next releases
|
||||
// @ts-ignore
|
||||
return (nuxtApp: NuxtApp) => plugin(nuxtApp, nuxtApp.provide)
|
||||
// return null
|
||||
if (process.dev) { legacyInjectPlugins.push(plugin) }
|
||||
// @ts-expect-error deliberate invalid second argument
|
||||
_plugin = (nuxtApp: NuxtApp) => plugin(nuxtApp, nuxtApp.provide)
|
||||
}
|
||||
if (!isNuxtPlugin(plugin)) {
|
||||
unwrappedPlugins.push(plugin)
|
||||
|
||||
// Allow usage without wrapper but warn
|
||||
if (process.dev && !isNuxtPlugin(_plugin)) { unwrappedPlugins.push(_plugin) }
|
||||
|
||||
plugins.push(_plugin)
|
||||
}
|
||||
return plugin
|
||||
}).filter(Boolean)
|
||||
|
||||
plugins.sort((a, b) => (a.meta?.order || orderMap.default) - (b.meta?.order || orderMap.default))
|
||||
|
||||
if (process.dev && legacyInjectPlugins.length) {
|
||||
console.warn('[warn] [nuxt] You are using a plugin with legacy Nuxt 2 format (context, inject) which is likely to be broken. In the future they will be ignored:', legacyInjectPlugins.map(p => p.name || p).join(','))
|
||||
@ -322,12 +363,53 @@ export function normalizePlugins (_plugins: Plugin[]) {
|
||||
console.warn('[warn] [nuxt] You are using a plugin that has not been wrapped in `defineNuxtPlugin`. It is advised to wrap your plugins as in the future this may enable enhancements:', unwrappedPlugins.map(p => p.name || p).join(','))
|
||||
}
|
||||
|
||||
return plugins as Plugin[]
|
||||
return plugins
|
||||
}
|
||||
|
||||
export function defineNuxtPlugin<T extends Record<string, unknown>> (plugin: Plugin<T>) {
|
||||
plugin[NuxtPluginIndicator] = true
|
||||
return plugin
|
||||
// -50: pre-all (nuxt)
|
||||
// -40: custom payload revivers (user)
|
||||
// -30: payload reviving (nuxt)
|
||||
// -20: pre (user) <-- pre mapped to this
|
||||
// -10: default (nuxt)
|
||||
// 0: default (user) <-- default behavior
|
||||
// +10: post (nuxt)
|
||||
// +20: post (user) <-- post mapped to this
|
||||
// +30: post-all (nuxt)
|
||||
|
||||
const orderMap: Record<NonNullable<ObjectPluginInput['enforce']>, number> = {
|
||||
pre: -20,
|
||||
default: 0,
|
||||
post: 20
|
||||
}
|
||||
|
||||
export function definePayloadPlugin<T extends Record<string, unknown>> (plugin: Plugin<T> | ObjectPluginInput<T>) {
|
||||
return defineNuxtPlugin(plugin, { order: -40 })
|
||||
}
|
||||
|
||||
export function defineNuxtPlugin<T extends Record<string, unknown>> (plugin: Plugin<T> | ObjectPluginInput<T>, meta?: PluginMeta): Plugin<T> {
|
||||
if (typeof plugin === 'function') { return defineNuxtPlugin({ setup: plugin }, meta) }
|
||||
|
||||
const wrapper: Plugin<T> = (nuxtApp) => {
|
||||
if (plugin.hooks) {
|
||||
nuxtApp.hooks.addHooks(plugin.hooks)
|
||||
}
|
||||
if (plugin.setup) {
|
||||
return plugin.setup(nuxtApp)
|
||||
}
|
||||
}
|
||||
|
||||
wrapper.meta = {
|
||||
name: meta?.name || plugin.name || plugin.setup?.name,
|
||||
order:
|
||||
meta?.order ||
|
||||
plugin.order ||
|
||||
orderMap[plugin.enforce || 'default'] ||
|
||||
orderMap.default
|
||||
}
|
||||
|
||||
wrapper[NuxtPluginIndicator] = true
|
||||
|
||||
return wrapper
|
||||
}
|
||||
|
||||
export function isNuxtPlugin (plugin: unknown) {
|
||||
|
@ -3,7 +3,9 @@ import { defineNuxtPlugin, useRuntimeConfig } from '#app/nuxt'
|
||||
import { useRouter } from '#app/composables/router'
|
||||
import { reloadNuxtApp } from '#app/composables/chunk'
|
||||
|
||||
export default defineNuxtPlugin((nuxtApp) => {
|
||||
export default defineNuxtPlugin({
|
||||
name: 'nuxt:chunk-reload',
|
||||
setup (nuxtApp) {
|
||||
const router = useRouter()
|
||||
const config = useRuntimeConfig()
|
||||
|
||||
@ -19,4 +21,5 @@ export default defineNuxtPlugin((nuxtApp) => {
|
||||
reloadNuxtApp({ path, persistState: true })
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
@ -3,7 +3,9 @@ import { parseURL } from 'ufo'
|
||||
import { useHead } from '@unhead/vue'
|
||||
import { defineNuxtPlugin } from '#app/nuxt'
|
||||
|
||||
export default defineNuxtPlugin((nuxtApp) => {
|
||||
export default defineNuxtPlugin({
|
||||
name: 'nuxt:cross-origin-prefetch',
|
||||
setup (nuxtApp) {
|
||||
const externalURLs = ref(new Set<string>())
|
||||
function generateRules () {
|
||||
return {
|
||||
@ -32,4 +34,5 @@ export default defineNuxtPlugin((nuxtApp) => {
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
@ -1,6 +1,10 @@
|
||||
import { createDebugger } from 'hookable'
|
||||
import { defineNuxtPlugin } from '#app/nuxt'
|
||||
|
||||
export default defineNuxtPlugin((nuxtApp) => {
|
||||
export default defineNuxtPlugin({
|
||||
name: 'nuxt:debug',
|
||||
enforce: 'pre',
|
||||
setup (nuxtApp) {
|
||||
createDebugger(nuxtApp.hooks, { tag: 'nuxt-app' })
|
||||
}
|
||||
})
|
||||
|
@ -1,9 +1,11 @@
|
||||
import { parseURL } from 'ufo'
|
||||
import { defineNuxtPlugin } from '#app/nuxt'
|
||||
import { loadPayload, isPrerendered } from '#app/composables/payload'
|
||||
import { isPrerendered, loadPayload } from '#app/composables/payload'
|
||||
import { useRouter } from '#app/composables/router'
|
||||
|
||||
export default defineNuxtPlugin((nuxtApp) => {
|
||||
export default defineNuxtPlugin({
|
||||
name: 'nuxt:payload',
|
||||
setup (nuxtApp) {
|
||||
// Only enable behavior if initial page is prerendered
|
||||
// TODO: Support hybrid and dev
|
||||
if (!isPrerendered()) {
|
||||
@ -24,4 +26,5 @@ export default defineNuxtPlugin((nuxtApp) => {
|
||||
if (!payload) { return }
|
||||
Object.assign(nuxtApp.static.data, payload.data)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { defineNuxtPlugin } from '#app/nuxt'
|
||||
|
||||
export default defineNuxtPlugin((nuxtApp) => {
|
||||
export default defineNuxtPlugin({
|
||||
name: 'nuxt:webpack-preload',
|
||||
setup (nuxtApp) {
|
||||
nuxtApp.vueApp.mixin({
|
||||
beforeCreate () {
|
||||
const { _registeredComponents } = this.$nuxt.ssrContext
|
||||
@ -8,4 +10,5 @@ export default defineNuxtPlugin((nuxtApp) => {
|
||||
_registeredComponents.add(__moduleIdentifier)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
@ -1,7 +1,10 @@
|
||||
import { defineNuxtPlugin } from '#app/nuxt'
|
||||
import { defineNuxtPlugin, useNuxtApp } from '#app/nuxt'
|
||||
|
||||
export default defineNuxtPlugin((nuxtApp) => {
|
||||
nuxtApp.hook('app:mounted', () => {
|
||||
export default defineNuxtPlugin({
|
||||
name: 'nuxt:restore-state',
|
||||
hooks: {
|
||||
'app:mounted' () {
|
||||
const nuxtApp = useNuxtApp()
|
||||
try {
|
||||
const state = sessionStorage.getItem('nuxt:reload:state')
|
||||
if (state) {
|
||||
@ -9,5 +12,6 @@ export default defineNuxtPlugin((nuxtApp) => {
|
||||
Object.assign(nuxtApp.payload.state, JSON.parse(state)?.state)
|
||||
}
|
||||
} catch {}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
27
packages/nuxt/src/app/plugins/revive-payload.client.ts
Normal file
27
packages/nuxt/src/app/plugins/revive-payload.client.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { reactive, ref, shallowReactive, shallowRef } from 'vue'
|
||||
import { definePayloadReviver, getNuxtClientPayload } from '#app/composables/payload'
|
||||
import { createError } from '#app/composables/error'
|
||||
import { callWithNuxt, defineNuxtPlugin } from '#app/nuxt'
|
||||
|
||||
const revivers = {
|
||||
NuxtError: (data: any) => createError(data),
|
||||
EmptyShallowRef: (data: any) => shallowRef(JSON.parse(data)),
|
||||
EmptyRef: (data: any) => ref(JSON.parse(data)),
|
||||
ShallowRef: (data: any) => shallowRef(data),
|
||||
ShallowReactive: (data: any) => shallowReactive(data),
|
||||
Ref: (data: any) => ref(data),
|
||||
Reactive: (data: any) => reactive(data)
|
||||
}
|
||||
|
||||
export default defineNuxtPlugin({
|
||||
name: 'nuxt:revive-payload:client',
|
||||
order: -30,
|
||||
async setup (nuxtApp) {
|
||||
for (const reviver in revivers) {
|
||||
definePayloadReviver(reviver, revivers[reviver as keyof typeof revivers])
|
||||
}
|
||||
Object.assign(nuxtApp.payload, await callWithNuxt(nuxtApp, getNuxtClientPayload, []))
|
||||
// For backwards compatibility - TODO: remove later
|
||||
window.__NUXT__ = nuxtApp.payload
|
||||
}
|
||||
})
|
24
packages/nuxt/src/app/plugins/revive-payload.server.ts
Normal file
24
packages/nuxt/src/app/plugins/revive-payload.server.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { isReactive, isRef, isShallow, toRaw } from 'vue'
|
||||
import { definePayloadReducer } from '#app/composables/payload'
|
||||
import { isNuxtError } from '#app/composables/error'
|
||||
import { defineNuxtPlugin } from '#app/nuxt'
|
||||
/* Defining a plugin that will be used by the Nuxt framework. */
|
||||
|
||||
const reducers = {
|
||||
NuxtError: (data: any) => isNuxtError(data) && data.toJSON(),
|
||||
EmptyShallowRef: (data: any) => isRef(data) && isShallow(data) && !data.value && JSON.stringify(data.value),
|
||||
EmptyRef: (data: any) => isRef(data) && !data.value && JSON.stringify(data.value),
|
||||
ShallowRef: (data: any) => isRef(data) && isShallow(data) && data.value,
|
||||
ShallowReactive: (data: any) => isReactive(data) && isShallow(data) && toRaw(data),
|
||||
Ref: (data: any) => isRef(data) && data.value,
|
||||
Reactive: (data: any) => isReactive(data) && toRaw(data)
|
||||
}
|
||||
|
||||
export default defineNuxtPlugin({
|
||||
name: 'nuxt:revive-payload:server',
|
||||
setup () {
|
||||
for (const reducer in reducers) {
|
||||
definePayloadReducer(reducer, reducers[reducer as keyof typeof reducers])
|
||||
}
|
||||
}
|
||||
})
|
@ -1,5 +1,5 @@
|
||||
import { reactive, h, isReadonly } from 'vue'
|
||||
import { parseURL, stringifyParsedURL, parseQuery, stringifyQuery, withoutBase, isEqual, joinURL } from 'ufo'
|
||||
import { h, isReadonly, reactive } from 'vue'
|
||||
import { isEqual, joinURL, parseQuery, parseURL, stringifyParsedURL, stringifyQuery, withoutBase } from 'ufo'
|
||||
import { createError } from 'h3'
|
||||
import { callWithNuxt, defineNuxtPlugin, useRuntimeConfig } from '../nuxt'
|
||||
import { clearError, showError } from '../composables/error'
|
||||
@ -96,7 +96,10 @@ interface Router {
|
||||
removeRoute: (name: string) => void
|
||||
}
|
||||
|
||||
export default defineNuxtPlugin<{ route: Route, router: Router }>((nuxtApp) => {
|
||||
export default defineNuxtPlugin<{ route: Route, router: Router }>({
|
||||
name: 'nuxt:router',
|
||||
enforce: 'pre',
|
||||
setup (nuxtApp) {
|
||||
const initialURL = process.client
|
||||
? withoutBase(window.location.pathname, useRuntimeConfig().app.baseURL) + window.location.search + window.location.hash
|
||||
: nuxtApp.ssrContext!.url
|
||||
@ -110,7 +113,7 @@ export default defineNuxtPlugin<{ route: Route, router: Router }>((nuxtApp) => {
|
||||
error: []
|
||||
}
|
||||
|
||||
const registerHook = <T extends keyof RouterHooks>(hook: T, guard: RouterHooks[T]) => {
|
||||
const registerHook = <T extends keyof RouterHooks> (hook: T, guard: RouterHooks[T]) => {
|
||||
hooks[hook].push(guard)
|
||||
return () => hooks[hook].splice(hooks[hook].indexOf(guard), 1)
|
||||
}
|
||||
@ -268,4 +271,5 @@ export default defineNuxtPlugin<{ route: Route, router: Router }>((nuxtApp) => {
|
||||
router
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
55
packages/nuxt/src/app/plugins/view-transitions.client.ts
Normal file
55
packages/nuxt/src/app/plugins/view-transitions.client.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import { useRouter } from '#app/composables/router'
|
||||
import { defineNuxtPlugin } from '#app/nuxt'
|
||||
|
||||
export default defineNuxtPlugin((nuxtApp) => {
|
||||
if (!document.startViewTransition) { return }
|
||||
|
||||
let finishTransition: undefined | (() => void)
|
||||
let abortTransition: undefined | (() => void)
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
router.beforeResolve((to) => {
|
||||
if (to.meta.pageTransition === false) { return }
|
||||
|
||||
const promise = new Promise<void>((resolve, reject) => {
|
||||
finishTransition = resolve
|
||||
abortTransition = reject
|
||||
})
|
||||
|
||||
let changeRoute: () => void
|
||||
const ready = new Promise<void>(resolve => (changeRoute = resolve))
|
||||
|
||||
const transition = document.startViewTransition!(() => {
|
||||
changeRoute()
|
||||
return promise
|
||||
})
|
||||
|
||||
transition.finished.then(() => {
|
||||
abortTransition = undefined
|
||||
finishTransition = undefined
|
||||
})
|
||||
|
||||
return ready
|
||||
})
|
||||
|
||||
nuxtApp.hook('vue:error', () => {
|
||||
abortTransition?.()
|
||||
abortTransition = undefined
|
||||
})
|
||||
|
||||
nuxtApp.hook('page:finish', () => {
|
||||
finishTransition?.()
|
||||
finishTransition = undefined
|
||||
})
|
||||
})
|
||||
|
||||
declare global {
|
||||
interface Document {
|
||||
startViewTransition?: (callback: () => Promise<void> | void) => {
|
||||
finished: Promise<void>
|
||||
updateCallbackDone: Promise<void>
|
||||
ready: Promise<void>
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
import { statSync } from 'node:fs'
|
||||
import { relative, resolve } from 'pathe'
|
||||
import { defineNuxtModule, resolveAlias, addTemplate, addPluginTemplate, updateTemplates } from '@nuxt/kit'
|
||||
import { addPluginTemplate, addTemplate, defineNuxtModule, resolveAlias, updateTemplates } from '@nuxt/kit'
|
||||
import type { Component, ComponentsDir, ComponentsOptions } from 'nuxt/schema'
|
||||
|
||||
import { distDir } from '../dirs'
|
||||
import { clientFallbackAutoIdPlugin } from './client-fallback-auto-id'
|
||||
import { componentsPluginTemplate, componentsTemplate, componentsIslandsTemplate, componentsTypeTemplate } from './templates'
|
||||
import { componentsIslandsTemplate, componentsPluginTemplate, componentsTemplate, componentsTypeTemplate } from './templates'
|
||||
import { scanComponents } from './scan'
|
||||
import { loaderPlugin } from './loader'
|
||||
import { TreeShakeTemplatePlugin } from './tree-shake'
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { defineComponent, createStaticVNode, computed, h, watch } from 'vue'
|
||||
import { computed, createStaticVNode, defineComponent, h, watch } from 'vue'
|
||||
import { debounce } from 'perfect-debounce'
|
||||
import { hash } from 'ohash'
|
||||
import { appendHeader } from 'h3'
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { basename, extname, join, dirname, relative } from 'pathe'
|
||||
import { basename, dirname, extname, join, relative } from 'pathe'
|
||||
import { globby } from 'globby'
|
||||
import { pascalCase, splitByCase } from 'scule'
|
||||
import { isIgnored } from '@nuxt/kit'
|
||||
|
@ -40,11 +40,14 @@ const components = ${genObjectFromRawEntries(globalComponents.map((c) => {
|
||||
return [c.pascalName, `defineAsyncComponent(${genDynamicImport(c.filePath, { comment })}.then(c => ${exp}))`]
|
||||
}))}
|
||||
|
||||
export default defineNuxtPlugin(nuxtApp => {
|
||||
export default defineNuxtPlugin({
|
||||
name: 'nuxt:global-components',
|
||||
setup (nuxtApp) {
|
||||
for (const name in components) {
|
||||
nuxtApp.vueApp.component(name, components[name])
|
||||
nuxtApp.vueApp.component('Lazy' + name, components[name])
|
||||
}
|
||||
}
|
||||
})
|
||||
`
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import { pathToFileURL } from 'node:url'
|
||||
import { parseURL } from 'ufo'
|
||||
import MagicString from 'magic-string'
|
||||
import { walk } from 'estree-walker'
|
||||
import type { CallExpression, Property, Identifier, MemberExpression, Literal, ReturnStatement, VariableDeclaration, ObjectExpression, Node, Pattern, AssignmentProperty, Program } from 'estree'
|
||||
import type { AssignmentProperty, CallExpression, Identifier, Literal, MemberExpression, Node, ObjectExpression, Pattern, Program, Property, ReturnStatement, VariableDeclaration } from 'estree'
|
||||
import { createUnplugin } from 'unplugin'
|
||||
import type { Component } from '@nuxt/schema'
|
||||
import { resolve } from 'pathe'
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { promises as fsp } from 'node:fs'
|
||||
import { dirname, resolve, join } from 'pathe'
|
||||
import { dirname, join, resolve } from 'pathe'
|
||||
import { defu } from 'defu'
|
||||
import { findPath, resolveFiles, normalizePlugin, normalizeTemplate, compileTemplate, templateUtils, tryResolveModule, resolvePath, resolveAlias } from '@nuxt/kit'
|
||||
import { compileTemplate, findPath, normalizePlugin, normalizeTemplate, resolveAlias, resolveFiles, resolvePath, templateUtils, tryResolveModule } from '@nuxt/kit'
|
||||
import type { Nuxt, NuxtApp, NuxtPlugin, NuxtTemplate, ResolvedNuxtTemplate } from 'nuxt/schema'
|
||||
|
||||
import * as defaultTemplates from './templates'
|
||||
|
@ -5,7 +5,7 @@ import { debounce } from 'perfect-debounce'
|
||||
import { normalize } from 'pathe'
|
||||
import type { Nuxt } from 'nuxt/schema'
|
||||
|
||||
import { createApp, generateApp as _generateApp } from './app'
|
||||
import { generateApp as _generateApp, createApp } from './app'
|
||||
|
||||
export async function build (nuxt: Nuxt) {
|
||||
const app = createApp(nuxt)
|
||||
@ -44,6 +44,10 @@ export async function build (nuxt: Nuxt) {
|
||||
}
|
||||
|
||||
function watch (nuxt: Nuxt) {
|
||||
if (nuxt.options.debug) {
|
||||
console.time('[nuxt] builder:chokidar:watch')
|
||||
}
|
||||
|
||||
const watcher = chokidar.watch(nuxt.options._layers.map(i => i.config.srcDir as string).filter(Boolean), {
|
||||
...nuxt.options.watchers.chokidar,
|
||||
cwd: nuxt.options.srcDir,
|
||||
@ -55,6 +59,10 @@ function watch (nuxt: Nuxt) {
|
||||
]
|
||||
})
|
||||
|
||||
if (nuxt.options.debug) {
|
||||
watcher.on('ready', () => console.timeEnd('[nuxt] builder:chokidar:watch'))
|
||||
}
|
||||
|
||||
watcher.on('all', (event, path) => nuxt.callHook('builder:watch', event, normalize(path)))
|
||||
nuxt.hook('close', () => watcher.close())
|
||||
return watcher
|
||||
|
36
packages/nuxt/src/core/features.ts
Normal file
36
packages/nuxt/src/core/features.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import { addDependency } from 'nypm'
|
||||
import { isPackageExists } from 'local-pkg'
|
||||
import { logger } from '@nuxt/kit'
|
||||
import prompts from 'prompts'
|
||||
|
||||
export async function ensurePackageInstalled (rootDir: string, name: string, searchPaths?: string[]) {
|
||||
if (isPackageExists(name, { paths: searchPaths })) {
|
||||
return true
|
||||
}
|
||||
|
||||
logger.info(`Package ${name} is missing`)
|
||||
|
||||
const { confirm } = await prompts({
|
||||
type: 'confirm',
|
||||
name: 'confirm',
|
||||
message: `Do you want to install ${name} package?`,
|
||||
initial: true
|
||||
})
|
||||
|
||||
if (!confirm) {
|
||||
return false
|
||||
}
|
||||
|
||||
logger.info(`Installing ${name}...`)
|
||||
try {
|
||||
await addDependency(name, {
|
||||
cwd: rootDir,
|
||||
dev: true
|
||||
})
|
||||
logger.success(`Installed ${name}`)
|
||||
return true
|
||||
} catch (err) {
|
||||
logger.error(err)
|
||||
return false
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import { existsSync, promises as fsp } from 'node:fs'
|
||||
import { resolve, join, relative } from 'pathe'
|
||||
import { createNitro, createDevServer, build, prepare, copyPublicAssets, writeTypes, scanHandlers, prerender } from 'nitropack'
|
||||
import type { NitroConfig, Nitro } from 'nitropack'
|
||||
import { join, relative, resolve } from 'pathe'
|
||||
import { build, copyPublicAssets, createDevServer, createNitro, prepare, prerender, scanHandlers, writeTypes } from 'nitropack'
|
||||
import type { Nitro, NitroConfig } from 'nitropack'
|
||||
import { logger, resolvePath } from '@nuxt/kit'
|
||||
import escapeRE from 'escape-string-regexp'
|
||||
import { defu } from 'defu'
|
||||
@ -37,6 +37,7 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
|
||||
dev: nuxt.options.dev,
|
||||
buildDir: nuxt.options.buildDir,
|
||||
imports: {
|
||||
autoImports: nuxt.options.imports.autoImport,
|
||||
imports: [
|
||||
{
|
||||
as: '__buildAssetsURL',
|
||||
@ -126,6 +127,18 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
|
||||
'nuxt/dist',
|
||||
'nuxt3/dist',
|
||||
distDir
|
||||
],
|
||||
traceInclude: [
|
||||
// force include files used in generated code from the runtime-compiler
|
||||
...(nuxt.options.experimental.runtimeVueCompiler && !nuxt.options.experimental.externalVue)
|
||||
? [
|
||||
...nuxt.options.modulesDir.reduce<string[]>((targets, path) => {
|
||||
const serverRendererPath = resolve(path, 'vue/server-renderer/index.js')
|
||||
if (existsSync(serverRendererPath)) { targets.push(serverRendererPath) }
|
||||
return targets
|
||||
}, [])
|
||||
]
|
||||
: []
|
||||
]
|
||||
},
|
||||
alias: {
|
||||
@ -137,11 +150,15 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
|
||||
vue: await resolvePath(`vue/dist/vue.cjs${nuxt.options.dev ? '' : '.prod'}.js`)
|
||||
},
|
||||
// Vue 3 mocks
|
||||
...nuxt.options.experimental.runtimeVueCompiler || nuxt.options.experimental.externalVue
|
||||
? {}
|
||||
: {
|
||||
'estree-walker': 'unenv/runtime/mock/proxy',
|
||||
'@babel/parser': 'unenv/runtime/mock/proxy',
|
||||
'@vue/compiler-core': 'unenv/runtime/mock/proxy',
|
||||
'@vue/compiler-dom': 'unenv/runtime/mock/proxy',
|
||||
'@vue/compiler-ssr': 'unenv/runtime/mock/proxy',
|
||||
'@vue/compiler-ssr': 'unenv/runtime/mock/proxy'
|
||||
},
|
||||
'@vue/devtools-api': 'vue-devtools-stub',
|
||||
|
||||
// Paths
|
||||
@ -156,6 +173,7 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
|
||||
'process.env.NUXT_NO_SCRIPTS': !!nuxt.options.experimental.noScripts && !nuxt.options.dev,
|
||||
'process.env.NUXT_INLINE_STYLES': !!nuxt.options.experimental.inlineSSRStyles,
|
||||
'process.env.NUXT_PAYLOAD_EXTRACTION': !!nuxt.options.experimental.payloadExtraction,
|
||||
'process.env.NUXT_JSON_PAYLOADS': !!nuxt.options.experimental.renderJsonPayloads,
|
||||
'process.env.NUXT_COMPONENT_ISLANDS': !!nuxt.options.experimental.componentIslands,
|
||||
'process.dev': nuxt.options.dev,
|
||||
__VUE_PROD_DEVTOOLS__: false
|
||||
@ -166,6 +184,9 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
|
||||
}
|
||||
})
|
||||
|
||||
// Resolve user-provided paths
|
||||
nitroConfig.srcDir = resolve(nuxt.options.rootDir, nuxt.options.srcDir, nitroConfig.srcDir!)
|
||||
|
||||
// Add head chunk for SPA renders
|
||||
const head = createHeadCore()
|
||||
head.push(nuxt.options.app.head)
|
||||
@ -231,6 +252,37 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
|
||||
nuxt.callHook('prerender:routes', { routes })
|
||||
})
|
||||
|
||||
// Enable runtime compiler client side
|
||||
if (nuxt.options.experimental.runtimeVueCompiler) {
|
||||
nuxt.hook('vite:extendConfig', (config, { isClient }) => {
|
||||
if (isClient) {
|
||||
if (Array.isArray(config.resolve!.alias)) {
|
||||
config.resolve!.alias.push({
|
||||
find: 'vue',
|
||||
replacement: 'vue/dist/vue.esm-bundler'
|
||||
})
|
||||
} else {
|
||||
config.resolve!.alias = {
|
||||
...config.resolve!.alias,
|
||||
vue: 'vue/dist/vue.esm-bundler'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
nuxt.hook('webpack:config', (configuration) => {
|
||||
const clientConfig = configuration.find(config => config.name === 'client')
|
||||
if (!clientConfig!.resolve) { clientConfig!.resolve!.alias = {} }
|
||||
if (Array.isArray(clientConfig!.resolve!.alias)) {
|
||||
clientConfig!.resolve!.alias.push({
|
||||
name: 'vue',
|
||||
alias: 'vue/dist/vue.esm-bundler'
|
||||
})
|
||||
} else {
|
||||
clientConfig!.resolve!.alias!.vue = 'vue/dist/vue.esm-bundler'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Setup handlers
|
||||
const devMiddlewareHandler = dynamicEventHandler()
|
||||
nitro.options.devHandlers.unshift({ handler: devMiddlewareHandler })
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { join, normalize, relative, resolve } from 'pathe'
|
||||
import { createHooks, createDebugger } from 'hookable'
|
||||
import { createDebugger, createHooks } from 'hookable'
|
||||
import type { LoadNuxtOptions } from '@nuxt/kit'
|
||||
import { resolvePath, resolveAlias, resolveFiles, loadNuxtConfig, nuxtCtx, installModule, addComponent, addVitePlugin, addWebpackPlugin, tryResolveModule, addPlugin } from '@nuxt/kit'
|
||||
import type { Nuxt, NuxtOptions, NuxtHooks } from 'nuxt/schema'
|
||||
import { addComponent, addPlugin, addVitePlugin, addWebpackPlugin, installModule, loadNuxtConfig, logger, nuxtCtx, resolveAlias, resolveFiles, resolvePath, tryResolveModule } from '@nuxt/kit'
|
||||
import type { Nuxt, NuxtHooks, NuxtOptions } from 'nuxt/schema'
|
||||
|
||||
import escapeRE from 'escape-string-regexp'
|
||||
import fse from 'fs-extra'
|
||||
@ -98,8 +98,12 @@ async function initNuxt (nuxt: Nuxt) {
|
||||
|
||||
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 }))
|
||||
const options = {
|
||||
sourcemap: nuxt.options.sourcemap.server || nuxt.options.sourcemap.client,
|
||||
transformerOptions: nuxt.options.optimization.asyncTransforms
|
||||
}
|
||||
addVitePlugin(UnctxTransformPlugin.vite(options))
|
||||
addWebpackPlugin(UnctxTransformPlugin.webpack(options))
|
||||
|
||||
// Add composable tree-shaking optimisations
|
||||
const serverTreeShakeOptions: TreeShakeComposablesPluginOptions = {
|
||||
@ -281,6 +285,19 @@ async function initNuxt (nuxt: Nuxt) {
|
||||
addPlugin(resolve(nuxt.options.appDir, 'plugins/restore-state.client'))
|
||||
}
|
||||
|
||||
// Add experimental automatic view transition api support
|
||||
if (nuxt.options.experimental.viewTransition) {
|
||||
addPlugin(resolve(nuxt.options.appDir, 'plugins/view-transitions.client'))
|
||||
}
|
||||
|
||||
// Add experimental support for custom types in JSON payload
|
||||
if (nuxt.options.experimental.renderJsonPayloads) {
|
||||
nuxt.hooks.hook('modules:done', () => {
|
||||
addPlugin(resolve(nuxt.options.appDir, 'plugins/revive-payload.client'))
|
||||
addPlugin(resolve(nuxt.options.appDir, 'plugins/revive-payload.server'))
|
||||
})
|
||||
}
|
||||
|
||||
// Track components used to render for webpack
|
||||
if (nuxt.options.builder === '@nuxt/webpack-builder') {
|
||||
addPlugin(resolve(nuxt.options.appDir, 'plugins/preload.server'))
|
||||
@ -359,6 +376,15 @@ export async function loadNuxt (opts: LoadNuxtOptions): Promise<Nuxt> {
|
||||
options._modules.push('@nuxt/telemetry')
|
||||
}
|
||||
|
||||
// Nuxt DevTools is currently opt-in
|
||||
if (options.devtools === true || (options.devtools && options.devtools.enabled !== false)) {
|
||||
if (await import('./features').then(r => r.ensurePackageInstalled(options.rootDir, '@nuxt/devtools', options.modulesDir))) {
|
||||
options._modules.push('@nuxt/devtools')
|
||||
} else {
|
||||
logger.warn('Failed to install `@nuxt/devtools`, please install it manually, or disable `devtools` in `nuxt.config`')
|
||||
}
|
||||
}
|
||||
|
||||
const nuxt = createNuxt(options)
|
||||
|
||||
if (nuxt.options.debug) {
|
||||
|
@ -1,30 +1,42 @@
|
||||
import { normalize } from 'pathe'
|
||||
import { pathToFileURL } from 'node:url'
|
||||
import { parseQuery, parseURL } from 'ufo'
|
||||
import type { TransformerOptions } from 'unctx/transform'
|
||||
import { createTransformer } from 'unctx/transform'
|
||||
import { createUnplugin } from 'unplugin'
|
||||
import type { Nuxt, NuxtApp } from 'nuxt/schema'
|
||||
|
||||
const TRANSFORM_MARKER = '/* _processed_nuxt_unctx_transform */\n'
|
||||
|
||||
export const UnctxTransformPlugin = (nuxt: Nuxt) => {
|
||||
const transformer = createTransformer({
|
||||
asyncFunctions: ['defineNuxtPlugin', 'defineNuxtRouteMiddleware']
|
||||
})
|
||||
interface UnctxTransformPluginOptions {
|
||||
sourcemap?: boolean
|
||||
transformerOptions: TransformerOptions
|
||||
}
|
||||
|
||||
let app: NuxtApp | undefined
|
||||
nuxt.hook('app:resolve', (_app) => { app = _app })
|
||||
|
||||
return createUnplugin((options: { sourcemap?: boolean } = {}) => ({
|
||||
export const UnctxTransformPlugin = createUnplugin((options: UnctxTransformPluginOptions) => {
|
||||
const transformer = createTransformer(options.transformerOptions)
|
||||
return {
|
||||
name: 'unctx:transform',
|
||||
enforce: 'post',
|
||||
transformInclude (id) {
|
||||
if (id.includes('macro=true')) { return true }
|
||||
const { pathname, search } = parseURL(decodeURIComponent(pathToFileURL(id).href))
|
||||
const query = parseQuery(search)
|
||||
|
||||
id = normalize(id).replace(/\?.*$/, '')
|
||||
return app?.plugins.some(i => i.src === id) || app?.middleware.some(m => m.path === id)
|
||||
// Vue files
|
||||
if (
|
||||
pathname.endsWith('.vue') ||
|
||||
'macro' in query ||
|
||||
('vue' in query && (query.type === 'template' || query.type === 'script' || 'setup' in query))
|
||||
) {
|
||||
return true
|
||||
}
|
||||
|
||||
// JavaScript files
|
||||
if (pathname.match(/\.((c|m)?j|t)sx?$/g)) {
|
||||
return true
|
||||
}
|
||||
},
|
||||
transform (code, id) {
|
||||
// TODO: needed for webpack - update transform in unctx/unplugin?
|
||||
if (code.startsWith(TRANSFORM_MARKER)) { return }
|
||||
if (code.startsWith(TRANSFORM_MARKER) || !transformer.shouldTransform(code)) { return }
|
||||
const result = transformer.transform(code)
|
||||
if (result) {
|
||||
return {
|
||||
@ -35,5 +47,5 @@ export const UnctxTransformPlugin = (nuxt: Nuxt) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { joinURL, withQuery } from 'ufo'
|
||||
import type { NitroErrorHandler } from 'nitropack'
|
||||
import type { H3Error } from 'h3'
|
||||
import { setResponseHeader, getRequestHeaders, setResponseStatus } from 'h3'
|
||||
import { getRequestHeaders, setResponseHeader, setResponseStatus } from 'h3'
|
||||
import { useNitroApp, useRuntimeConfig } from '#internal/nitro'
|
||||
import { normalizeError, isJsonRequest } from '#internal/nitro/utils'
|
||||
import { isJsonRequest, normalizeError } from '#internal/nitro/utils'
|
||||
|
||||
export default <NitroErrorHandler> async function errorhandler (error: H3Error, event) {
|
||||
// Parse and normalize error
|
||||
|
@ -2,14 +2,15 @@ import { createRenderer, renderResourceHeaders } from 'vue-bundle-renderer/runti
|
||||
import type { RenderResponse } from 'nitropack'
|
||||
import type { Manifest } from 'vite'
|
||||
import type { H3Event } from 'h3'
|
||||
import { appendHeader, getQuery, writeEarlyHints, readBody, createError } from 'h3'
|
||||
import { appendHeader, createError, getQuery, readBody, writeEarlyHints } from 'h3'
|
||||
import devalue from '@nuxt/devalue'
|
||||
import { stringify, uneval } from 'devalue'
|
||||
import destr from 'destr'
|
||||
import { joinURL, withoutTrailingSlash } from 'ufo'
|
||||
import { renderToString as _renderToString } from 'vue/server-renderer'
|
||||
import { hash } from 'ohash'
|
||||
|
||||
import { useRuntimeConfig, defineRenderHandler, getRouteRules } from '#internal/nitro'
|
||||
import { defineRenderHandler, getRouteRules, useRuntimeConfig } from '#internal/nitro'
|
||||
import { useNitroApp } from '#internal/nitro/app'
|
||||
|
||||
// eslint-disable-next-line import/no-restricted-paths
|
||||
@ -121,14 +122,15 @@ const getSPARenderer = lazyCachedFunction(async () => {
|
||||
const renderToString = (ssrContext: NuxtSSRContext) => {
|
||||
const config = useRuntimeConfig()
|
||||
ssrContext!.payload = {
|
||||
_errors: {},
|
||||
serverRendered: false,
|
||||
config: {
|
||||
public: config.public,
|
||||
app: config.app
|
||||
},
|
||||
data: {},
|
||||
state: {}
|
||||
}
|
||||
ssrContext.config = {
|
||||
public: config.public,
|
||||
app: config.app
|
||||
}
|
||||
ssrContext!.renderMeta = ssrContext!.renderMeta ?? getStaticRenderedHead
|
||||
return Promise.resolve(result)
|
||||
}
|
||||
@ -160,7 +162,7 @@ async function getIslandContext (event: H3Event): Promise<NuxtIslandContext> {
|
||||
|
||||
const PAYLOAD_CACHE = (process.env.NUXT_PAYLOAD_EXTRACTION && process.env.prerender) ? new Map() : null // TODO: Use LRU cache
|
||||
const ISLAND_CACHE = (process.env.NUXT_COMPONENT_ISLANDS && process.env.prerender) ? new Map() : null // TODO: Use LRU cache
|
||||
const PAYLOAD_URL_RE = /\/_payload(\.[a-zA-Z0-9]+)?.js(\?.*)?$/
|
||||
const PAYLOAD_URL_RE = process.env.NUXT_JSON_PAYLOADS ? /\/_payload(\.[a-zA-Z0-9]+)?.json(\?.*)?$/ : /\/_payload(\.[a-zA-Z0-9]+)?.js(\?.*)?$/
|
||||
const ROOT_NODE_REGEX = new RegExp(`^<${appRootTag} id="${appRootId}">([\\s\\S]*)</${appRootTag}>$`)
|
||||
|
||||
const PRERENDER_NO_SSR_ROUTES = new Set(['/index.html', '/200.html', '/404.html'])
|
||||
@ -219,12 +221,13 @@ export default defineRenderHandler(async (event) => {
|
||||
error: !!ssrError,
|
||||
nuxt: undefined!, /* NuxtApp */
|
||||
payload: (ssrError ? { error: ssrError } : {}) as NuxtSSRContext['payload'],
|
||||
_payloadReducers: {},
|
||||
islandContext
|
||||
}
|
||||
|
||||
// Whether we are prerendering route
|
||||
const _PAYLOAD_EXTRACTION = process.env.prerender && process.env.NUXT_PAYLOAD_EXTRACTION && !ssrContext.noSSR
|
||||
const payloadURL = _PAYLOAD_EXTRACTION ? joinURL(useRuntimeConfig().app.baseURL, url, '_payload.js') : undefined
|
||||
const payloadURL = _PAYLOAD_EXTRACTION ? joinURL(useRuntimeConfig().app.baseURL, url, process.env.NUXT_JSON_PAYLOADS ? '_payload.json' : '_payload.js') : undefined
|
||||
if (process.env.prerender) {
|
||||
ssrContext.payload.prerenderedAt = Date.now()
|
||||
}
|
||||
@ -260,7 +263,7 @@ export default defineRenderHandler(async (event) => {
|
||||
|
||||
if (_PAYLOAD_EXTRACTION) {
|
||||
// Hint nitro to prerender payload for this route
|
||||
appendHeader(event, 'x-nitro-prerender', joinURL(url, '_payload.js'))
|
||||
appendHeader(event, 'x-nitro-prerender', joinURL(url, process.env.NUXT_JSON_PAYLOADS ? '_payload.json' : '_payload.js'))
|
||||
// Use same ssr context to generate payload for this route
|
||||
PAYLOAD_CACHE!.set(withoutTrailingSlash(url), renderPayloadResponse(ssrContext))
|
||||
}
|
||||
@ -273,14 +276,18 @@ export default defineRenderHandler(async (event) => {
|
||||
? await renderInlineStyles(ssrContext.modules ?? ssrContext._registeredComponents ?? [])
|
||||
: ''
|
||||
|
||||
const NO_SCRIPTS = process.env.NUXT_NO_SCRIPTS || routeOptions.experimentalNoScripts
|
||||
|
||||
// Create render context
|
||||
const htmlContext: NuxtRenderHTMLContext = {
|
||||
island: Boolean(islandContext),
|
||||
htmlAttrs: normalizeChunks([renderedMeta.htmlAttrs]),
|
||||
head: normalizeChunks([
|
||||
renderedMeta.headTags,
|
||||
_PAYLOAD_EXTRACTION ? `<link rel="modulepreload" href="${payloadURL}">` : null,
|
||||
_rendered.renderResourceHints(),
|
||||
process.env.NUXT_JSON_PAYLOADS
|
||||
? _PAYLOAD_EXTRACTION ? `<link rel="modulepreload" href="${payloadURL}">` : null
|
||||
: _PAYLOAD_EXTRACTION ? `<link rel="preload" as="fetch" crossorigin="anonymous" href="${payloadURL}">` : null,
|
||||
NO_SCRIPTS ? null : _rendered.renderResourceHints(),
|
||||
_rendered.renderStyles(),
|
||||
inlinedStyles,
|
||||
ssrContext.styles
|
||||
@ -292,13 +299,17 @@ export default defineRenderHandler(async (event) => {
|
||||
]),
|
||||
body: [_rendered.html],
|
||||
bodyAppend: normalizeChunks([
|
||||
process.env.NUXT_NO_SCRIPTS
|
||||
NO_SCRIPTS
|
||||
? undefined
|
||||
: (_PAYLOAD_EXTRACTION
|
||||
? `<script type="module">import p from "${payloadURL}";window.__NUXT__={...p,...(${devalue(splitPayload(ssrContext).initial)})}</script>`
|
||||
: `<script>window.__NUXT__=${devalue(ssrContext.payload)}</script>`
|
||||
? process.env.NUXT_JSON_PAYLOADS
|
||||
? renderPayloadJsonScript({ id: '__NUXT_DATA__', ssrContext, data: splitPayload(ssrContext).initial, src: payloadURL })
|
||||
: renderPayloadScript({ ssrContext, data: splitPayload(ssrContext).initial, src: payloadURL })
|
||||
: process.env.NUXT_JSON_PAYLOADS
|
||||
? renderPayloadJsonScript({ id: '__NUXT_DATA__', ssrContext, data: ssrContext.payload })
|
||||
: renderPayloadScript({ ssrContext, data: ssrContext.payload })
|
||||
),
|
||||
_rendered.renderScripts(),
|
||||
routeOptions.experimentalNoScripts ? undefined : _rendered.renderScripts(),
|
||||
// Note: bodyScripts may contain tags other than <script>
|
||||
renderedMeta.bodyScripts
|
||||
])
|
||||
@ -420,16 +431,39 @@ async function renderInlineStyles (usedModules: Set<string> | string[]) {
|
||||
|
||||
function renderPayloadResponse (ssrContext: NuxtSSRContext) {
|
||||
return <RenderResponse> {
|
||||
body: `export default ${devalue(splitPayload(ssrContext).payload)}`,
|
||||
body: process.env.NUXT_JSON_PAYLOADS
|
||||
? stringify(splitPayload(ssrContext).payload, ssrContext._payloadReducers)
|
||||
: `export default ${devalue(splitPayload(ssrContext).payload)}`,
|
||||
statusCode: ssrContext.event.node.res.statusCode,
|
||||
statusMessage: ssrContext.event.node.res.statusMessage,
|
||||
headers: {
|
||||
'content-type': 'text/javascript;charset=UTF-8',
|
||||
'content-type': process.env.NUXT_JSON_PAYLOADS ? 'application/json;charset=utf-8' : 'text/javascript;charset=utf-8',
|
||||
'x-powered-by': 'Nuxt'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function renderPayloadJsonScript (opts: { id: string, ssrContext: NuxtSSRContext, data?: any, src?: string }) {
|
||||
const attrs = [
|
||||
'type="application/json"',
|
||||
`id="${opts.id}"`,
|
||||
`data-ssr="${!(process.env.NUXT_NO_SSR || opts.ssrContext.noSSR)}"`,
|
||||
opts.src ? `data-src="${opts.src}"` : ''
|
||||
].filter(Boolean)
|
||||
const contents = opts.data ? stringify(opts.data, opts.ssrContext._payloadReducers) : ''
|
||||
return `<script ${attrs.join(' ')}>${contents}</script>` +
|
||||
`<script>window.__NUXT__={};window.__NUXT__.config=${uneval(opts.ssrContext.config)}</script>`
|
||||
}
|
||||
|
||||
function renderPayloadScript (opts: { ssrContext: NuxtSSRContext, data?: any, src?: string }) {
|
||||
opts.data.config = opts.ssrContext.config
|
||||
const _PAYLOAD_EXTRACTION = process.env.prerender && process.env.NUXT_PAYLOAD_EXTRACTION && !opts.ssrContext.noSSR
|
||||
if (_PAYLOAD_EXTRACTION) {
|
||||
return `<script type="module">import p from "${opts.src}";window.__NUXT__={...p,...(${devalue(opts.data)})}</script>`
|
||||
}
|
||||
return `<script>window.__NUXT__=${devalue(opts.data)}</script>`
|
||||
}
|
||||
|
||||
function splitPayload (ssrContext: NuxtSSRContext) {
|
||||
const { data, prerenderedAt, ...initial } = ssrContext.payload
|
||||
return {
|
||||
|
@ -1,13 +1,13 @@
|
||||
import { existsSync } from 'node:fs'
|
||||
import { writeFile, mkdir } from 'node:fs/promises'
|
||||
import { mkdir, writeFile } from 'node:fs/promises'
|
||||
import { dirname, resolve } from 'pathe'
|
||||
import chokidar from 'chokidar'
|
||||
import { defu } from 'defu'
|
||||
import { debounce } from 'perfect-debounce'
|
||||
import { defineNuxtModule, createResolver } from '@nuxt/kit'
|
||||
import { createResolver, defineNuxtModule } from '@nuxt/kit'
|
||||
import {
|
||||
resolveSchema as resolveUntypedSchema,
|
||||
generateTypes
|
||||
generateTypes,
|
||||
resolveSchema as resolveUntypedSchema
|
||||
} from 'untyped'
|
||||
import type { Schema, SchemaDefinition } from 'untyped'
|
||||
// @ts-ignore
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { genArrayFromRaw, genDynamicImport, genExport, genImport, genObjectFromRawEntries, genString, genSafeVariableName } from 'knitwork'
|
||||
import { genArrayFromRaw, genDynamicImport, genExport, genImport, genObjectFromRawEntries, genSafeVariableName, genString } from 'knitwork'
|
||||
import { isAbsolute, join, relative, resolve } from 'pathe'
|
||||
import { resolveSchema, generateTypes } from 'untyped'
|
||||
import { generateTypes, resolveSchema } from 'untyped'
|
||||
import escapeRE from 'escape-string-regexp'
|
||||
import { hash } from 'ohash'
|
||||
import { camelCase } from 'scule'
|
||||
@ -40,6 +40,11 @@ export const errorComponentTemplate: NuxtTemplate<TemplateContext> = {
|
||||
filename: 'error-component.mjs',
|
||||
getContents: ctx => genExport(ctx.app.errorComponent!, ['default'])
|
||||
}
|
||||
// TODO: Use an alias
|
||||
export const testComponentWrapperTemplate = {
|
||||
filename: 'test-component-wrapper.mjs',
|
||||
getContents: (ctx: TemplateContext) => genExport(resolve(ctx.nuxt.options.appDir, 'components/test-component-wrapper'), ['default'])
|
||||
}
|
||||
|
||||
export const cssTemplate: NuxtTemplate<TemplateContext> = {
|
||||
filename: 'css.mjs',
|
||||
@ -219,10 +224,10 @@ type IsAny<T> = 0 extends 1 & T ? true : false
|
||||
|
||||
type MergedAppConfig<Resolved extends Record<string, any>, Custom extends Record<string, any>> = {
|
||||
[K in keyof Resolved]: K extends keyof Custom
|
||||
? Custom[K] extends Record<string, any>
|
||||
? IsAny<Custom[K]> extends true
|
||||
? Resolved[K]
|
||||
: Resolved[K] extends Record<string, any>
|
||||
: Custom[K] extends Record<string, any>
|
||||
? Resolved[K] extends Record<string, any>
|
||||
? MergedAppConfig<Resolved[K], Custom[K]>
|
||||
: Exclude<Custom[K], undefined>
|
||||
: Exclude<Custom[K], undefined>
|
||||
@ -291,6 +296,7 @@ export const nuxtConfigTemplate = {
|
||||
getContents: (ctx: TemplateContext) => {
|
||||
return [
|
||||
...Object.entries(ctx.nuxt.options.app).map(([k, v]) => `export const ${camelCase('app-' + k)} = ${JSON.stringify(v)}`),
|
||||
`export const renderJsonPayloads = ${!!ctx.nuxt.options.experimental.renderJsonPayloads}`,
|
||||
`export const devPagesDir = ${ctx.nuxt.options.dev ? JSON.stringify(ctx.nuxt.options.dir.pages) : 'null'}`
|
||||
].join('\n\n')
|
||||
}
|
||||
|
@ -14,14 +14,6 @@ export default defineNuxtModule({
|
||||
// Transpile @unhead/vue
|
||||
nuxt.options.build.transpile.push('@unhead/vue')
|
||||
|
||||
// TODO: remove alias in v3.4
|
||||
nuxt.options.alias['#head'] = nuxt.options.alias['#app']
|
||||
nuxt.hook('prepare:types', ({ tsConfig }) => {
|
||||
tsConfig.compilerOptions = tsConfig.compilerOptions || {}
|
||||
delete tsConfig.compilerOptions.paths['#head']
|
||||
delete tsConfig.compilerOptions.paths['#head/*']
|
||||
})
|
||||
|
||||
// Register components
|
||||
const componentsPath = resolve(runtimeDir, 'components')
|
||||
for (const componentName of components) {
|
||||
|
@ -4,7 +4,9 @@ import { defineNuxtPlugin } from '#app/nuxt'
|
||||
// @ts-expect-error untyped
|
||||
import { appHead } from '#build/nuxt.config.mjs'
|
||||
|
||||
export default defineNuxtPlugin((nuxtApp) => {
|
||||
export default defineNuxtPlugin({
|
||||
name: 'nuxt:head',
|
||||
setup (nuxtApp) {
|
||||
const createHead = process.server ? createServerHead : createClientHead
|
||||
const head = createHead()
|
||||
head.push(appHead)
|
||||
@ -38,4 +40,5 @@ export default defineNuxtPlugin((nuxtApp) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -2,7 +2,10 @@
|
||||
import { polyfillAsVueUseHead } from '@unhead/vue/polyfill'
|
||||
import { defineNuxtPlugin } from '#app/nuxt'
|
||||
|
||||
export default defineNuxtPlugin((nuxtApp) => {
|
||||
export default defineNuxtPlugin({
|
||||
name: 'nuxt:vueuse-head-polyfill',
|
||||
setup (nuxtApp) {
|
||||
// avoid breaking ecosystem dependencies using low-level @vueuse/head APIs
|
||||
polyfillAsVueUseHead(nuxtApp.vueApp._context.provides.usehead)
|
||||
}
|
||||
})
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { addVitePlugin, addWebpackPlugin, defineNuxtModule, addTemplate, resolveAlias, useNuxt, updateTemplates } from '@nuxt/kit'
|
||||
import { isAbsolute, join, relative, resolve, normalize } from 'pathe'
|
||||
import { addTemplate, addVitePlugin, addWebpackPlugin, defineNuxtModule, resolveAlias, updateTemplates, useNuxt } from '@nuxt/kit'
|
||||
import { isAbsolute, join, normalize, relative, resolve } from 'pathe'
|
||||
import type { Import, Unimport } from 'unimport'
|
||||
import { createUnimport, scanDirExports } from 'unimport'
|
||||
import type { ImportsOptions, ImportPresetWithDeprecation } from 'nuxt/schema'
|
||||
import type { ImportPresetWithDeprecation, ImportsOptions } from 'nuxt/schema'
|
||||
|
||||
import { TransformPlugin } from './transform'
|
||||
import { defaultPresets } from './presets'
|
||||
|
@ -23,6 +23,7 @@ const appPreset = defineUnimportPreset({
|
||||
'defineNuxtComponent',
|
||||
'useNuxtApp',
|
||||
'defineNuxtPlugin',
|
||||
'definePayloadPlugin',
|
||||
'reloadNuxtApp',
|
||||
'useRuntimeConfig',
|
||||
'useState',
|
||||
@ -55,7 +56,9 @@ const appPreset = defineUnimportPreset({
|
||||
'prefetchComponents',
|
||||
'loadPayload',
|
||||
'preloadPayload',
|
||||
'isPrerendered'
|
||||
'isPrerendered',
|
||||
'definePayloadReducer',
|
||||
'definePayloadReviver'
|
||||
]
|
||||
})
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
import { existsSync, readdirSync } from 'node:fs'
|
||||
import { defineNuxtModule, addTemplate, addPlugin, addVitePlugin, addWebpackPlugin, findPath, addComponent, updateTemplates } from '@nuxt/kit'
|
||||
import { addComponent, addPlugin, addTemplate, addVitePlugin, addWebpackPlugin, defineNuxtModule, findPath, updateTemplates } from '@nuxt/kit'
|
||||
import { join, relative, resolve } from 'pathe'
|
||||
import { genString, genImport, genObjectFromRawEntries } from 'knitwork'
|
||||
import { genImport, genObjectFromRawEntries, genString } from 'knitwork'
|
||||
import escapeRE from 'escape-string-regexp'
|
||||
import { joinURL } from 'ufo'
|
||||
import type { NuxtApp, NuxtPage } from 'nuxt/schema'
|
||||
|
||||
import { distDir } from '../dirs'
|
||||
import { resolvePagesRoutes, normalizeRoutes } from './utils'
|
||||
import { normalizeRoutes, resolvePagesRoutes } from './utils'
|
||||
import type { PageMetaPluginOptions } from './page-meta'
|
||||
import { PageMetaPlugin } from './page-meta'
|
||||
|
||||
@ -156,8 +156,10 @@ export default defineNuxtModule({
|
||||
layer => resolve(layer.config.srcDir, layer.config.dir?.pages || 'pages')
|
||||
)
|
||||
}
|
||||
nuxt.hook('modules:done', () => {
|
||||
addVitePlugin(PageMetaPlugin.vite(pageMetaOptions))
|
||||
addWebpackPlugin(PageMetaPlugin.webpack(pageMetaOptions))
|
||||
})
|
||||
|
||||
// Add prefetching support for middleware & layouts
|
||||
addPlugin(resolve(runtimeDir, 'plugins/prefetch.client'))
|
||||
|
@ -2,8 +2,8 @@ import { pathToFileURL } from 'node:url'
|
||||
import { createUnplugin } from 'unplugin'
|
||||
import { parseQuery, parseURL } from 'ufo'
|
||||
import type { StaticImport } from 'mlly'
|
||||
import { findStaticImports, findExports, parseStaticImport } from 'mlly'
|
||||
import type { CallExpression, Identifier, Expression } from 'estree'
|
||||
import { findExports, findStaticImports, parseStaticImport } from 'mlly'
|
||||
import type { CallExpression, Expression, Identifier } from 'estree'
|
||||
import type { Node } from 'estree-walker'
|
||||
import { walk } from 'estree-walker'
|
||||
import MagicString from 'magic-string'
|
||||
|
@ -1,15 +1,15 @@
|
||||
import { computed, defineComponent, h, provide, reactive, onMounted, nextTick, Suspense, Transition } from 'vue'
|
||||
import type { VNode, KeepAliveProps, TransitionProps } from 'vue'
|
||||
import { Suspense, Transition, computed, defineComponent, h, nextTick, onMounted, provide, reactive } from 'vue'
|
||||
import type { KeepAliveProps, TransitionProps, VNode } from 'vue'
|
||||
import { RouterView } from 'vue-router'
|
||||
import { defu } from 'defu'
|
||||
import type { RouteLocationNormalized, RouteLocationNormalizedLoaded, RouteLocation } from 'vue-router'
|
||||
import type { RouteLocation, RouteLocationNormalized, RouteLocationNormalizedLoaded } from 'vue-router'
|
||||
|
||||
import type { RouterViewSlotProps } from './utils'
|
||||
import { generateRouteKey, wrapInKeepAlive } from './utils'
|
||||
import { useNuxtApp } from '#app/nuxt'
|
||||
import { _wrapIf } from '#app/components/utils'
|
||||
// @ts-ignore
|
||||
import { appPageTransition as defaultPageTransition, appKeepalive as defaultKeepaliveConfig } from '#build/nuxt.config.mjs'
|
||||
import { appKeepalive as defaultKeepaliveConfig, appPageTransition as defaultPageTransition } from '#build/nuxt.config.mjs'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'NuxtPage',
|
||||
|
@ -1,13 +1,14 @@
|
||||
import { hasProtocol } from 'ufo'
|
||||
import { defineNuxtPlugin, useNuxtApp } from '#app/nuxt'
|
||||
import { defineNuxtPlugin } from '#app/nuxt'
|
||||
import { useRouter } from '#app/composables/router'
|
||||
// @ts-ignore
|
||||
import layouts from '#build/layouts'
|
||||
// @ts-ignore
|
||||
import { namedMiddleware } from '#build/middleware'
|
||||
|
||||
export default defineNuxtPlugin(() => {
|
||||
const nuxtApp = useNuxtApp()
|
||||
export default defineNuxtPlugin({
|
||||
name: 'nuxt:prefetch',
|
||||
setup (nuxtApp) {
|
||||
const router = useRouter()
|
||||
|
||||
// Force layout prefetch on route changes
|
||||
@ -38,4 +39,5 @@ export default defineNuxtPlugin(() => {
|
||||
layouts[layout]()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
@ -2,17 +2,17 @@ import { computed, isReadonly, reactive, shallowRef } from 'vue'
|
||||
import type { Ref } from 'vue'
|
||||
import type { RouteLocation, Router } from 'vue-router'
|
||||
import {
|
||||
createRouter,
|
||||
createWebHistory,
|
||||
createMemoryHistory,
|
||||
createWebHashHistory
|
||||
createRouter,
|
||||
createWebHashHistory,
|
||||
createWebHistory
|
||||
} from 'vue-router'
|
||||
import { createError } from 'h3'
|
||||
import { withoutBase, isEqual } from 'ufo'
|
||||
import { isEqual, withoutBase } from 'ufo'
|
||||
|
||||
import type { PageMeta, RouteMiddleware, Plugin } from '../../../app/index'
|
||||
import type { PageMeta, Plugin, RouteMiddleware } from '../../../app/index'
|
||||
import { callWithNuxt, defineNuxtPlugin, useRuntimeConfig } from '#app/nuxt'
|
||||
import { showError, clearError, useError } from '#app/composables/error'
|
||||
import { clearError, showError, useError } from '#app/composables/error'
|
||||
import { useRequestEvent } from '#app/composables/ssr'
|
||||
import { useState } from '#app/composables/state'
|
||||
import { navigateTo } from '#app/composables/router'
|
||||
@ -45,7 +45,10 @@ function createCurrentLocation (
|
||||
return path + search + hash
|
||||
}
|
||||
|
||||
export default defineNuxtPlugin(async (nuxtApp) => {
|
||||
export default defineNuxtPlugin({
|
||||
name: 'nuxt:router',
|
||||
enforce: 'pre',
|
||||
async setup (nuxtApp) {
|
||||
let routerBase = useRuntimeConfig().app.baseURL
|
||||
if (routerOptions.hashMode && !routerBase.includes('#')) {
|
||||
// allow the user to provide a `#` in the middle: `/base/#/app`
|
||||
@ -198,4 +201,5 @@ export default defineNuxtPlugin(async (nuxtApp) => {
|
||||
})
|
||||
|
||||
return { provide: { router } }
|
||||
}
|
||||
}) as Plugin<{ router: Router }>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import type { RouterScrollBehavior, RouteLocationNormalized } from 'vue-router'
|
||||
import type { RouteLocationNormalized, RouterScrollBehavior } from 'vue-router'
|
||||
import { nextTick } from 'vue'
|
||||
import type { RouterConfig } from 'nuxt/schema'
|
||||
import { useNuxtApp } from '#app/nuxt'
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { KeepAlive, h } from 'vue'
|
||||
import type { RouterView, RouteLocationMatched, RouteLocationNormalizedLoaded } from 'vue-router'
|
||||
import type { RouteLocationMatched, RouteLocationNormalizedLoaded, RouterView } from 'vue-router'
|
||||
|
||||
type InstanceOf<T> = T extends new (...args: any[]) => infer R ? R : never
|
||||
type RouterViewSlot = Exclude<InstanceOf<typeof RouterView>['$slots']['default'], undefined>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user