feat: support singlefile output

dev-postmessage-to-online
Yu Zhu 2023-03-26 01:20:58 +08:00
parent 54d42242c1
commit a1e11cf159
13 changed files with 154 additions and 43 deletions

1
.env.online Normal file
View File

@ -0,0 +1 @@
VITE_IS_ONLINE=true

View File

@ -4,8 +4,9 @@
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"dev": "vite --mode online",
"build": "tsc && vite build --mode online",
"build-singlefile": "tsx tools/generate_assets.ts && tsc && vite build --mode singlefile && tsx tools/fix-singlefile.ts ",
"preview": "vite preview",
"format": "prettier --write src"
},
@ -36,8 +37,10 @@
"@types/react": "^18.0.27",
"@types/react-dom": "^18.0.10",
"@types/three": "^0.149.0",
"@types/fs-extra": "^11.0.1",
"@vitejs/plugin-react": "^3.1.0",
"typescript": "^4.9.3",
"vite": "^4.1.0"
"vite": "^4.1.0",
"vite-plugin-conditional-compiler": "^0.1.1"
}
}

View File

@ -3,6 +3,7 @@ lockfileVersion: 5.4
specifiers:
'@mediapipe/pose': ^0.5.1675469404
'@types/dat.gui': ^0.7.7
'@types/fs-extra': ^11.0.1
'@types/react': ^18.0.27
'@types/react-dom': ^18.0.10
'@types/three': ^0.149.0
@ -26,6 +27,7 @@ specifiers:
type-fest: ^3.6.1
typescript: ^4.9.3
vite: ^4.1.0
vite-plugin-conditional-compiler: ^0.1.1
vite-plugin-pwa: ^0.14.4
workbox-window: ^6.5.4
@ -53,12 +55,14 @@ dependencies:
devDependencies:
'@types/dat.gui': 0.7.7
'@types/fs-extra': 11.0.1
'@types/react': 18.0.28
'@types/react-dom': 18.0.11
'@types/three': 0.149.0
'@vitejs/plugin-react': 3.1.0_vite@4.1.4
typescript: 4.9.5
vite: 4.1.4
vite-plugin-conditional-compiler: 0.1.1
packages:
@ -1830,13 +1834,25 @@ packages:
resolution: {integrity: sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==}
dev: false
/@types/fs-extra/11.0.1:
resolution: {integrity: sha512-MxObHvNl4A69ofaTRU8DFqvgzzv8s9yRtaPPm5gud9HDNvpB3GPQFvNuTWAI59B9huVGV5jXYJwbCsmBsOGYWA==}
dependencies:
'@types/jsonfile': 6.1.1
'@types/node': 18.14.6
dev: true
/@types/json-schema/7.0.11:
resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==}
dev: false
/@types/jsonfile/6.1.1:
resolution: {integrity: sha512-GSgiRCVeapDN+3pqA35IkQwasaCh/0YFH5dEF6S88iDvEn901DjOeH3/QPY+XYP1DFzDZPvIvfeEgk+7br5png==}
dependencies:
'@types/node': 18.14.6
dev: true
/@types/node/18.14.6:
resolution: {integrity: sha512-93+VvleD3mXwlLI/xASjw0FzKcwzl3OdTCzm1LaRfqgS21gfFtK3zDXM5Op9TeeMsJVOaJ2VRDpT9q4Y3d0AvA==}
dev: false
/@types/prop-types/15.7.5:
resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==}
@ -3244,6 +3260,13 @@ packages:
dependencies:
'@jridgewell/sourcemap-codec': 1.4.14
/magic-string/0.30.0:
resolution: {integrity: sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==}
engines: {node: '>=12'}
dependencies:
'@jridgewell/sourcemap-codec': 1.4.14
dev: true
/merge-stream/2.0.0:
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
dev: false
@ -3951,6 +3974,12 @@ packages:
punycode: 2.3.0
dev: false
/vite-plugin-conditional-compiler/0.1.1:
resolution: {integrity: sha512-1QKTJ9/kWuqwWxtIEhtxENUQlfRfgjDyeAtic91ArQFjzI71necB7Sp9F5IGR/L1zIQXkkXBvidLLJkTJcp/OQ==}
dependencies:
magic-string: 0.30.0
dev: true
/vite-plugin-pwa/0.14.4_pchkumgzq6po4w4enhsumrku2u:
resolution: {integrity: sha512-M7Ct0so8OlouMkTWgXnl8W1xU95glITSKIe7qswZf1tniAstO2idElGCnsrTJ5NPNSx1XqfTCOUj8j94S6FD7Q==}
peerDependencies:

