UniApp Template
The UniApp template provides a cross-platform development solution for H5, Mini Programs, and App, perfect for building applications that run on multiple platforms with a single codebase.
Technical Stack
- UniApp - Cross-platform framework
- Vue 3 - Progressive JavaScript framework
- TypeScript - Type-safe development
- Vite - Fast build tool and dev server
- Tailwind CSS - Utility-first CSS framework
- Vue i18n - Internationalization
Quick Start
1. Create Project
bash
# Initialize project
vup init my-uniapp-project
cd my-uniapp-project
# Add UniApp template
vup add my-uniapp
2. Install Dependencies
bash
# Install dependencies
pnpm install
3. Start Development
bash
# Start development server
cd apps/my-uniapp
pnpm dev
The application will be available at http://localhost:9301
.
Supported Platforms
- H5 - Web applications
- WeChat Mini Program - WeChat mini program
- Alipay Mini Program - Alipay mini program
- Baidu Mini Program - Baidu mini program
- ByteDance Mini Program - ByteDance mini program
- QQ Mini Program - QQ mini program
- App - iOS and Android applications
Project Structure
apps/my-uniapp/
├── src/
│ ├── assets/ # Static assets
│ │ └── images/ # Image files
│ ├── locales/ # Internationalization
│ │ ├── index.ts # i18n configuration
│ │ ├── en-US.ts # English translations
│ │ └── zh-CN.ts # Chinese translations
│ ├── pages/ # Pages
│ │ └── index/ # Home page
│ │ ├── index.vue # Home page component
│ │ └── index.scss # Home page styles
│ ├── static/ # Static resources
│ │ └── logo.png # Logo image
│ ├── App.vue # Root component
│ ├── main.ts # Application entry point
│ ├── manifest.json # App configuration
│ ├── pages.json # Pages configuration
│ └── uni.scss # Global styles
├── package.json # Dependencies and scripts
├── tsconfig.json # TypeScript configuration
├── tailwind.config.js # Tailwind CSS configuration
└── vite.config.ts # Vite configuration
Core Features
Cross-platform Development
vue
<!-- pages/index/index.vue -->
<template>
<view class="container">
<image class="logo" src="/static/logo.png" mode="aspectFit"></image>
<text class="title">{{ title }}</text>
<text class="description">{{ description }}</text>
<button class="btn" @click="handleClick">Click Me</button>
</view>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const title = ref('UniApp Application');
const description = ref('Cross-platform development with UniApp');
const handleClick = () => {
uni.showToast({
title: 'Button clicked!',
icon: 'success',
});
};
</script>
<style lang="scss" scoped>
.container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
padding: 20px;
}
.logo {
width: 200px;
height: 200px;
margin-bottom: 20px;
}
.title {
font-size: 24px;
font-weight: bold;
margin-bottom: 10px;
color: #333;
}
.description {
font-size: 16px;
color: #666;
margin-bottom: 30px;
text-align: center;
}
.btn {
background-color: #007aff;
color: white;
border: none;
border-radius: 8px;
padding: 12px 24px;
font-size: 16px;
}
</style>
Platform-specific Code
vue
<template>
<view class="platform-specific">
<!-- #ifdef H5 -->
<view class="h5-only">This content only shows on H5</view>
<!-- #endif -->
<!-- #ifdef MP-WEIXIN -->
<view class="wechat-only"
>This content only shows on WeChat Mini Program</view
>
<!-- #endif -->
<!-- #ifdef APP-PLUS -->
<view class="app-only">This content only shows on App</view>
<!-- #endif -->
</view>
</template>
<script setup lang="ts">
// Platform-specific logic
// #ifdef H5
const isH5 = true;
// #endif
// #ifdef MP-WEIXIN
const isWeChat = true;
// #endif
// #ifdef APP-PLUS
const isApp = true;
// #endif
</script>
Internationalization
typescript
// locales/en-US.ts
export default {
common: {
title: 'UniApp Application',
description: 'Cross-platform development with UniApp',
button: 'Click Me',
},
navigation: {
home: 'Home',
about: 'About',
},
};
typescript
// locales/zh-CN.ts
export default {
common: {
title: 'UniApp 应用',
description: '使用 UniApp 进行跨平台开发',
button: '点击我',
},
navigation: {
home: '首页',
about: '关于',
},
};
Tailwind CSS Styling
vue
<template>
<view class="min-h-screen bg-gray-100">
<view class="container mx-auto px-4 py-8">
<view class="bg-white rounded-lg shadow-md p-6">
<text class="text-2xl font-bold text-gray-900 mb-4">
{{ $t('common.title') }}
</text>
<text class="text-gray-600 mb-6">
{{ $t('common.description') }}
</text>
<button
class="bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded"
@click="handleClick"
>
{{ $t('common.button') }}
</button>
</view>
</view>
</view>
</template>
Development Tools
Vite Configuration
typescript
// vite.config.ts
import { defineConfig } from 'vite';
import uni from '@dcloudio/vite-plugin-uni';
import { resolve } from 'path';
export default defineConfig({
plugins: [uni()],
resolve: {
alias: {
'@': resolve(__dirname, './src'),
'@shared': resolve(__dirname, '../../_shared'),
},
},
css: {
postcss: resolve(__dirname, '../../postcss.config.js'),
},
server: {
host: '0.0.0.0',
port: 9301,
open: false,
},
});
TypeScript Configuration
json
// tsconfig.json
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./dist",
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@shared/*": ["../../_shared/*"]
}
},
"include": ["src/**/*", "src/**/*.vue", "src/*.vue"]
}
Tailwind CSS Configuration
javascript
// tailwind.config.js
module.exports = {
content: ['./src/**/*.{vue,js,ts,jsx,tsx}', './src/**/*.html'],
theme: {
extend: {},
},
plugins: [],
corePlugins: {
preflight: false, // Disable preflight for UniApp
},
};
Available Scripts
json
{
"scripts": {
"dev": "uni dev",
"build": "uni build",
"build:h5": "uni build --platform h5",
"build:mp-weixin": "uni build --platform mp-weixin",
"build:app": "uni build --platform app",
"lint": "eslint src/ --ext .vue,.ts,.js",
"lint:fix": "eslint src/ --ext .vue,.ts,.js --fix",
"format": "prettier --write \"src/**/*.{js,ts,vue,json,css,scss}\"",
"format:check": "prettier --check \"src/**/*.{js,ts,vue,json,css,scss}\""
}
}
Platform-specific Configuration
H5 Configuration
json
// manifest.json
{
"h5": {
"title": "UniApp Application",
"template": "index.html",
"router": {
"mode": "hash",
"base": "./"
},
"optimization": {
"treeShaking": {
"enable": true
}
}
}
}
Mini Program Configuration
json
// manifest.json
{
"mp-weixin": {
"appid": "your-appid",
"setting": {
"urlCheck": false,
"es6": true,
"enhance": true,
"postcss": true,
"minified": true
},
"usingComponents": true
}
}
App Configuration
json
// manifest.json
{
"app-plus": {
"usingComponents": true,
"nvueStyleCompiler": "uni-app",
"compilerVersion": 3,
"splashscreen": {
"alwaysShowBeforeRender": true,
"waiting": true,
"autoclose": true,
"delay": 0
},
"modules": {},
"distribute": {
"android": {
"permissions": [
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\" />",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\" />",
"<uses-permission android:name=\"android.permission.VIBRATE\" />",
"<uses-permission android:name=\"android.permission.READ_LOGS\" />",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\" />",
"<uses-feature android:name=\"android.hardware.camera.autofocus\" />",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />",
"<uses-permission android:name=\"android.permission.CAMERA\" />",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\" />",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\" />",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\" />",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\" />",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\" />",
"<uses-feature android:name=\"android.hardware.camera\" />",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\" />"
]
},
"ios": {},
"sdkConfigs": {}
}
}
}
Best Practices
Component Development
vue
<template>
<view class="custom-component">
<slot name="header"></slot>
<view class="content">
<slot></slot>
</view>
<slot name="footer"></slot>
</view>
</template>
<script setup lang="ts">
interface Props {
title?: string;
visible?: boolean;
}
const props = withDefaults(defineProps<Props>(), {
title: '',
visible: true,
});
const emit = defineEmits<{
click: [event: Event];
change: [value: string];
}>();
const handleClick = (event: Event) => {
emit('click', event);
};
</script>
<style lang="scss" scoped>
.custom-component {
@apply p-4 bg-white rounded-lg shadow-md;
}
</style>
API Calls
typescript
// utils/api.ts
export interface ApiResponse<T = any> {
code: number;
message: string;
data: T;
}
export class ApiService {
private baseURL: string;
constructor(baseURL: string) {
this.baseURL = baseURL;
}
async request<T = any>(
url: string,
options: RequestOptions = {}
): Promise<ApiResponse<T>> {
try {
const response = await uni.request({
url: `${this.baseURL}${url}`,
method: options.method || 'GET',
data: options.data,
header: {
'Content-Type': 'application/json',
...options.header,
},
});
return response.data as ApiResponse<T>;
} catch (error) {
throw new Error(`API request failed: ${error.message}`);
}
}
}
interface RequestOptions {
method?: 'GET' | 'POST' | 'PUT' | 'DELETE';
data?: any;
header?: Record<string, string>;
}
Build and Deployment
H5 Build
bash
# Build for H5
pnpm build:h5
# The built files will be in the dist/build/h5 directory
Mini Program Build
bash
# Build for WeChat Mini Program
pnpm build:mp-weixin
# The built files will be in the dist/build/mp-weixin directory
App Build
bash
# Build for App
pnpm build:app
# The built files will be in the dist/build/app directory