programing

Vue 3 SSR 앱에서 라우터의 vuex 스토어를 사용하려면 어떻게 해야 합니까?

coolbiz 2022. 7. 4. 23:02
반응형

Vue 3 SSR 앱에서 라우터의 vuex 스토어를 사용하려면 어떻게 해야 합니까?

SSR, Vue-Cli, Vuex 및 Typescript를 사용하는 Vue3 프로젝트가 있습니다.

라우터 페이지에서 데이터를 Vuex Store에 커밋해야 합니다..vue 파일에서는 이것을 사용합니다.vuex.d.ts로 입력되는 $store는 다음과 같습니다.

this.$store.commit("setFoo", "Bar")

그러나 이 인스턴스 또는 vue 인스턴스가 없는 ts 파일(라우터/index.ts)에서 이를 수행하려면 어떻게 해야 합니까?

저장소 인덱스 파일을 가져오고 다음을 커밋했습니다.

import store from "@/store/index"

store.commit("setFoo", "Bar")

그런데 에러가 난다.

'() = > 저장 유형 <{ foo: string; } >'ts(2339)에 'commit' 속성이 없습니다.

저장소 파일(SSR를 실행 중이므로 저장소는 싱글톤일 수 없습니다):

import Vuex from "vuex"

export default function () {
  return new Vuex.Store({
    state: () => ({
      foo: "foo",
    }),
    mutations: {
      setFoo(state, payload) {
        state.foo = payload
      },
    },
  })
}

vuex 4에 대한 저장소 파일 업데이트:

import { createStore } from "vuex"

const store = {
  state: () => ({
    foo: "foo",
  })
}

export default function () {
  return createStore(store)
}

entry-client.syslog:

import createApp from "./main"

const { app, router } = createApp()

router.isReady().then(() => {
  app.mount("#app", true)
})

entry-server.ts:

import createApp from "./main"

export default function () {
  const { app, router } = createApp()

  return {
    app,
    router,
  }
}

main.filename:

import { createSSRApp, createApp, h } from "vue"
import { isSSR } from "@/helpers"
import createRouter from "@/router"
import createStore from "@/store"
import axios from "axios"
import VueAxios from "vue-axios"
import App from "@/App.vue"

export default function () {

  const rootComponent = {
    render: () => h(App),
    components: { App },
  }

  const app = (isSSR() ? createSSRApp : createApp)(rootComponent)
  const router = createRouter()
  const store = createStore()

  app.use(VueAxios, axios)
  app.use(router)
  app.use(store)

  app.provide("axios", app.config.globalProperties.axios)

  return {
    app,
    router,
    store,
  }
}

Router/index.ts:

  import { createRouter, createWebHistory, createMemoryHistory } from "vue-router"
  import store from "@/store/index"
  import axios from "axios"
  import MockAdapter from "axios-mock-adapter"
  import { routes } from "./routes"
  import { isSSR } from "@/helpers"

  const history = isSSR()
    ? createMemoryHistory()
    : createWebHistory(process.env.BASE_URL)

  const router = createRouter({ routes, history })

  router.beforeEach(async (to, from, next) => {
   // do stuff with store
  })
  
  export default function () {
    return router
  }

