docs: update build pattern conversion plan with consistent naming and mode handling

- Change build:* naming from hyphen to colon (build:web-dev → build:web:dev)
- Add missing build:web:test and build:web:prod scripts
- Update build:electron:dev to include electron startup (build + start)
- Remove hardcoded --mode electron to allow proper mode override
- Add comprehensive mode override behavior documentation
- Fix mode conflicts between hardcoded and passed --mode arguments

The plan now properly supports:
- Development builds with default --mode development
- Testing builds with explicit --mode test override
- Production builds with explicit --mode production override
- Consistent naming across all platforms (web, capacitor, electron)
This commit is contained in:
Matthew Raymer
2025-07-09 13:13:44 +00:00
parent 95b038c717
commit b35c1d693f
11 changed files with 4209 additions and 0 deletions

View File

@@ -0,0 +1,293 @@
<template>
<div class="lazy-loading-example">
<!-- Loading state with Suspense -->
<Suspense>
<template #default>
<!-- Main content with lazy-loaded components -->
<div class="content">
<h1>Lazy Loading Example</h1>
<!-- Lazy-loaded heavy component -->
<LazyHeavyComponent
v-if="showHeavyComponent"
:data="heavyComponentData"
@data-processed="handleDataProcessed"
/>
<!-- Conditionally loaded components -->
<LazyQRScanner
v-if="showQRScanner"
@qr-detected="handleQRDetected"
/>
<LazyThreeJSViewer
v-if="showThreeJS"
:model-url="threeJSModelUrl"
@model-loaded="handleModelLoaded"
/>
<!-- Route-based lazy loading -->
<router-view v-slot="{ Component }">
<component :is="Component" />
</router-view>
</div>
</template>
<!-- Loading fallback -->
<template #fallback>
<div class="loading-fallback">
<div class="spinner"></div>
<p>Loading components...</p>
</div>
</template>
</Suspense>
<!-- Control buttons -->
<div class="controls">
<button @click="toggleHeavyComponent">
{{ showHeavyComponent ? 'Hide' : 'Show' }} Heavy Component
</button>
<button @click="toggleQRScanner">
{{ showQRScanner ? 'Hide' : 'Show' }} QR Scanner
</button>
<button @click="toggleThreeJS">
{{ showThreeJS ? 'Hide' : 'Show' }} 3D Viewer
</button>
</div>
</div>
</template>
<script lang="ts">
import { Component, Vue, Prop, Watch } from 'vue-facing-decorator';
import { defineAsyncComponent } from 'vue';
/**
* Lazy Loading Example Component
*
* Demonstrates various lazy loading patterns with vue-facing-decorator:
* - defineAsyncComponent for heavy components
* - Conditional loading based on user interaction
* - Suspense for loading states
* - Route-based lazy loading
*
* @author Matthew Raymer
* @version 1.0.0
*/
@Component({
name: 'LazyLoadingExample',
components: {
// Lazy-loaded components with loading and error states
LazyHeavyComponent: defineAsyncComponent({
loader: () => import('./sub-components/HeavyComponent.vue'),
loadingComponent: {
template: '<div class="loading">Loading heavy component...</div>'
},
errorComponent: {
template: '<div class="error">Failed to load heavy component</div>'
},
delay: 200, // Show loading component after 200ms
timeout: 10000 // Timeout after 10 seconds
}),
LazyQRScanner: defineAsyncComponent({
loader: () => import('./sub-components/QRScannerComponent.vue'),
loadingComponent: {
template: '<div class="loading">Initializing QR scanner...</div>'
},
errorComponent: {
template: '<div class="error">QR scanner not available</div>'
}
}),
LazyThreeJSViewer: defineAsyncComponent({
loader: () => import('./sub-components/ThreeJSViewer.vue'),
loadingComponent: {
template: '<div class="loading">Loading 3D viewer...</div>'
},
errorComponent: {
template: '<div class="error">3D viewer failed to load</div>'
}
})
}
})
export default class LazyLoadingExample extends Vue {
// Component state
@Prop({ default: false }) readonly initialLoadHeavy!: boolean;
// Reactive properties
showHeavyComponent = false;
showQRScanner = false;
showThreeJS = false;
// Component data
heavyComponentData = {
items: Array.from({ length: 1000 }, (_, i) => ({ id: i, name: `Item ${i}` })),
filters: { category: 'all', status: 'active' },
sortBy: 'name'
};
threeJSModelUrl = '/models/lupine_plant/scene.gltf';
// Computed properties
get isLoadingAnyComponent(): boolean {
return this.showHeavyComponent || this.showQRScanner || this.showThreeJS;
}
get componentCount(): number {
let count = 0;
if (this.showHeavyComponent) count++;
if (this.showQRScanner) count++;
if (this.showThreeJS) count++;
return count;
}
// Lifecycle hooks
mounted(): void {
console.log('[LazyLoadingExample] Component mounted');
// Initialize based on props
if (this.initialLoadHeavy) {
this.showHeavyComponent = true;
}
// Preload critical components
this.preloadCriticalComponents();
}
// Methods
toggleHeavyComponent(): void {
this.showHeavyComponent = !this.showHeavyComponent;
console.log('[LazyLoadingExample] Heavy component toggled:', this.showHeavyComponent);
}
toggleQRScanner(): void {
this.showQRScanner = !this.showQRScanner;
console.log('[LazyLoadingExample] QR scanner toggled:', this.showQRScanner);
}
toggleThreeJS(): void {
this.showThreeJS = !this.showThreeJS;
console.log('[LazyLoadingExample] ThreeJS viewer toggled:', this.showThreeJS);
}
handleDataProcessed(data: any): void {
console.log('[LazyLoadingExample] Data processed:', data);
// Handle processed data from heavy component
}
handleQRDetected(qrData: string): void {
console.log('[LazyLoadingExample] QR code detected:', qrData);
// Handle QR code data
}
handleModelLoaded(modelInfo: any): void {
console.log('[LazyLoadingExample] 3D model loaded:', modelInfo);
// Handle 3D model loaded event
}
/**
* Preload critical components for better UX
*/
private preloadCriticalComponents(): void {
// Preload components that are likely to be used
if (process.env.NODE_ENV === 'production') {
// In production, preload based on user behavior patterns
this.preloadComponent(() => import('./sub-components/HeavyComponent.vue'));
}
}
/**
* Preload a component without rendering it
*/
private preloadComponent(componentLoader: () => Promise<any>): void {
componentLoader().catch(error => {
console.warn('[LazyLoadingExample] Preload failed:', error);
});
}
// Watchers
@Watch('showHeavyComponent')
onHeavyComponentToggle(newValue: boolean): void {
if (newValue) {
// Component is being shown - could trigger analytics
console.log('[LazyLoadingExample] Heavy component shown');
}
}
@Watch('componentCount')
onComponentCountChange(newCount: number): void {
console.log('[LazyLoadingExample] Active component count:', newCount);
}
}
</script>
<style scoped>
.lazy-loading-example {
padding: 20px;
max-width: 1200px;
margin: 0 auto;
}
.content {
margin-bottom: 20px;
}
.controls {
display: flex;
gap: 10px;
flex-wrap: wrap;
margin-top: 20px;
}
.controls button {
padding: 10px 20px;
border: 1px solid #ccc;
border-radius: 4px;
background: #f8f9fa;
cursor: pointer;
transition: background-color 0.2s;
}
.controls button:hover {
background: #e9ecef;
}
.loading-fallback {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 40px;
text-align: center;
}
.spinner {
width: 40px;
height: 40px;
border: 4px solid #f3f3f3;
border-top: 4px solid #3498db;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 20px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.loading {
padding: 20px;
text-align: center;
color: #666;
}
.error {
padding: 20px;
text-align: center;
color: #dc3545;
background: #f8d7da;
border: 1px solid #f5c6cb;
border-radius: 4px;
}
</style>