Vue3 without Nuxt.js로 SSR을 시험해 봤어요.log

26926 단어 Vue.jsSSRtech
https://v3.vuejs.org/guide/ssr/introduction.html
Nuxt.js + Vue.js의 SSR에 경험이 있기 때문에 (손으로 하는 일이 거의 없기 때문에) Vue.SSR은 js로만 시도되었습니다.Nuxt.제이스는 편하지만 너무 친절하고 답답한 일도 많아서 Vue.나는 줄곧 js만으로 전단을 구축할 수 있는지를 고려하고 있다.
그나저나 Vue3는 처음이에요.타입 스크립트와의 친화성이 높아졌다는 소문을 듣고 타입 스크립트도 사용해 봤다.평소 혈액형은 잘 안 쓰지만 그래도 노력해 보고 싶어요.

해봤어요.


Vue3 프로젝트 설정


우선 제작 프로젝트부터 시작한다.
yarn global add @vue/cli @vue/cli-service-global
이렇게 하면 vuevue-cli-service를 사용할 수 있다.
vue create vue-sample
로 대화적으로 잘 만들어진 느낌.자세한 상황https://cli.vuejs.org/guide/creating-a-project.html#vue-create은 여기 있습니다.Manually select features -> ✔ TypeScript/✔ Router/✔ Vuex

entry-client.ts / entry-server.제작ts


방금 한 프로젝트라면src/main.ts이 진입점이다.SSR을 진행하기 때문에 서버와 클라이언트(브라우저)로 입구점을 분할하고 웹팩으로 각각 구축하는 것이 좋다.
SSR+SPA는 이른바 유니버설 자바스크립트(Isomorphic JavaScript)이기 때문에 대부분의 코드가 노드다.js든 브라우저든 자바스크립트 엔진은 동작을 써야 합니다.vue 파일로 표현된 Vue의 Single File Component는 서버나 클라이언트 모두 가상 DOM을 재현하는 데 그쳐 동작이 변하지 않습니다.서버와 클라이언트의 차이점은 재현된 가상 DOM이'살아있는 HTML에 적용'인지'문자열화된 후 HTTP Response Body로 보내기'인지 여부다.
가상 DOM의 사용 방법이 다르기 때문에 이 부분은 서버와 클라이언트가 각각 작성해야 한다.말은 그렇지만 기본적으로 모두 Vue입니다.js 호스트에서 준비한 프레임워크 이용자로서 처리를 설명하면 됩니다.이 글의 첫머리에 소개된 문서에는 상세한 기술이 있으니 위의 내용을 참조할 수 있다.
https://v3.vuejs.org/guide/ssr/structure.html
https://v3.vuejs.org/guide/ssr/routing.html
이 부근의 페이지는 참고할 수 있다.다만, 문서에 JavaScript의 코드가 예시되어 있기 때문에 TypeScript로 처리해 보았습니다.
entry-client.ts
import { createSSRApp } from 'vue'
import { createWebHistory } from 'vue-router'
import App from './App.vue'
import createRouter from './router'
import store from './store'

const app = createSSRApp(App)
const router = createRouter(createWebHistory())

app.use(store)
app.use(router)

router.isReady().then(() => {
  app.mount('#app')
})
entry-server.ts
import { createSSRApp, App } from 'vue'
import { createMemoryHistory, Router } from 'vue-router'
import createRouter from './router'

import AppComponent from './App.vue'

export interface ServerEntryPoint {
  app: App;
  router: Router;
}

export default function (): ServerEntryPoint {
  const app = createSSRApp(AppComponent)
  const router = createRouter(createMemoryHistory())

  app.use(router)

  return { app, router }
}
또한 기본적으로 생성된 src/router/index입니다.ts는createWebHistory를 전제로 쓰기 때문에 로터History를 외부에서 주입하는 것을 고쳐야 합니다.(createMemoryHistory 대신 서버에서createWebHistory를 사용하기 때문에 입구점에 따라 RouterHistory도 다르다)
router/index.ts
import { createRouter, RouteRecordRaw, RouterHistory, Router } from 'vue-router'
import Home from '../views/Home.vue'