패키지json:

  "scripts": {
    "build:all": "npm run build:client && npm run build:server",
    "build:client": "vue-cli-service build --dest dist/client",
    "build:server": "export SSR=1 || set SSR=1&& vue-cli-service build --dest dist/server",
    "build:server:dev": "export SSR=1 || set SSR=1&& vue-cli-service build --mode development --dest dist/server",
    "serve:client": "vue-cli-service serve",
    "serve:server": "node ./dist/server/server.js",
    "lint": "vue-cli-service lint"
  },
  "dependencies": {
    "@vue/server-renderer": "^3.2.4",
    "axios": "^0.21.1",
    "core-js": "^3.6.5",
    "express": "^4.17.1",
    "vue": "^3.0.0",
    "vue-axios": "^3.2.5",
    "vue-router": "^4.0.0-0",
    "vuex": "^4.0.0-0"
  },
  "devDependencies": {
    "@typescript-eslint/eslint-plugin": "^4.18.0",
    "@typescript-eslint/parser": "^4.18.0",
    "@vue/cli-plugin-babel": "^5.0.0-beta.3",
    "@vue/cli-plugin-eslint": "^5.0.0-beta.3",
    "@vue/cli-plugin-router": "^5.0.0-beta.3",
    "@vue/cli-plugin-typescript": "^5.0.0-beta.3",
    "@vue/cli-plugin-vuex": "^5.0.0-beta.3",
    "@vue/cli-service": "^5.0.0-beta.3",
    "@vue/compiler-sfc": "^3.0.0",
    "@vue/eslint-config-prettier": "^6.0.0",
    "@vue/eslint-config-typescript": "^7.0.0",
    "axios-mock-adapter": "^1.20.0",
    "eslint": "^7.20.0",
    "eslint-plugin-prettier": "^3.3.1",
    "eslint-plugin-vue": "^7.6.0",
    "node-sass": "^4.12.0",
    "prettier": "^2.2.1",
    "sass-loader": "^8.0.2",
    "typescript": "~4.1.5",
    "webpack-manifest-plugin": "^4.0.2",
    "webpack-node-externals": "^3.0.0"
  }

스테이트풀 싱글톤 회피 규칙은 메인앱인스턴스 및 스토어뿐만 아니라 라우터에도 적용됩니다.

현재 사용 중인 제품Router/index.ts스테이트풀싱글톤을 만듭니다.대신 필요한 것은 각 서버 요구가 새로운 라우터 인스턴스를 얻을 수 있도록 "라우터 팩토리" 함수를 작성하는 것입니다.스토어 인스턴스를 전달할 수 있는 이점도 있습니다.

Router/index.ts

  import { createRouter, createWebHistory, createMemoryHistory } from "vue-router"
  import axios from "axios"
  import MockAdapter from "axios-mock-adapter"
  import { routes } from "./routes"
  import { isSSR } from "@/helpers"

  const createHistory = isSSR()
    ? createMemoryHistory
    : createWebHistory

  export default function (store) {
    const router = createRouter({ 
      routes, 
      history: createHistory(process.env.BASE_URL)
    })

    router.beforeEach(async (to, from, next) => {
      // do stuff with store (store comes from argument)
    })
  
    return router
  }

서버 번들과 클라이언트 번들은 둘 다 사용해야 합니다(표준을 사용하는 경우).createApp, 클라이언트하이드레이션이 작동하지 않습니다.

Vue는createSSRApp클라이언트 측 코드에서 모든 DOM 요소를 재생성하는 대신 기존 정적 HTML에 물을 공급하도록 Vue에 지시하는 방법

main.js

import { createSSRApp, h } from "vue"
import { isSSR } from "@/helpers"
import createRouter from "@/router"
import createStore from "@/store"
import axios from "axios"
import VueAxios from "vue-axios"
import App from "@/App.vue"

export default function () {

  const rootComponent = {
    render: () => h(App),
    components: { App },
  }

  const app = createSSRApp(rootComponent)
  const store = createStore()
  const router = createRouter(store)

  app.use(VueAxios, axios)
  app.use(router)
  app.use(store)

  app.provide("axios", app.config.globalProperties.axios)

  return {
    app,
    router,
    store,
  }
}

기본 내보내기는 함수입니다.

export default function () {

대신 이걸 하고 싶었던 것 같아요.

export default new Vuex.Store({...})

기능으로서 보관하고 싶은 경우는, 시험해 볼 수도 있습니다.store().commit그러나 store()를 호출할 때마다 새로운 Vuex 인스턴스가 생성됩니다.

언급URL : https://stackoverflow.com/questions/68993708/how-do-i-use-vuex-store-in-the-router-in-vue-3-ssr-app

반응형