App.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. import Vue from 'vue'
  2. import { decode, parsePath, withoutBase, withoutTrailingSlash, normalizeURL } from 'ufo'
  3. <% utilsImports = [
  4. ...(features.asyncData || features.fetch) ? [
  5. 'getMatchedComponentsInstances',
  6. 'getChildrenComponentInstancesUsingFetch',
  7. 'promisify',
  8. 'globalHandleError',
  9. 'urlJoin'
  10. ] : [],
  11. ...features.layouts ? [
  12. 'sanitizeComponent'
  13. ]: []
  14. ] %>
  15. <% if (utilsImports.length) { %>import { <%= utilsImports.join(', ') %> } from './utils'<% } %>
  16. import NuxtError from '<%= components.ErrorPage ? components.ErrorPage : "./components/nuxt-error.vue" %>'
  17. <% if (loading) { %>import NuxtLoading from '<%= (typeof loading === "string" ? loading : "./components/nuxt-loading.vue") %>'<% } %>
  18. <% if (buildIndicator) { %>import NuxtBuildIndicator from './components/nuxt-build-indicator'<% } %>
  19. <% css.forEach((c) => { %>
  20. import '<%= relativeToBuild(resolvePath(c.src || c, { isStyle: true })) %>'
  21. <% }) %>
  22. <% if (features.layouts) { %>
  23. <%= Object.keys(layouts).map((key) => {
  24. if (splitChunks.layouts) {
  25. return `const _${hash(key)} = () => import('${layouts[key]}' /* webpackChunkName: "${wChunk('layouts/' + key)}" */).then(m => sanitizeComponent(m.default || m))`
  26. } else {
  27. return `import _${hash(key)} from '${layouts[key]}'`
  28. }
  29. }).join('\n') %>
  30. <% if (splitChunks.layouts) { %>
  31. let resolvedLayouts = {}
  32. const layouts = { <%= Object.keys(layouts).map(key => `"_${key}": _${hash(key)}`).join(',') %> }<%= isTest ? '// eslint-disable-line' : '' %>
  33. <% } else { %>
  34. const layouts = { <%= Object.keys(layouts).map(key => `"_${key}": sanitizeComponent(_${hash(key)})`).join(',') %> }<%= isTest ? '// eslint-disable-line' : '' %>
  35. <% } %>
  36. <% } %>
  37. export default {
  38. render (h, props) {
  39. <% if (loading) { %>const loadingEl = h('NuxtLoading', { ref: 'loading' })<% } %>
  40. <% if (features.layouts) { %>
  41. const layoutEl = h(this.layout || 'nuxt')
  42. const templateEl = h('div', {
  43. domProps: {
  44. id: '__layout'
  45. },
  46. key: this.layoutName
  47. }, [layoutEl])
  48. <% } else { %>
  49. const templateEl = h('nuxt')
  50. <% } %>
  51. <% if (features.transitions) { %>
  52. const transitionEl = h('transition', {
  53. props: {
  54. name: '<%= layoutTransition.name %>',
  55. mode: '<%= layoutTransition.mode %>'
  56. },
  57. on: {
  58. beforeEnter (el) {
  59. // Ensure to trigger scroll event after calling scrollBehavior
  60. window.<%= globals.nuxt %>.$nextTick(() => {
  61. window.<%= globals.nuxt %>.$emit('triggerScroll')
  62. })
  63. }
  64. }
  65. }, [templateEl])
  66. <% } %>
  67. return h('div', {
  68. domProps: {
  69. id: '<%= globals.id %>'
  70. }
  71. }, [
  72. <% if (loading) { %>loadingEl, <% } %>
  73. <% if (buildIndicator) { %>h(NuxtBuildIndicator), <% } %>
  74. <% if (features.transitions) { %>transitionEl<% } else { %>templateEl<% } %>
  75. ])
  76. },
  77. <% if (features.clientOnline || features.layouts) { %>
  78. data: () => ({
  79. <% if (features.clientOnline) { %>
  80. isOnline: true,
  81. <% } %>
  82. <% if (features.layouts) { %>
  83. layout: null,
  84. layoutName: '',
  85. <% } %>
  86. <% if (features.fetch) { %>
  87. nbFetching: 0
  88. <% } %>
  89. }),
  90. <% } %>
  91. beforeCreate () {
  92. Vue.util.defineReactive(this, 'nuxt', this.$options.nuxt)
  93. },
  94. created () {
  95. // Add this.$nuxt in child instances
  96. this.$root.$options.<%= globals.nuxt %> = this
  97. if (process.client) {
  98. // add to window so we can listen when ready
  99. window.<%= globals.nuxt %> = <%= (globals.nuxt !== '$nuxt' ? 'window.$nuxt = ' : '') %>this
  100. <% if (features.clientOnline) { %>
  101. this.refreshOnlineStatus()
  102. // Setup the listeners
  103. window.addEventListener('online', this.refreshOnlineStatus)
  104. window.addEventListener('offline', this.refreshOnlineStatus)
  105. <% } %>
  106. }
  107. // Add $nuxt.error()
  108. this.error = this.nuxt.error
  109. // Add $nuxt.context
  110. this.context = this.$options.context
  111. },
  112. <% if (loading || isFullStatic) { %>
  113. async mounted () {
  114. <% if (loading) { %>this.$loading = this.$refs.loading<% } %>
  115. <% if (isFullStatic) {%>
  116. if (this.isPreview) {
  117. if (this.$store && this.$store._actions.nuxtServerInit) {
  118. <% if (loading) { %>this.$loading.start()<% } %>
  119. await this.$store.dispatch('nuxtServerInit', this.context)
  120. }
  121. await this.refresh()
  122. <% if (loading) { %>this.$loading.finish()<% } %>
  123. }
  124. <% } %>
  125. },
  126. <% } %>
  127. watch: {
  128. 'nuxt.err': 'errorChanged'
  129. },
  130. <% if (features.clientOnline) { %>
  131. computed: {
  132. isOffline () {
  133. return !this.isOnline
  134. },
  135. <% if (features.fetch) { %>
  136. isFetching () {
  137. return this.nbFetching > 0
  138. },<% } %>
  139. <% if (nuxtOptions.target === 'static') { %>
  140. isPreview () {
  141. return Boolean(this.$options.previewData)
  142. },<% } %>
  143. },
  144. <% } %>
  145. methods: {
  146. <%= isTest ? '/* eslint-disable comma-dangle */' : '' %>
  147. <% if (features.clientOnline) { %>
  148. refreshOnlineStatus () {
  149. if (process.client) {
  150. if (typeof window.navigator.onLine === 'undefined') {
  151. // If the browser doesn't support connection status reports
  152. // assume that we are online because most apps' only react
  153. // when they now that the connection has been interrupted
  154. this.isOnline = true
  155. } else {
  156. this.isOnline = window.navigator.onLine
  157. }
  158. }
  159. },
  160. <% } %>
  161. async refresh () {
  162. <% if (features.asyncData || features.fetch) { %>
  163. const pages = getMatchedComponentsInstances(this.$route)
  164. if (!pages.length) {
  165. return
  166. }
  167. <% if (loading) { %>this.$loading.start()<% } %>
  168. const promises = pages.map((page) => {
  169. const p = []
  170. <% if (features.fetch) { %>
  171. // Old fetch
  172. if (page.$options.fetch && page.$options.fetch.length) {
  173. p.push(promisify(page.$options.fetch, this.context))
  174. }
  175. if (page.$fetch) {
  176. p.push(page.$fetch())
  177. } else {
  178. // Get all component instance to call $fetch
  179. for (const component of getChildrenComponentInstancesUsingFetch(page.$vnode.componentInstance)) {
  180. p.push(component.$fetch())
  181. }
  182. }
  183. <% } %>
  184. <% if (features.asyncData) { %>
  185. if (page.$options.asyncData) {
  186. p.push(
  187. promisify(page.$options.asyncData, this.context)
  188. .then((newData) => {
  189. for (const key in newData) {
  190. Vue.set(page.$data, key, newData[key])
  191. }
  192. })
  193. )
  194. }
  195. <% } %>
  196. return Promise.all(p)
  197. })
  198. try {
  199. await Promise.all(promises)
  200. } catch (error) {
  201. <% if (loading) { %>this.$loading.fail(error)<% } %>
  202. globalHandleError(error)
  203. this.error(error)
  204. }
  205. <% if (loading) { %>this.$loading.finish()<% } %>
  206. <% } %>
  207. },
  208. <% if (splitChunks.layouts) { %>async <% } %>errorChanged () {
  209. if (this.nuxt.err) {
  210. <% if (loading) { %>
  211. if (this.$loading) {
  212. if (this.$loading.fail) {
  213. this.$loading.fail(this.nuxt.err)
  214. }
  215. if (this.$loading.finish) {
  216. this.$loading.finish()
  217. }
  218. }
  219. <% } %>
  220. let errorLayout = (NuxtError.options || NuxtError).layout;
  221. if (typeof errorLayout === 'function') {
  222. errorLayout = errorLayout(this.context)
  223. }
  224. <% if (splitChunks.layouts) { %>
  225. await this.loadLayout(errorLayout)
  226. <% } %>
  227. this.setLayout(errorLayout)
  228. }
  229. },
  230. <% if (features.layouts) { %>
  231. <% if (splitChunks.layouts) { %>
  232. setLayout (layout) {
  233. <% if (debug) { %>
  234. if(layout && typeof layout !== 'string') {
  235. throw new Error('[nuxt] Avoid using non-string value as layout property.')
  236. }
  237. <% } %>
  238. if (!layout || !resolvedLayouts['_' + layout]) {
  239. layout = 'default'
  240. }
  241. this.layoutName = layout
  242. let _layout = '_' + layout
  243. this.layout = resolvedLayouts[_layout]
  244. return this.layout
  245. },
  246. loadLayout (layout) {
  247. const undef = !layout
  248. const nonexistent = !(layouts['_' + layout] || resolvedLayouts['_' + layout])
  249. let _layout = '_' + ((undef || nonexistent) ? 'default' : layout)
  250. if (resolvedLayouts[_layout]) {
  251. return Promise.resolve(resolvedLayouts[_layout])
  252. }
  253. return layouts[_layout]()
  254. .then((Component) => {
  255. resolvedLayouts[_layout] = Component
  256. delete layouts[_layout]
  257. return resolvedLayouts[_layout]
  258. })
  259. .catch((e) => {
  260. if (this.<%= globals.nuxt %>) {
  261. return this.<%= globals.nuxt %>.error({ statusCode: 500, message: e.message })
  262. }
  263. })
  264. },
  265. <% } else { %>
  266. setLayout (layout) {
  267. <% if (debug) { %>
  268. if(layout && typeof layout !== 'string') {
  269. throw new Error('[nuxt] Avoid using non-string value as layout property.')
  270. }
  271. <% } %>
  272. if (!layout || !layouts['_' + layout]) {
  273. layout = 'default'
  274. }
  275. this.layoutName = layout
  276. this.layout = layouts['_' + layout]
  277. return this.layout
  278. },
  279. loadLayout (layout) {
  280. if (!layout || !layouts['_' + layout]) {
  281. layout = 'default'
  282. }
  283. return Promise.resolve(layouts['_' + layout])
  284. },
  285. <% } /* splitChunks.layouts */ %>
  286. <% } /* features.layouts */ %>
  287. <% if (isFullStatic) { %>
  288. getRouterBase() {
  289. return withoutTrailingSlash(this.$router.options.base)
  290. },
  291. getRoutePath(route = '/') {
  292. const base = this.getRouterBase()
  293. return withoutTrailingSlash(withoutBase(parsePath(route).pathname, base))
  294. },
  295. getStaticAssetsPath(route = '/') {
  296. const { staticAssetsBase } = window.<%= globals.context %>
  297. return urlJoin(staticAssetsBase, this.getRoutePath(route))
  298. },
  299. <% if (nuxtOptions.generate.manifest) { %>
  300. async fetchStaticManifest() {
  301. return window.__NUXT_IMPORT__('manifest.js', normalizeURL(urlJoin(this.getStaticAssetsPath(), 'manifest.js')))
  302. },
  303. <% } %>
  304. setPagePayload(payload) {
  305. this._pagePayload = payload
  306. this._fetchCounters = {}
  307. },
  308. async fetchPayload(route, prefetch) {
  309. const path = decode(this.getRoutePath(route))
  310. <% if (nuxtOptions.generate.manifest) { %>
  311. const manifest = await this.fetchStaticManifest()
  312. if (!manifest.routes.includes(path)) {
  313. if (!prefetch) { this.setPagePayload(false) }
  314. throw new Error(`Route ${path} is not pre-rendered`)
  315. }
  316. <% } %>
  317. const src = urlJoin(this.getStaticAssetsPath(route), 'payload.js')
  318. try {
  319. const payload = await window.__NUXT_IMPORT__(path, normalizeURL(src))
  320. if (!prefetch) { this.setPagePayload(payload) }
  321. return payload
  322. } catch (err) {
  323. if (!prefetch) { this.setPagePayload(false) }
  324. throw err
  325. }
  326. }
  327. <% } %>
  328. },
  329. <% if (loading) { %>
  330. components: {
  331. NuxtLoading
  332. }
  333. <% } %>
  334. <%= isTest ? '/* eslint-enable comma-dangle */' : '' %>
  335. }