28 changed files with 3603 additions and 0 deletions
@ -0,0 +1,183 @@ |
|||||||
|
import Vue from 'vue' |
||||||
|
import { decode, parsePath, withoutBase, withoutTrailingSlash, normalizeURL } from 'ufo' |
||||||
|
|
||||||
|
import { getMatchedComponentsInstances, getChildrenComponentInstancesUsingFetch, promisify, globalHandleError, urlJoin, sanitizeComponent } from './utils' |
||||||
|
import NuxtError from '../src/layouts/error.vue' |
||||||
|
|
||||||
|
import '../node_modules/element-ui/lib/theme-chalk/index.css' |
||||||
|
|
||||||
|
import '../node_modules/video.js/dist/video-js.css' |
||||||
|
|
||||||
|
import '../node_modules/vue-video-player/src/custom-theme.css' |
||||||
|
|
||||||
|
import _6dce6561 from '../src/layouts/common.vue' |
||||||
|
import _6ef953c7 from '../src/layouts/detail.vue' |
||||||
|
import _6f6c098b from './layouts/default.vue' |
||||||
|
|
||||||
|
const layouts = { "_common": sanitizeComponent(_6dce6561),"_detail": sanitizeComponent(_6ef953c7),"_default": sanitizeComponent(_6f6c098b) } |
||||||
|
|
||||||
|
export default { |
||||||
|
render (h, props) { |
||||||
|
const layoutEl = h(this.layout || 'nuxt') |
||||||
|
const templateEl = h('div', { |
||||||
|
domProps: { |
||||||
|
id: '__layout' |
||||||
|
}, |
||||||
|
key: this.layoutName |
||||||
|
}, [layoutEl]) |
||||||
|
|
||||||
|
const transitionEl = h('transition', { |
||||||
|
props: { |
||||||
|
name: 'layout', |
||||||
|
mode: 'out-in' |
||||||
|
}, |
||||||
|
on: { |
||||||
|
beforeEnter (el) { |
||||||
|
// Ensure to trigger scroll event after calling scrollBehavior
|
||||||
|
window.$nuxt.$nextTick(() => { |
||||||
|
window.$nuxt.$emit('triggerScroll') |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
}, [templateEl]) |
||||||
|
|
||||||
|
return h('div', { |
||||||
|
domProps: { |
||||||
|
id: '__nuxt' |
||||||
|
} |
||||||
|
}, [ |
||||||
|
|
||||||
|
transitionEl |
||||||
|
]) |
||||||
|
}, |
||||||
|
|
||||||
|
data: () => ({ |
||||||
|
isOnline: true, |
||||||
|
|
||||||
|
layout: null, |
||||||
|
layoutName: '', |
||||||
|
|
||||||
|
nbFetching: 0 |
||||||
|
}), |
||||||
|
|
||||||
|
beforeCreate () { |
||||||
|
Vue.util.defineReactive(this, 'nuxt', this.$options.nuxt) |
||||||
|
}, |
||||||
|
created () { |
||||||
|
// Add this.$nuxt in child instances
|
||||||
|
this.$root.$options.$nuxt = this |
||||||
|
|
||||||
|
if (process.client) { |
||||||
|
// add to window so we can listen when ready
|
||||||
|
window.$nuxt = this |
||||||
|
|
||||||
|
this.refreshOnlineStatus() |
||||||
|
// Setup the listeners
|
||||||
|
window.addEventListener('online', this.refreshOnlineStatus) |
||||||
|
window.addEventListener('offline', this.refreshOnlineStatus) |
||||||
|
} |
||||||
|
// Add $nuxt.error()
|
||||||
|
this.error = this.nuxt.error |
||||||
|
// Add $nuxt.context
|
||||||
|
this.context = this.$options.context |
||||||
|
}, |
||||||
|
|
||||||
|
watch: { |
||||||
|
'nuxt.err': 'errorChanged' |
||||||
|
}, |
||||||
|
|
||||||
|
computed: { |
||||||
|
isOffline () { |
||||||
|
return !this.isOnline |
||||||
|
}, |
||||||
|
|
||||||
|
isFetching () { |
||||||
|
return this.nbFetching > 0 |
||||||
|
}, |
||||||
|
}, |
||||||
|
|
||||||
|
methods: { |
||||||
|
refreshOnlineStatus () { |
||||||
|
if (process.client) { |
||||||
|
if (typeof window.navigator.onLine === 'undefined') { |
||||||
|
// If the browser doesn't support connection status reports
|
||||||
|
// assume that we are online because most apps' only react
|
||||||
|
// when they now that the connection has been interrupted
|
||||||
|
this.isOnline = true |
||||||
|
} else { |
||||||
|
this.isOnline = window.navigator.onLine |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
async refresh () { |
||||||
|
const pages = getMatchedComponentsInstances(this.$route) |
||||||
|
|
||||||
|
if (!pages.length) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
const promises = pages.map((page) => { |
||||||
|
const p = [] |
||||||
|
|
||||||
|
// Old fetch
|
||||||
|
if (page.$options.fetch && page.$options.fetch.length) { |
||||||
|
p.push(promisify(page.$options.fetch, this.context)) |
||||||
|
} |
||||||
|
if (page.$fetch) { |
||||||
|
p.push(page.$fetch()) |
||||||
|
} else { |
||||||
|
// Get all component instance to call $fetch
|
||||||
|
for (const component of getChildrenComponentInstancesUsingFetch(page.$vnode.componentInstance)) { |
||||||
|
p.push(component.$fetch()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (page.$options.asyncData) { |
||||||
|
p.push( |
||||||
|
promisify(page.$options.asyncData, this.context) |
||||||
|
.then((newData) => { |
||||||
|
for (const key in newData) { |
||||||
|
Vue.set(page.$data, key, newData[key]) |
||||||
|
} |
||||||
|
}) |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
return Promise.all(p) |
||||||
|
}) |
||||||
|
try { |
||||||
|
await Promise.all(promises) |
||||||
|
} catch (error) { |
||||||
|
globalHandleError(error) |
||||||
|
this.error(error) |
||||||
|
} |
||||||
|
}, |
||||||
|
errorChanged () { |
||||||
|
if (this.nuxt.err) { |
||||||
|
let errorLayout = (NuxtError.options || NuxtError).layout; |
||||||
|
|
||||||
|
if (typeof errorLayout === 'function') { |
||||||
|
errorLayout = errorLayout(this.context) |
||||||
|
} |
||||||
|
|
||||||
|
this.setLayout(errorLayout) |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
setLayout (layout) { |
||||||
|
if (!layout || !layouts['_' + layout]) { |
||||||
|
layout = 'default' |
||||||
|
} |
||||||
|
this.layoutName = layout |
||||||
|
this.layout = layouts['_' + layout] |
||||||
|
return this.layout |
||||||
|
}, |
||||||
|
loadLayout (layout) { |
||||||
|
if (!layout || !layouts['_' + layout]) { |
||||||
|
layout = 'default' |
||||||
|
} |
||||||
|
return Promise.resolve(layouts['_' + layout]) |
||||||
|
}, |
||||||
|
}, |
||||||
|
} |
@ -0,0 +1,205 @@ |
|||||||
|
import Axios from 'axios' |
||||||
|
import defu from 'defu' |
||||||
|
|
||||||
|
// Axios.prototype cannot be modified
|
||||||
|
const axiosExtra = { |
||||||
|
setBaseURL (baseURL) { |
||||||
|
this.defaults.baseURL = baseURL |
||||||
|
}, |
||||||
|
setHeader (name, value, scopes = 'common') { |
||||||
|
for (const scope of Array.isArray(scopes) ? scopes : [ scopes ]) { |
||||||
|
if (!value) { |
||||||
|
delete this.defaults.headers[scope][name]; |
||||||
|
continue |
||||||
|
} |
||||||
|
this.defaults.headers[scope][name] = value |
||||||
|
} |
||||||
|
}, |
||||||
|
setToken (token, type, scopes = 'common') { |
||||||
|
const value = !token ? null : (type ? type + ' ' : '') + token |
||||||
|
this.setHeader('Authorization', value, scopes) |
||||||
|
}, |
||||||
|
onRequest(fn) { |
||||||
|
this.interceptors.request.use(config => fn(config) || config) |
||||||
|
}, |
||||||
|
onResponse(fn) { |
||||||
|
this.interceptors.response.use(response => fn(response) || response) |
||||||
|
}, |
||||||
|
onRequestError(fn) { |
||||||
|
this.interceptors.request.use(undefined, error => fn(error) || Promise.reject(error)) |
||||||
|
}, |
||||||
|
onResponseError(fn) { |
||||||
|
this.interceptors.response.use(undefined, error => fn(error) || Promise.reject(error)) |
||||||
|
}, |
||||||
|
onError(fn) { |
||||||
|
this.onRequestError(fn) |
||||||
|
this.onResponseError(fn) |
||||||
|
}, |
||||||
|
create(options) { |
||||||
|
return createAxiosInstance(defu(options, this.defaults)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Request helpers ($get, $post, ...)
|
||||||
|
for (const method of ['request', 'delete', 'get', 'head', 'options', 'post', 'put', 'patch']) { |
||||||
|
axiosExtra['$' + method] = function () { return this[method].apply(this, arguments).then(res => res && res.data) } |
||||||
|
} |
||||||
|
|
||||||
|
const extendAxiosInstance = axios => { |
||||||
|
for (const key in axiosExtra) { |
||||||
|
axios[key] = axiosExtra[key].bind(axios) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const createAxiosInstance = axiosOptions => { |
||||||
|
// Create new axios instance
|
||||||
|
const axios = Axios.create(axiosOptions) |
||||||
|
axios.CancelToken = Axios.CancelToken |
||||||
|
axios.isCancel = Axios.isCancel |
||||||
|
|
||||||
|
// Extend axios proto
|
||||||
|
extendAxiosInstance(axios) |
||||||
|
|
||||||
|
// Intercept to apply default headers
|
||||||
|
axios.onRequest((config) => { |
||||||
|
config.headers = { ...axios.defaults.headers.common, ...config.headers } |
||||||
|
}) |
||||||
|
|
||||||
|
// Setup interceptors
|
||||||
|
|
||||||
|
setupCredentialsInterceptor(axios) |
||||||
|
setupProgress(axios) |
||||||
|
|
||||||
|
return axios |
||||||
|
} |
||||||
|
|
||||||
|
const setupCredentialsInterceptor = axios => { |
||||||
|
// Send credentials only to relative and API Backend requests
|
||||||
|
axios.onRequest(config => { |
||||||
|
if (config.withCredentials === undefined) { |
||||||
|
if (!/^https?:\/\//i.test(config.url) || config.url.indexOf(config.baseURL) === 0) { |
||||||
|
config.withCredentials = true |
||||||
|
} |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
const setupProgress = (axios) => { |
||||||
|
if (process.server) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// A noop loading inteterface for when $nuxt is not yet ready
|
||||||
|
const noopLoading = { |
||||||
|
finish: () => { }, |
||||||
|
start: () => { }, |
||||||
|
fail: () => { }, |
||||||
|
set: () => { } |
||||||
|
} |
||||||
|
|
||||||
|
const $loading = () => { |
||||||
|
const $nuxt = typeof window !== 'undefined' && window['$nuxt'] |
||||||
|
return ($nuxt && $nuxt.$loading && $nuxt.$loading.set) ? $nuxt.$loading : noopLoading |
||||||
|
} |
||||||
|
|
||||||
|
let currentRequests = 0 |
||||||
|
|
||||||
|
axios.onRequest(config => { |
||||||
|
if (config && config.progress === false) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
currentRequests++ |
||||||
|
}) |
||||||
|
|
||||||
|
axios.onResponse(response => { |
||||||
|
if (response && response.config && response.config.progress === false) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
currentRequests-- |
||||||
|
if (currentRequests <= 0) { |
||||||
|
currentRequests = 0 |
||||||
|
$loading().finish() |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
axios.onError(error => { |
||||||
|
if (error && error.config && error.config.progress === false) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
currentRequests-- |
||||||
|
|
||||||
|
if (Axios.isCancel(error)) { |
||||||
|
if (currentRequests <= 0) { |
||||||
|
currentRequests = 0 |
||||||
|
$loading().finish() |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
$loading().fail() |
||||||
|
$loading().finish() |
||||||
|
}) |
||||||
|
|
||||||
|
const onProgress = e => { |
||||||
|
if (!currentRequests || !e.total) { |
||||||
|
return |
||||||
|
} |
||||||
|
const progress = ((e.loaded * 100) / (e.total * currentRequests)) |
||||||
|
$loading().set(Math.min(100, progress)) |
||||||
|
} |
||||||
|
|
||||||
|
axios.defaults.onUploadProgress = onProgress |
||||||
|
axios.defaults.onDownloadProgress = onProgress |
||||||
|
} |
||||||
|
|
||||||
|
export default (ctx, inject) => { |
||||||
|
// runtimeConfig
|
||||||
|
const runtimeConfig = ctx.$config && ctx.$config.axios || {} |
||||||
|
// baseURL
|
||||||
|
const baseURL = process.browser |
||||||
|
? (runtimeConfig.browserBaseURL || runtimeConfig.browserBaseUrl || runtimeConfig.baseURL || runtimeConfig.baseUrl || 'http://localhost:3000/web') |
||||||
|
: (runtimeConfig.baseURL || runtimeConfig.baseUrl || process.env._AXIOS_BASE_URL_ || 'http://localhost:3000/web') |
||||||
|
|
||||||
|
// Create fresh objects for all default header scopes
|
||||||
|
// Axios creates only one which is shared across SSR requests!
|
||||||
|
// https://github.com/mzabriskie/axios/blob/master/lib/defaults.js
|
||||||
|
const headers = { |
||||||
|
"common": { |
||||||
|
"Accept": "application/json, text/plain, */*" |
||||||
|
}, |
||||||
|
"delete": {}, |
||||||
|
"get": {}, |
||||||
|
"head": {}, |
||||||
|
"post": {}, |
||||||
|
"put": {}, |
||||||
|
"patch": {} |
||||||
|
} |
||||||
|
|
||||||
|
const axiosOptions = { |
||||||
|
baseURL, |
||||||
|
headers |
||||||
|
} |
||||||
|
|
||||||
|
// Proxy SSR request headers headers
|
||||||
|
if (process.server && ctx.req && ctx.req.headers) { |
||||||
|
const reqHeaders = { ...ctx.req.headers } |
||||||
|
for (const h of ["accept","cf-connecting-ip","cf-ray","content-length","content-md5","content-type","host","x-forwarded-host","x-forwarded-port","x-forwarded-proto"]) { |
||||||
|
delete reqHeaders[h] |
||||||
|
} |
||||||
|
axiosOptions.headers.common = { ...reqHeaders, ...axiosOptions.headers.common } |
||||||
|
} |
||||||
|
|
||||||
|
if (process.server) { |
||||||
|
// Don't accept brotli encoding because Node can't parse it
|
||||||
|
axiosOptions.headers.common['accept-encoding'] = 'gzip, deflate' |
||||||
|
} |
||||||
|
|
||||||
|
const axios = createAxiosInstance(axiosOptions) |
||||||
|
|
||||||
|
// Inject axios to the context as $axios
|
||||||
|
ctx.$axios = axios |
||||||
|
inject('axios', axios) |
||||||
|
} |
@ -0,0 +1,617 @@ |
|||||||
|
import Vue from 'vue' |
||||||
|
import fetch from 'unfetch' |
||||||
|
import middleware from './middleware.js' |
||||||
|
import { |
||||||
|
applyAsyncData, |
||||||
|
promisify, |
||||||
|
middlewareSeries, |
||||||
|
sanitizeComponent, |
||||||
|
resolveRouteComponents, |
||||||
|
getMatchedComponents, |
||||||
|
getMatchedComponentsInstances, |
||||||
|
flatMapComponents, |
||||||
|
setContext, |
||||||
|
getLocation, |
||||||
|
compile, |
||||||
|
getQueryDiff, |
||||||
|
globalHandleError, |
||||||
|
isSamePath, |
||||||
|
urlJoin |
||||||
|
} from './utils.js' |
||||||
|
import { createApp, NuxtError } from './index.js' |
||||||
|
import fetchMixin from './mixins/fetch.client' |
||||||
|
import NuxtLink from './components/nuxt-link.client.js' // should be included after ./index.js
|
||||||
|
|
||||||
|
// Fetch mixin
|
||||||
|
if (!Vue.__nuxt__fetch__mixin__) { |
||||||
|
Vue.mixin(fetchMixin) |
||||||
|
Vue.__nuxt__fetch__mixin__ = true |
||||||
|
} |
||||||
|
|
||||||
|
// Component: <NuxtLink>
|
||||||
|
Vue.component(NuxtLink.name, NuxtLink) |
||||||
|
Vue.component('NLink', NuxtLink) |
||||||
|
|
||||||
|
if (!global.fetch) { global.fetch = fetch } |
||||||
|
|
||||||
|
// Global shared references
|
||||||
|
let _lastPaths = [] |
||||||
|
let app |
||||||
|
let router |
||||||
|
let store |
||||||
|
|
||||||
|
// Try to rehydrate SSR data from window
|
||||||
|
const NUXT = window.__NUXT__ || {} |
||||||
|
|
||||||
|
const $config = NUXT.config || {} |
||||||
|
if ($config._app) { |
||||||
|
__webpack_public_path__ = urlJoin($config._app.cdnURL, $config._app.assetsPath) |
||||||
|
} |
||||||
|
|
||||||
|
Object.assign(Vue.config, {"silent":true,"performance":false}) |
||||||
|
|
||||||
|
const errorHandler = Vue.config.errorHandler || console.error |
||||||
|
|
||||||
|
// Create and mount App
|
||||||
|
createApp(null, NUXT.config).then(mountApp).catch(errorHandler) |
||||||
|
|
||||||
|
function componentOption (component, key, ...args) { |
||||||
|
if (!component || !component.options || !component.options[key]) { |
||||||
|
return {} |
||||||
|
} |
||||||
|
const option = component.options[key] |
||||||
|
if (typeof option === 'function') { |
||||||
|
return option(...args) |
||||||
|
} |
||||||
|
return option |
||||||
|
} |
||||||
|
|
||||||
|
function mapTransitions (toComponents, to, from) { |
||||||
|
const componentTransitions = (component) => { |
||||||
|
const transition = componentOption(component, 'transition', to, from) || {} |
||||||
|
return (typeof transition === 'string' ? { name: transition } : transition) |
||||||
|
} |
||||||
|
|
||||||
|
const fromComponents = from ? getMatchedComponents(from) : [] |
||||||
|
const maxDepth = Math.max(toComponents.length, fromComponents.length) |
||||||
|
|
||||||
|
const mergedTransitions = [] |
||||||
|
for (let i=0; i<maxDepth; i++) { |
||||||
|
// Clone original objects to prevent overrides
|
||||||
|
const toTransitions = Object.assign({}, componentTransitions(toComponents[i])) |
||||||
|
const transitions = Object.assign({}, componentTransitions(fromComponents[i])) |
||||||
|
|
||||||
|
// Combine transitions & prefer `leave` properties of "from" route
|
||||||
|
Object.keys(toTransitions) |
||||||
|
.filter(key => typeof toTransitions[key] !== 'undefined' && !key.toLowerCase().includes('leave')) |
||||||
|
.forEach((key) => { transitions[key] = toTransitions[key] }) |
||||||
|
|
||||||
|
mergedTransitions.push(transitions) |
||||||
|
} |
||||||
|
return mergedTransitions |
||||||
|
} |
||||||
|
|
||||||
|
async function loadAsyncComponents (to, from, next) { |
||||||
|
// Check if route changed (this._routeChanged), only if the page is not an error (for validate())
|
||||||
|
this._routeChanged = Boolean(app.nuxt.err) || from.name !== to.name |
||||||
|
this._paramChanged = !this._routeChanged && from.path !== to.path |
||||||
|
this._queryChanged = !this._paramChanged && from.fullPath !== to.fullPath |
||||||
|
this._diffQuery = (this._queryChanged ? getQueryDiff(to.query, from.query) : []) |
||||||
|
|
||||||
|
try { |
||||||
|
if (this._queryChanged) { |
||||||
|
const Components = await resolveRouteComponents( |
||||||
|
to, |
||||||
|
(Component, instance) => ({ Component, instance }) |
||||||
|
) |
||||||
|
// Add a marker on each component that it needs to refresh or not
|
||||||
|
const startLoader = Components.some(({ Component, instance }) => { |
||||||
|
const watchQuery = Component.options.watchQuery |
||||||
|
if (watchQuery === true) { |
||||||
|
return true |
||||||
|
} |
||||||
|
if (Array.isArray(watchQuery)) { |
||||||
|
return watchQuery.some(key => this._diffQuery[key]) |
||||||
|
} |
||||||
|
if (typeof watchQuery === 'function') { |
||||||
|
return watchQuery.apply(instance, [to.query, from.query]) |
||||||
|
} |
||||||
|
return false |
||||||
|
}) |
||||||
|
} |
||||||
|
// Call next()
|
||||||
|
next() |
||||||
|
} catch (error) { |
||||||
|
const err = error || {} |
||||||
|
const statusCode = err.statusCode || err.status || (err.response && err.response.status) || 500 |
||||||
|
const message = err.message || '' |
||||||
|
|
||||||
|
// Handle chunk loading errors
|
||||||
|
// This may be due to a new deployment or a network problem
|
||||||
|
if (/^Loading( CSS)? chunk (\d)+ failed\./.test(message)) { |
||||||
|
window.location.reload(true /* skip cache */) |
||||||
|
return // prevent error page blinking for user
|
||||||
|
} |
||||||
|
|
||||||
|
this.error({ statusCode, message }) |
||||||
|
this.$nuxt.$emit('routeChanged', to, from, err) |
||||||
|
next() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function applySSRData (Component, ssrData) { |
||||||
|
if (NUXT.serverRendered && ssrData) { |
||||||
|
applyAsyncData(Component, ssrData) |
||||||
|
} |
||||||
|
|
||||||
|
Component._Ctor = Component |
||||||
|
return Component |
||||||
|
} |
||||||
|
|
||||||
|
// Get matched components
|
||||||
|
function resolveComponents (route) { |
||||||
|
return flatMapComponents(route, async (Component, _, match, key, index) => { |
||||||
|
// If component is not resolved yet, resolve it
|
||||||
|
if (typeof Component === 'function' && !Component.options) { |
||||||
|
Component = await Component() |
||||||
|
} |
||||||
|
// Sanitize it and save it
|
||||||
|
const _Component = applySSRData(sanitizeComponent(Component), NUXT.data ? NUXT.data[index] : null) |
||||||
|
match.components[key] = _Component |
||||||
|
return _Component |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
function callMiddleware (Components, context, layout) { |
||||||
|
let midd = ["device"] |
||||||
|
let unknownMiddleware = false |
||||||
|
|
||||||
|
// If layout is undefined, only call global middleware
|
||||||
|
if (typeof layout !== 'undefined') { |
||||||
|
midd = [] // Exclude global middleware if layout defined (already called before)
|
||||||
|
layout = sanitizeComponent(layout) |
||||||
|
if (layout.options.middleware) { |
||||||
|
midd = midd.concat(layout.options.middleware) |
||||||
|
} |
||||||
|
Components.forEach((Component) => { |
||||||
|
if (Component.options.middleware) { |
||||||
|
midd = midd.concat(Component.options.middleware) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
midd = midd.map((name) => { |
||||||
|
if (typeof name === 'function') { |
||||||
|
return name |
||||||
|
} |
||||||
|
if (typeof middleware[name] !== 'function') { |
||||||
|
unknownMiddleware = true |
||||||
|
this.error({ statusCode: 500, message: 'Unknown middleware ' + name }) |
||||||
|
} |
||||||
|
return middleware[name] |
||||||
|
}) |
||||||
|
|
||||||
|
if (unknownMiddleware) { |
||||||
|
return |
||||||
|
} |
||||||
|
return middlewareSeries(midd, context) |
||||||
|
} |
||||||
|
|
||||||
|
async function render (to, from, next) { |
||||||
|
if (this._routeChanged === false && this._paramChanged === false && this._queryChanged === false) { |
||||||
|
return next() |
||||||
|
} |
||||||
|
// Handle first render on SPA mode
|
||||||
|
let spaFallback = false |
||||||
|
if (to === from) { |
||||||
|
_lastPaths = [] |
||||||
|
spaFallback = true |
||||||
|
} else { |
||||||
|
const fromMatches = [] |
||||||
|
_lastPaths = getMatchedComponents(from, fromMatches).map((Component, i) => { |
||||||
|
return compile(from.matched[fromMatches[i]].path)(from.params) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
// nextCalled is true when redirected
|
||||||
|
let nextCalled = false |
||||||
|
const _next = (path) => { |
||||||
|
if (nextCalled) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
nextCalled = true |
||||||
|
next(path) |
||||||
|
} |
||||||
|
|
||||||
|
// Update context
|
||||||
|
await setContext(app, { |
||||||
|
route: to, |
||||||
|
from, |
||||||
|
next: _next.bind(this) |
||||||
|
}) |
||||||
|
this._dateLastError = app.nuxt.dateErr |
||||||
|
this._hadError = Boolean(app.nuxt.err) |
||||||
|
|
||||||
|
// Get route's matched components
|
||||||
|
const matches = [] |
||||||
|
const Components = getMatchedComponents(to, matches) |
||||||
|
|
||||||
|
// If no Components matched, generate 404
|
||||||
|
if (!Components.length) { |
||||||
|
// Default layout
|
||||||
|
await callMiddleware.call(this, Components, app.context) |
||||||
|
if (nextCalled) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// Load layout for error page
|
||||||
|
const errorLayout = (NuxtError.options || NuxtError).layout |
||||||
|
const layout = await this.loadLayout( |
||||||
|
typeof errorLayout === 'function' |
||||||
|
? errorLayout.call(NuxtError, app.context) |
||||||
|
: errorLayout |
||||||
|
) |
||||||
|
|
||||||
|
await callMiddleware.call(this, Components, app.context, layout) |
||||||
|
if (nextCalled) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// Show error page
|
||||||
|
app.context.error({ statusCode: 404, message: 'This page could not be found' }) |
||||||
|
return next() |
||||||
|
} |
||||||
|
|
||||||
|
// Update ._data and other properties if hot reloaded
|
||||||
|
Components.forEach((Component) => { |
||||||
|
if (Component._Ctor && Component._Ctor.options) { |
||||||
|
Component.options.asyncData = Component._Ctor.options.asyncData |
||||||
|
Component.options.fetch = Component._Ctor.options.fetch |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
// Apply transitions
|
||||||
|
this.setTransitions(mapTransitions(Components, to, from)) |
||||||
|
|
||||||
|
try { |
||||||
|
// Call middleware
|
||||||
|
await callMiddleware.call(this, Components, app.context) |
||||||
|
if (nextCalled) { |
||||||
|
return |
||||||
|
} |
||||||
|
if (app.context._errored) { |
||||||
|
return next() |
||||||
|
} |
||||||
|
|
||||||
|
// Set layout
|
||||||
|
let layout = Components[0].options.layout |
||||||
|
if (typeof layout === 'function') { |
||||||
|
layout = layout(app.context) |
||||||
|
} |
||||||
|
layout = await this.loadLayout(layout) |
||||||
|
|
||||||
|
// Call middleware for layout
|
||||||
|
await callMiddleware.call(this, Components, app.context, layout) |
||||||
|
if (nextCalled) { |
||||||
|
return |
||||||
|
} |
||||||
|
if (app.context._errored) { |
||||||
|
return next() |
||||||
|
} |
||||||
|
|
||||||
|
// Call .validate()
|
||||||
|
let isValid = true |
||||||
|
try { |
||||||
|
for (const Component of Components) { |
||||||
|
if (typeof Component.options.validate !== 'function') { |
||||||
|
continue |
||||||
|
} |
||||||
|
|
||||||
|
isValid = await Component.options.validate(app.context) |
||||||
|
|
||||||
|
if (!isValid) { |
||||||
|
break |
||||||
|
} |
||||||
|
} |
||||||
|
} catch (validationError) { |
||||||
|
// ...If .validate() threw an error
|
||||||
|
this.error({ |
||||||
|
statusCode: validationError.statusCode || '500', |
||||||
|
message: validationError.message |
||||||
|
}) |
||||||
|
return next() |
||||||
|
} |
||||||
|
|
||||||
|
// ...If .validate() returned false
|
||||||
|
if (!isValid) { |
||||||
|
this.error({ statusCode: 404, message: 'This page could not be found' }) |
||||||
|
return next() |
||||||
|
} |
||||||
|
|
||||||
|
let instances |
||||||
|
// Call asyncData & fetch hooks on components matched by the route.
|
||||||
|
await Promise.all(Components.map(async (Component, i) => { |
||||||
|
// Check if only children route changed
|
||||||
|
Component._path = compile(to.matched[matches[i]].path)(to.params) |
||||||
|
Component._dataRefresh = false |
||||||
|
const childPathChanged = Component._path !== _lastPaths[i] |
||||||
|
// Refresh component (call asyncData & fetch) when:
|
||||||
|
// Route path changed part includes current component
|
||||||
|
// Or route param changed part includes current component and watchParam is not `false`
|
||||||
|
// Or route query is changed and watchQuery returns `true`
|
||||||
|
if (this._routeChanged && childPathChanged) { |
||||||
|
Component._dataRefresh = true |
||||||
|
} else if (this._paramChanged && childPathChanged) { |
||||||
|
const watchParam = Component.options.watchParam |
||||||
|
Component._dataRefresh = watchParam !== false |
||||||
|
} else if (this._queryChanged) { |
||||||
|
const watchQuery = Component.options.watchQuery |
||||||
|
if (watchQuery === true) { |
||||||
|
Component._dataRefresh = true |
||||||
|
} else if (Array.isArray(watchQuery)) { |
||||||
|
Component._dataRefresh = watchQuery.some(key => this._diffQuery[key]) |
||||||
|
} else if (typeof watchQuery === 'function') { |
||||||
|
if (!instances) { |
||||||
|
instances = getMatchedComponentsInstances(to) |
||||||
|
} |
||||||
|
Component._dataRefresh = watchQuery.apply(instances[i], [to.query, from.query]) |
||||||
|
} |
||||||
|
} |
||||||
|
if (!this._hadError && this._isMounted && !Component._dataRefresh) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
const promises = [] |
||||||
|
|
||||||
|
const hasAsyncData = ( |
||||||
|
Component.options.asyncData && |
||||||
|
typeof Component.options.asyncData === 'function' |
||||||
|
) |
||||||
|
|
||||||
|
const hasFetch = Boolean(Component.options.fetch) && Component.options.fetch.length |
||||||
|
|
||||||
|
// Call asyncData(context)
|
||||||
|
if (hasAsyncData) { |
||||||
|
const promise = promisify(Component.options.asyncData, app.context) |
||||||
|
|
||||||
|
promise.then((asyncDataResult) => { |
||||||
|
applyAsyncData(Component, asyncDataResult) |
||||||
|
}) |
||||||
|
promises.push(promise) |
||||||
|
} |
||||||
|
|
||||||
|
// Check disabled page loading
|
||||||
|
this.$loading.manual = Component.options.loading === false |
||||||
|
|
||||||
|
// Call fetch(context)
|
||||||
|
if (hasFetch) { |
||||||
|
let p = Component.options.fetch(app.context) |
||||||
|
if (!p || (!(p instanceof Promise) && (typeof p.then !== 'function'))) { |
||||||
|
p = Promise.resolve(p) |
||||||
|
} |
||||||
|
p.then((fetchResult) => { |
||||||
|
}) |
||||||
|
promises.push(p) |
||||||
|
} |
||||||
|
|
||||||
|
return Promise.all(promises) |
||||||
|
})) |
||||||
|
|
||||||
|
// If not redirected
|
||||||
|
if (!nextCalled) { |
||||||
|
next() |
||||||
|
} |
||||||
|
} catch (err) { |
||||||
|
const error = err || {} |
||||||
|
if (error.message === 'ERR_REDIRECT') { |
||||||
|
return this.$nuxt.$emit('routeChanged', to, from, error) |
||||||
|
} |
||||||
|
_lastPaths = [] |
||||||
|
|
||||||
|
globalHandleError(error) |
||||||
|
|
||||||
|
// Load error layout
|
||||||
|
let layout = (NuxtError.options || NuxtError).layout |
||||||
|
if (typeof layout === 'function') { |
||||||
|
layout = layout(app.context) |
||||||
|
} |
||||||
|
await this.loadLayout(layout) |
||||||
|
|
||||||
|
this.error(error) |
||||||
|
this.$nuxt.$emit('routeChanged', to, from, error) |
||||||
|
next() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Fix components format in matched, it's due to code-splitting of vue-router
|
||||||
|
function normalizeComponents (to, ___) { |
||||||
|
flatMapComponents(to, (Component, _, match, key) => { |
||||||
|
if (typeof Component === 'object' && !Component.options) { |
||||||
|
// Updated via vue-router resolveAsyncComponents()
|
||||||
|
Component = Vue.extend(Component) |
||||||
|
Component._Ctor = Component |
||||||
|
match.components[key] = Component |
||||||
|
} |
||||||
|
return Component |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
function setLayoutForNextPage (to) { |
||||||
|
// Set layout
|
||||||
|
let hasError = Boolean(this.$options.nuxt.err) |
||||||
|
if (this._hadError && this._dateLastError === this.$options.nuxt.dateErr) { |
||||||
|
hasError = false |
||||||
|
} |
||||||
|
let layout = hasError |
||||||
|
? (NuxtError.options || NuxtError).layout |
||||||
|
: to.matched[0].components.default.options.layout |
||||||
|
|
||||||
|
if (typeof layout === 'function') { |
||||||
|
layout = layout(app.context) |
||||||
|
} |
||||||
|
|
||||||
|
this.setLayout(layout) |
||||||
|
} |
||||||
|
|
||||||
|
function checkForErrors (app) { |
||||||
|
// Hide error component if no error
|
||||||
|
if (app._hadError && app._dateLastError === app.$options.nuxt.dateErr) { |
||||||
|
app.error() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// When navigating on a different route but the same component is used, Vue.js
|
||||||
|
// Will not update the instance data, so we have to update $data ourselves
|
||||||
|
function fixPrepatch (to, ___) { |
||||||
|
if (this._routeChanged === false && this._paramChanged === false && this._queryChanged === false) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
const instances = getMatchedComponentsInstances(to) |
||||||
|
const Components = getMatchedComponents(to) |
||||||
|
|
||||||
|
let triggerScroll = false |
||||||
|
|
||||||
|
Vue.nextTick(() => { |
||||||
|
instances.forEach((instance, i) => { |
||||||
|
if (!instance || instance._isDestroyed) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
if ( |
||||||
|
instance.constructor._dataRefresh && |
||||||
|
Components[i] === instance.constructor && |
||||||
|
instance.$vnode.data.keepAlive !== true && |
||||||
|
typeof instance.constructor.options.data === 'function' |
||||||
|
) { |
||||||
|
const newData = instance.constructor.options.data.call(instance) |
||||||
|
for (const key in newData) { |
||||||
|
Vue.set(instance.$data, key, newData[key]) |
||||||
|
} |
||||||
|
|
||||||
|
triggerScroll = true |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
if (triggerScroll) { |
||||||
|
// Ensure to trigger scroll event after calling scrollBehavior
|
||||||
|
window.$nuxt.$nextTick(() => { |
||||||
|
window.$nuxt.$emit('triggerScroll') |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
checkForErrors(this) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
function nuxtReady (_app) { |
||||||
|
window.onNuxtReadyCbs.forEach((cb) => { |
||||||
|
if (typeof cb === 'function') { |
||||||
|
cb(_app) |
||||||
|
} |
||||||
|
}) |
||||||
|
// Special JSDOM
|
||||||
|
if (typeof window._onNuxtLoaded === 'function') { |
||||||
|
window._onNuxtLoaded(_app) |
||||||
|
} |
||||||
|
// Add router hooks
|
||||||
|
router.afterEach((to, from) => { |
||||||
|
// Wait for fixPrepatch + $data updates
|
||||||
|
Vue.nextTick(() => _app.$nuxt.$emit('routeChanged', to, from)) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
async function mountApp (__app) { |
||||||
|
// Set global variables
|
||||||
|
app = __app.app |
||||||
|
router = __app.router |
||||||
|
store = __app.store |
||||||
|
|
||||||
|
// Create Vue instance
|
||||||
|
const _app = new Vue(app) |
||||||
|
|
||||||
|
// Load layout
|
||||||
|
const layout = NUXT.layout || 'default' |
||||||
|
await _app.loadLayout(layout) |
||||||
|
_app.setLayout(layout) |
||||||
|
|
||||||
|
// Mounts Vue app to DOM element
|
||||||
|
const mount = () => { |
||||||
|
_app.$mount('#__nuxt') |
||||||
|
|
||||||
|
// Add afterEach router hooks
|
||||||
|
router.afterEach(normalizeComponents) |
||||||
|
|
||||||
|
router.afterEach(setLayoutForNextPage.bind(_app)) |
||||||
|
|
||||||
|
router.afterEach(fixPrepatch.bind(_app)) |
||||||
|
|
||||||
|
// Listen for first Vue update
|
||||||
|
Vue.nextTick(() => { |
||||||
|
// Call window.{{globals.readyCallback}} callbacks
|
||||||
|
nuxtReady(_app) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
// Resolve route components
|
||||||
|
const Components = await Promise.all(resolveComponents(app.context.route)) |
||||||
|
|
||||||
|
// Enable transitions
|
||||||
|
_app.setTransitions = _app.$options.nuxt.setTransitions.bind(_app) |
||||||
|
if (Components.length) { |
||||||
|
_app.setTransitions(mapTransitions(Components, router.currentRoute)) |
||||||
|
_lastPaths = router.currentRoute.matched.map(route => compile(route.path)(router.currentRoute.params)) |
||||||
|
} |
||||||
|
|
||||||
|
// Initialize error handler
|
||||||
|
_app.$loading = {} // To avoid error while _app.$nuxt does not exist
|
||||||
|
if (NUXT.error) { |
||||||
|
_app.error(NUXT.error) |
||||||
|
} |
||||||
|
|
||||||
|
// Add beforeEach router hooks
|
||||||
|
router.beforeEach(loadAsyncComponents.bind(_app)) |
||||||
|
router.beforeEach(render.bind(_app)) |
||||||
|
|
||||||
|
// Fix in static: remove trailing slash to force hydration
|
||||||
|
// Full static, if server-rendered: hydrate, to allow custom redirect to generated page
|
||||||
|
|
||||||
|
// Fix in static: remove trailing slash to force hydration
|
||||||
|
if (NUXT.serverRendered && isSamePath(NUXT.routePath, _app.context.route.path)) { |
||||||
|
return mount() |
||||||
|
} |
||||||
|
|
||||||
|
// First render on client-side
|
||||||
|
const clientFirstMount = () => { |
||||||
|
normalizeComponents(router.currentRoute, router.currentRoute) |
||||||
|
setLayoutForNextPage.call(_app, router.currentRoute) |
||||||
|
checkForErrors(_app) |
||||||
|
// Don't call fixPrepatch.call(_app, router.currentRoute, router.currentRoute) since it's first render
|
||||||
|
mount() |
||||||
|
} |
||||||
|
|
||||||
|
// fix: force next tick to avoid having same timestamp when an error happen on spa fallback
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 0)) |
||||||
|
render.call(_app, router.currentRoute, router.currentRoute, (path) => { |
||||||
|
// If not redirected
|
||||||
|
if (!path) { |
||||||
|
clientFirstMount() |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// Add a one-time afterEach hook to
|
||||||
|
// mount the app wait for redirect and route gets resolved
|
||||||
|
const unregisterHook = router.afterEach((to, from) => { |
||||||
|
unregisterHook() |
||||||
|
clientFirstMount() |
||||||
|
}) |
||||||
|
|
||||||
|
// Push the path and let route to be resolved
|
||||||
|
router.push(path, undefined, (err) => { |
||||||
|
if (err) { |
||||||
|
errorHandler(err) |
||||||
|
} |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
@ -0,0 +1,42 @@ |
|||||||
|
export const Barrage = () => import('../../src/components/Barrage.vue' /* webpackChunkName: "components/barrage" */).then(c => wrapFunctional(c.default || c)) |
||||||
|
export const BottomRightFixed = () => import('../../src/components/BottomRightFixed.vue' /* webpackChunkName: "components/bottom-right-fixed" */).then(c => wrapFunctional(c.default || c)) |
||||||
|
export const CommonHeader = () => import('../../src/components/CommonHeader.vue' /* webpackChunkName: "components/common-header" */).then(c => wrapFunctional(c.default || c)) |
||||||
|
export const DoctorItem = () => import('../../src/components/DoctorItem.vue' /* webpackChunkName: "components/doctor-item" */).then(c => wrapFunctional(c.default || c)) |
||||||
|
export const DoctorVideoItem = () => import('../../src/components/DoctorVideoItem.vue' /* webpackChunkName: "components/doctor-video-item" */).then(c => wrapFunctional(c.default || c)) |
||||||
|
export const MobileHeader = () => import('../../src/components/MobileHeader.vue' /* webpackChunkName: "components/mobile-header" */).then(c => wrapFunctional(c.default || c)) |
||||||
|
export const NotLogin = () => import('../../src/components/NotLogin.vue' /* webpackChunkName: "components/not-login" */).then(c => wrapFunctional(c.default || c)) |
||||||
|
export const UserInfoCommon = () => import('../../src/components/UserInfoCommon.vue' /* webpackChunkName: "components/user-info-common" */).then(c => wrapFunctional(c.default || c)) |
||||||
|
export const VideoArticleListItem = () => import('../../src/components/VideoArticleListItem.vue' /* webpackChunkName: "components/video-article-list-item" */).then(c => wrapFunctional(c.default || c)) |
||||||
|
export const WebFooter = () => import('../../src/components/WebFooter.vue' /* webpackChunkName: "components/web-footer" */).then(c => wrapFunctional(c.default || c)) |
||||||
|
export const WebHeader = () => import('../../src/components/WebHeader.vue' /* webpackChunkName: "components/web-header" */).then(c => wrapFunctional(c.default || c)) |
||||||
|
|
||||||
|
// nuxt/nuxt.js#8607
|
||||||
|
function wrapFunctional(options) { |
||||||
|
if (!options || !options.functional) { |
||||||
|
return options |
||||||
|
} |
||||||
|
|
||||||
|
const propKeys = Array.isArray(options.props) ? options.props : Object.keys(options.props || {}) |
||||||
|
|
||||||
|
return { |
||||||
|
render(h) { |
||||||
|
const attrs = {} |
||||||
|
const props = {} |
||||||
|
|
||||||
|
for (const key in this.$attrs) { |
||||||
|
if (propKeys.includes(key)) { |
||||||
|
props[key] = this.$attrs[key] |
||||||
|
} else { |
||||||
|
attrs[key] = this.$attrs[key] |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return h(options, { |
||||||
|
on: this.$listeners, |
||||||
|
attrs, |
||||||
|
props, |
||||||
|
scopedSlots: this.$scopedSlots, |
||||||
|
}, this.$slots.default) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,122 @@ |
|||||||
|
|
||||||
|
export default { |
||||||
|
name: 'NuxtChild', |
||||||
|
functional: true, |
||||||
|
props: { |
||||||
|
nuxtChildKey: { |
||||||
|
type: String, |
||||||
|
default: '' |
||||||
|
}, |
||||||
|
keepAlive: Boolean, |
||||||
|
keepAliveProps: { |
||||||
|
type: Object, |
||||||
|
default: undefined |
||||||
|
} |
||||||
|
}, |
||||||
|
render (_, { parent, data, props }) { |
||||||
|
const h = parent.$createElement |
||||||
|
|
||||||
|
data.nuxtChild = true |
||||||
|
const _parent = parent |
||||||
|
const transitions = parent.$nuxt.nuxt.transitions |
||||||
|
const defaultTransition = parent.$nuxt.nuxt.defaultTransition |
||||||
|
|
||||||
|
let depth = 0 |
||||||
|
while (parent) { |
||||||
|
if (parent.$vnode && parent.$vnode.data.nuxtChild) { |
||||||
|
depth++ |
||||||
|
} |
||||||
|
parent = parent.$parent |
||||||
|
} |
||||||
|
data.nuxtChildDepth = depth |
||||||
|
const transition = transitions[depth] || defaultTransition |
||||||
|
const transitionProps = {} |
||||||
|
transitionsKeys.forEach((key) => { |
||||||
|
if (typeof transition[key] !== 'undefined') { |
||||||
|
transitionProps[key] = transition[key] |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
const listeners = {} |
||||||
|
listenersKeys.forEach((key) => { |
||||||
|
if (typeof transition[key] === 'function') { |
||||||
|
listeners[key] = transition[key].bind(_parent) |
||||||
|
} |
||||||
|
}) |
||||||
|
if (process.client) { |
||||||
|
// Add triggerScroll event on beforeEnter (fix #1376)
|
||||||
|
const beforeEnter = listeners.beforeEnter |
||||||
|
listeners.beforeEnter = (el) => { |
||||||
|
// Ensure to trigger scroll event after calling scrollBehavior
|
||||||
|
window.$nuxt.$nextTick(() => { |
||||||
|
window.$nuxt.$emit('triggerScroll') |
||||||
|
}) |
||||||
|
if (beforeEnter) { |
||||||
|
return beforeEnter.call(_parent, el) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// make sure that leave is called asynchronous (fix #5703)
|
||||||
|
if (transition.css === false) { |
||||||
|
const leave = listeners.leave |
||||||
|
|
||||||
|
// only add leave listener when user didnt provide one
|
||||||
|
// or when it misses the done argument
|
||||||
|
if (!leave || leave.length < 2) { |
||||||
|
listeners.leave = (el, done) => { |
||||||
|
if (leave) { |
||||||
|
leave.call(_parent, el) |
||||||
|
} |
||||||
|
|
||||||
|
_parent.$nextTick(done) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
let routerView = h('routerView', data) |
||||||
|
|
||||||
|
if (props.keepAlive) { |
||||||
|
routerView = h('keep-alive', { props: props.keepAliveProps }, [routerView]) |
||||||
|
} |
||||||
|
|
||||||
|
return h('transition', { |
||||||
|
props: transitionProps, |
||||||
|
on: listeners |
||||||
|
}, [routerView]) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const transitionsKeys = [ |
||||||
|
'name', |
||||||
|
'mode', |
||||||
|
'appear', |
||||||
|
'css', |
||||||
|
'type', |
||||||
|
'duration', |
||||||
|
'enterClass', |
||||||
|
'leaveClass', |
||||||
|
'appearClass', |
||||||
|
'enterActiveClass', |
||||||
|
'enterActiveClass', |
||||||
|
'leaveActiveClass', |
||||||
|
'appearActiveClass', |
||||||
|
'enterToClass', |
||||||
|
'leaveToClass', |
||||||
|
'appearToClass' |
||||||
|
] |
||||||
|
|
||||||
|
const listenersKeys = [ |
||||||
|
'beforeEnter', |
||||||
|
'enter', |
||||||
|
'afterEnter', |
||||||
|
'enterCancelled', |
||||||
|
'beforeLeave', |
||||||
|
'leave', |
||||||
|
'afterLeave', |
||||||
|
'leaveCancelled', |
||||||
|
'beforeAppear', |
||||||
|
'appear', |
||||||
|
'afterAppear', |
||||||
|
'appearCancelled' |
||||||
|
] |
@ -0,0 +1,96 @@ |
|||||||
|
<template> |
||||||
|
<div class="__nuxt-error-page"> |
||||||
|
<div class="error"> |
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="90" height="90" fill="#DBE1EC" viewBox="0 0 48 48"> |
||||||
|
<path d="M22 30h4v4h-4zm0-16h4v12h-4zm1.99-10C12.94 4 4 12.95 4 24s8.94 20 19.99 20S44 35.05 44 24 35.04 4 23.99 4zM24 40c-8.84 0-16-7.16-16-16S15.16 8 24 8s16 7.16 16 16-7.16 16-16 16z" /> |
||||||
|
</svg> |
||||||
|
|
||||||
|
<div class="title">{{ message }}</div> |
||||||
|
<p v-if="statusCode === 404" class="description"> |
||||||
|
<a v-if="typeof $route === 'undefined'" class="error-link" href="/"></a> |
||||||
|
<NuxtLink v-else class="error-link" to="/">Back to the home page</NuxtLink> |
||||||
|
</p> |
||||||
|
|
||||||
|
<div class="logo"> |
||||||
|
<a href="https://nuxtjs.org" target="_blank" rel="noopener">Nuxt</a> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
export default { |
||||||
|
name: 'NuxtError', |
||||||
|
props: { |
||||||
|
error: { |
||||||
|
type: Object, |
||||||
|
default: null |
||||||
|
} |
||||||
|
}, |
||||||
|
computed: { |
||||||
|
statusCode () { |
||||||
|
return (this.error && this.error.statusCode) || 500 |
||||||
|
}, |
||||||
|
message () { |
||||||
|
return this.error.message || 'Error' |
||||||
|
} |
||||||
|
}, |
||||||
|
head () { |
||||||
|
return { |
||||||
|
title: this.message, |
||||||
|
meta: [ |
||||||
|
{ |
||||||
|
name: 'viewport', |
||||||
|
content: 'width=device-width,initial-scale=1.0,minimum-scale=1.0' |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style> |
||||||
|
.__nuxt-error-page { |
||||||
|
padding: 1rem; |
||||||
|
background: #F7F8FB; |
||||||
|
color: #47494E; |
||||||
|
text-align: center; |
||||||
|
display: flex; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
flex-direction: column; |
||||||
|
font-family: sans-serif; |
||||||
|
font-weight: 100 !important; |
||||||
|
-ms-text-size-adjust: 100%; |
||||||
|
-webkit-text-size-adjust: 100%; |
||||||
|
-webkit-font-smoothing: antialiased; |
||||||
|
position: absolute; |
||||||
|
top: 0; |
||||||
|
left: 0; |
||||||
|
right: 0; |
||||||
|
bottom: 0; |
||||||
|
} |
||||||
|
.__nuxt-error-page .error { |
||||||
|
max-width: 450px; |
||||||
|
} |
||||||
|
.__nuxt-error-page .title { |
||||||
|
font-size: 1.5rem; |
||||||
|
margin-top: 15px; |
||||||
|
color: #47494E; |
||||||
|
margin-bottom: 8px; |
||||||
|
} |
||||||
|
.__nuxt-error-page .description { |
||||||
|
color: #7F828B; |
||||||
|
line-height: 21px; |
||||||
|
margin-bottom: 10px; |
||||||
|
} |
||||||
|
.__nuxt-error-page a { |
||||||
|
color: #7F828B !important; |
||||||
|
text-decoration: none; |
||||||
|
} |
||||||
|
.__nuxt-error-page .logo { |
||||||
|
position: fixed; |
||||||
|
left: 12px; |
||||||
|
bottom: 12px; |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,98 @@ |
|||||||
|
import Vue from 'vue' |
||||||
|
|
||||||
|
const requestIdleCallback = window.requestIdleCallback || |
||||||
|
function (cb) { |
||||||
|
const start = Date.now() |
||||||
|
return setTimeout(function () { |
||||||
|
cb({ |
||||||
|
didTimeout: false, |
||||||
|
timeRemaining: () => Math.max(0, 50 - (Date.now() - start)) |
||||||
|
}) |
||||||
|
}, 1) |
||||||
|
} |
||||||
|
|
||||||
|
const cancelIdleCallback = window.cancelIdleCallback || function (id) { |
||||||
|
clearTimeout(id) |
||||||
|
} |
||||||
|
|
||||||
|
const observer = window.IntersectionObserver && new window.IntersectionObserver((entries) => { |
||||||
|
entries.forEach(({ intersectionRatio, target: link }) => { |
||||||
|
if (intersectionRatio <= 0 || !link.__prefetch) { |
||||||
|
return |
||||||
|
} |
||||||
|
link.__prefetch() |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'NuxtLink', |
||||||
|
extends: Vue.component('RouterLink'), |
||||||
|
props: { |
||||||
|
prefetch: { |
||||||
|
type: Boolean, |
||||||
|
default: true |
||||||
|
}, |
||||||
|
noPrefetch: { |
||||||
|
type: Boolean, |
||||||
|
default: false |
||||||
|
} |
||||||
|
}, |
||||||
|
mounted () { |
||||||
|
if (this.prefetch && !this.noPrefetch) { |
||||||
|
this.handleId = requestIdleCallback(this.observe, { timeout: 2e3 }) |
||||||
|
} |
||||||
|
}, |
||||||
|
beforeDestroy () { |
||||||
|
cancelIdleCallback(this.handleId) |
||||||
|
|
||||||
|
if (this.__observed) { |
||||||
|
observer.unobserve(this.$el) |
||||||
|
delete this.$el.__prefetch |
||||||
|
} |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
observe () { |
||||||
|
// If no IntersectionObserver, avoid prefetching
|
||||||
|
if (!observer) { |
||||||
|
return |
||||||
|
} |
||||||
|
// Add to observer
|
||||||
|
if (this.shouldPrefetch()) { |
||||||
|
this.$el.__prefetch = this.prefetchLink.bind(this) |
||||||
|
observer.observe(this.$el) |
||||||
|
this.__observed = true |
||||||
|
} |
||||||
|
}, |
||||||
|
shouldPrefetch () { |
||||||
|
return this.getPrefetchComponents().length > 0 |
||||||
|
}, |
||||||
|
canPrefetch () { |
||||||
|
const conn = navigator.connection |
||||||
|
const hasBadConnection = this.$nuxt.isOffline || (conn && ((conn.effectiveType || '').includes('2g') || conn.saveData)) |
||||||
|
|
||||||
|
return !hasBadConnection |
||||||
|
}, |
||||||
|
getPrefetchComponents () { |
||||||
|
const ref = this.$router.resolve(this.to, this.$route, this.append) |
||||||
|
const Components = ref.resolved.matched.map(r => r.components.default) |
||||||
|
|
||||||
|
return Components.filter(Component => typeof Component === 'function' && !Component.options && !Component.__prefetched) |
||||||
|
}, |
||||||
|
prefetchLink () { |
||||||
|
if (!this.canPrefetch()) { |
||||||
|
return |
||||||
|
} |
||||||
|
// Stop observing this link (in case of internet connection changes)
|
||||||
|
observer.unobserve(this.$el) |
||||||
|
const Components = this.getPrefetchComponents() |
||||||
|
|
||||||
|
for (const Component of Components) { |
||||||
|
const componentOrPromise = Component() |
||||||
|
if (componentOrPromise instanceof Promise) { |
||||||
|
componentOrPromise.catch(() => {}) |
||||||
|
} |
||||||
|
Component.__prefetched = true |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,16 @@ |
|||||||
|
import Vue from 'vue' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'NuxtLink', |
||||||
|
extends: Vue.component('RouterLink'), |
||||||
|
props: { |
||||||
|
prefetch: { |
||||||
|
type: Boolean, |
||||||
|
default: true |
||||||
|
}, |
||||||
|
noPrefetch: { |
||||||
|
type: Boolean, |
||||||
|
default: false |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,101 @@ |
|||||||
|
import Vue from 'vue' |
||||||
|
import { compile } from '../utils' |
||||||
|
|
||||||
|
import NuxtError from '../../src/layouts/error.vue' |
||||||
|
|
||||||
|
import NuxtChild from './nuxt-child' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'Nuxt', |
||||||
|
components: { |
||||||
|
NuxtChild, |
||||||
|
NuxtError |
||||||
|
}, |
||||||
|
props: { |
||||||
|
nuxtChildKey: { |
||||||
|
type: String, |
||||||
|
default: undefined |
||||||
|
}, |
||||||
|
keepAlive: Boolean, |
||||||
|
keepAliveProps: { |
||||||
|
type: Object, |
||||||
|
default: undefined |
||||||
|
}, |
||||||
|
name: { |
||||||
|
type: String, |
||||||
|
default: 'default' |
||||||
|
} |
||||||
|
}, |
||||||
|
errorCaptured (error) { |
||||||
|
// if we receive and error while showing the NuxtError component
|
||||||
|
// capture the error and force an immediate update so we re-render
|
||||||
|
// without the NuxtError component
|
||||||
|
if (this.displayingNuxtError) { |
||||||
|
this.errorFromNuxtError = error |
||||||
|
this.$forceUpdate() |
||||||
|
} |
||||||
|
}, |
||||||
|
computed: { |
||||||
|
routerViewKey () { |
||||||
|
// If nuxtChildKey prop is given or current route has children
|
||||||
|
if (typeof this.nuxtChildKey !== 'undefined' || this.$route.matched.length > 1) { |
||||||
|
return this.nuxtChildKey || compile(this.$route.matched[0].path)(this.$route.params) |
||||||
|
} |
||||||
|
|
||||||
|
const [matchedRoute] = this.$route.matched |
||||||
|
|
||||||
|
if (!matchedRoute) { |
||||||
|
return this.$route.path |
||||||
|
} |
||||||
|
|
||||||
|
const Component = matchedRoute.components.default |
||||||
|
|
||||||
|
if (Component && Component.options) { |
||||||
|
const { options } = Component |
||||||
|
|
||||||
|
if (options.key) { |
||||||
|
return (typeof options.key === 'function' ? options.key(this.$route) : options.key) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const strict = /\/$/.test(matchedRoute.path) |
||||||
|
return strict ? this.$route.path : this.$route.path.replace(/\/$/, '') |
||||||
|
} |
||||||
|
}, |
||||||
|
beforeCreate () { |
||||||
|
Vue.util.defineReactive(this, 'nuxt', this.$root.$options.nuxt) |
||||||
|
}, |
||||||
|
render (h) { |
||||||
|
// if there is no error
|
||||||
|
if (!this.nuxt.err) { |
||||||
|
// Directly return nuxt child
|
||||||
|
return h('NuxtChild', { |
||||||
|
key: this.routerViewKey, |
||||||
|
props: this.$props |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
// if an error occurred within NuxtError show a simple
|
||||||
|
// error message instead to prevent looping
|
||||||
|
if (this.errorFromNuxtError) { |
||||||
|
this.$nextTick(() => (this.errorFromNuxtError = false)) |
||||||
|
|
||||||
|
return h('div', {}, [ |
||||||
|
h('h2', 'An error occurred while showing the error page'), |
||||||
|
h('p', 'Unfortunately an error occurred and while showing the error page another error occurred'), |
||||||
|
h('p', `Error details: ${this.errorFromNuxtError.toString()}`), |
||||||
|
h('nuxt-link', { props: { to: '/' } }, 'Go back to home') |
||||||
|
]) |
||||||
|
} |
||||||
|
|
||||||
|
// track if we are showing the NuxtError component
|
||||||
|
this.displayingNuxtError = true |
||||||
|
this.$nextTick(() => (this.displayingNuxtError = false)) |
||||||
|
|
||||||
|
return h(NuxtError, { |
||||||
|
props: { |
||||||
|
error: this.nuxt.err |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,7 @@ |
|||||||
|
import Vue from 'vue' |
||||||
|
import * as components from './index' |
||||||
|
|
||||||
|
for (const name in components) { |
||||||
|
Vue.component(name, components[name]) |
||||||
|
Vue.component('Lazy' + name, components[name]) |
||||||
|
} |
@ -0,0 +1,19 @@ |
|||||||
|
# Discovered Components |
||||||
|
|
||||||
|
This is an auto-generated list of components discovered by [nuxt/components](https://github.com/nuxt/components). |
||||||
|
|
||||||
|
You can directly use them in pages and other components without the need to import them. |
||||||
|
|
||||||
|
**Tip:** If a component is conditionally rendered with `v-if` and is big, it is better to use `Lazy` or `lazy-` prefix to lazy load. |
||||||
|
|
||||||
|
- `<Barrage>` | `<barrage>` (components/Barrage.vue) |
||||||
|
- `<BottomRightFixed>` | `<bottom-right-fixed>` (components/BottomRightFixed.vue) |
||||||
|
- `<CommonHeader>` | `<common-header>` (components/CommonHeader.vue) |
||||||
|
- `<DoctorItem>` | `<doctor-item>` (components/DoctorItem.vue) |
||||||
|
- `<DoctorVideoItem>` | `<doctor-video-item>` (components/DoctorVideoItem.vue) |
||||||
|
- `<MobileHeader>` | `<mobile-header>` (components/MobileHeader.vue) |
||||||
|
- `<NotLogin>` | `<not-login>` (components/NotLogin.vue) |
||||||
|
- `<UserInfoCommon>` | `<user-info-common>` (components/UserInfoCommon.vue) |
||||||
|
- `<VideoArticleListItem>` | `<video-article-list-item>` (components/VideoArticleListItem.vue) |
||||||
|
- `<WebFooter>` | `<web-footer>` (components/WebFooter.vue) |
||||||
|
- `<WebHeader>` | `<web-header>` (components/WebHeader.vue) |
@ -0,0 +1 @@ |
|||||||
|
// This file is intentionally left empty for noop aliases
|
@ -0,0 +1,304 @@ |
|||||||
|
import Vue from 'vue' |
||||||
|
import Vuex from 'vuex' |
||||||
|
import Meta from 'vue-meta' |
||||||
|
import ClientOnly from 'vue-client-only' |
||||||
|
import NoSsr from 'vue-no-ssr' |
||||||
|
import { createRouter } from './router.js' |
||||||
|
import NuxtChild from './components/nuxt-child.js' |
||||||
|
import NuxtError from '../src/layouts/error.vue' |
||||||
|
import Nuxt from './components/nuxt.js' |
||||||
|
import App from './App.js' |
||||||
|
import { setContext, getLocation, getRouteData, normalizeError } from './utils' |
||||||
|
import { createStore } from './store.js' |
||||||
|
|
||||||
|
/* Plugins */ |
||||||
|
|
||||||
|
import nuxt_plugin_plugin_1ebeed53 from 'nuxt_plugin_plugin_1ebeed53' // Source: ./components/plugin.js (mode: 'all')
|
||||||
|
import nuxt_plugin_axios_3f743ce9 from 'nuxt_plugin_axios_3f743ce9' // Source: ./axios.js (mode: 'all')
|
||||||
|
import nuxt_plugin_elementui_d905880e from 'nuxt_plugin_elementui_d905880e' // Source: ../src/plugins/element-ui (mode: 'all')
|
||||||
|
import nuxt_plugin_axios_2228ef02 from 'nuxt_plugin_axios_2228ef02' // Source: ../src/plugins/axios (mode: 'all')
|
||||||
|
import nuxt_plugin_filters_2abc1387 from 'nuxt_plugin_filters_2abc1387' // Source: ../src/plugins/filters (mode: 'all')
|
||||||
|
import nuxt_plugin_vueqr_234f70b3 from 'nuxt_plugin_vueqr_234f70b3' // Source: ../src/plugins/vueqr (mode: 'all')
|
||||||
|
import nuxt_plugin_video_2349f707 from 'nuxt_plugin_video_2349f707' // Source: ../src/plugins/video (mode: 'client')
|
||||||
|
import nuxt_plugin_swiper_68e7f06e from 'nuxt_plugin_swiper_68e7f06e' // Source: ../src/plugins/swiper.js (mode: 'client')
|
||||||
|
import nuxt_plugin_wxshare_5d8a49ee from 'nuxt_plugin_wxshare_5d8a49ee' // Source: ../src/plugins/wx-share.js (mode: 'client')
|
||||||
|
import nuxt_plugin_baidu_7b6ad772 from 'nuxt_plugin_baidu_7b6ad772' // Source: ../src/plugins/baidu.js (mode: 'client')
|
||||||
|
|
||||||
|
// Component: <ClientOnly>
|
||||||
|
Vue.component(ClientOnly.name, ClientOnly) |
||||||
|
|
||||||
|
// TODO: Remove in Nuxt 3: <NoSsr>
|
||||||
|
Vue.component(NoSsr.name, { |
||||||
|
...NoSsr, |
||||||
|
render (h, ctx) { |
||||||
|
if (process.client && !NoSsr._warned) { |
||||||
|
NoSsr._warned = true |
||||||
|
|
||||||
|
console.warn('<no-ssr> has been deprecated and will be removed in Nuxt 3, please use <client-only> instead') |
||||||
|
} |
||||||
|
return NoSsr.render(h, ctx) |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
// Component: <NuxtChild>
|
||||||
|
Vue.component(NuxtChild.name, NuxtChild) |
||||||
|
Vue.component('NChild', NuxtChild) |
||||||
|
|
||||||
|
// Component NuxtLink is imported in server.js or client.js
|
||||||
|
|
||||||
|
// Component: <Nuxt>
|
||||||
|
Vue.component(Nuxt.name, Nuxt) |
||||||
|
|
||||||
|
Object.defineProperty(Vue.prototype, '$nuxt', { |
||||||
|
get() { |
||||||
|
const globalNuxt = this.$root.$options.$nuxt |
||||||
|
if (process.client && !globalNuxt && typeof window !== 'undefined') { |
||||||
|
return window.$nuxt |
||||||
|
} |
||||||
|
return globalNuxt |
||||||
|
}, |
||||||
|
configurable: true |
||||||
|
}) |
||||||
|
|
||||||
|
Vue.use(Meta, {"keyName":"head","attribute":"data-n-head","ssrAttribute":"data-n-head-ssr","tagIDKeyName":"hid"}) |
||||||
|
|
||||||
|
const defaultTransition = {"name":"page","mode":"out-in","appear":false,"appearClass":"appear","appearActiveClass":"appear-active","appearToClass":"appear-to"} |
||||||
|
|
||||||
|
const originalRegisterModule = Vuex.Store.prototype.registerModule |
||||||
|
|
||||||
|
function registerModule (path, rawModule, options = {}) { |
||||||
|
const preserveState = process.client && ( |
||||||
|
Array.isArray(path) |
||||||
|
? !!path.reduce((namespacedState, path) => namespacedState && namespacedState[path], this.state) |
||||||
|
: path in this.state |
||||||
|
) |
||||||
|
return originalRegisterModule.call(this, path, rawModule, { preserveState, ...options }) |
||||||
|
} |
||||||
|
|
||||||
|
async function createApp(ssrContext, config = {}) { |
||||||
|
const router = await createRouter(ssrContext, config) |
||||||
|
|
||||||
|
const store = createStore(ssrContext) |
||||||
|
// Add this.$router into store actions/mutations
|
||||||
|
store.$router = router |
||||||
|
|
||||||
|
// Fix SSR caveat https://github.com/nuxt/nuxt.js/issues/3757#issuecomment-414689141
|
||||||
|
store.registerModule = registerModule |
||||||
|
|
||||||
|
// Create Root instance
|
||||||
|
|
||||||
|
// here we inject the router and store to all child components,
|
||||||
|
// making them available everywhere as `this.$router` and `this.$store`.
|
||||||
|
const app = { |
||||||
|
head: {"title":"糖尿病网 - 服务糖尿病患者的知识社区","htmlAttrs":{"lang":"en"},"meta":[{"charset":"utf-8"},{"name":"viewport","content":"initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0,width=device-width,user-scalable=no,viewport-fit=cover"},{"hid":"description","name":"description","content":"糖尿病网,服务糖尿病患者的知识平台!以帮助糖尿病患者科学管理身体为目标,提供最新鲜、专业的健康管理资讯。"},{"hid":"keywords","name":"keywords","content":"糖尿病,健康管理,控糖,血糖,血糖管理,科普,知识社区,专业资讯,干货,糖友,疾病,公益,有用,深度,饮食知识"},{"name":"format-detection","content":"telephone=no"}],"link":[{"rel":"icon","type":"image\u002Fx-icon","href":"\u002Ffavicon.ico"}],"script":[{"src":"https:\u002F\u002Fhm.baidu.com\u002Fhm.js?c17780012e32ae356918a39fe159755e"}],"style":[]}, |
||||||
|
|
||||||
|
store, |
||||||
|
router, |
||||||
|
nuxt: { |
||||||
|
defaultTransition, |
||||||
|
transitions: [defaultTransition], |
||||||
|
setTransitions (transitions) { |
||||||
|
if (!Array.isArray(transitions)) { |
||||||
|
transitions = [transitions] |
||||||
|
} |
||||||
|
transitions = transitions.map((transition) => { |
||||||
|
if (!transition) { |
||||||
|
transition = defaultTransition |
||||||
|
} else if (typeof transition === 'string') { |
||||||
|
transition = Object.assign({}, defaultTransition, { name: transition }) |
||||||
|
} else { |
||||||
|
transition = Object.assign({}, defaultTransition, transition) |
||||||
|
} |
||||||
|
return transition |
||||||
|
}) |
||||||
|
this.$options.nuxt.transitions = transitions |
||||||
|
return transitions |
||||||
|
}, |
||||||
|
|
||||||
|
err: null, |
||||||
|
dateErr: null, |
||||||
|
error (err) { |
||||||
|
err = err || null |
||||||
|
app.context._errored = Boolean(err) |
||||||
|
err = err ? normalizeError(err) : null |
||||||
|
let nuxt = app.nuxt // to work with @vue/composition-api, see https://github.com/nuxt/nuxt.js/issues/6517#issuecomment-573280207
|
||||||
|
if (this) { |
||||||
|
nuxt = this.nuxt || this.$options.nuxt |
||||||
|
} |
||||||
|
nuxt.dateErr = Date.now() |
||||||
|
nuxt.err = err |
||||||
|
// Used in src/server.js
|
||||||
|
if (ssrContext) { |
||||||
|
ssrContext.nuxt.error = err |
||||||
|
} |
||||||
|
return err |
||||||
|
} |
||||||
|
}, |
||||||
|
...App |
||||||
|
} |
||||||
|
|
||||||
|
// Make app available into store via this.app
|
||||||
|
store.app = app |
||||||
|
|
||||||
|
const next = ssrContext ? ssrContext.next : location => app.router.push(location) |
||||||
|
// Resolve route
|
||||||
|
let route |
||||||
|
if (ssrContext) { |
||||||
|
route = router.resolve(ssrContext.url).route |
||||||
|
} else { |
||||||
|
const path = getLocation(router.options.base, router.options.mode) |
||||||
|
route = router.resolve(path).route |
||||||
|
} |
||||||
|
|
||||||
|
// Set context to app.context
|
||||||
|
await setContext(app, { |
||||||
|
store, |
||||||
|
route, |
||||||
|
next, |
||||||
|
error: app.nuxt.error.bind(app), |
||||||
|
payload: ssrContext ? ssrContext.payload : undefined, |
||||||
|
req: ssrContext ? ssrContext.req : undefined, |
||||||
|
res: ssrContext ? ssrContext.res : undefined, |
||||||
|
beforeRenderFns: ssrContext ? ssrContext.beforeRenderFns : undefined, |
||||||
|
ssrContext |
||||||
|
}) |
||||||
|
|
||||||
|
function inject(key, value) { |
||||||
|
if (!key) { |
||||||
|
throw new Error('inject(key, value) has no key provided') |
||||||
|
} |
||||||
|
if (value === undefined) { |
||||||
|
throw new Error(`inject('${key}', value) has no value provided`) |
||||||
|
} |
||||||
|
|
||||||
|
key = '$' + key |
||||||
|
// Add into app
|
||||||
|
app[key] = value |
||||||
|
// Add into context
|
||||||
|
if (!app.context[key]) { |
||||||
|
app.context[key] = value |
||||||
|
} |
||||||
|
|
||||||
|
// Add into store
|
||||||
|
store[key] = app[key] |
||||||
|
|
||||||
|
// Check if plugin not already installed
|
||||||
|
const installKey = '__nuxt_' + key + '_installed__' |
||||||
|
if (Vue[installKey]) { |
||||||
|
return |
||||||
|
} |
||||||
|
Vue[installKey] = true |
||||||
|
// Call Vue.use() to install the plugin into vm
|
||||||
|
Vue.use(() => { |
||||||
|
if (!Object.prototype.hasOwnProperty.call(Vue.prototype, key)) { |
||||||
|
Object.defineProperty(Vue.prototype, key, { |
||||||
|
get () { |
||||||
|
return this.$root.$options[key] |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
// Inject runtime config as $config
|
||||||
|
inject('config', config) |
||||||
|
|
||||||
|
if (process.client) { |
||||||
|
// Replace store state before plugins execution
|
||||||
|
if (window.__NUXT__ && window.__NUXT__.state) { |
||||||
|
store.replaceState(window.__NUXT__.state) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Add enablePreview(previewData = {}) in context for plugins
|
||||||
|
if (process.static && process.client) { |
||||||
|
app.context.enablePreview = function (previewData = {}) { |
||||||
|
app.previewData = Object.assign({}, previewData) |
||||||
|
inject('preview', previewData) |
||||||
|
} |
||||||
|
} |
||||||
|
// Plugin execution
|
||||||
|
|
||||||
|
if (typeof nuxt_plugin_plugin_1ebeed53 === 'function') { |
||||||
|
await nuxt_plugin_plugin_1ebeed53(app.context, inject) |
||||||
|
} |
||||||
|
|
||||||
|
if (typeof nuxt_plugin_axios_3f743ce9 === 'function') { |
||||||
|
await nuxt_plugin_axios_3f743ce9(app.context, inject) |
||||||
|
} |
||||||
|
|
||||||
|
if (typeof nuxt_plugin_elementui_d905880e === 'function') { |
||||||
|
await nuxt_plugin_elementui_d905880e(app.context, inject) |
||||||
|
} |
||||||
|
|
||||||
|
if (typeof nuxt_plugin_axios_2228ef02 === 'function') { |
||||||
|
await nuxt_plugin_axios_2228ef02(app.context, inject) |
||||||
|
} |
||||||
|
|
||||||
|
if (typeof nuxt_plugin_filters_2abc1387 === 'function') { |
||||||
|
await nuxt_plugin_filters_2abc1387(app.context, inject) |
||||||
|
} |
||||||
|
|
||||||
|
if (typeof nuxt_plugin_vueqr_234f70b3 === 'function') { |
||||||
|
await nuxt_plugin_vueqr_234f70b3(app.context, inject) |
||||||
|
} |
||||||
|
|
||||||
|
if (process.client && typeof nuxt_plugin_video_2349f707 === 'function') { |
||||||
|
await nuxt_plugin_video_2349f707(app.context, inject) |
||||||
|
} |
||||||
|
|
||||||
|
if (process.client && typeof nuxt_plugin_swiper_68e7f06e === 'function') { |
||||||
|
await nuxt_plugin_swiper_68e7f06e(app.context, inject) |
||||||
|
} |
||||||
|
|
||||||
|
if (process.client && typeof nuxt_plugin_wxshare_5d8a49ee === 'function') { |
||||||
|
await nuxt_plugin_wxshare_5d8a49ee(app.context, inject) |
||||||
|
} |
||||||
|
|
||||||
|
if (process.client && typeof nuxt_plugin_baidu_7b6ad772 === 'function') { |
||||||
|
await nuxt_plugin_baidu_7b6ad772(app.context, inject) |
||||||
|
} |
||||||
|
|
||||||
|
// Lock enablePreview in context
|
||||||
|
if (process.static && process.client) { |
||||||
|
app.context.enablePreview = function () { |
||||||
|
console.warn('You cannot call enablePreview() outside a plugin.') |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Wait for async component to be resolved first
|
||||||
|
await new Promise((resolve, reject) => { |
||||||
|
// Ignore 404s rather than blindly replacing URL in browser
|
||||||
|
if (process.client) { |
||||||
|
const { route } = router.resolve(app.context.route.fullPath) |
||||||
|
if (!route.matched.length) { |
||||||
|
return resolve() |
||||||
|
} |
||||||
|
} |
||||||
|
router.replace(app.context.route.fullPath, resolve, (err) => { |
||||||
|
// https://github.com/vuejs/vue-router/blob/v3.4.3/src/util/errors.js
|
||||||
|
if (!err._isRouter) return reject(err) |
||||||
|
if (err.type !== 2 /* NavigationFailureType.redirected */) return resolve() |
||||||
|
|
||||||
|
// navigated to a different route in router guard
|
||||||
|
const unregister = router.afterEach(async (to, from) => { |
||||||
|
if (process.server && ssrContext && ssrContext.url) { |
||||||
|
ssrContext.url = to.fullPath |
||||||
|
} |
||||||
|
app.context.route = await getRouteData(to) |
||||||
|
app.context.params = to.params || {} |
||||||
|
app.context.query = to.query || {} |
||||||
|
unregister() |
||||||
|
resolve() |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
return { |
||||||
|
store, |
||||||
|
app, |
||||||
|
router |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export { createApp, NuxtError } |
@ -0,0 +1,82 @@ |
|||||||
|
const chunks = {} // chunkId => exports
|
||||||
|
const chunksInstalling = {} // chunkId => Promise
|
||||||
|
const failedChunks = {} |
||||||
|
|
||||||
|
function importChunk(chunkId, src) { |
||||||
|
// Already installed
|
||||||
|
if (chunks[chunkId]) { |
||||||
|
return Promise.resolve(chunks[chunkId]) |
||||||
|
} |
||||||
|
|
||||||
|
// Failed loading
|
||||||
|
if (failedChunks[chunkId]) { |
||||||
|
return Promise.reject(failedChunks[chunkId]) |
||||||
|
} |
||||||
|
|
||||||
|
// Installing
|
||||||
|
if (chunksInstalling[chunkId]) { |
||||||
|
return chunksInstalling[chunkId] |
||||||
|
} |
||||||
|
|
||||||
|
// Set a promise in chunk cache
|
||||||
|
let resolve, reject |
||||||
|
const promise = chunksInstalling[chunkId] = new Promise((_resolve, _reject) => { |
||||||
|
resolve = _resolve |
||||||
|
reject = _reject |
||||||
|
}) |
||||||
|
|
||||||
|
// Clear chunk data from cache
|
||||||
|
delete chunks[chunkId] |
||||||
|
|
||||||
|
// Start chunk loading
|
||||||
|
const script = document.createElement('script') |
||||||
|
script.charset = 'utf-8' |
||||||
|
script.timeout = 120 |
||||||
|
script.src = src |
||||||
|
let timeout |
||||||
|
|
||||||
|
// Create error before stack unwound to get useful stacktrace later
|
||||||
|
const error = new Error() |
||||||
|
|
||||||
|
// Complete handlers
|
||||||
|
const onScriptComplete = script.onerror = script.onload = (event) => { |
||||||
|
// Cleanups
|
||||||
|
clearTimeout(timeout) |
||||||
|
delete chunksInstalling[chunkId] |
||||||
|
|
||||||
|
// Avoid mem leaks in IE
|
||||||
|
script.onerror = script.onload = null |
||||||
|
|
||||||
|
// Verify chunk is loaded
|
||||||
|
if (chunks[chunkId]) { |
||||||
|
return resolve(chunks[chunkId]) |
||||||
|
} |
||||||
|
|
||||||
|
// Something bad happened
|
||||||
|
const errorType = event && (event.type === 'load' ? 'missing' : event.type) |
||||||
|
const realSrc = event && event.target && event.target.src |
||||||
|
error.message = 'Loading chunk ' + chunkId + ' failed.\n(' + errorType + ': ' + realSrc + ')' |
||||||
|
error.name = 'ChunkLoadError' |
||||||
|
error.type = errorType |
||||||
|
error.request = realSrc |
||||||
|
failedChunks[chunkId] = error |
||||||
|
reject(error) |
||||||
|
} |
||||||
|
|
||||||
|
// Timeout
|
||||||
|
timeout = setTimeout(() => { |
||||||
|
onScriptComplete({ type: 'timeout', target: script }) |
||||||
|
}, 120000) |
||||||
|
|
||||||
|
// Append script
|
||||||
|
document.head.appendChild(script) |
||||||
|
|
||||||
|
// Return promise
|
||||||
|
return promise |
||||||
|
} |
||||||
|
|
||||||
|
export function installJsonp() { |
||||||
|
window.__NUXT_JSONP__ = function (chunkId, exports) { chunks[chunkId] = exports } |
||||||
|
window.__NUXT_JSONP_CACHE__ = chunks |
||||||
|
window.__NUXT_IMPORT__ = importChunk |
||||||
|
} |
@ -0,0 +1,108 @@ |
|||||||
|
<style> |
||||||
|
#nuxt-loading { |
||||||
|
background: white; |
||||||
|
visibility: hidden; |
||||||
|
opacity: 0; |
||||||
|
position: absolute; |
||||||
|
left: 0; |
||||||
|
right: 0; |
||||||
|
top: 0; |
||||||
|
bottom: 0; |
||||||
|
display: flex; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
flex-direction: column; |
||||||
|
animation: nuxtLoadingIn 10s ease; |
||||||
|
-webkit-animation: nuxtLoadingIn 10s ease; |
||||||
|
animation-fill-mode: forwards; |
||||||
|
overflow: hidden; |
||||||
|
} |
||||||
|
|
||||||
|
@keyframes nuxtLoadingIn { |
||||||
|
0% { |
||||||
|
visibility: hidden; |
||||||
|
opacity: 0; |
||||||
|
} |
||||||
|
20% { |
||||||
|
visibility: visible; |
||||||
|
opacity: 0; |
||||||
|
} |
||||||
|
100% { |
||||||
|
visibility: visible; |
||||||
|
opacity: 1; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@-webkit-keyframes nuxtLoadingIn { |
||||||
|
0% { |
||||||
|
visibility: hidden; |
||||||
|
opacity: 0; |
||||||
|
} |
||||||
|
20% { |
||||||
|
visibility: visible; |
||||||
|
opacity: 0; |
||||||
|
} |
||||||
|
100% { |
||||||
|
visibility: visible; |
||||||
|
opacity: 1; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#nuxt-loading>div, |
||||||
|
#nuxt-loading>div:after { |
||||||
|
border-radius: 50%; |
||||||
|
width: 5rem; |
||||||
|
height: 5rem; |
||||||
|
} |
||||||
|
|
||||||
|
#nuxt-loading>div { |
||||||
|
font-size: 10px; |
||||||
|
position: relative; |
||||||
|
text-indent: -9999em; |
||||||
|
border: .5rem solid #F5F5F5; |
||||||
|
border-left: .5rem solid #D3D3D3; |
||||||
|
-webkit-transform: translateZ(0); |
||||||
|
-ms-transform: translateZ(0); |
||||||
|
transform: translateZ(0); |
||||||
|
-webkit-animation: nuxtLoading 1.1s infinite linear; |
||||||
|
animation: nuxtLoading 1.1s infinite linear; |
||||||
|
} |
||||||
|
|
||||||
|
#nuxt-loading.error>div { |
||||||
|
border-left: .5rem solid #ff4500; |
||||||
|
animation-duration: 5s; |
||||||
|
} |
||||||
|
|
||||||
|
@-webkit-keyframes nuxtLoading { |
||||||
|
0% { |
||||||
|
-webkit-transform: rotate(0deg); |
||||||
|
transform: rotate(0deg); |
||||||
|
} |
||||||
|
100% { |
||||||
|
-webkit-transform: rotate(360deg); |
||||||
|
transform: rotate(360deg); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@keyframes nuxtLoading { |
||||||
|
0% { |
||||||
|
-webkit-transform: rotate(0deg); |
||||||
|
transform: rotate(0deg); |
||||||
|
} |
||||||
|
100% { |
||||||
|
-webkit-transform: rotate(360deg); |
||||||
|
transform: rotate(360deg); |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
||||||
|
|
||||||
|
<script> |
||||||
|
window.addEventListener('error', function () { |
||||||
|
var e = document.getElementById('nuxt-loading'); |
||||||
|
if (e) { |
||||||
|
e.className += ' error'; |
||||||
|
} |
||||||
|
}); |
||||||
|
</script> |
||||||
|
|
||||||
|
<div id="nuxt-loading" aria-live="polite" role="status"><div>Loading...</div></div> |
@ -0,0 +1,9 @@ |
|||||||
|
const middleware = {} |
||||||
|
|
||||||
|
middleware['authenticated'] = require('../src/middleware/authenticated.js') |
||||||
|
middleware['authenticated'] = middleware['authenticated'].default || middleware['authenticated'] |
||||||
|
|
||||||
|
middleware['device'] = require('../src/middleware/device.js') |
||||||
|
middleware['device'] = middleware['device'].default || middleware['device'] |
||||||
|
|
||||||
|
export default middleware |
@ -0,0 +1,90 @@ |
|||||||
|
import Vue from 'vue' |
||||||
|
import { hasFetch, normalizeError, addLifecycleHook, createGetCounter } from '../utils' |
||||||
|
|
||||||
|
const isSsrHydration = (vm) => vm.$vnode && vm.$vnode.elm && vm.$vnode.elm.dataset && vm.$vnode.elm.dataset.fetchKey |
||||||
|
const nuxtState = window.__NUXT__ |
||||||
|
|
||||||
|
export default { |
||||||
|
beforeCreate () { |
||||||
|
if (!hasFetch(this)) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
this._fetchDelay = typeof this.$options.fetchDelay === 'number' ? this.$options.fetchDelay : 200 |
||||||
|
|
||||||
|
Vue.util.defineReactive(this, '$fetchState', { |
||||||
|
pending: false, |
||||||
|
error: null, |
||||||
|
timestamp: Date.now() |
||||||
|
}) |
||||||
|
|
||||||
|
this.$fetch = $fetch.bind(this) |
||||||
|
addLifecycleHook(this, 'created', created) |
||||||
|
addLifecycleHook(this, 'beforeMount', beforeMount) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function beforeMount() { |
||||||
|
if (!this._hydrated) { |
||||||
|
return this.$fetch() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function created() { |
||||||
|
if (!isSsrHydration(this)) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// Hydrate component
|
||||||
|
this._hydrated = true |
||||||
|
this._fetchKey = this.$vnode.elm.dataset.fetchKey |
||||||
|
const data = nuxtState.fetch[this._fetchKey] |
||||||
|
|
||||||
|
// If fetch error
|
||||||
|
if (data && data._error) { |
||||||
|
this.$fetchState.error = data._error |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// Merge data
|
||||||
|
for (const key in data) { |
||||||
|
Vue.set(this.$data, key, data[key]) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function $fetch() { |
||||||
|
if (!this._fetchPromise) { |
||||||
|
this._fetchPromise = $_fetch.call(this) |
||||||
|
.then(() => { delete this._fetchPromise }) |
||||||
|
} |
||||||
|
return this._fetchPromise |
||||||
|
} |
||||||
|
|
||||||
|
async function $_fetch() { |
||||||
|
this.$nuxt.nbFetching++ |
||||||
|
this.$fetchState.pending = true |
||||||
|
this.$fetchState.error = null |
||||||
|
this._hydrated = false |
||||||
|
let error = null |
||||||
|
const startTime = Date.now() |
||||||
|
|
||||||
|
try { |
||||||
|
await this.$options.fetch.call(this) |
||||||
|
} catch (err) { |
||||||
|
if (process.dev) { |
||||||
|
console.error('Error in fetch():', err) |
||||||
|
} |
||||||
|
error = normalizeError(err) |
||||||
|
} |
||||||
|
|
||||||
|
const delayLeft = this._fetchDelay - (Date.now() - startTime) |
||||||
|
if (delayLeft > 0) { |
||||||
|
await new Promise(resolve => setTimeout(resolve, delayLeft)) |
||||||
|
} |
||||||
|
|
||||||
|
this.$fetchState.error = error |
||||||
|
this.$fetchState.pending = false |
||||||
|
this.$fetchState.timestamp = Date.now() |
||||||
|
|
||||||
|
this.$nextTick(() => this.$nuxt.nbFetching--) |
||||||
|
} |
@ -0,0 +1,65 @@ |
|||||||
|
import Vue from 'vue' |
||||||
|
import { hasFetch, normalizeError, addLifecycleHook, purifyData, createGetCounter } from '../utils' |
||||||
|
|
||||||
|
async function serverPrefetch() { |
||||||
|
if (!this._fetchOnServer) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// Call and await on $fetch
|
||||||
|
try { |
||||||
|
await this.$options.fetch.call(this) |
||||||
|
} catch (err) { |
||||||
|
if (process.dev) { |
||||||
|
console.error('Error in fetch():', err) |
||||||
|
} |
||||||
|
this.$fetchState.error = normalizeError(err) |
||||||
|
} |
||||||
|
this.$fetchState.pending = false |
||||||
|
|
||||||
|
// Define an ssrKey for hydration
|
||||||
|
this._fetchKey = this._fetchKey || this.$ssrContext.fetchCounters['']++ |
||||||
|
|
||||||
|
// Add data-fetch-key on parent element of Component
|
||||||
|
const attrs = this.$vnode.data.attrs = this.$vnode.data.attrs || {} |
||||||
|
attrs['data-fetch-key'] = this._fetchKey |
||||||
|
|
||||||
|
// Add to ssrContext for window.__NUXT__.fetch
|
||||||
|
|
||||||
|
this.$ssrContext.nuxt.fetch[this._fetchKey] = |
||||||
|
this.$fetchState.error ? { _error: this.$fetchState.error } : purifyData(this._data) |
||||||
|
} |
||||||
|
|
||||||
|
export default { |
||||||
|
created() { |
||||||
|
if (!hasFetch(this)) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
if (typeof this.$options.fetchOnServer === 'function') { |
||||||
|
this._fetchOnServer = this.$options.fetchOnServer.call(this) !== false |
||||||
|
} else { |
||||||
|
this._fetchOnServer = this.$options.fetchOnServer !== false |
||||||
|
} |
||||||
|
|
||||||
|
const defaultKey = this.$options._scopeId || this.$options.name || '' |
||||||
|
const getCounter = createGetCounter(this.$ssrContext.fetchCounters, defaultKey) |
||||||
|
|
||||||
|
if (typeof this.$options.fetchKey === 'function') { |
||||||
|
this._fetchKey = this.$options.fetchKey.call(this, getCounter) |
||||||
|
} else { |
||||||
|
const key = 'string' === typeof this.$options.fetchKey ? this.$options.fetchKey : defaultKey |
||||||
|
this._fetchKey = key ? key + ':' + getCounter(key) : String(getCounter(key)) |
||||||
|
} |
||||||
|
|
||||||
|
// Added for remove vue undefined warning while ssr
|
||||||
|
this.$fetch = () => {} // issue #8043
|
||||||
|
Vue.util.defineReactive(this, '$fetchState', { |
||||||
|
pending: true, |
||||||
|
error: null, |
||||||
|
timestamp: Date.now() |
||||||
|
}) |
||||||
|
|
||||||
|
addLifecycleHook(this, 'serverPrefetch', serverPrefetch) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,133 @@ |
|||||||
|
import Vue from 'vue' |
||||||
|
import Router from 'vue-router' |
||||||
|
import { normalizeURL, decode } from 'ufo' |
||||||
|
import { interopDefault } from './utils' |
||||||
|
import scrollBehavior from './router.scrollBehavior.js' |
||||||
|
|
||||||
|
const _4b81ed11 = () => interopDefault(import('../src/pages/article/index.vue' /* webpackChunkName: "pages/article/index" */)) |
||||||
|
const _45864e0c = () => interopDefault(import('../src/pages/doctor/index.vue' /* webpackChunkName: "pages/doctor/index" */)) |
||||||
|
const _3729b6ed = () => interopDefault(import('../src/pages/more.vue' /* webpackChunkName: "pages/more" */)) |
||||||
|
const _779b537a = () => interopDefault(import('../src/pages/search/index.vue' /* webpackChunkName: "pages/search/index" */)) |
||||||
|
const _240caca6 = () => interopDefault(import('../src/pages/user/index.vue' /* webpackChunkName: "pages/user/index" */)) |
||||||
|
const _4ad07256 = () => interopDefault(import('../src/pages/video/index.vue' /* webpackChunkName: "pages/video/index" */)) |
||||||
|
const _394ae834 = () => interopDefault(import('../src/pages/other/about.vue' /* webpackChunkName: "pages/other/about" */)) |
||||||
|
const _4c6b2b63 = () => interopDefault(import('../src/pages/other/agreement.vue' /* webpackChunkName: "pages/other/agreement" */)) |
||||||
|
const _114b4da8 = () => interopDefault(import('../src/pages/other/cookies.vue' /* webpackChunkName: "pages/other/cookies" */)) |
||||||
|
const _23ed8784 = () => interopDefault(import('../src/pages/other/corporate.vue' /* webpackChunkName: "pages/other/corporate" */)) |
||||||
|
const _9e1bc1dc = () => interopDefault(import('../src/pages/other/disclaimer.vue' /* webpackChunkName: "pages/other/disclaimer" */)) |
||||||
|
const _2424f59e = () => interopDefault(import('../src/pages/other/link.vue' /* webpackChunkName: "pages/other/link" */)) |
||||||
|
const _5edfebbe = () => interopDefault(import('../src/pages/other/privacy.vue' /* webpackChunkName: "pages/other/privacy" */)) |
||||||
|
const _3b2c0424 = () => interopDefault(import('../src/pages/user/setting.vue' /* webpackChunkName: "pages/user/setting" */)) |
||||||
|
const _3a19ffb9 = () => interopDefault(import('../src/pages/article/_id.vue' /* webpackChunkName: "pages/article/_id" */)) |
||||||
|
const _3a40d1e2 = () => interopDefault(import('../src/pages/doctor/_id.vue' /* webpackChunkName: "pages/doctor/_id" */)) |
||||||
|
const _6763123e = () => interopDefault(import('../src/pages/video/_id.vue' /* webpackChunkName: "pages/video/_id" */)) |
||||||
|
const _147516ea = () => interopDefault(import('../src/pages/index.vue' /* webpackChunkName: "pages/index" */)) |
||||||
|
|
||||||
|
const emptyFn = () => {} |
||||||
|
|
||||||
|
Vue.use(Router) |
||||||
|
|
||||||
|
export const routerOptions = { |
||||||
|
mode: 'history', |
||||||
|
base: '/', |
||||||
|
linkActiveClass: 'nuxt-link-active', |
||||||
|
linkExactActiveClass: 'nuxt-link-exact-active', |
||||||
|
scrollBehavior, |
||||||
|
|
||||||
|
routes: [{ |
||||||
|
path: "/article", |
||||||
|
component: _4b81ed11, |
||||||
|
name: "article" |
||||||
|
}, { |
||||||
|
path: "/doctor", |
||||||
|
component: _45864e0c, |
||||||
|
name: "doctor" |
||||||
|
}, { |
||||||
|
path: "/more", |
||||||
|
component: _3729b6ed, |
||||||
|
name: "more" |
||||||
|
}, { |
||||||
|
path: "/search", |
||||||
|
component: _779b537a, |
||||||
|
name: "search" |
||||||
|
}, { |
||||||
|
path: "/user", |
||||||
|
component: _240caca6, |
||||||
|
name: "user" |
||||||
|
}, { |
||||||
|
path: "/video", |
||||||
|
component: _4ad07256, |
||||||
|
name: "video" |
||||||
|
}, { |
||||||
|
path: "/other/about", |
||||||
|
component: _394ae834, |
||||||
|
name: "other-about" |
||||||
|
}, { |
||||||
|
path: "/other/agreement", |
||||||
|
component: _4c6b2b63, |
||||||
|
name: "other-agreement" |
||||||
|
}, { |
||||||
|
path: "/other/cookies", |
||||||
|
component: _114b4da8, |
||||||
|
name: "other-cookies" |
||||||
|
}, { |
||||||
|
path: "/other/corporate", |
||||||
|
component: _23ed8784, |
||||||
|
name: "other-corporate" |
||||||
|
}, { |
||||||
|
path: "/other/disclaimer", |
||||||
|
component: _9e1bc1dc, |
||||||
|
name: "other-disclaimer" |
||||||
|
}, { |
||||||
|
path: "/other/link", |
||||||
|
component: _2424f59e, |
||||||
|
name: "other-link" |
||||||
|
}, { |
||||||
|
path: "/other/privacy", |
||||||
|
component: _5edfebbe, |
||||||
|
name: "other-privacy" |
||||||
|
}, { |
||||||
|
path: "/user/setting", |
||||||
|
component: _3b2c0424, |
||||||
|
name: "user-setting" |
||||||
|
}, { |
||||||
|
path: "/article/:id", |
||||||
|
component: _3a19ffb9, |
||||||
|
name: "article-id" |
||||||
|
}, { |
||||||
|
path: "/doctor/:id", |
||||||
|
component: _3a40d1e2, |
||||||
|
name: "doctor-id" |
||||||
|
}, { |
||||||
|
path: "/video/:id", |
||||||
|
component: _6763123e, |
||||||
|
name: "video-id" |
||||||
|
}, { |
||||||
|
path: "/", |
||||||
|
component: _147516ea, |
||||||
|
name: "index" |
||||||
|
}], |
||||||
|
|
||||||
|
fallback: false |
||||||
|
} |
||||||
|
|
||||||
|
export function createRouter (ssrContext, config) { |
||||||
|
const base = (config._app && config._app.basePath) || routerOptions.base |
||||||
|
const router = new Router({ ...routerOptions, base }) |
||||||
|
|
||||||
|
// TODO: remove in Nuxt 3
|
||||||
|
const originalPush = router.push |
||||||
|
router.push = function push (location, onComplete = emptyFn, onAbort) { |
||||||
|
return originalPush.call(this, location, onComplete, onAbort) |
||||||
|
} |
||||||
|
|
||||||
|
const resolve = router.resolve.bind(router) |
||||||
|
router.resolve = (to, current, append) => { |
||||||
|
if (typeof to === 'string') { |
||||||
|
to = normalizeURL(to) |
||||||
|
} |
||||||
|
return resolve(to, current, append) |
||||||
|
} |
||||||
|
|
||||||
|
return router |
||||||
|
} |
@ -0,0 +1,76 @@ |
|||||||
|
import { getMatchedComponents, setScrollRestoration } from './utils' |
||||||
|
|
||||||
|
if (process.client) { |
||||||
|
if ('scrollRestoration' in window.history) { |
||||||
|
setScrollRestoration('manual') |
||||||
|
|
||||||
|
// reset scrollRestoration to auto when leaving page, allowing page reload
|
||||||
|
// and back-navigation from other pages to use the browser to restore the
|
||||||
|
// scrolling position.
|
||||||
|
window.addEventListener('beforeunload', () => { |
||||||
|
setScrollRestoration('auto') |
||||||
|
}) |
||||||
|
|
||||||
|
// Setting scrollRestoration to manual again when returning to this page.
|
||||||
|
window.addEventListener('load', () => { |
||||||
|
setScrollRestoration('manual') |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function shouldScrollToTop(route) { |
||||||
|
const Pages = getMatchedComponents(route) |
||||||
|
if (Pages.length === 1) { |
||||||
|
const { options = {} } = Pages[0] |
||||||
|
return options.scrollToTop !== false |
||||||
|
} |
||||||
|
return Pages.some(({ options }) => options && options.scrollToTop) |
||||||
|
} |
||||||
|
|
||||||
|
export default function (to, from, savedPosition) { |
||||||
|
// If the returned position is falsy or an empty object, will retain current scroll position
|
||||||
|
let position = false |
||||||
|
const isRouteChanged = to !== from |
||||||
|
|
||||||
|
// savedPosition is only available for popstate navigations (back button)
|
||||||
|
if (savedPosition) { |
||||||
|
position = savedPosition |
||||||
|
} else if (isRouteChanged && shouldScrollToTop(to)) { |
||||||
|
position = { x: 0, y: 0 } |
||||||
|
} |
||||||
|
|
||||||
|
const nuxt = window.$nuxt |
||||||
|
|
||||||
|
if ( |
||||||
|
// Initial load (vuejs/vue-router#3199)
|
||||||
|
!isRouteChanged || |
||||||
|
// Route hash changes
|
||||||
|
(to.path === from.path && to.hash !== from.hash) |
||||||
|
) { |
||||||
|
nuxt.$nextTick(() => nuxt.$emit('triggerScroll')) |
||||||
|
} |
||||||
|
|
||||||
|
return new Promise((resolve) => { |
||||||
|
// wait for the out transition to complete (if necessary)
|
||||||
|
nuxt.$once('triggerScroll', () => { |
||||||
|
// coords will be used if no selector is provided,
|
||||||
|
// or if the selector didn't match any element.
|
||||||
|
if (to.hash) { |
||||||
|
let hash = to.hash |
||||||
|
// CSS.escape() is not supported with IE and Edge.
|
||||||
|
if (typeof window.CSS !== 'undefined' && typeof window.CSS.escape !== 'undefined') { |
||||||
|
hash = '#' + window.CSS.escape(hash.substr(1)) |
||||||
|
} |
||||||
|
try { |
||||||
|
if (document.querySelector(hash)) { |
||||||
|
// scroll to anchor by returning the selector
|
||||||
|
position = { selector: hash } |
||||||
|
} |
||||||
|
} catch (e) { |
||||||
|
console.warn('Failed to save scroll position. Please add CSS.escape() polyfill (https://github.com/mathiasbynens/CSS.escape).') |
||||||
|
} |
||||||
|
} |
||||||
|
resolve(position) |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
@ -0,0 +1,110 @@ |
|||||||
|
[ |
||||||
|
{ |
||||||
|
"name": "article", |
||||||
|
"path": "/article", |
||||||
|
"component": "/home/kola-wsl/project/tangwang-pc/src/pages/article/index.vue", |
||||||
|
"chunkName": "pages/article/index" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "doctor", |
||||||
|
"path": "/doctor", |
||||||
|
"component": "/home/kola-wsl/project/tangwang-pc/src/pages/doctor/index.vue", |
||||||
|
"chunkName": "pages/doctor/index" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "more", |
||||||
|
"path": "/more", |
||||||
|
"component": "/home/kola-wsl/project/tangwang-pc/src/pages/more.vue", |
||||||
|
"chunkName": "pages/more" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "search", |
||||||
|
"path": "/search", |
||||||
|
"component": "/home/kola-wsl/project/tangwang-pc/src/pages/search/index.vue", |
||||||
|
"chunkName": "pages/search/index" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "user", |
||||||
|
"path": "/user", |
||||||
|
"component": "/home/kola-wsl/project/tangwang-pc/src/pages/user/index.vue", |
||||||
|
"chunkName": "pages/user/index" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "video", |
||||||
|
"path": "/video", |
||||||
|
"component": "/home/kola-wsl/project/tangwang-pc/src/pages/video/index.vue", |
||||||
|
"chunkName": "pages/video/index" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "other-about", |
||||||
|
"path": "/other/about", |
||||||
|
"component": "/home/kola-wsl/project/tangwang-pc/src/pages/other/about.vue", |
||||||
|
"chunkName": "pages/other/about" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "other-agreement", |
||||||
|
"path": "/other/agreement", |
||||||
|
"component": "/home/kola-wsl/project/tangwang-pc/src/pages/other/agreement.vue", |
||||||
|
"chunkName": "pages/other/agreement" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "other-cookies", |
||||||
|
"path": "/other/cookies", |
||||||
|
"component": "/home/kola-wsl/project/tangwang-pc/src/pages/other/cookies.vue", |
||||||
|
"chunkName": "pages/other/cookies" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "other-corporate", |
||||||
|
"path": "/other/corporate", |
||||||
|
"component": "/home/kola-wsl/project/tangwang-pc/src/pages/other/corporate.vue", |
||||||
|
"chunkName": "pages/other/corporate" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "other-disclaimer", |
||||||
|
"path": "/other/disclaimer", |
||||||
|
"component": "/home/kola-wsl/project/tangwang-pc/src/pages/other/disclaimer.vue", |
||||||
|
"chunkName": "pages/other/disclaimer" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "other-link", |
||||||
|
"path": "/other/link", |
||||||
|
"component": "/home/kola-wsl/project/tangwang-pc/src/pages/other/link.vue", |
||||||
|
"chunkName": "pages/other/link" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "other-privacy", |
||||||
|
"path": "/other/privacy", |
||||||
|
"component": "/home/kola-wsl/project/tangwang-pc/src/pages/other/privacy.vue", |
||||||
|
"chunkName": "pages/other/privacy" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "user-setting", |
||||||
|
"path": "/user/setting", |
||||||
|
"component": "/home/kola-wsl/project/tangwang-pc/src/pages/user/setting.vue", |
||||||
|
"chunkName": "pages/user/setting" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "article-id", |
||||||
|
"path": "/article/:id", |
||||||
|
"component": "/home/kola-wsl/project/tangwang-pc/src/pages/article/_id.vue", |
||||||
|
"chunkName": "pages/article/_id" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "doctor-id", |
||||||
|
"path": "/doctor/:id", |
||||||
|
"component": "/home/kola-wsl/project/tangwang-pc/src/pages/doctor/_id.vue", |
||||||
|
"chunkName": "pages/doctor/_id" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "video-id", |
||||||
|
"path": "/video/:id", |
||||||
|
"component": "/home/kola-wsl/project/tangwang-pc/src/pages/video/_id.vue", |
||||||
|
"chunkName": "pages/video/_id" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "index", |
||||||
|
"path": "/", |
||||||
|
"component": "/home/kola-wsl/project/tangwang-pc/src/pages/index.vue", |
||||||
|
"chunkName": "pages/index" |
||||||
|
} |
||||||
|
] |
@ -0,0 +1,292 @@ |
|||||||
|
import Vue from 'vue' |
||||||
|
import { joinURL, normalizeURL, withQuery } from 'ufo' |
||||||
|
import fetch from 'node-fetch' |
||||||
|
import middleware from './middleware.js' |
||||||
|
import { |
||||||
|
applyAsyncData, |
||||||
|
middlewareSeries, |
||||||
|
sanitizeComponent, |
||||||
|
getMatchedComponents, |
||||||
|
promisify |
||||||
|
} from './utils.js' |
||||||
|
import fetchMixin from './mixins/fetch.server' |
||||||
|
import { createApp, NuxtError } from './index.js' |
||||||
|
import NuxtLink from './components/nuxt-link.server.js' // should be included after ./index.js
|
||||||
|
|
||||||
|
// Update serverPrefetch strategy
|
||||||
|
Vue.config.optionMergeStrategies.serverPrefetch = Vue.config.optionMergeStrategies.created |
||||||
|
|
||||||
|
// Fetch mixin
|
||||||
|
if (!Vue.__nuxt__fetch__mixin__) { |
||||||
|
Vue.mixin(fetchMixin) |
||||||
|
Vue.__nuxt__fetch__mixin__ = true |
||||||
|
} |
||||||
|
|
||||||
|
// Component: <NuxtLink>
|
||||||
|
Vue.component(NuxtLink.name, NuxtLink) |
||||||
|
Vue.component('NLink', NuxtLink) |
||||||
|
|
||||||
|
if (!global.fetch) { global.fetch = fetch } |
||||||
|
|
||||||
|
const noopApp = () => new Vue({ render: h => h('div', { domProps: { id: '__nuxt' } }) }) |
||||||
|
|
||||||
|
const createNext = ssrContext => (opts) => { |
||||||
|
// If static target, render on client-side
|
||||||
|
ssrContext.redirected = opts |
||||||
|
if (ssrContext.target === 'static' || !ssrContext.res) { |
||||||
|
ssrContext.nuxt.serverRendered = false |
||||||
|
return |
||||||
|
} |
||||||
|
let fullPath = withQuery(opts.path, opts.query) |
||||||
|
const $config = ssrContext.runtimeConfig || {} |
||||||
|
const routerBase = ($config._app && $config._app.basePath) || '/' |
||||||
|
if (!fullPath.startsWith('http') && (routerBase !== '/' && !fullPath.startsWith(routerBase))) { |
||||||
|
fullPath = joinURL(routerBase, fullPath) |
||||||
|
} |
||||||
|
// Avoid loop redirect
|
||||||
|
if (decodeURI(fullPath) === decodeURI(ssrContext.url)) { |
||||||
|
ssrContext.redirected = false |
||||||
|
return |
||||||
|
} |
||||||
|
ssrContext.res.writeHead(opts.status, { |
||||||
|
Location: normalizeURL(fullPath) |
||||||
|
}) |
||||||
|
ssrContext.res.end() |
||||||
|
} |
||||||
|
|
||||||
|
// This exported function will be called by `bundleRenderer`.
|
||||||
|
// This is where we perform data-prefetching to determine the
|
||||||
|
// state of our application before actually rendering it.
|
||||||
|
// Since data fetching is async, this function is expected to
|
||||||
|
// return a Promise that resolves to the app instance.
|
||||||
|
export default async (ssrContext) => { |
||||||
|
// Create ssrContext.next for simulate next() of beforeEach() when wanted to redirect
|
||||||
|
ssrContext.redirected = false |
||||||
|
ssrContext.next = createNext(ssrContext) |
||||||
|
// Used for beforeNuxtRender({ Components, nuxtState })
|
||||||
|
ssrContext.beforeRenderFns = [] |
||||||
|
// Nuxt object (window.{{globals.context}}, defaults to window.__NUXT__)
|
||||||
|
ssrContext.nuxt = { layout: 'default', data: [], fetch: {}, error: null, state: null, serverRendered: true, routePath: '' } |
||||||
|
|
||||||
|
ssrContext.fetchCounters = {} |
||||||
|
|
||||||
|
// Remove query from url is static target
|
||||||
|
|
||||||
|
// Public runtime config
|
||||||
|
ssrContext.nuxt.config = ssrContext.runtimeConfig.public |
||||||
|
if (ssrContext.nuxt.config._app) { |
||||||
|
__webpack_public_path__ = joinURL(ssrContext.nuxt.config._app.cdnURL, ssrContext.nuxt.config._app.assetsPath) |
||||||
|
} |
||||||
|
// Create the app definition and the instance (created for each request)
|
||||||
|
const { app, router, store } = await createApp(ssrContext, ssrContext.runtimeConfig.private) |
||||||
|
const _app = new Vue(app) |
||||||
|
// Add ssr route path to nuxt context so we can account for page navigation between ssr and csr
|
||||||
|
ssrContext.nuxt.routePath = app.context.route.path |
||||||
|
|
||||||
|
// Add meta infos (used in renderer.js)
|
||||||
|
ssrContext.meta = _app.$meta() |
||||||
|
|
||||||
|
// Keep asyncData for each matched component in ssrContext (used in app/utils.js via this.$ssrContext)
|
||||||
|
ssrContext.asyncData = {} |
||||||
|
|
||||||
|
const beforeRender = async () => { |
||||||
|
// Call beforeNuxtRender() methods
|
||||||
|
await Promise.all(ssrContext.beforeRenderFns.map(fn => promisify(fn, { Components, nuxtState: ssrContext.nuxt }))) |
||||||
|
|
||||||
|
ssrContext.rendered = () => { |
||||||
|
// Add the state from the vuex store
|
||||||
|
ssrContext.nuxt.state = store.state |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const renderErrorPage = async () => { |
||||||
|
// Don't server-render the page in static target
|
||||||
|
if (ssrContext.target === 'static') { |
||||||
|
ssrContext.nuxt.serverRendered = false |
||||||
|
} |
||||||
|
|
||||||
|
// Load layout for error page
|
||||||
|
const layout = (NuxtError.options || NuxtError).layout |
||||||
|
const errLayout = typeof layout === 'function' ? layout.call(NuxtError, app.context) : layout |
||||||
|
ssrContext.nuxt.layout = errLayout || 'default' |
||||||
|
await _app.loadLayout(errLayout) |
||||||
|
_app.setLayout(errLayout) |
||||||
|
|
||||||
|
await beforeRender() |
||||||
|
return _app |
||||||
|
} |
||||||
|
const render404Page = () => { |
||||||
|
app.context.error({ statusCode: 404, path: ssrContext.url, message: 'This page could not be found' }) |
||||||
|
return renderErrorPage() |
||||||
|
} |
||||||
|
|
||||||
|
// Components are already resolved by setContext -> getRouteData (app/utils.js)
|
||||||
|
const Components = getMatchedComponents(app.context.route) |
||||||
|
|
||||||
|
/* |
||||||
|
** Dispatch store nuxtServerInit |
||||||
|
*/ |
||||||
|
if (store._actions && store._actions.nuxtServerInit) { |
||||||
|
try { |
||||||
|
await store.dispatch('nuxtServerInit', app.context) |
||||||
|
} catch (err) { |
||||||
|
console.debug('Error occurred when calling nuxtServerInit: ', err.message) |
||||||
|
throw err |
||||||
|
} |
||||||
|
} |
||||||
|
// ...If there is a redirect or an error, stop the process
|
||||||
|
if (ssrContext.redirected) { |
||||||
|
return noopApp() |
||||||
|
} |
||||||
|
if (ssrContext.nuxt.error) { |
||||||
|
return renderErrorPage() |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
** Call global middleware (nuxt.config.js) |
||||||
|
*/ |
||||||
|
let midd = ["device"] |
||||||
|
midd = midd.map((name) => { |
||||||
|
if (typeof name === 'function') { |
||||||
|
return name |
||||||
|
} |
||||||
|
if (typeof middleware[name] !== 'function') { |
||||||
|
app.context.error({ statusCode: 500, message: 'Unknown middleware ' + name }) |
||||||
|
} |
||||||
|
return middleware[name] |
||||||
|
}) |
||||||
|
await middlewareSeries(midd, app.context) |
||||||
|
// ...If there is a redirect or an error, stop the process
|
||||||
|
if (ssrContext.redirected) { |
||||||
|
return noopApp() |
||||||
|
} |
||||||
|
if (ssrContext.nuxt.error) { |
||||||
|
return renderErrorPage() |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
** Set layout |
||||||
|
*/ |
||||||
|
let layout = Components.length ? Components[0].options.layout : NuxtError.layout |
||||||
|
if (typeof layout === 'function') { |
||||||
|
layout = layout(app.context) |
||||||
|
} |
||||||
|
await _app.loadLayout(layout) |
||||||
|
if (ssrContext.nuxt.error) { |
||||||
|
return renderErrorPage() |
||||||
|
} |
||||||
|
layout = _app.setLayout(layout) |
||||||
|
ssrContext.nuxt.layout = _app.layoutName |
||||||
|
|
||||||
|
/* |
||||||
|
** Call middleware (layout + pages) |
||||||
|
*/ |
||||||
|
midd = [] |
||||||
|
|
||||||
|
layout = sanitizeComponent(layout) |
||||||
|
if (layout.options.middleware) { |
||||||
|
midd = midd.concat(layout.options.middleware) |
||||||
|
} |
||||||
|
|
||||||
|
Components.forEach((Component) => { |
||||||
|
if (Component.options.middleware) { |
||||||
|
midd = midd.concat(Component.options.middleware) |
||||||
|
} |
||||||
|
}) |
||||||
|
midd = midd.map((name) => { |
||||||
|
if (typeof name === 'function') { |
||||||
|
return name |
||||||
|
} |
||||||
|
if (typeof middleware[name] !== 'function') { |
||||||
|
app.context.error({ statusCode: 500, message: 'Unknown middleware ' + name }) |
||||||
|
} |
||||||
|
return middleware[name] |
||||||
|
}) |
||||||
|
await middlewareSeries(midd, app.context) |
||||||
|
// ...If there is a redirect or an error, stop the process
|
||||||
|
if (ssrContext.redirected) { |
||||||
|
return noopApp() |
||||||
|
} |
||||||
|
if (ssrContext.nuxt.error) { |
||||||
|
return renderErrorPage() |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
** Call .validate() |
||||||
|
*/ |
||||||
|
let isValid = true |
||||||
|
try { |
||||||
|
for (const Component of Components) { |
||||||
|
if (typeof Component.options.validate !== 'function') { |
||||||
|
continue |
||||||
|
} |
||||||
|
|
||||||
|
isValid = await Component.options.validate(app.context) |
||||||
|
|
||||||
|
if (!isValid) { |
||||||
|
break |
||||||
|
} |
||||||
|
} |
||||||
|
} catch (validationError) { |
||||||
|
// ...If .validate() threw an error
|
||||||
|
app.context.error({ |
||||||
|
statusCode: validationError.statusCode || '500', |
||||||
|
message: validationError.message |
||||||
|
}) |
||||||
|
return renderErrorPage() |
||||||
|
} |
||||||
|
|
||||||
|
// ...If .validate() returned false
|
||||||
|
if (!isValid) { |
||||||
|
// Render a 404 error page
|
||||||
|
return render404Page() |
||||||
|
} |
||||||
|
|
||||||
|
// If no Components found, returns 404
|
||||||
|
if (!Components.length) { |
||||||
|
return render404Page() |
||||||
|
} |
||||||
|
|
||||||
|
// Call asyncData & fetch hooks on components matched by the route.
|
||||||
|
const asyncDatas = await Promise.all(Components.map((Component) => { |
||||||
|
const promises = [] |
||||||
|
|
||||||
|
// Call asyncData(context)
|
||||||
|
if (Component.options.asyncData && typeof Component.options.asyncData === 'function') { |
||||||
|
const promise = promisify(Component.options.asyncData, app.context) |
||||||
|
promise.then((asyncDataResult) => { |
||||||
|
ssrContext.asyncData[Component.cid] = asyncDataResult |
||||||
|
applyAsyncData(Component) |
||||||
|
return asyncDataResult |
||||||
|
}) |
||||||
|
promises.push(promise) |
||||||
|
} else { |
||||||
|
promises.push(null) |
||||||
|
} |
||||||
|
|
||||||
|
// Call fetch(context)
|
||||||
|
if (Component.options.fetch && Component.options.fetch.length) { |
||||||
|
promises.push(Component.options.fetch(app.context)) |
||||||
|
} else { |
||||||
|
promises.push(null) |
||||||
|
} |
||||||
|
|
||||||
|
return Promise.all(promises) |
||||||
|
})) |
||||||
|
|
||||||
|
// datas are the first row of each
|
||||||
|
ssrContext.nuxt.data = asyncDatas.map(r => r[0] || {}) |
||||||
|
|
||||||
|
// ...If there is a redirect or an error, stop the process
|
||||||
|
if (ssrContext.redirected) { |
||||||
|
return noopApp() |
||||||
|
} |
||||||
|
if (ssrContext.nuxt.error) { |
||||||
|
return renderErrorPage() |
||||||
|
} |
||||||
|
|
||||||
|
// Call beforeNuxtRender methods & add store state
|
||||||
|
await beforeRender() |
||||||
|
|
||||||
|
return _app |
||||||
|
} |
@ -0,0 +1,130 @@ |
|||||||
|
import Vue from 'vue' |
||||||
|
import Vuex from 'vuex' |
||||||
|
|
||||||
|
Vue.use(Vuex) |
||||||
|
|
||||||
|
const VUEX_PROPERTIES = ['state', 'getters', 'actions', 'mutations'] |
||||||
|
|
||||||
|
let store = {}; |
||||||
|
|
||||||
|
(function updateModules () { |
||||||
|
store = normalizeRoot(require('../src/store/index.js'), 'store/index.js') |
||||||
|
|
||||||
|
// If store is an exported method = classic mode (deprecated)
|
||||||
|
|
||||||
|
// Enforce store modules
|
||||||
|
store.modules = store.modules || {} |
||||||
|
|
||||||
|
resolveStoreModules(require('../src/store/device.js'), 'device.js') |
||||||
|
resolveStoreModules(require('../src/store/user.js'), 'user.js') |
||||||
|
|
||||||
|
// If the environment supports hot reloading...
|
||||||
|
})() |
||||||
|
|
||||||
|
// createStore
|
||||||
|
export const createStore = store instanceof Function ? store : () => { |
||||||
|
return new Vuex.Store(Object.assign({ |
||||||
|
strict: (process.env.NODE_ENV !== 'production') |
||||||
|
}, store)) |
||||||
|
} |
||||||
|
|
||||||
|
function normalizeRoot (moduleData, filePath) { |
||||||
|
moduleData = moduleData.default || moduleData |
||||||
|
|
||||||
|
if (moduleData.commit) { |
||||||
|
throw new Error(`[nuxt] ${filePath} should export a method that returns a Vuex instance.`) |
||||||
|
} |
||||||
|
|
||||||
|
if (typeof moduleData !== 'function') { |
||||||
|
// Avoid TypeError: setting a property that has only a getter when overwriting top level keys
|
||||||
|
moduleData = Object.assign({}, moduleData) |
||||||
|
} |
||||||
|
return normalizeModule(moduleData, filePath) |
||||||
|
} |
||||||
|
|
||||||
|
function normalizeModule (moduleData, filePath) { |
||||||
|
if (moduleData.state && typeof moduleData.state !== 'function') { |
||||||
|
console.warn(`'state' should be a method that returns an object in ${filePath}`) |
||||||
|
|
||||||
|
const state = Object.assign({}, moduleData.state) |
||||||
|
// Avoid TypeError: setting a property that has only a getter when overwriting top level keys
|
||||||
|
moduleData = Object.assign({}, moduleData, { state: () => state }) |
||||||
|
} |
||||||
|
return moduleData |
||||||
|
} |
||||||
|
|
||||||
|
function resolveStoreModules (moduleData, filename) { |
||||||
|
moduleData = moduleData.default || moduleData |
||||||
|
// Remove store src + extension (./foo/index.js -> foo/index)
|
||||||
|
const namespace = filename.replace(/\.(js|mjs)$/, '') |
||||||
|
const namespaces = namespace.split('/') |
||||||
|
let moduleName = namespaces[namespaces.length - 1] |
||||||
|
const filePath = `store/${filename}` |
||||||
|
|
||||||
|
moduleData = moduleName === 'state' |
||||||
|
? normalizeState(moduleData, filePath) |
||||||
|
: normalizeModule(moduleData, filePath) |
||||||
|
|
||||||
|
// If src is a known Vuex property
|
||||||
|
if (VUEX_PROPERTIES.includes(moduleName)) { |
||||||
|
const property = moduleName |
||||||
|
const propertyStoreModule = getStoreModule(store, namespaces, { isProperty: true }) |
||||||
|
|
||||||
|
// Replace state since it's a function
|
||||||
|
mergeProperty(propertyStoreModule, moduleData, property) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// If file is foo/index.js, it should be saved as foo
|
||||||
|
const isIndexModule = (moduleName === 'index') |
||||||
|
if (isIndexModule) { |
||||||
|
namespaces.pop() |
||||||
|
moduleName = namespaces[namespaces.length - 1] |
||||||
|
} |
||||||
|
|
||||||
|
const storeModule = getStoreModule(store, namespaces) |
||||||
|
|
||||||
|
for (const property of VUEX_PROPERTIES) { |
||||||
|
mergeProperty(storeModule, moduleData[property], property) |
||||||
|
} |
||||||
|
|
||||||
|
if (moduleData.namespaced === false) { |
||||||
|
delete storeModule.namespaced |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function normalizeState (moduleData, filePath) { |
||||||
|
if (typeof moduleData !== 'function') { |
||||||
|
console.warn(`${filePath} should export a method that returns an object`) |
||||||
|
const state = Object.assign({}, moduleData) |
||||||
|
return () => state |
||||||
|
} |
||||||
|
return normalizeModule(moduleData, filePath) |
||||||
|
} |
||||||
|
|
||||||
|
function getStoreModule (storeModule, namespaces, { isProperty = false } = {}) { |
||||||
|
// If ./mutations.js
|
||||||
|
if (!namespaces.length || (isProperty && namespaces.length === 1)) { |
||||||
|
return storeModule |
||||||
|
} |
||||||
|
|
||||||
|
const namespace = namespaces.shift() |
||||||
|
|
||||||
|
storeModule.modules[namespace] = storeModule.modules[namespace] || {} |
||||||
|
storeModule.modules[namespace].namespaced = true |
||||||
|
storeModule.modules[namespace].modules = storeModule.modules[namespace].modules || {} |
||||||
|
|
||||||
|
return getStoreModule(storeModule.modules[namespace], namespaces, { isProperty }) |
||||||
|
} |
||||||
|
|
||||||
|
function mergeProperty (storeModule, moduleData, property) { |
||||||
|
if (!moduleData) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
if (property === 'state') { |
||||||
|
storeModule.state = moduleData || storeModule.state |
||||||
|
} else { |
||||||
|
storeModule[property] = Object.assign({}, storeModule[property], moduleData) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,627 @@ |
|||||||
|
import Vue from 'vue' |
||||||
|
import { isSamePath as _isSamePath, joinURL, normalizeURL, withQuery, withoutTrailingSlash } from 'ufo' |
||||||
|
|
||||||
|
// window.{{globals.loadedCallback}} hook
|
||||||
|
// Useful for jsdom testing or plugins (https://github.com/tmpvar/jsdom#dealing-with-asynchronous-script-loading)
|
||||||
|
if (process.client) { |
||||||
|
window.onNuxtReadyCbs = [] |
||||||
|
window.onNuxtReady = (cb) => { |
||||||
|
window.onNuxtReadyCbs.push(cb) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export function createGetCounter (counterObject, defaultKey = '') { |
||||||
|
return function getCounter (id = defaultKey) { |
||||||
|
if (counterObject[id] === undefined) { |
||||||
|
counterObject[id] = 0 |
||||||
|
} |
||||||
|
return counterObject[id]++ |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export function empty () {} |
||||||
|
|
||||||
|
export function globalHandleError (error) { |
||||||
|
if (Vue.config.errorHandler) { |
||||||
|
Vue.config.errorHandler(error) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export function interopDefault (promise) { |
||||||
|
return promise.then(m => m.default || m) |
||||||
|
} |
||||||
|
|
||||||
|
export function hasFetch(vm) { |
||||||
|
return vm.$options && typeof vm.$options.fetch === 'function' && !vm.$options.fetch.length |
||||||
|
} |
||||||
|
export function purifyData(data) { |
||||||
|
if (process.env.NODE_ENV === 'production') { |
||||||
|
return data |
||||||
|
} |
||||||
|
|
||||||
|
return Object.entries(data).filter( |
||||||
|
([key, value]) => { |
||||||
|
const valid = !(value instanceof Function) && !(value instanceof Promise) |
||||||
|
if (!valid) { |
||||||
|
console.warn(`${key} is not able to be stringified. This will break in a production environment.`) |
||||||
|
} |
||||||
|
return valid |
||||||
|
} |
||||||
|
).reduce((obj, [key, value]) => { |
||||||
|
obj[key] = value |
||||||
|
return obj |
||||||
|
}, {}) |
||||||
|
} |
||||||
|
export function getChildrenComponentInstancesUsingFetch(vm, instances = []) { |
||||||
|
const children = vm.$children || [] |
||||||
|
for (const child of children) { |
||||||
|
if (child.$fetch) { |
||||||
|
instances.push(child) |
||||||
|
continue; // Don't get the children since it will reload the template
|
||||||
|
} |
||||||
|
if (child.$children) { |
||||||
|
getChildrenComponentInstancesUsingFetch(child, instances) |
||||||
|
} |
||||||
|
} |
||||||
|
return instances |
||||||
|
} |
||||||
|
|
||||||
|
export function applyAsyncData (Component, asyncData) { |
||||||
|
if ( |
||||||
|
// For SSR, we once all this function without second param to just apply asyncData
|
||||||
|
// Prevent doing this for each SSR request
|
||||||
|
!asyncData && Component.options.__hasNuxtData |
||||||
|
) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
const ComponentData = Component.options._originDataFn || Component.options.data || function () { return {} } |
||||||
|
Component.options._originDataFn = ComponentData |
||||||
|
|
||||||
|
Component.options.data = function () { |
||||||
|
const data = ComponentData.call(this, this) |
||||||
|
if (this.$ssrContext) { |
||||||
|
asyncData = this.$ssrContext.asyncData[Component.cid] |
||||||
|
} |
||||||
|
return { ...data, ...asyncData } |
||||||
|
} |
||||||
|
|
||||||
|
Component.options.__hasNuxtData = true |
||||||
|
|
||||||
|
if (Component._Ctor && Component._Ctor.options) { |
||||||
|
Component._Ctor.options.data = Component.options.data |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export function sanitizeComponent (Component) { |
||||||
|
// If Component already sanitized
|
||||||
|
if (Component.options && Component._Ctor === Component) { |
||||||
|
return Component |
||||||
|
} |
||||||
|
if (!Component.options) { |
||||||
|
Component = Vue.extend(Component) // fix issue #6
|
||||||
|
Component._Ctor = Component |
||||||
|
} else { |
||||||
|
Component._Ctor = Component |
||||||
|
Component.extendOptions = Component.options |
||||||
|
} |
||||||
|
// If no component name defined, set file path as name, (also fixes #5703)
|
||||||
|
if (!Component.options.name && Component.options.__file) { |
||||||
|
Component.options.name = Component.options.__file |
||||||
|
} |
||||||
|
return Component |
||||||
|
} |
||||||
|
|
||||||
|
export function getMatchedComponents (route, matches = false, prop = 'components') { |
||||||
|
return Array.prototype.concat.apply([], route.matched.map((m, index) => { |
||||||
|
return Object.keys(m[prop]).map((key) => { |
||||||
|
matches && matches.push(index) |
||||||
|
return m[prop][key] |
||||||
|
}) |
||||||
|
})) |
||||||
|
} |
||||||
|
|
||||||
|
export function getMatchedComponentsInstances (route, matches = false) { |
||||||
|
return getMatchedComponents(route, matches, 'instances') |
||||||
|
} |
||||||
|
|
||||||
|
export function flatMapComponents (route, fn) { |
||||||
|
return Array.prototype.concat.apply([], route.matched.map((m, index) => { |
||||||
|
return Object.keys(m.components).reduce((promises, key) => { |
||||||
|
if (m.components[key]) { |
||||||
|
promises.push(fn(m.components[key], m.instances[key], m, key, index)) |
||||||
|
} else { |
||||||
|
delete m.components[key] |
||||||
|
} |
||||||
|
return promises |
||||||
|
}, []) |
||||||
|
})) |
||||||
|
} |
||||||
|
|
||||||
|
export function resolveRouteComponents (route, fn) { |
||||||
|
return Promise.all( |
||||||
|
flatMapComponents(route, async (Component, instance, match, key) => { |
||||||
|
// If component is a function, resolve it
|
||||||
|
if (typeof Component === 'function' && !Component.options) { |
||||||
|
try { |
||||||
|
Component = await Component() |
||||||
|
} catch (error) { |
||||||
|
// Handle webpack chunk loading errors
|
||||||
|
// This may be due to a new deployment or a network problem
|
||||||
|
if ( |
||||||
|
error && |
||||||
|
error.name === 'ChunkLoadError' && |
||||||
|
typeof window !== 'undefined' && |
||||||
|
window.sessionStorage |
||||||
|
) { |
||||||
|
const timeNow = Date.now() |
||||||
|
const previousReloadTime = parseInt(window.sessionStorage.getItem('nuxt-reload')) |
||||||
|
|
||||||
|
// check for previous reload time not to reload infinitely
|
||||||
|
if (!previousReloadTime || previousReloadTime + 60000 < timeNow) { |
||||||
|
window.sessionStorage.setItem('nuxt-reload', timeNow) |
||||||
|
window.location.reload(true /* skip cache */) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
throw error |
||||||
|
} |
||||||
|
} |
||||||
|
match.components[key] = Component = sanitizeComponent(Component) |
||||||
|
return typeof fn === 'function' ? fn(Component, instance, match, key) : Component |
||||||
|
}) |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
export async function getRouteData (route) { |
||||||
|
if (!route) { |
||||||
|
return |
||||||
|
} |
||||||
|
// Make sure the components are resolved (code-splitting)
|
||||||
|
await resolveRouteComponents(route) |
||||||
|
// Send back a copy of route with meta based on Component definition
|
||||||
|
return { |
||||||
|
...route, |
||||||
|
meta: getMatchedComponents(route).map((Component, index) => { |
||||||
|
return { ...Component.options.meta, ...(route.matched[index] || {}).meta } |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export async function setContext (app, context) { |
||||||
|
// If context not defined, create it
|
||||||
|
if (!app.context) { |
||||||
|
app.context = { |
||||||
|
isStatic: process.static, |
||||||
|
isDev: false, |
||||||
|
isHMR: false, |
||||||
|
app, |
||||||
|
store: app.store, |
||||||
|
payload: context.payload, |
||||||
|
error: context.error, |
||||||
|
base: app.router.options.base, |
||||||
|
env: {"VUE_APP_TITLE":"production"} |
||||||
|
} |
||||||
|
// Only set once
|
||||||
|
|
||||||
|
if (context.req) { |
||||||
|
app.context.req = context.req |
||||||
|
} |
||||||
|
if (context.res) { |
||||||
|
app.context.res = context.res |
||||||
|
} |
||||||
|
|
||||||
|
if (context.ssrContext) { |
||||||
|
app.context.ssrContext = context.ssrContext |
||||||
|
} |
||||||
|
app.context.redirect = (status, path, query) => { |
||||||
|
if (!status) { |
||||||
|
return |
||||||
|
} |
||||||
|
app.context._redirected = true |
||||||
|
// if only 1 or 2 arguments: redirect('/') or redirect('/', { foo: 'bar' })
|
||||||
|
let pathType = typeof path |
||||||
|
if (typeof status !== 'number' && (pathType === 'undefined' || pathType === 'object')) { |
||||||
|
query = path || {} |
||||||
|
path = status |
||||||
|
pathType = typeof path |
||||||
|
status = 302 |
||||||
|
} |
||||||
|
if (pathType === 'object') { |
||||||
|
path = app.router.resolve(path).route.fullPath |
||||||
|
} |
||||||
|
// "/absolute/route", "./relative/route" or "../relative/route"
|
||||||
|
if (/(^[.]{1,2}\/)|(^\/(?!\/))/.test(path)) { |
||||||
|
app.context.next({ |
||||||
|
path, |
||||||
|
query, |
||||||
|
status |
||||||
|
}) |
||||||
|
} else { |
||||||
|
path = withQuery(path, query) |
||||||
|
if (process.server) { |
||||||
|
app.context.next({ |
||||||
|
path, |
||||||
|
status |
||||||
|
}) |
||||||
|
} |
||||||
|
if (process.client) { |
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/API/Location/replace
|
||||||
|
window.location.replace(path) |
||||||
|
|
||||||
|
// Throw a redirect error
|
||||||
|
throw new Error('ERR_REDIRECT') |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
if (process.server) { |
||||||
|
app.context.beforeNuxtRender = fn => context.beforeRenderFns.push(fn) |
||||||
|
} |
||||||
|
if (process.client) { |
||||||
|
app.context.nuxtState = window.__NUXT__ |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Dynamic keys
|
||||||
|
const [currentRouteData, fromRouteData] = await Promise.all([ |
||||||
|
getRouteData(context.route), |
||||||
|
getRouteData(context.from) |
||||||
|
]) |
||||||
|
|
||||||
|
if (context.route) { |
||||||
|
app.context.route = currentRouteData |
||||||
|
} |
||||||
|
|
||||||
|
if (context.from) { |
||||||
|
app.context.from = fromRouteData |
||||||
|
} |
||||||
|
|
||||||
|
app.context.next = context.next |
||||||
|
app.context._redirected = false |
||||||
|
app.context._errored = false |
||||||
|
app.context.isHMR = false |
||||||
|
app.context.params = app.context.route.params || {} |
||||||
|
app.context.query = app.context.route.query || {} |
||||||
|
} |
||||||
|
|
||||||
|
export function middlewareSeries (promises, appContext) { |
||||||
|
if (!promises.length || appContext._redirected || appContext._errored) { |
||||||
|
return Promise.resolve() |
||||||
|
} |
||||||
|
return promisify(promises[0], appContext) |
||||||
|
.then(() => { |
||||||
|
return middlewareSeries(promises.slice(1), appContext) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
export function promisify (fn, context) { |
||||||
|
let promise |
||||||
|
if (fn.length === 2) { |
||||||
|
// fn(context, callback)
|
||||||
|
promise = new Promise((resolve) => { |
||||||
|
fn(context, function (err, data) { |
||||||
|
if (err) { |
||||||
|
context.error(err) |
||||||
|
} |
||||||
|
data = data || {} |
||||||
|
resolve(data) |
||||||
|
}) |
||||||
|
}) |
||||||
|
} else { |
||||||
|
promise = fn(context) |
||||||
|
} |
||||||
|
|
||||||
|
if (promise && promise instanceof Promise && typeof promise.then === 'function') { |
||||||
|
return promise |
||||||
|
} |
||||||
|
return Promise.resolve(promise) |
||||||
|
} |
||||||
|
|
||||||
|
// Imported from vue-router
|
||||||
|
export function getLocation (base, mode) { |
||||||
|
if (mode === 'hash') { |
||||||
|
return window.location.hash.replace(/^#\//, '') |
||||||
|
} |
||||||
|
|
||||||
|
base = decodeURI(base).slice(0, -1) // consideration is base is normalized with trailing slash
|
||||||
|
let path = decodeURI(window.location.pathname) |
||||||
|
|
||||||
|
if (base && path.startsWith(base)) { |
||||||
|
path = path.slice(base.length) |
||||||
|
} |
||||||
|
|
||||||
|
const fullPath = (path || '/') + window.location.search + window.location.hash |
||||||
|
|
||||||
|
return normalizeURL(fullPath) |
||||||
|
} |
||||||
|
|
||||||
|
// Imported from path-to-regexp
|
||||||
|
|
||||||
|
/** |
||||||
|
* Compile a string to a template function for the path. |
||||||
|
* |
||||||
|
* @param {string} str |
||||||
|
* @param {Object=} options |
||||||
|
* @return {!function(Object=, Object=)} |
||||||
|
*/ |
||||||
|
export function compile (str, options) { |
||||||
|
return tokensToFunction(parse(str, options), options) |
||||||
|
} |
||||||
|
|
||||||
|
export function getQueryDiff (toQuery, fromQuery) { |
||||||
|
const diff = {} |
||||||
|
const queries = { ...toQuery, ...fromQuery } |
||||||
|
for (const k in queries) { |
||||||
|
if (String(toQuery[k]) !== String(fromQuery[k])) { |
||||||
|
diff[k] = true |
||||||
|
} |
||||||
|
} |
||||||
|
return diff |
||||||
|
} |
||||||
|
|
||||||
|
export function normalizeError (err) { |
||||||
|
let message |
||||||
|
if (!(err.message || typeof err === 'string')) { |
||||||
|
try { |
||||||
|
message = JSON.stringify(err, null, 2) |
||||||
|
} catch (e) { |
||||||
|
message = `[${err.constructor.name}]` |
||||||
|
} |
||||||
|
} else { |
||||||
|
message = err.message || err |
||||||
|
} |
||||||
|
return { |
||||||
|
...err, |
||||||
|
message, |
||||||
|
statusCode: (err.statusCode || err.status || (err.response && err.response.status) || 500) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* The main path matching regexp utility. |
||||||
|
* |
||||||
|
* @type {RegExp} |
||||||
|
*/ |
||||||
|
const PATH_REGEXP = new RegExp([ |
||||||
|
// Match escaped characters that would otherwise appear in future matches.
|
||||||
|
// This allows the user to escape special characters that won't transform.
|
||||||
|
'(\\\\.)', |
||||||
|
// Match Express-style parameters and un-named parameters with a prefix
|
||||||
|
// and optional suffixes. Matches appear as:
|
||||||
|
//
|
||||||
|
// "/:test(\\d+)?" => ["/", "test", "\d+", undefined, "?", undefined]
|
||||||
|
// "/route(\\d+)" => [undefined, undefined, undefined, "\d+", undefined, undefined]
|
||||||
|
// "/*" => ["/", undefined, undefined, undefined, undefined, "*"]
|
||||||
|
'([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))' |
||||||
|
].join('|'), 'g') |
||||||
|
|
||||||
|
/** |
||||||
|
* Parse a string for the raw tokens. |
||||||
|
* |
||||||
|
* @param {string} str |
||||||
|
* @param {Object=} options |
||||||
|
* @return {!Array} |
||||||
|
*/ |
||||||
|
function parse (str, options) { |
||||||
|
const tokens = [] |
||||||
|
let key = 0 |
||||||
|
let index = 0 |
||||||
|
let path = '' |
||||||
|
const defaultDelimiter = (options && options.delimiter) || '/' |
||||||
|
let res |
||||||
|
|
||||||
|
while ((res = PATH_REGEXP.exec(str)) != null) { |
||||||
|
const m = res[0] |
||||||
|
const escaped = res[1] |
||||||
|
const offset = res.index |
||||||
|
path += str.slice(index, offset) |
||||||
|
index = offset + m.length |
||||||
|
|
||||||
|
// Ignore already escaped sequences.
|
||||||
|
if (escaped) { |
||||||
|
path += escaped[1] |
||||||
|
continue |
||||||
|
} |
||||||
|
|
||||||
|
const next = str[index] |
||||||
|
const prefix = res[2] |
||||||
|
const name = res[3] |
||||||
|
const capture = res[4] |
||||||
|
const group = res[5] |
||||||
|
const modifier = res[6] |
||||||
|
const asterisk = res[7] |
||||||
|
|
||||||
|
// Push the current path onto the tokens.
|
||||||
|
if (path) { |
||||||
|
tokens.push(path) |
||||||
|
path = '' |
||||||
|
} |
||||||
|
|
||||||
|
const partial = prefix != null && next != null && next !== prefix |
||||||
|
const repeat = modifier === '+' || modifier === '*' |
||||||
|
const optional = modifier === '?' || modifier === '*' |
||||||
|
const delimiter = res[2] || defaultDelimiter |
||||||
|
const pattern = capture || group |
||||||
|
|
||||||
|
tokens.push({ |
||||||
|
name: name || key++, |
||||||
|
prefix: prefix || '', |
||||||
|
delimiter, |
||||||
|
optional, |
||||||
|
repeat, |
||||||
|
partial, |
||||||
|
asterisk: Boolean(asterisk), |
||||||
|
pattern: pattern ? escapeGroup(pattern) : (asterisk ? '.*' : '[^' + escapeString(delimiter) + ']+?') |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
// Match any characters still remaining.
|
||||||
|
if (index < str.length) { |
||||||
|
path += str.substr(index) |
||||||
|
} |
||||||
|
|
||||||
|
// If the path exists, push it onto the end.
|
||||||
|
if (path) { |
||||||
|
tokens.push(path) |
||||||
|
} |
||||||
|
|
||||||
|
return tokens |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Prettier encoding of URI path segments. |
||||||
|
* |
||||||
|
* @param {string} |
||||||
|
* @return {string} |
||||||
|
*/ |
||||||
|
function encodeURIComponentPretty (str, slashAllowed) { |
||||||
|
const re = slashAllowed ? /[?#]/g : /[/?#]/g |
||||||
|
return encodeURI(str).replace(re, (c) => { |
||||||
|
return '%' + c.charCodeAt(0).toString(16).toUpperCase() |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Encode the asterisk parameter. Similar to `pretty`, but allows slashes. |
||||||
|
* |
||||||
|
* @param {string} |
||||||
|
* @return {string} |
||||||
|
*/ |
||||||
|
function encodeAsterisk (str) { |
||||||
|
return encodeURIComponentPretty(str, true) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Escape a regular expression string. |
||||||
|
* |
||||||
|
* @param {string} str |
||||||
|
* @return {string} |
||||||
|
*/ |
||||||
|
function escapeString (str) { |
||||||
|
return str.replace(/([.+*?=^!:${}()[\]|/\\])/g, '\\$1') |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Escape the capturing group by escaping special characters and meaning. |
||||||
|
* |
||||||
|
* @param {string} group |
||||||
|
* @return {string} |
||||||
|
*/ |
||||||
|
function escapeGroup (group) { |
||||||
|
return group.replace(/([=!:$/()])/g, '\\$1') |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Expose a method for transforming tokens into the path function. |
||||||
|
*/ |
||||||
|
function tokensToFunction (tokens, options) { |
||||||
|
// Compile all the tokens into regexps.
|
||||||
|
const matches = new Array(tokens.length) |
||||||
|
|
||||||
|
// Compile all the patterns before compilation.
|
||||||
|
for (let i = 0; i < tokens.length; i++) { |
||||||
|
if (typeof tokens[i] === 'object') { |
||||||
|
matches[i] = new RegExp('^(?:' + tokens[i].pattern + ')$', flags(options)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return function (obj, opts) { |
||||||
|
let path = '' |
||||||
|
const data = obj || {} |
||||||
|
const options = opts || {} |
||||||
|
const encode = options.pretty ? encodeURIComponentPretty : encodeURIComponent |
||||||
|
|
||||||
|
for (let i = 0; i < tokens.length; i++) { |
||||||
|
const token = tokens[i] |
||||||
|
|
||||||
|
if (typeof token === 'string') { |
||||||
|
path += token |
||||||
|
|
||||||
|
continue |
||||||
|
} |
||||||
|
|
||||||
|
const value = data[token.name || 'pathMatch'] |
||||||
|
let segment |
||||||
|
|
||||||
|
if (value == null) { |
||||||
|
if (token.optional) { |
||||||
|
// Prepend partial segment prefixes.
|
||||||
|
if (token.partial) { |
||||||
|
path += token.prefix |
||||||
|
} |
||||||
|
|
||||||
|
continue |
||||||
|
} else { |
||||||
|
throw new TypeError('Expected "' + token.name + '" to be defined') |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (Array.isArray(value)) { |
||||||
|
if (!token.repeat) { |
||||||
|
throw new TypeError('Expected "' + token.name + '" to not repeat, but received `' + JSON.stringify(value) + '`') |
||||||
|
} |
||||||
|
|
||||||
|
if (value.length === 0) { |
||||||
|
if (token.optional) { |
||||||
|
continue |
||||||
|
} else { |
||||||
|
throw new TypeError('Expected "' + token.name + '" to not be empty') |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
for (let j = 0; j < value.length; j++) { |
||||||
|
segment = encode(value[j]) |
||||||
|
|
||||||
|
if (!matches[i].test(segment)) { |
||||||
|
throw new TypeError('Expected all "' + token.name + '" to match "' + token.pattern + '", but received `' + JSON.stringify(segment) + '`') |
||||||
|
} |
||||||
|
|
||||||
|
path += (j === 0 ? token.prefix : token.delimiter) + segment |
||||||
|
} |
||||||
|
|
||||||
|
continue |
||||||
|
} |
||||||
|
|
||||||
|
segment = token.asterisk ? encodeAsterisk(value) : encode(value) |
||||||
|
|
||||||
|
if (!matches[i].test(segment)) { |
||||||
|
throw new TypeError('Expected "' + token.name + '" to match "' + token.pattern + '", but received "' + segment + '"') |
||||||
|
} |
||||||
|
|
||||||
|
path += token.prefix + segment |
||||||
|
} |
||||||
|
|
||||||
|
return path |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the flags for a regexp from the options. |
||||||
|
* |
||||||
|
* @param {Object} options |
||||||
|
* @return {string} |
||||||
|
*/ |
||||||
|
function flags (options) { |
||||||
|
return options && options.sensitive ? '' : 'i' |
||||||
|
} |
||||||
|
|
||||||
|
export function addLifecycleHook(vm, hook, fn) { |
||||||
|
if (!vm.$options[hook]) { |
||||||
|
vm.$options[hook] = [] |
||||||
|
} |
||||||
|
if (!vm.$options[hook].includes(fn)) { |
||||||
|
vm.$options[hook].push(fn) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export const urlJoin = joinURL |
||||||
|
|
||||||
|
export const stripTrailingSlash = withoutTrailingSlash |
||||||
|
|
||||||
|
export const isSamePath = _isSamePath |
||||||
|
|
||||||
|
export function setScrollRestoration (newVal) { |
||||||
|
try { |
||||||
|
window.history.scrollRestoration = newVal; |
||||||
|
} catch(e) {} |
||||||
|
} |
@ -0,0 +1,35 @@ |
|||||||
|
{ |
||||||
|
"Barrage": { |
||||||
|
"description": "Auto imported from components/Barrage.vue" |
||||||
|
}, |
||||||
|
"BottomRightFixed": { |
||||||
|
"description": "Auto imported from components/BottomRightFixed.vue" |
||||||
|
}, |
||||||
|
"CommonHeader": { |
||||||
|
"description": "Auto imported from components/CommonHeader.vue" |
||||||
|
}, |
||||||
|
"DoctorItem": { |
||||||
|
"description": "Auto imported from components/DoctorItem.vue" |
||||||
|
}, |
||||||
|
"DoctorVideoItem": { |
||||||
|
"description": "Auto imported from components/DoctorVideoItem.vue" |
||||||
|
}, |
||||||
|
"MobileHeader": { |
||||||
|
"description": "Auto imported from components/MobileHeader.vue" |
||||||
|
}, |
||||||
|
"NotLogin": { |
||||||
|
"description": "Auto imported from components/NotLogin.vue" |
||||||
|
}, |
||||||
|
"UserInfoCommon": { |
||||||
|
"description": "Auto imported from components/UserInfoCommon.vue" |
||||||
|
}, |
||||||
|
"VideoArticleListItem": { |
||||||
|
"description": "Auto imported from components/VideoArticleListItem.vue" |
||||||
|
}, |
||||||
|
"WebFooter": { |
||||||
|
"description": "Auto imported from components/WebFooter.vue" |
||||||
|
}, |
||||||
|
"WebHeader": { |
||||||
|
"description": "Auto imported from components/WebHeader.vue" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,9 @@ |
|||||||
|
<!DOCTYPE html> |
||||||
|
<html {{ HTML_ATTRS }}> |
||||||
|
<head {{ HEAD_ATTRS }}> |
||||||
|
{{ HEAD }} |
||||||
|
</head> |
||||||
|
<body {{ BODY_ATTRS }}> |
||||||
|
{{ APP }} |
||||||
|
</body> |
||||||
|
</html> |
@ -0,0 +1,23 @@ |
|||||||
|
<!DOCTYPE html> |
||||||
|
<html> |
||||||
|
<head> |
||||||
|
<title>Server error</title> |
||||||
|
<meta charset="utf-8"> |
||||||
|
<meta content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" name=viewport> |
||||||
|
<style> |
||||||
|
.__nuxt-error-page{padding: 1rem;background:#f7f8fb;color:#47494e;text-align:center;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;font-family:sans-serif;font-weight:100!important;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;-webkit-font-smoothing:antialiased;position:absolute;top:0;left:0;right:0;bottom:0}.__nuxt-error-page .error{max-width:450px}.__nuxt-error-page .title{font-size:24px;font-size:1.5rem;margin-top:15px;color:#47494e;margin-bottom:8px}.__nuxt-error-page .description{color:#7f828b;line-height:21px;margin-bottom:10px}.__nuxt-error-page a{color:#7f828b!important;text-decoration:none}.__nuxt-error-page .logo{position:fixed;left:12px;bottom:12px} |
||||||
|
</style> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
<div class="__nuxt-error-page"> |
||||||
|
<div class="error"> |
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="90" height="90" fill="#DBE1EC" viewBox="0 0 48 48"><path d="M22 30h4v4h-4zm0-16h4v12h-4zm1.99-10C12.94 4 4 12.95 4 24s8.94 20 19.99 20S44 35.05 44 24 35.04 4 23.99 4zM24 40c-8.84 0-16-7.16-16-16S15.16 8 24 8s16 7.16 16 16-7.16 16-16 16z"/></svg> |
||||||
|
<div class="title">Server error</div> |
||||||
|
<div class="description">An error occurred in the application and your page could not be served. If you are the application owner, check your logs for details.</div> |
||||||
|
</div> |
||||||
|
<div class="logo"> |
||||||
|
<a href="https://nuxtjs.org" target="_blank" rel="noopener">Nuxt</a> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</body> |
||||||
|
</html> |
Loading…
Reference in new issue