- @capacitor/camera 정적 import 제거 → 네이티브에서만 동적 import (웹은 카메라를 호출하지도 않는데 정적 import가 AccountView 청크 평가를 깨뜨려 모바일 웹에서 진입 시 청크 로드 실패 → onError 새로고침 → 로그인 루프 발생) - router.onError 경로별 1회 새로고침으로 제한(무한 루프 방지) + 성공 시 플래그 정리 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+12
-6
@@ -108,15 +108,21 @@ router.beforeEach((to, from) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// 새 배포로 청크 해시가 바뀐 뒤, 캐시된 옛 index.html 이 삭제된 옛 청크를 부르면
|
// 새 배포로 청크 해시가 바뀐 뒤, 캐시된 옛 index.html 이 삭제된 옛 청크를 부르면
|
||||||
// 동적 import 가 실패한다. 이 경우 목적지로 전체 새로고침해 최신 index.html 을 받게 한다.
|
// 동적 import 가 실패한다. 이 경우 목적지로 1회 전체 새로고침해 최신 index.html 을 받게 한다.
|
||||||
let reloadingForChunk = false
|
// (경로별 1회만 — 새로고침 후에도 실패하면 무한 새로고침/로그인 루프를 막기 위해 중단)
|
||||||
router.onError((err, to) => {
|
router.onError((err, to) => {
|
||||||
const msg = (err && err.message) || ''
|
const msg = (err && err.message) || ''
|
||||||
const chunkError = /dynamically imported module|Importing a module script failed|Failed to fetch dynamically imported module|ChunkLoadError|error loading dynamically imported module/i.test(msg)
|
const chunkError = /dynamically imported module|Importing a module script failed|Failed to fetch dynamically imported module|ChunkLoadError|error loading dynamically imported module/i.test(msg)
|
||||||
if (chunkError && !reloadingForChunk) {
|
if (!chunkError) return
|
||||||
reloadingForChunk = true
|
const path = to?.fullPath || window.location.pathname
|
||||||
window.location.assign(to?.fullPath || window.location.pathname)
|
const key = 'chunk-reload:' + path
|
||||||
}
|
if (sessionStorage.getItem(key)) return // 이미 한 번 새로고침했는데 또 실패 → 루프 방지
|
||||||
|
sessionStorage.setItem(key, '1')
|
||||||
|
window.location.assign(path)
|
||||||
|
})
|
||||||
|
// 정상 진입 시 해당 경로의 새로고침 플래그 정리 (다음 배포 때 다시 동작하도록)
|
||||||
|
router.afterEach((to) => {
|
||||||
|
sessionStorage.removeItem('chunk-reload:' + to.fullPath)
|
||||||
})
|
})
|
||||||
|
|
||||||
export default router
|
export default router
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { accountApi } from '@/api/accountApi'
|
|||||||
import IconBtn from '@/components/ui/IconBtn.vue'
|
import IconBtn from '@/components/ui/IconBtn.vue'
|
||||||
import { imageToBlob, parseReceiptText } from '@/utils/receiptOcr'
|
import { imageToBlob, parseReceiptText } from '@/utils/receiptOcr'
|
||||||
import { Capacitor } from '@capacitor/core'
|
import { Capacitor } from '@capacitor/core'
|
||||||
import { Camera, CameraResultType, CameraSource } from '@capacitor/camera'
|
// @capacitor/camera 는 네이티브에서만 동적 로드 (웹은 file input 사용 — 정적 import 시 모바일 웹 청크 로드 실패 유발)
|
||||||
|
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
const year = ref(now.getFullYear())
|
const year = ref(now.getFullYear())
|
||||||
@@ -70,7 +70,7 @@ function pickReceipt() {
|
|||||||
async function chooseCamera() {
|
async function chooseCamera() {
|
||||||
receiptPickerOpen.value = false
|
receiptPickerOpen.value = false
|
||||||
if (Capacitor.isNativePlatform()) {
|
if (Capacitor.isNativePlatform()) {
|
||||||
await captureFrom(CameraSource.Camera)
|
await captureFrom('CAMERA')
|
||||||
} else {
|
} else {
|
||||||
webCapture.value = true
|
webCapture.value = true
|
||||||
await nextTick()
|
await nextTick()
|
||||||
@@ -80,17 +80,19 @@ async function chooseCamera() {
|
|||||||
async function chooseGallery() {
|
async function chooseGallery() {
|
||||||
receiptPickerOpen.value = false
|
receiptPickerOpen.value = false
|
||||||
if (Capacitor.isNativePlatform()) {
|
if (Capacitor.isNativePlatform()) {
|
||||||
await captureFrom(CameraSource.Photos)
|
await captureFrom('PHOTOS')
|
||||||
} else {
|
} else {
|
||||||
webCapture.value = false
|
webCapture.value = false
|
||||||
await nextTick()
|
await nextTick()
|
||||||
receiptInput.value?.click()
|
receiptInput.value?.click()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async function captureFrom(source) {
|
// 네이티브 전용 — 카메라 플러그인을 이 시점에만 동적 로드
|
||||||
|
async function captureFrom(sourceKey) {
|
||||||
try {
|
try {
|
||||||
|
const { Camera, CameraResultType, CameraSource } = await import('@capacitor/camera')
|
||||||
const photo = await Camera.getPhoto({
|
const photo = await Camera.getPhoto({
|
||||||
source,
|
source: sourceKey === 'CAMERA' ? CameraSource.Camera : CameraSource.Photos,
|
||||||
resultType: CameraResultType.DataUrl,
|
resultType: CameraResultType.DataUrl,
|
||||||
quality: 70,
|
quality: 70,
|
||||||
correctOrientation: true,
|
correctOrientation: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user