const routes: Array<RouteRecordRaw> = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  }
]

const router = function (history: RouterHistory): Router {
  return createRouter({ history, routes })
}

export default router
파일 첫머리에 욕먹을 거야. 아니, import Router History, Router.IDE를 사용하면 자동으로 추가될 수 있지만vim로 썼기 때문에 vue-router-next 코드를 보고 유형의 이름을 조사했습니다.vim에도 플러그인 같은 게 있는 것 같은데 넣는 습관(또는 넣기 싫다고 한다)이 없기 때문에 VS 코드 등으로 환경을 만드는 게 좋다.
역시 자바스크립트는 틀이 필요 없나요?

주제 밖의 말: vue-cli-s 서비스의 오류


TypeScript에 국한된 것이 아니라 TypeScript의 오류인지 TypeScript의 오류인지 (아직 TypeScript의 오류 이외의 오류가 발생하지 않았기 때문) 알 수 없지만, vue-cli-servicebuild에서 오류가 발생했을 때 아무런 소식도 없고 의미가 불분명하다.
 ERROR  Build failed with errors.
그뿐입니다.왜?이렇게 하면 상세한 내용을 볼 수 있지만 entry-server.ts의 구축 오류가 보이지 않습니다.
https://cli.vuejs.org/guide/cli-service.html#vue-cli-service-build
오류 세부 정보 같은 로그도 없습니다.
나는 아직 상세하게 표시하는 기능이 없다고 생각한다. 무엇을 하는 것이 비교적 좋을 것 같지만, 문서를 찾는 것은 매우 번거롭다. 이후에 코드를 다시 보자.

vue.config.js 수정


https://v3.vuejs.org/guide/ssr/build-config.html
나는 단지 여기에 쓴 일을 할 뿐이다.
덧붙여 webpack-manifest-pluginwebpack-node-externals는 각각 진행yarn add -D해야 한다.
yarn add -D webpack-manifest-plugin webpack-node-externals
webpack-manifest-plugin는 마니페스트다.는 json을 생성하는 Webpack Plugin입니다.문서에 예시된 vue.config.js에서build:server에서는 ssr-manifest만 있습니다.json을 생성합니다.
ssr-manifest.json
{
  "app.css": "/css/app.8a184b2c.css",
  "app.js": "/js/app.baf28ace.js",
  "app.css.map": "/css/app.8a184b2c.css.map",
  "app.js.map": "/js/app.baf28ace.js.map",
  "favicon.ico": "/favicon.ico",
  "img/logo.png": "/img/logo.82b9c7a5.png",
  "index.html": "/index.html"
}
용도를 보면 상상이 간다.
https://webpack.js.org/concepts/manifest/
Webpack에서importrequire__webpack_require__로 바뀌었는데 Manifest가 실제 불러올 모듈의 표식자와 관련이 있는 것 같습니다.
예를 들어 require("app.js")가 실제로 __webpack_require__("app.js")로 바뀌었고 운행 시간에 Manifest를 참조할 것이다.아마webpack-node-externals Webpack으로 파일을 처리하지 않는 것 같아요.예컨대.css 파일은 서버 측면에서 묶을 필요가 없기 때문에 (클라이언트를 만들 때 서버에서 묶은 파일을 참조하여 응답할 수 있음) 서버를 구축할 때 외부 의존을 유지합니다.추상적인 부분만 이해하다.

server.잡지를 만들다


Vue.js는 HTML 렌더링 기능만 있기 때문에 HTTP 서버의 기능을 따로 준비해야 합니다.여러분을 제일 좋아해요.js를 사용합니다.
yarn add express
server.js
const path = require('path')
const express = require('express')
const fs = require('fs')
const { renderToString } = require('@vue/server-renderer')
const manifest = require('./dist/server/ssr-manifest.json')

const server = express()

const appPath = path.join(__dirname, 'dist', 'server', manifest['app.js'])
const createApp = require(appPath).default

