Skip to content

Commit 5ae7745

Browse files
committed
Updated code
1 parent 530d07f commit 5ae7745

File tree

17 files changed

+1603
-1491
lines changed

17 files changed

+1603
-1491
lines changed

1.nuxt/1.essentials/5.fetch-data-handle-errors/pages/blog/[id].vue

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const runtimeConfig = useRuntimeConfig()
1414
const { data: post, error } = await useFetch(`/posts/${route.params.id}`, {
1515
baseURL: runtimeConfig.public['apiBaseUrl']
1616
})
17+
1718
const failure = unref(error)
1819
if (failure !== null) {
1920
// Show a full screen error page on the `error.vue` page.

1.nuxt/1.essentials/6.state-management/package-lock.json

+1,259-1,422
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

1.nuxt/1.essentials/6.state-management/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@
88
"postinstall": "nuxt prepare"
99
},
1010
"devDependencies": {
11-
"nuxt": "^3.2.3"
11+
"nuxt": "^3.4.1"
1212
}
1313
}
+13-32
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,22 @@
11
<template>
2-
<p v-if="isServerPostEvent">
3-
Well done! Resources are updated on the server side.
4-
</p>
5-
<div v-else>
6-
<site-header />
7-
<nav-main />
8-
<NuxtPage />
9-
</div>
2+
<site-header />
3+
<nav-main />
4+
<NuxtPage />
105
</template>
116

