Merge branch 'main' of github.com:nuxt/nuxt3 into main

This commit is contained in:
Pooya Parsa 2021-02-09 15:56:21 +01:00
commit b4251b1389
7 changed files with 49 additions and 36 deletions

View File

@ -1,25 +1,22 @@
import { Ref, toRef, onMounted, watch, getCurrentInstance, onUnmounted } from 'vue' import { Ref, ref, toRef, onMounted, watch, getCurrentInstance, onUnmounted } from 'vue'
import { Nuxt, useNuxt } from 'nuxt/app' import { Nuxt, useNuxt } from 'nuxt/app'
import { $fetch } from 'ohmyfetch'
import { useData } from './data' import { useData } from './data'
export type HTTPRequest = string | { method: string, url: string } export type AsyncDataFn<T> = (ctx?: Nuxt) => Promise<T>
export type FetchRequest<T> = HTTPRequest | ((ctx: Nuxt) => HTTPRequest | Promise<T>)
export interface FetchOptions { export interface AsyncDataOptions {
server?: boolean server?: boolean
defer?: boolean defer?: boolean
fetcher?: Function
key?: string
} }
export interface FetchObj<T> { export interface AsyncDataObj<T> {
data: Ref<T> data: Ref<T>
fetch: Function pending: Ref<boolean>
refresh: Function
error?: any error?: any
} }
export function useFetch (defaults?: FetchOptions) { export function useAsyncData (defaults?: AsyncDataOptions) {
const nuxt = useNuxt() const nuxt = useNuxt()
const vm = getCurrentInstance() const vm = getCurrentInstance()
@ -40,31 +37,32 @@ export function useFetch (defaults?: FetchOptions) {
}) })
} }
return async function fetch<T = any> (request: FetchRequest<T>, options?: FetchOptions): Promise<FetchObj<T>> { return async function asyncData<T = any> (handler: AsyncDataFn<T>, options?: AsyncDataOptions): Promise<AsyncDataObj<T>> {
if (typeof handler !== 'function') {
throw new TypeError('asyncData handler must be a function')
}
options = { options = {
server: true, server: true,
defer: false, defer: false,
fetcher: globalThis.$fetch || $fetch,
...defaults, ...defaults,
...options ...options
} }
const key = String(dataRef++) const key = String(dataRef++)
const pending = ref(true)
const fetch = async () => { const fetch = async () => {
const _request = typeof request === 'function' pending.value = true
? request(nuxt) const _handler = handler(nuxt)
: request
if (_request instanceof Promise) { if (_handler instanceof Promise) {
// Let user resolve if request is promise // Let user resolve if request is promise
data[key] = await _request // TODO: handle error
} else if (_request && (typeof _request === 'string' || _request.url)) { data[key] = await _handler
// Make HTTP request when request is string (url) or { url, ...opts } pending.value = false
data[key] = await options.fetcher(_request)
} else { } else {
// Invalid request // Invalid request
throw new Error('Invalid fetch request: ' + _request) throw new TypeError('Invalid asyncData handler: ' + _handler)
} }
} }
@ -73,6 +71,9 @@ export function useFetch (defaults?: FetchOptions) {
// Client side // Client side
if (process.client) { if (process.client) {
// 1. Hydration (server: true): no fetch // 1. Hydration (server: true): no fetch
if (nuxt.isHydrating && options.server) {
pending.value = false
}
// 2. Initial load (server: false): fetch on mounted // 2. Initial load (server: false): fetch on mounted
if (nuxt.isHydrating && !options.server) { if (nuxt.isHydrating && !options.server) {
// Fetch on mounted (initial load or deferred fetch) // Fetch on mounted (initial load or deferred fetch)
@ -86,10 +87,8 @@ export function useFetch (defaults?: FetchOptions) {
await fetch() await fetch()
} }
} }
// Watch request // Watch handler
if (typeof request === 'function') { watch(handler.bind(null, nuxt), fetch)
watch(request, fetch)
}
} }
// Server side // Server side
@ -99,7 +98,8 @@ export function useFetch (defaults?: FetchOptions) {
return { return {
data: toRef<any, string>(data, key), data: toRef<any, string>(data, key),
fetch pending,
refresh: fetch
} }
} }
} }

View File

@ -1,3 +1,3 @@
export { useFetch } from './fetch' export { useAsyncData } from './asyncData'
export { useData } from './data' export { useData } from './data'
export { useHydration } from './hydrate' export { useHydration } from './hydrate'

View File

@ -51,11 +51,13 @@ export function createNuxt (options: CreateOptions) {
nuxt.provide = (name: string, value: any) => { nuxt.provide = (name: string, value: any) => {
const $name = '$' + name const $name = '$' + name
defineGetter(nuxt.app, $name, value) defineGetter(nuxt, $name, value)
defineGetter(nuxt.app.config.globalProperties, $name, value) defineGetter(nuxt.app.config.globalProperties, $name, value)
} }
nuxt.provide('nuxt', nuxt) // Inject $nuxt
defineGetter(nuxt.app, '$nuxt', nuxt)
defineGetter(nuxt.app.config.globalProperties, '$nuxt', nuxt)
// Expose nuxt to the renderContext // Expose nuxt to the renderContext
if (nuxt.ssrContext) { if (nuxt.ssrContext) {

View File

@ -0,0 +1,6 @@
<template>
<div>
<!-- TODO: Move this page to @nuxt/nice -->
404 | Page Not Found
</div>
</template>

View File

@ -13,11 +13,6 @@ import routes from '~build/routes'
export default <Plugin> function router (nuxt) { export default <Plugin> function router (nuxt) {
const { app } = nuxt const { app } = nuxt
// TODO: move this outside this plugin
if (!routes.length) {
return
}
app.component('NuxtPage', NuxtPage) app.component('NuxtPage', NuxtPage)
app.component('NuxtLink', RouterLink) app.component('NuxtLink', RouterLink)

View File

@ -43,6 +43,16 @@ export async function createApp (
if (app.pages) { if (app.pages) {
app.routes.push(...(await resolvePagesRoutes(builder, app))) app.routes.push(...(await resolvePagesRoutes(builder, app)))
} }
// Add 404 page is not added
const page404 = app.routes.find(route => route.name === '404')
if (!page404) {
app.routes.push({
name: '404',
path: '/:catchAll(.*)*',
file: resolve(nuxt.options.appDir, 'pages/404.vue'),
children: []
})
}
// TODO: Hook to extend routes // TODO: Hook to extend routes
app.templates.routes = serializeRoutes(app.routes) app.templates.routes = serializeRoutes(app.routes)
@ -69,7 +79,7 @@ function formatRoute (route: NuxtRoute) {
name: route.name, name: route.name,
path: route.path, path: route.path,
children: route.children.map(formatRoute), children: route.children.map(formatRoute),
// TODO: avoid exposing to prod // TODO: avoid exposing to prod, using process.env.NODE_ENV ?
__file: route.file, __file: route.file,
component: `{() => import('${route.file}' /* webpackChunkName: '${route.name}' */)}` component: `{() => import('${route.file}' /* webpackChunkName: '${route.name}' */)}`
} }

View File

@ -299,7 +299,7 @@ function normalizeConfig (_options: CliConfiguration) {
// Append ignorePrefix glob to ignore // Append ignorePrefix glob to ignore
if (typeof options.ignorePrefix === 'string') { if (typeof options.ignorePrefix === 'string') {
options.ignore.push(`**/${options.ignorePrefix}*.*`) options.ignore.push(`${options.ignorePrefix}*`)
} }
// Compression middleware legacy // Compression middleware legacy