9
src/assets.ts Normal file
View File

@ -0,0 +1,9 @@
import handFBXFileUrl from '../models/hand.fbx?url'
import footFBXFileUrl from '../models/foot.fbx?url'
import posesLibraryUrl from './poses/data.bin?url'
export default {
'models/hand.fbx': handFBXFileUrl,
'models/foot.fbx': footFBXFileUrl,
'src/poses/data.bin': posesLibraryUrl,
}

3
src/env.d.ts vendored Normal file
View File

@ -0,0 +1,3 @@
interface ImportMetaEnv {
readonly VITE_IS_ONLINE?: boolean
}

View File

@ -1,9 +0,0 @@
import handFBXFileUrl from '../../../models/hand.fbx?url'
import footFBXFileUrl from '../../../models/foot.fbx?url'
import posesLibraryUrl from '../../poses/data.bin?url'
export default {
'models/hand.fbx': handFBXFileUrl,
'models/foot.fbx': footFBXFileUrl,
'src/poses/data.bin': posesLibraryUrl,
}

View File

@ -10,7 +10,7 @@ import Swal from 'sweetalert2'
import { BodyEditor } from '../../editor'
import i18n from '../../i18n'
import { Oops } from '../../components'
import assets from './assets'
import assets from '../../assets'
import * as dat from 'dat.gui'
export class Helper {

View File

@ -9,7 +9,7 @@ import { canvasElement, createDatGui, statsElement } from './gui'
import Swal from 'sweetalert2'
import { CreateTemplateBody, LoadFoot, LoadHand } from '../../body'
import assets from './assets'
import assets from '../../assets'
import { Helper } from './helper'
async function LoadBodyData() {

View File

@ -1,6 +1,9 @@
/// <reference types="vite-plugin-pwa/client" />
// #v-ifdef VITE_IS_ONLINE
import { registerSW } from 'virtual:pwa-register'
// #v-endif
import Swal from 'sweetalert2'
import i18n from '../../i18n'
@ -13,6 +16,7 @@ async function PWAPopup(update: (reloadPage?: boolean) => Promise<void>) {
}
}
export function PWACheck() {
if (import.meta.env.MODE !== 'online') return
const updateSW = registerSW({
onNeedRefresh() {
console.log('有更新,需要刷新!!')

View File

@ -3,6 +3,7 @@ import { Class } from 'type-fest'
// https://github.com/google/mediapipe/blob/master/docs/solutions/pose.md#resources
import type { Results, Pose, PoseConfig } from '@mediapipe/pose'
import * as MediapipePose from '@mediapipe/pose'
import assets from '../assets'
// @mediapipe/pose is not an es module ??
// Extract Pose from the window to solve the problem
@ -15,6 +16,10 @@ console.log('MyPose', MyPose)
const pose = new MyPose({
locateFile: (file) => {
if (file in assets) {
console.log('local', file)
return (assets as any)[file]
}
const url = `https://cdn.jsdelivr.net/npm/@mediapipe/pose/${file}`
console.log('load pose model', url)

8
tools/fix-singlefile.ts Normal file
View File

@ -0,0 +1,8 @@
import fs from 'fs-extra'
const content = fs.readFileSync('dist/index.html').toString()
fs.writeFile(
'dist/index.html',
content.replace(`type="module" crossorigin`, 'defer')
)

51
tools/generate_assets.ts Normal file
View File

@ -0,0 +1,51 @@
import fs from 'fs-extra'
import path from 'path'
const list: Record<
string,
{
prefix?: string
mimetype: string
}
> = {
'models/foot.fbx': { mimetype: 'application/octet-stream' },
'models/hand.fbx': { mimetype: 'application/octet-stream' },
'src/poses/data.bin': { mimetype: 'application/octet-stream' },
'pose_landmark_full.tflite': {
prefix: 'node_modules/@mediapipe/pose/',
mimetype: 'application/octet-stream',
},
'pose_web.binarypb': {
prefix: 'node_modules/@mediapipe/pose/',
mimetype: 'application/octet-stream',
},
'pose_solution_packed_assets.data': {
prefix: 'node_modules/@mediapipe/pose/',
mimetype: 'application/octet-stream',
},
'pose_solution_simd_wasm_bin.wasm': {
prefix: 'node_modules/@mediapipe/pose/',
mimetype: 'application/wasm',
},
'pose_solution_packed_assets_loader.js': {
prefix: 'node_modules/@mediapipe/pose/',
mimetype: 'application/javascript',
},
'pose_solution_simd_wasm_bin.js': {
prefix: 'node_modules/@mediapipe/pose/',
mimetype: 'application/javascript',
},
}
const output = Object.fromEntries(
Object.entries(list).map(([file, { prefix, mimetype }]) => [
file,
`data:${mimetype};base64,${fs
.readFileSync(path.join(prefix ?? '.', file))
.toString('base64')}`,
])
)
fs.writeFile(
'src/assets.ts',
'export default ' + JSON.stringify(output, null, 4)
)

View File

@ -1,37 +1,44 @@
import { defineConfig, type UserConfigExport } from 'vite'
import { defineConfig, UserConfigFn } from 'vite'
import react from '@vitejs/plugin-react'
import { VitePWA } from 'vite-plugin-pwa'
import { visualizer } from 'rollup-plugin-visualizer'
import { resolve } from 'path'
import ConditionalCompile from 'vite-plugin-conditional-compiler'
// https://vitejs.dev/config/
const config: UserConfigExport = {
base: '/open-pose-editor/',
define: {
global: {},
__APP_VERSION__: JSON.stringify('v0.0.2'),
__APP_BUILD_TIME__: Date.now(),
},
build: {},
plugins: [
react(),
VitePWA({
workbox: {
globPatterns: [
'**/*.{js,css,html,ico,png,svg,mp3,obj,fbx,bin}',
],
},
manifest: {
name: 'open pose editor',
short_name: 'open pose editor',
description: 'open pose editor (Yu Zhu)',
theme_color: '#ffffff',
background_color: '#ffffff',
display: 'standalone',
},
}),
visualizer(),
],
const config: UserConfigFn = ({ command, mode, ssrBuild }) => {
const pwa = VitePWA({
workbox: {
globPatterns: ['**/*.{js,css,html,ico,png,svg,mp3,obj,fbx,bin}'],
},
manifest: {
name: 'open pose editor',
short_name: 'open pose editor',
description: 'open pose editor (Yu Zhu)',
theme_color: '#ffffff',
background_color: '#ffffff',
display: 'standalone',
},
})
return {
base: mode === 'singlefile' ? './' : '/open-pose-editor/',
define: {
global: {},
__APP_VERSION__: JSON.stringify('v0.0.2'),
__APP_BUILD_TIME__: Date.now(),
},
build: {
assetsDir: mode === 'singlefile' ? '.' : 'assets',
emptyOutDir: true,
},
plugins: [
react(),
mode === 'online' ? pwa : null,
visualizer(),
ConditionalCompile(),
],
}
}
export default defineConfig(config)