127
<script setup>
13-
const nuxtApp = useNuxtApp()
14-
const runtimeConfig = useRuntimeConfig()
15-
const { items } = useCart()
8+
if (!import.meta.env.SSR) {
9+
const runtimeConfig = useRuntimeConfig()
10+
const cartId = runtimeConfig.public['appCartId']
11+
const cookie = useCookie(cartId)
12+
const { items } = useCart()
1613
17-
const isServerPostEvent = ref(false)
18-
const requestMethods = ['PATCH', 'POST', 'PUT', 'DELETE']
19-
20-
if (import.meta.env.SSR) {
21-
// https://nuxt.com/docs/api/composables/use-request-event
22-
const event = useRequestEvent()
23-
24-
const req = event.node.req
25-
const url = event.node.req.url
26-
const string = url.substring(url.indexOf('?'))
27-
const params = new URLSearchParams(string)
28-
29-
if (requestMethods.includes(req.method)) {
30-
isServerPostEvent.value = true
31-
}
32-
33-
if (params.has('cart') && params.get('cart') === 'set') {
34-
items.value = await normalizeBody(req)
14+
// If cookie is gone, that means the data in Redis is gone too, so delete
15+
// the cart in `localstorage` too.
16+
if (!cookie.value) {
17+
localStorage.removeItem(cartId)
3518
}
36-
} else {
37-
const id = runtimeConfig.public['appCartId']
38-
const cart = localStorage.getItem(id)
19+
const cart = localStorage.getItem(cartId)
3920
items.value = JSON.parse(cart) ?? []
4021
}
4122
</script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
'use strict'
2+
3+
export default (options) => {
4+
function get (name, cookie) {
5+
const resource = cookie ?? document.cookie
6+
7+
let string = resource.match(`(?:(?:^|.*; *)${name} *= *([^;]*).*$)|^.*$`)[1]
8+
if (string) {
9+
string = decodeURIComponent(string)
10+
}
11+
if (string === 'undefined'
12+
|| string === undefined
13+
|| string === ''
14+
) {
15+
string = null
16+
}
17+
18+
return JSON.parse(string)
19+
}
20+
21+
function set (name, value) {
22+
let maxAge = 0
23+
24+
// If options contains maxAge then we're configuring max-age.
25+
if (options.maxAge) {
26+
maxAge = options.maxAge
27+
}
28+
29+
// If options contains days then we're configuring max-age.
30+
if (options.days) {
31+
maxAge = options.days * 60 * 60 * 24
32+
}
33+
34+
// Finally, creating the key. Must set `path=/` in the cookie or Firefox
35+
// won't remove the expired cookie automatically until the browser is
36+
// closed.
37+
document.cookie = `${name}=${encodeURIComponent(value)}; max-age=${maxAge}; path=/`
38+
}
39+
40+
function drop (name) {
41+
document.cookie = name + '=;expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/'
42+
}
43+
44+
// observe, eye, spy, note, track, follow, guard, study, mark, monitor.
45+
function observe (ref, name) {
46+
// https://vuejs.org/api/reactivity-core.html#watch
47+
watch(ref, (newVal, prevVal) => {
48+
// Uncomment to see the result.
49+
// console.log('newVal =', newVal)
50+
// console.log('count.value =', count.value)
51+
52+
// Stringify the reactive object before storing.
53+
set(name, JSON.stringify(ref.value))
54+
}, {
55+
// Force deep traversal of the source if it is an object, so that the
56+
// callback fires on deep mutations.
57+
deep: true
58+
})
59+
}
60+
61+
return {
62+
get,
63+
set,
64+
drop,
65+
observe
66+
}
67+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// https://nuxt.com/docs/guide/directory-structure/middleware
2+
export default defineNuxtRouteMiddleware(async (to, from) => {
3+
// console.log('global middleware from `/middleware/` that runs on every route change')
4+
if (import.meta.env.SSR) {
5+
const runtimeConfig = useRuntimeConfig()
6+
const cartId = runtimeConfig.public['appCartId']
7+
const { items } = useCart()
8+
9+
// Reset before populating.
10+
items.value = []
11+
12+
// Get the value of the cart from cookie and use it to set a key in Redis
13+
// db.
14+
// https://nuxt.com/docs/api/composables/use-request-event
15+
// const event = useRequestEvent()
16+
// const req = event.node.req
17+
// const cookie = req.headers.cookie
18+
const cookie = useCookie(cartId) || null
19+
const key = cookie.value ? `${cartId}:${cookie.value}` : null
20+
// console.log('cookie =', cookie.value)
21+
// console.log('key =', key)
22+
23+
if (key) {
24+
const { data } = await useFetch(`/api/carts/${key}`)
25+
const cart = data.value ?? []
26+
items.value = cart
27+
}
28+
}
29+
})

1.nuxt/1.essentials/7.store-management/package-lock.json

+81-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

1.nuxt/1.essentials/7.store-management/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
},
1313
"dependencies": {
1414
"@pinia/nuxt": "^0.4.6",
15-
"pinia": "^2.0.30"
15+
"pinia": "^2.0.30",
16+
"redis": "^4.6.6"
1617
}
1718
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
'use strict'
2+
3+
// https://redis.io/docs/clients/nodejs/
4+
import { createClient } from 'redis'
5+
6+
export default eventHandler(async event => {
7+
const id = event.context.params.id
8+
9+
// Stop right here if no id.
10+
if (!id) {
11+
return null
12+
}
13+
14+
const client = createClient()
15+
client.on('error', err => console.log('Redis Client Error', err))
16+
await client.connect()
17+
18+
return JSON.parse(await client.get(id))
19+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
'use strict'
2+
3+
// https://redis.io/docs/clients/nodejs/
4+
import { createClient } from 'redis'
5+
6+
// https://nitro.unjs.io/guide/introduction/routing#specific-request-method
7+
// https://nuxt.com/docs/guide/directory-structure/server#matching-http-method
8+
// https://nuxt.com/docs/guide/directory-structure/server#handling-requests-with-body
9+
export default eventHandler(async event => {
10+
const runtimeConfig = useRuntimeConfig()
11+
const cartId = runtimeConfig.public['appCartId']
12+
13+
// Get the value of the cart from cookie and use it to set a key in Redis
14+
// db, e.g. `example.com:cart:1683665729834`.
15+
// const cookie = event.req.headers.cookie
16+
// console.log('cookie =', cookie)
17+
18+
// Use the `getCookie` API from h3 to retrieve your cookie in the headers.
19+
// https://nuxt.com/docs/api/composables/use-cookie#handling-cookies-in-api-routes
20+
const value = getCookie(event, cartId) || null
21+
const key = value ? `${cartId}:${value}` : null
22+
23+
// Stop right here if no key.
24+
if (!key) {
25+
return null
26+
}
27+
28+
const body = await readBody(event)
29+
30+
const client = createClient()
31+
client.on('error', err => console.log('Redis Client Error', err))
32+
await client.connect()
33+
34+
// Expire in [x] days.
35+
// const days = 30
36+
// const expire = days * 24 * 60 * 60
37+
38+
// Expire in [x] minutes.
39+
const expire = 5 * 60
40+
41+
// Sets a time-to-live (TTL) of one minute for the cached data,
42+
// after which it will expire and the next request will have to
43+
// set the data again.
44+
// EX seconds -- Set the specified expire time, in seconds.
45+
// https://redis.io/commands/set/
46+
return await client.set(key, JSON.stringify(body), { 'EX': expire })
47+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default eventHandler(() => {
2+
return { message: 'Hello World!' }
3+
})

0 commit comments

Comments
 (0)