Skip to content

앱 엔트리포인트

Raw
<!doctype html>
<html lang="ko">
  <head>
    <meta charset="utf-8" />
    <meta content="IE=edge" http-equiv="X-UA-Compatible" />
    <meta content="width=device-width,initial-scale=1.0" name="viewport" />
    <meta content="no-cache, no-store, must-revalidate" http-equiv="Cache-Control" />
    <meta content="no-cache" http-equiv="Pragma" />
    <meta content="0" http-equiv="Expires" />
    <link href="/favicon.ico" rel="icon" />
    <link href="/cdn/Pretendard-1.3.9/web/static/pretendard.css" rel="stylesheet" />
    <script src="/env.js"></script>
    <script>
      // API 서버 preconnect 동적 추가
      ;(function () {
        var apiUrl = (window.__ENV__ && window.__ENV__.VITE_API_BASE_URL) || ''
        if (!apiUrl) return
        try {
          var origin = new URL(apiUrl).origin
          var link = document.createElement('link')
          link.rel = 'preconnect'
          link.href = origin
          link.crossOrigin = 'anonymous'
          document.head.appendChild(link)
        } catch (e) {}
      })()
    </script>
    <title>데이터메이커 시냅스</title>
  </head>
  <body style="background-color: #1a1f2c; margin: 0;">
    <noscript><strong>JavaScript를 활성화해주세요.</strong></noscript>
    <div id="app"></div>
    <script type="module" src="/src/main.js"></script>
  </body>
</html>

staging - public/index.html (Webpack 템플릿)

Section titled “staging - public/index.html (Webpack 템플릿)”
<!doctype html>
<html lang="">
  <head>
    <meta charset="utf-8" />
    <meta content="IE=edge" http-equiv="X-UA-Compatible" />
    <meta content="width=device-width,initial-scale=1.0" name="viewport" />
    <meta content="no-cache, no-store, must-revalidate" http-equiv="Cache-Control" />
    <link href="<%= BASE_URL %>favicon.ico" rel="icon" />
    <link href="<%= BASE_URL %>cdn/Pretendard-1.3.9/web/static/pretendard.css" rel="stylesheet" />
    <title><%= process.env.BRAND_TITLE || '데이터메이커 시냅스' %></title>
  </head>
  <body style="background-color: #1e2533; margin: 0;">
    <noscript><strong>JavaScript를 활성화해주세요.</strong></noscript>
    <div id="app"></div>
  </body>
</html>
항목mainstaging
위치프로젝트 루트 index.htmlpublic/index.html
템플릿 문법없음 (정적 HTML)<%= %> (HtmlWebpackPlugin)
스크립트 로드<script type="module" src="/src/main.js">Webpack이 자동 주입
환경변수env.js 런타임 로드 + preconnectprocess.env 빌드타임 주입
배경색#1a1f2c#1e2533
타이틀하드코딩환경변수 기반 (BRAND_TITLE)
import { createApp } from 'vue'
import App from '@/app/app.vue'
import store from '@/app/app-store'
import router from '@/app/app-routes'
import i18n from '@/i18n'
import { initSentry } from '@/plugins/sentry'
import { registerPlugins } from '@/plugins'
import { registerComponents } from '@/plugins/components'

const app = createApp(App)

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

initSentry(app, router)
registerPlugins(app)
registerComponents(app)

app.mount('#app')

// Service Worker 등록
if ('serviceWorker' in navigator) {
  /* ... */
}
import Vue from 'vue'
import App from '@/app/app.vue'
import store from '@/app/app-store'
import router from '@/app/app-routes'
import i18n from '@/i18n'

// Vue 2 플러그인 등록
import VueCompositionAPI from '@vue/composition-api'
import { BootstrapVue } from 'bootstrap-vue'
import VueToast from 'vue-toast-notification'
import VueWorker from 'vue-worker'
import VJsoneditor from 'v-jsoneditor'
import CKEditor from '@ckeditor/ckeditor5-vue2'
import VueFormulate from '@braid/vue-formulate'

Vue.use(VueCompositionAPI)
Vue.use(BootstrapVue)
Vue.use(VueToast)
Vue.use(VueWorker)
Vue.use(VJsoneditor)
Vue.use(CKEditor)
Vue.use(VueFormulate)

// 글로벌 컴포넌트 등록
Vue.component('v-select', vSelect)
Vue.component('page-header', PageHeader)
// ... 기타 글로벌 컴포넌트

// Sentry 초기화
Sentry.init({ Vue, dsn: '...' })

new Vue({
  router,
  store,
  i18n,
  render: (h) => h(App)
}).$mount('#app')
import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(),
  routes: [
    ...dashboardRoutes,
    ...annotatorRoutes,
    ...authRoutes,
    { path: '/:pathMatch(.*)*', redirect: '/auth/login' }
  ]
})

// Navigation Guard
router.beforeEach(async (to, from, next) => {
  // 인증 및 테넌트 확인
})
import VueRouter from 'vue-router'

const router = new VueRouter({
  mode: 'history',
  routes: [
    ...dashboardRoutes,
    ...annotatorRoutes,
    { path: '*', redirect: '/auth/login' }
  ]
})

// Navigation Guard
router.beforeEach(async (to, from, next) => {
  // 인증 및 테넌트 확인
})
항목mainstaging
생성 방식createRouter()new VueRouter()
HistorycreateWebHistory()mode: 'history'
Catch-all/:pathMatch(.*)**
import { createStore } from 'vuex'
import createPersistedState from 'vuex-persist'

const store = createStore({
  modules: {
    annotator,
    imageAnnotator,
    pcdAnnotator,
    textAnnotator,
    audioAnnotator,
    videoAnnotator,
    promptAnnotator,
    dashboard
  },
  plugins: [new VuexPersistence({ /* ... */ }).plugin]
})
import Vuex from 'vuex'
import createPersistedState from 'vuex-persistedstate'

const store = new Vuex.Store({
  modules: {
    annotator,
    imageAnnotator,
    pcdAnnotator,
    textAnnotator,
    audioAnnotator,
    videoAnnotator,
    promptAnnotator,
    dashboard
  },
  plugins: [createPersistedState({ /* ... */ })]
})
항목mainstaging
생성 방식createStore()new Vuex.Store()
Persistencevuex-persistvuex-persistedstate
import { createI18n } from 'vue-i18n'

const i18n = createI18n({
  legacy: false, // Composition API 모드
  globalInjection: true, // $t 템플릿에서 사용 가능
  locale: 'ko',
  fallbackLocale: 'ko',
  messages: {
    /* import.meta.glob('./locales/*.json') */
  }
})
import VueI18n from 'vue-i18n'

const i18n = new VueI18n({
  locale: 'ko',
  fallbackLocale: 'ko',
  messages: {
    /* require.context('./locales', ...) */
  }
})
항목mainstaging
생성 방식createI18n()new VueI18n()
API 모드Composition (legacy: false)Options (legacy)
파일 로드import.meta.globrequire.context