server.use('/img', express.static(path.join(__dirname, './dist/client', 'img')))
server.use('/js', express.static(path.join(__dirname, './dist/client', 'js')))
server.use('/css', express.static(path.join(__dirname, './dist/client', 'css')))
server.use(
  '/favicon.ico',
  express.static(path.join(__dirname, './dist/client', 'favicon.ico'))
)

server.get('*', async (req, res) => {
  const { app, router } = createApp()

  await router.push(req.url)
  await router.isReady()

  const appContent = await renderToString(app)

  fs.readFile(path.join(__dirname, '/dist/client/index.html'), (err, html) => {
    if (err) {
      throw err
    }

    html = html
      .toString()
      .replace('<div id="app">', `<div id="app">${appContent}`)
    res.setHeader('Content-Type', 'text/html')
    res.send(html)
  })
})

console.log('You can navigate to http://localhost:8080')

server.listen(8080)
Vue.js의 문서 예시와 거의 같습니다.
Static File은 ./dist/client부터 마운트되지만 실제로 서버를 디버깅할 때 필요한 수정 사항이 있을 수 있습니다.그리고,Vue.js의 렌더링 결과.replace에 대해 힘을 느끼는 기능.
server.ts 안 골라요?귀찮아서 싫어.
멍청한 소리를 하면 이 코드는 가장 고객측의 코드이고 이 코드를 사용하는 다른 코드가 없기 때문에 TypeScript로 쓰지 않아도 괜찮겠지?이런 기분이야.내용도 간단하다.

화면 깜박임 개선


↑에서 프롬프트entry-client.ts에서는 개선이 완료됐지만, SSR의 HTML을 로드한 후app.mount("#app") 동작 시 DOM 트리가 모두 새로 고쳐지고 화면이 깜박거린다.
이것은 클라이언트 측에서 createApp 대신 createSSRApp를 사용함으로써 개선되었다.
https://v3.vuejs.org/guide/ssr/hydration.html
Nuxt.js 등에서도 간혹 볼 수 있지만 SSR의 HTML과 고객이 재현한 가상 DOM 사이에 차이가 있으면 고장이 발생할 수 있습니다.Vue.js의 경우 클라이언트의 가상 DOM을 사용하여 DOM 트리를 간단하게 재구성합니다.
createApp을 사용하면 검증이 불가능하기 때문에 비용이 들지 않나요.확실히 서버가 빈 HTML로 답장하면 검증에 실패할 수 있기 때문에 검증할 필요가 없다고 할 수 있다.이 일대는 실제 베일이다.js의 코드를 읽으면 많은 발견이 있을 수 있습니다.

Next


여기서는 대체로 SSR의 Vue가 가능하다.js 프로젝트를 완성했습니다.Nuxt.js 등에 비해 불편하지만 그에 상응하는 조합도 좋고 기초가 얇아서 의존도가 적다는 것도 장점이다.구체적으로 말하면 NODE_ENV=production yarn install 이후의 node이다modules는 18.4MB에 불과하다고 합니다.(AWS Lambda 위에 놓기 쉽습니다!)
하지만 불편한 점도 있다.
Nuxt.js에서 페이지보다 낮습니다.vue를 설정하면 경로를 마음대로 정의할 수 있지만, 너무 간단한 이 항목은 스스로 써야 합니다. ./router/index.ts뭐, 써도 되는데 파일마다 쓸 수 있잖아?그래서 나는 <route> 디렉터리를 추가해서 유사할 수 있는지 없는지를 시험해 보고 싶다.
그리고 구성 요소 단위로 미리 보고 싶어 일찍부터 스토리북을 시도해 보고 싶었다.
GraphiQL API의 응답에 TypeScript의 유형을 설정하든지, TypeScript의 유형에서 GraphiQL API의 조회를 생성하든지, 그런 것도 하고 싶다.API 응답 유형을 정의하고 API 통신을 하는 객체에 전달하면 통신할 수 있습니다.이렇게
네가 원할 때 다시 해라.
했어요.
https://zenn.dev/niaeashes/articles/0e624fc986888d

좋은 웹페이지 즐겨찾기