Github Pages로 Nuxt 2 프로젝트 배포 시 동적 라우팅 구현하기
Github Pages에서 Nuxt 배포하기
초코스프레드는 별도의 서버 호스팅을 받을 필요 없이 무료로 위키를 올릴 수 있도록, 저예산/소규모 위키를 목표로 하고 있는 프로젝트입니다. (사실상 스프레드시트 파서입니다.)
기존 초코스프레드는 정적 html 페이지를 그대로 Github pages로 deploy했었습니다.
그런데 이렇게 페이지를 만들면 API 키가 전부 노출이 되어 안전하지도 않고, 쿼리스트링 형태로 문서 제목이 붙어 어딘가 너저분한 느낌이 들고 불편했습니다.
그래서 이 두 가지를 개선하고자 Nuxt를 사용하게 된 것입니다.
Nuxt에서는 pages/ 폴더 아래에 vue파일을 집어넣으면 그게 그대로 라우팅이 됩니다. 즉 pages/index.vue
는 /
로, pages/intro.vue
는 /intro/
로 라우팅이 되는 형태입니다.
그리고 이게 Github 액션을 사용한 빌드에서도 적용됩니다.
그런데 동적 라우팅, 예를 들어서
jyhyun1008.github.io/posts/123
같은 경우는 어떻게 할까요?
pages/posts
폴더 아래에 _id.vue
와 같이 밑줄+파라미터 이름 을 넣으면 됩니다.
그리고 당연하게도, 정적 페이지 빌드를 하면 이 페이지는 빠지게 됩니다(...)
위키는 대문 페이지를 제외하고는 거의 대부분의 페이지가 동적 페이지로 되어 있는데, 만들었던 위키 페이지를 정적 페이지로 generate 하니, 대문을 제외한 모든 페이지가 날아가 있었습니다.
그래서 이 문제를 해결하고자 했는데, 공식 문서 를 찾아보는 것으로 의외로 간단하게 해결이 됐습니다.
아래는 공식 문서에서 제시하는 예시입니다.
//nuxt.config.js
import axios from 'axios'
export default {
generate: {
routes(callback) {
axios
.get('https://my-api/users')
.then(res => {
const routes = res.data.map(user => {
return '/users/' + user.id
})
callback(null, routes)
})
.catch(callback)
}
}
}
generate → routes 아래에 fetch를 통해 어떤 페이지를 라우팅할 지 배열을 불러와서 저장하는 맥락입니다.
그러니 사실은...
동적 라우팅처럼 보이는 것에 가까울 것 같습니다. 유저가 접속할 수 있는 모든 경우의 수의 페이지만큼 정적 파일을 생성하고, 이걸 deploy하는 것이기 때문입니다.
저는 axios는 사용 안하고... 그냥 async + await fetch 로 했습니다. 아래 코드에서 secret이라든지 저에게 맞추어진 id같은 부분은 줄을 그었습니다.
구글 아이디 인증을 하고, 스프레드 시트를 불러와서 시트의 제목마다 라우터를 만들어주는 구조입니다.
//nuxt.config.js
generate: {
async routes(callback) {
var secretKey = process.env.PRIVATE_KEY.replace(/\\n/gm, '\n')
const token = jwt.sign(
{ "iss": "-------------", "scope": "https://www.googleapis.com/auth/spreadsheets", "aud": "https://oauth2.googleapis.com/token" },
secretKey,
{ algorithm: 'RS256', expiresIn: "1h", keyid: "------------" }
);
const googleAuthUrl = 'https://oauth2.googleapis.com/token'
const googleAuthParam = {
method: 'POST',
headers: {
'content-type': "application/x-www-form-urlencoded",
},
body: querystring.stringify({
grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
assertion: token
})
}
var authData = await fetch(googleAuthUrl, googleAuthParam)
var authRes = await authData.json()
const googleSheetUrl = `https://sheets.googleapis.com/v4/spreadsheets/------------/`
const googleSheetParam = {
method: 'GET',
headers: {
"content-type": "application/json",
Authorization: "Bearer " + authRes.access_token,
},
}
var sheetData3 = await fetch(googleSheetUrl, googleSheetParam)
var sheetRes3 = await sheetData3.json()
var wikiListArray = sheetRes3.sheets
var wikiList = []
for (let i=0; i<wikiListArray.length; i++) {
wikiList.push('/'+encodeURIComponent(wikiListArray[i].properties.title))
}
const routes = wikiList
callback(null, routes)
}
}