Compare commits
No commits in common. "e4702b877f94d12364e06eb1a449cf2dcc6d91db" and "5bcd94a3d0efd64f14515d56b761f59fc098b81f" have entirely different histories.
e4702b877f
...
5bcd94a3d0
@ -22,8 +22,7 @@
|
|||||||
"three": "^0.172.0",
|
"three": "^0.172.0",
|
||||||
"vue": "^3.3.0",
|
"vue": "^3.3.0",
|
||||||
"vue-i18n": "^9.1.9",
|
"vue-i18n": "^9.1.9",
|
||||||
"vue-router": "^4.5.0",
|
"vue-router": "^4.5.0"
|
||||||
"register-service-worker": "^1.7.2"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@rushstack/eslint-patch": "^1.6.1",
|
"@rushstack/eslint-patch": "^1.6.1",
|
||||||
@ -45,8 +44,6 @@
|
|||||||
"sass-loader": "^13.3.3",
|
"sass-loader": "^13.3.3",
|
||||||
"typescript": "^4.9.4",
|
"typescript": "^4.9.4",
|
||||||
"vite": "4.1.4",
|
"vite": "4.1.4",
|
||||||
"vite-plugin-pwa": "^0.17.5",
|
"vue-tsc": "^1.0.24"
|
||||||
"vue-tsc": "^1.0.24",
|
|
||||||
"workbox-window": "^7.0.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
19
src/main.ts
19
src/main.ts
@ -3,25 +3,6 @@ import App from './App.vue'
|
|||||||
import 'ant-design-vue/dist/reset.css';
|
import 'ant-design-vue/dist/reset.css';
|
||||||
import Antd from 'ant-design-vue';
|
import Antd from 'ant-design-vue';
|
||||||
import router from './router/router';
|
import router from './router/router';
|
||||||
import { registerSW } from 'virtual:pwa-register'
|
|
||||||
import { isPwa, showPwaInstallPrompt } from './utils/pwa';
|
|
||||||
|
|
||||||
const updateSW = registerSW({
|
|
||||||
onNeedRefresh() {
|
|
||||||
// 当发现新版本时,可以在这里提示用户
|
|
||||||
console.log('发现新版本')
|
|
||||||
},
|
|
||||||
onOfflineReady() {
|
|
||||||
// 当离线功能准备就绪时
|
|
||||||
console.log('应用已经可以离线使用')
|
|
||||||
if (isPwa()) {
|
|
||||||
console.log('PWA 模式')
|
|
||||||
} else {
|
|
||||||
// showPwaInstallPrompt()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const app = createApp(App);
|
const app = createApp(App);
|
||||||
app.use(Antd);
|
app.use(Antd);
|
||||||
app.use(router);
|
app.use(router);
|
||||||
|
@ -2,108 +2,23 @@
|
|||||||
<div>
|
<div>
|
||||||
<video
|
<video
|
||||||
id="video"
|
id="video"
|
||||||
:src="mediaSource"
|
src="/static/test.mp4"
|
||||||
style="display: none"
|
style="display: none"
|
||||||
loop
|
loop
|
||||||
crossorigin="anonymous"
|
crossorigin="anonymous"
|
||||||
></video>
|
></video>
|
||||||
<canvas id="canvas"></canvas>
|
<canvas id="canvas"></canvas>
|
||||||
<div class="play-button" v-show="!isPlaying" @click="handleClick">
|
<button @click="handleClick">播放</button>
|
||||||
<i class="play-icon"></i>
|
|
||||||
</div>
|
|
||||||
<div class="upload-container">
|
|
||||||
<input
|
|
||||||
type="file"
|
|
||||||
ref="fileInput"
|
|
||||||
@change="handleFileUpload"
|
|
||||||
accept="image/*,video/*"
|
|
||||||
style="display: none"
|
|
||||||
/>
|
|
||||||
<button class="upload-btn" @click="triggerFileUpload">
|
|
||||||
上传图片/视频
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import { onMounted, onUnmounted, ref } from "vue";
|
import { onMounted, onUnmounted } from "vue";
|
||||||
|
|
||||||
const isPlaying = ref(false);
|
|
||||||
const fileInput = ref<HTMLInputElement | null>(null);
|
|
||||||
const mediaSource = ref("/static/test.mp4");
|
|
||||||
const isVideo = ref(true);
|
|
||||||
const texture = ref<THREE.VideoTexture | THREE.Texture | null>(null);
|
|
||||||
|
|
||||||
const triggerFileUpload = () => {
|
|
||||||
fileInput.value?.click();
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
if (isVideo.value) {
|
|
||||||
const video = document.getElementById("video") as HTMLVideoElement;
|
const video = document.getElementById("video") as HTMLVideoElement;
|
||||||
video.play();
|
video.play();
|
||||||
isPlaying.value = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const createImageTexture = (url: string): Promise<THREE.Texture> => {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
const loader = new THREE.TextureLoader();
|
|
||||||
loader.load(url, (texture) => {
|
|
||||||
texture.minFilter = THREE.LinearFilter;
|
|
||||||
texture.magFilter = THREE.LinearFilter;
|
|
||||||
resolve(texture);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleFileUpload = async (event: Event) => {
|
|
||||||
const input = event.target as HTMLInputElement;
|
|
||||||
const file = input.files?.[0];
|
|
||||||
|
|
||||||
if (file) {
|
|
||||||
const url = URL.createObjectURL(file);
|
|
||||||
const video = document.getElementById("video") as HTMLVideoElement;
|
|
||||||
|
|
||||||
// 先暂停当前播放
|
|
||||||
video.pause();
|
|
||||||
isPlaying.value = false;
|
|
||||||
|
|
||||||
if (file.type.startsWith("video/")) {
|
|
||||||
isVideo.value = true;
|
|
||||||
// 更新视频源
|
|
||||||
mediaSource.value = url;
|
|
||||||
|
|
||||||
// 如果是视频,等待加载后再播放
|
|
||||||
video.addEventListener(
|
|
||||||
"loadeddata",
|
|
||||||
async () => {
|
|
||||||
try {
|
|
||||||
texture.value = new THREE.VideoTexture(video);
|
|
||||||
texture.value.minFilter = THREE.LinearFilter;
|
|
||||||
texture.value.magFilter = THREE.LinearFilter;
|
|
||||||
texture.value.format = THREE.RGBFormat;
|
|
||||||
await video.play();
|
|
||||||
isPlaying.value = true;
|
|
||||||
} catch (err) {
|
|
||||||
console.error("视频播放失败:", err);
|
|
||||||
isPlaying.value = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ once: true }
|
|
||||||
);
|
|
||||||
} else if (file.type.startsWith("image/")) {
|
|
||||||
isVideo.value = false;
|
|
||||||
mediaSource.value = "";
|
|
||||||
// 创建图片纹理
|
|
||||||
texture.value = await createImageTexture(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重置文件输入,允许重复上传相同文件
|
|
||||||
input.value = "";
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 创建场景和相机
|
// 创建场景和相机
|
||||||
@ -121,30 +36,21 @@ onMounted(async () => {
|
|||||||
canvas: document.querySelector("#canvas"),
|
canvas: document.querySelector("#canvas"),
|
||||||
});
|
});
|
||||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||||
|
|
||||||
// 获取视频元素
|
// 获取视频元素
|
||||||
const video = document.getElementById("video") as HTMLVideoElement;
|
const video = document.getElementById("video") as HTMLVideoElement;
|
||||||
|
|
||||||
// 创建初始视频纹理
|
// 创建视频纹理
|
||||||
texture.value = new THREE.VideoTexture(video);
|
const videoTexture = new THREE.VideoTexture(video);
|
||||||
texture.value.minFilter = THREE.LinearFilter;
|
videoTexture.minFilter = THREE.LinearFilter;
|
||||||
texture.value.magFilter = THREE.LinearFilter;
|
videoTexture.magFilter = THREE.LinearFilter;
|
||||||
texture.value.format = THREE.RGBFormat;
|
videoTexture.format = THREE.RGBFormat;
|
||||||
|
|
||||||
// 等待视频加载完成后播放
|
// 播放视频
|
||||||
video.addEventListener(
|
|
||||||
"loadeddata",
|
|
||||||
async () => {
|
|
||||||
try {
|
try {
|
||||||
await video.play();
|
await video.play();
|
||||||
isPlaying.value = true;
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("视频播放失败:", err);
|
console.error("视频播放失败:", err);
|
||||||
isPlaying.value = false;
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{ once: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
// 创建平面几何体
|
// 创建平面几何体
|
||||||
const geometry = new THREE.PlaneGeometry(10, 10, 200, 200);
|
const geometry = new THREE.PlaneGeometry(10, 10, 200, 200);
|
||||||
@ -170,7 +76,7 @@ onMounted(async () => {
|
|||||||
vec3 pos = position;
|
vec3 pos = position;
|
||||||
|
|
||||||
// 基于位置和时间生成随机值
|
// 基于位置和时间生成随机值
|
||||||
float rand = random(pos.xy) * 1.01 - 0.01;
|
float rand = random(pos.xy) * 2.0 - 1.0;
|
||||||
vRandom = rand;
|
vRandom = rand;
|
||||||
|
|
||||||
// 计算打散效果
|
// 计算打散效果
|
||||||
@ -208,49 +114,29 @@ onMounted(async () => {
|
|||||||
varying float vRandom;
|
varying float vRandom;
|
||||||
uniform float time;
|
uniform float time;
|
||||||
|
|
||||||
// 颜色调整辅助函数
|
|
||||||
vec3 adjustColor(vec3 color) {
|
|
||||||
// 增加对比度
|
|
||||||
vec3 contrast = (color - 0.5) * 1.4 + 0.5;
|
|
||||||
|
|
||||||
// 计算亮度
|
|
||||||
float luminance = dot(contrast, vec3(0.299, 0.587, 0.114));
|
|
||||||
|
|
||||||
// 增加饱和度
|
|
||||||
vec3 saturated = mix(vec3(luminance), contrast, 1.3);
|
|
||||||
|
|
||||||
// 稍微压暗高光
|
|
||||||
saturated = pow(saturated, vec3(1.1));
|
|
||||||
|
|
||||||
return saturated;
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
// 马赛克大小
|
// 减小马赛克大小
|
||||||
float mosaicSize = 1000.0;
|
float mosaicSize = 1000.0;
|
||||||
vec2 mosaicUv = floor(vUv * mosaicSize) / mosaicSize;
|
vec2 mosaicUv = floor(vUv * mosaicSize) / mosaicSize;
|
||||||
|
|
||||||
// 减小抖动效果
|
// 减小抖动效果
|
||||||
float jitter = sin(time * 2.0 + vRandom * 1.28) * 0.001;
|
float jitter = sin(time * 2.0 + vRandom * 6.28) * 0.000001;
|
||||||
mosaicUv += vec2(jitter);
|
mosaicUv += vec2(jitter);
|
||||||
|
|
||||||
vec4 texColor = texture2D(mainTexture, mosaicUv);
|
vec4 texColor = texture2D(mainTexture, mosaicUv);
|
||||||
|
|
||||||
// 调整颜色
|
|
||||||
vec3 adjustedColor = adjustColor(texColor.rgb);
|
|
||||||
|
|
||||||
// 调整扭曲和淡出效果
|
// 调整扭曲和淡出效果
|
||||||
float distortionFactor = 1.0 - vDist * 0.005;
|
float distortionFactor = 1.0 - vDist * 0.05;
|
||||||
float alpha = 0.99 + 0.01 * sin(time * 2.0 + vRandom * 6.28);
|
float alpha = 0.9 + 0.1 * sin(time * 2.0 + vRandom * 6.28);
|
||||||
|
|
||||||
// 边缘淡出效果
|
// 边缘淡出效果
|
||||||
float edgeFade = 1.0 - length(gl_PointCoord - vec2(0.5)) * 2.0;
|
float edgeFade = 1.0 - length(gl_PointCoord - vec2(0.5)) * 2.0;
|
||||||
edgeFade = smoothstep(0.0, 0.5, edgeFade);
|
edgeFade = smoothstep(0.0, 0.5, edgeFade);
|
||||||
|
|
||||||
gl_FragColor = vec4(adjustedColor, texColor.a * alpha * edgeFade);
|
gl_FragColor = vec4(texColor.rgb * distortionFactor, texColor.a * alpha * edgeFade);
|
||||||
}`,
|
}`,
|
||||||
uniforms: {
|
uniforms: {
|
||||||
mainTexture: { value: texture.value },
|
mainTexture: { value: videoTexture },
|
||||||
mouse: { value: new THREE.Vector2(0, 0) },
|
mouse: { value: new THREE.Vector2(0, 0) },
|
||||||
radius: { value: 0.5 },
|
radius: { value: 0.5 },
|
||||||
time: { value: 0 },
|
time: { value: 0 },
|
||||||
@ -280,11 +166,8 @@ onMounted(async () => {
|
|||||||
function animate() {
|
function animate() {
|
||||||
requestAnimationFrame(animate);
|
requestAnimationFrame(animate);
|
||||||
|
|
||||||
if (texture.value) {
|
if (video.readyState === video.HAVE_ENOUGH_DATA) {
|
||||||
if (isVideo.value && video.readyState === video.HAVE_ENOUGH_DATA) {
|
videoTexture.needsUpdate = true;
|
||||||
(texture.value as THREE.VideoTexture).needsUpdate = true;
|
|
||||||
}
|
|
||||||
material.uniforms.mainTexture.value = texture.value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
material.uniforms.time.value += 0.016;
|
material.uniforms.time.value += 0.016;
|
||||||
@ -302,16 +185,6 @@ onMounted(async () => {
|
|||||||
|
|
||||||
renderer.setSize(width, height);
|
renderer.setSize(width, height);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 监听视频暂停事件
|
|
||||||
video.addEventListener("pause", () => {
|
|
||||||
isPlaying.value = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
// 监听视频播放事件
|
|
||||||
video.addEventListener("play", () => {
|
|
||||||
isPlaying.value = true;
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 组件卸载时清理
|
// 组件卸载时清理
|
||||||
@ -320,17 +193,6 @@ onUnmounted(() => {
|
|||||||
video.pause();
|
video.pause();
|
||||||
video.src = "";
|
video.src = "";
|
||||||
video.load();
|
video.load();
|
||||||
|
|
||||||
// 清理创建的对象URL
|
|
||||||
if (mediaSource.value.startsWith("blob:")) {
|
|
||||||
URL.revokeObjectURL(mediaSource.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 清理纹理
|
|
||||||
if (texture.value) {
|
|
||||||
texture.value.dispose();
|
|
||||||
texture.value = null;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -340,58 +202,4 @@ canvas {
|
|||||||
height: 100vh;
|
height: 100vh;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.play-button {
|
|
||||||
position: fixed;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
width: 80px;
|
|
||||||
height: 80px;
|
|
||||||
background: rgba(0, 0, 0, 0.6);
|
|
||||||
border-radius: 50%;
|
|
||||||
cursor: pointer;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
transition: all 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.play-button:hover {
|
|
||||||
background: rgba(0, 0, 0, 0.8);
|
|
||||||
transform: translate(-50%, -50%) scale(1.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.play-icon {
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
border-style: solid;
|
|
||||||
border-width: 20px 0 20px 30px;
|
|
||||||
border-color: transparent transparent transparent #ffffff;
|
|
||||||
margin-left: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.upload-container {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 20px;
|
|
||||||
left: 50%;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.upload-btn {
|
|
||||||
background: rgba(0, 0, 0, 0.6);
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
padding: 10px 20px;
|
|
||||||
border-radius: 20px;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 14px;
|
|
||||||
transition: all 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.upload-btn:hover {
|
|
||||||
background: rgba(0, 0, 0, 0.8);
|
|
||||||
transform: scale(1.05);
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -2,43 +2,13 @@ import { createRouter, createWebHashHistory } from "vue-router";
|
|||||||
import Index from "../pages/file/index.vue";
|
import Index from "../pages/file/index.vue";
|
||||||
import Voice from "../pages/voice/webrtcVoice.vue";
|
import Voice from "../pages/voice/webrtcVoice.vue";
|
||||||
import PointShader from "../pages/pointShader/pointShader.vue";
|
import PointShader from "../pages/pointShader/pointShader.vue";
|
||||||
import { disablePwaPrompt, enablePwaPrompt } from '../utils/pwa';
|
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHashHistory(),
|
history: createWebHashHistory(),
|
||||||
routes: [
|
routes: [
|
||||||
{
|
{ path: "/", component: Index },
|
||||||
path: "/",
|
{ path: "/voice", component: Voice },
|
||||||
component: Index,
|
{ path: "/pointShader", component: PointShader },
|
||||||
meta: {
|
|
||||||
showPwaPrompt: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/voice",
|
|
||||||
component: Voice,
|
|
||||||
meta: {
|
|
||||||
showPwaPrompt: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/pointShader",
|
|
||||||
component: PointShader,
|
|
||||||
meta: {
|
|
||||||
showPwaPrompt: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
// 路由守卫控制 PWA 提示
|
|
||||||
router.beforeEach((to, from, next) => {
|
|
||||||
if (to.meta.showPwaPrompt) {
|
|
||||||
enablePwaPrompt();
|
|
||||||
} else {
|
|
||||||
disablePwaPrompt();
|
|
||||||
}
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
11
src/types/virtual-pwa-register.d.ts
vendored
11
src/types/virtual-pwa-register.d.ts
vendored
@ -1,11 +0,0 @@
|
|||||||
declare module 'virtual:pwa-register' {
|
|
||||||
export interface RegisterSWOptions {
|
|
||||||
immediate?: boolean
|
|
||||||
onNeedRefresh?: () => void
|
|
||||||
onOfflineReady?: () => void
|
|
||||||
onRegistered?: (registration: ServiceWorkerRegistration | undefined) => void
|
|
||||||
onRegisterError?: (error: any) => void
|
|
||||||
}
|
|
||||||
|
|
||||||
export function registerSW(options?: RegisterSWOptions): (reloadPage?: boolean) => Promise<void>
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
// PWA 安装状态
|
|
||||||
let deferredPrompt: any = null;
|
|
||||||
|
|
||||||
// 控制是否显示安装提示
|
|
||||||
let showInstallPrompt = true;
|
|
||||||
|
|
||||||
// 监听 beforeinstallprompt 事件
|
|
||||||
window.addEventListener('beforeinstallprompt', (e) => {
|
|
||||||
if (!showInstallPrompt) {
|
|
||||||
e.preventDefault();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
deferredPrompt = e;
|
|
||||||
});
|
|
||||||
|
|
||||||
// 检查是否为 PWA 模式
|
|
||||||
export const isPwa = () => {
|
|
||||||
return window.matchMedia('(display-mode: standalone)').matches ||
|
|
||||||
(window.navigator as any).standalone ||
|
|
||||||
document.referrer.includes('android-app://');
|
|
||||||
};
|
|
||||||
|
|
||||||
// 禁用 PWA 安装提示
|
|
||||||
export const disablePwaPrompt = () => {
|
|
||||||
showInstallPrompt = false;
|
|
||||||
if (deferredPrompt) {
|
|
||||||
deferredPrompt = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 启用 PWA 安装提示
|
|
||||||
export const enablePwaPrompt = () => {
|
|
||||||
showInstallPrompt = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 手动触发 PWA 安装提示
|
|
||||||
export const showPwaInstallPrompt = async () => {
|
|
||||||
if (!deferredPrompt) {
|
|
||||||
console.log('No PWA installation prompt available');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
deferredPrompt.prompt();
|
|
||||||
const { outcome } = await deferredPrompt.userChoice;
|
|
||||||
deferredPrompt = null;
|
|
||||||
return outcome;
|
|
||||||
};
|
|
Binary file not shown.
Before Width: | Height: | Size: 5.2 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.1 KiB |
@ -1,43 +1,13 @@
|
|||||||
import { defineConfig } from 'vite'
|
import { defineConfig } from 'vite'
|
||||||
import basicSsl from '@vitejs/plugin-basic-ssl'
|
import basicSsl from '@vitejs/plugin-basic-ssl'
|
||||||
import vue from '@vitejs/plugin-vue'
|
import vue from '@vitejs/plugin-vue'
|
||||||
import { VitePWA } from 'vite-plugin-pwa'
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
build: {
|
build: {
|
||||||
// 开发阶段启用源码映射:https://uniapp.dcloud.net.cn/tutorial/migration-to-vue3.html#需主动开启-sourcemap
|
// 开发阶段启用源码映射:https://uniapp.dcloud.net.cn/tutorial/migration-to-vue3.html#需主动开启-sourcemap
|
||||||
sourcemap: process.env.NODE_ENV === 'development',
|
sourcemap: process.env.NODE_ENV === 'development',
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [vue(), basicSsl()],
|
||||||
vue(),
|
|
||||||
basicSsl(),
|
|
||||||
VitePWA({
|
|
||||||
registerType: 'autoUpdate',
|
|
||||||
manifest: {
|
|
||||||
name: 'P2P Explorer',
|
|
||||||
short_name: 'P2P Explorer',
|
|
||||||
description: 'P2P文件传输与浏览工具',
|
|
||||||
theme_color: '#f5f5f5',//米色
|
|
||||||
background_color: '#f5f5f5',
|
|
||||||
icons: [
|
|
||||||
{
|
|
||||||
src: '/static/icon64.png',
|
|
||||||
sizes: '64x64',
|
|
||||||
type: 'image/png'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: '/static/icon256.png',
|
|
||||||
sizes: '256x256',
|
|
||||||
type: 'image/png'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
workbox: {
|
|
||||||
globPatterns: ['**/*.{js,css,html,ico,png,svg,webp}'],
|
|
||||||
runtimeCaching: []
|
|
||||||
}
|
|
||||||
})
|
|
||||||
],
|
|
||||||
server: {
|
server: {
|
||||||
host: '0.0.0.0',
|
host: '0.0.0.0',
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user