First Mini Program
This guide will walk you through creating your first mini program from scratch, covering the basic setup, development process, and deployment.
📋 Table of Contents
- Project Setup
- Basic Structure
- Creating Pages
- Adding Components
- Styling Your App
- Adding Functionality
- Testing Your App
- Deployment
🚀 Project Setup
Prerequisites
Before starting, ensure you have:
- WeChat Developer Tools installed
- A registered mini program account
- Basic knowledge of HTML, CSS, and JavaScript
Creating a New Project
Open WeChat Developer Tools
Click "Create Project"
Fill in project information:
- Project Name:
my-first-miniprogram
- Directory: Choose an empty folder
- AppID: Use your registered AppID or test AppID
- Development Mode: Mini Program
- Backend Service: Don't use cloud service (for now)
- Project Name:
Select template: JavaScript Basic Template
Click "Create"
🏗️ Basic Structure
After creating the project, you'll see this file structure:
my-first-miniprogram/
├── pages/
│ ├── index/
│ │ ├── index.js # Page logic
│ │ ├── index.json # Page configuration
│ │ ├── index.wxml # Page structure
│ │ └── index.wxss # Page styles
│ └── logs/
│ ├── logs.js
│ ├── logs.json
│ ├── logs.wxml
│ └── logs.wxss
├── utils/
│ └── util.js # Utility functions
├── app.js # App logic
├── app.json # App configuration
├── app.wxss # Global styles
├── project.config.json # Project configuration
└── sitemap.json # SEO configuration
Understanding Key Files
app.json - App Configuration
{
"pages": [
"pages/index/index",
"pages/logs/logs"
],
"window": {
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#fff",
"navigationBarTitleText": "My First Mini Program",
"navigationBarTextStyle": "black"
},
"style": "v2",
"sitemapLocation": "sitemap.json"
}
app.js - App Logic
App({
onLaunch() {
// App launched
console.log('App launched')
// Get system info
const systemInfo = wx.getSystemInfoSync()
console.log('System info:', systemInfo)
// Store global data
this.globalData.systemInfo = systemInfo
},
onShow() {
// App shown (foreground)
console.log('App shown')
},
onHide() {
// App hidden (background)
console.log('App hidden')
},
globalData: {
userInfo: null,
systemInfo: null
}
})
📄 Creating Pages
Let's create a new page for our app - a profile page.
Step 1: Add Page to app.json
{
"pages": [
"pages/index/index",
"pages/profile/profile",
"pages/logs/logs"
]
}
Step 2: Create Page Files
Create the pages/profile/
directory and add these files:
profile.js
Page({
data: {
userInfo: null,
hasUserInfo: false,
canIUseGetUserProfile: false
},
onLoad() {
// Check if getUserProfile is available
if (wx.getUserProfile) {
this.setData({
canIUseGetUserProfile: true
})
}
},
getUserProfile() {
wx.getUserProfile({
desc: 'Used to display user information',
success: (res) => {
console.log('User info:', res.userInfo)
this.setData({
userInfo: res.userInfo,
hasUserInfo: true
})
// Store in global data
getApp().globalData.userInfo = res.userInfo
},
fail: (error) => {
console.error('Get user profile failed:', error)
wx.showToast({
title: 'Authorization failed',
icon: 'error'
})
}
})
},
onShareAppMessage() {
return {
title: 'Check out my profile!',
path: '/pages/profile/profile'
}
}
})
profile.wxml
<view class="container">
<view class="profile-header">
<text class="title">My Profile</text>
</view>
<view class="profile-content">
<block wx:if="{{hasUserInfo}}">
<view class="user-info">
<image class="avatar" src="{{userInfo.avatarUrl}}" mode="cover"></image>
<view class="user-details">
<text class="nickname">{{userInfo.nickName}}</text>
<text class="location">{{userInfo.country}} {{userInfo.province}} {{userInfo.city}}</text>
</view>
</view>
<view class="stats">
<view class="stat-item">
<text class="stat-number">0</text>
<text class="stat-label">Posts</text>
</view>
<view class="stat-item">
<text class="stat-number">0</text>
<text class="stat-label">Followers</text>
</view>
<view class="stat-item">
<text class="stat-number">0</text>
<text class="stat-label">Following</text>
</view>
</view>
</block>
<block wx:else>
<view class="no-user-info">
<text class="hint">Please authorize to view profile</text>
<button
wx:if="{{canIUseGetUserProfile}}"
bindtap="getUserProfile"
class="auth-button"
type="primary"
>
Get User Info
</button>
</view>
</block>
</view>
</view>
profile.wxss
.container {
padding: 20rpx;
background-color: #f5f5f5;
min-height: 100vh;
}
.profile-header {
text-align: center;
margin-bottom: 40rpx;
}
.title {
font-size: 36rpx;
font-weight: bold;
color: #333;
}
.profile-content {
background-color: white;
border-radius: 20rpx;
padding: 40rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
}
.user-info {
display: flex;
align-items: center;
margin-bottom: 40rpx;
}
.avatar {
width: 120rpx;
height: 120rpx;
border-radius: 60rpx;
margin-right: 30rpx;
}
.user-details {
flex: 1;
}
.nickname {
display: block;
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 10rpx;
}
.location {
font-size: 24rpx;
color: #666;
}
.stats {
display: flex;
justify-content: space-around;
border-top: 1rpx solid #eee;
padding-top: 30rpx;
}
.stat-item {
text-align: center;
}
.stat-number {
display: block;
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 10rpx;
}
.stat-label {
font-size: 24rpx;
color: #666;
}
.no-user-info {
text-align: center;
padding: 60rpx 0;
}
.hint {
display: block;
font-size: 28rpx;
color: #666;
margin-bottom: 40rpx;
}
.auth-button {
width: 300rpx;
height: 80rpx;
line-height: 80rpx;
border-radius: 40rpx;
}
profile.json
{
"navigationBarTitleText": "Profile",
"enablePullDownRefresh": false
}
🧩 Adding Components
Let's create a reusable component for displaying statistics.
Step 1: Create Component Directory
Create components/stat-card/
directory.
stat-card.js
Component({
properties: {
title: {
type: String,
value: ''
},
value: {
type: Number,
value: 0
},
icon: {
type: String,
value: ''
}
},
methods: {
onTap() {
this.triggerEvent('tap', {
title: this.properties.title,
value: this.properties.value
})
}
}
})
stat-card.wxml
<view class="stat-card" bindtap="onTap">
<view class="icon">{{icon}}</view>
<view class="content">
<text class="value">{{value}}</text>
<text class="title">{{title}}</text>
</view>
</view>
stat-card.wxss
.stat-card {
background-color: white;
border-radius: 16rpx;
padding: 30rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
display: flex;
align-items: center;
margin-bottom: 20rpx;
}
.icon {
font-size: 48rpx;
margin-right: 20rpx;
}
.content {
flex: 1;
}
.value {
display: block;
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 8rpx;
}
.title {
font-size: 24rpx;
color: #666;
}
stat-card.json
{
"component": true
}
Step 2: Use Component in Page
Update profile.json
:
{
"navigationBarTitleText": "Profile",
"enablePullDownRefresh": false,
"usingComponents": {
"stat-card": "/components/stat-card/stat-card"
}
}
Update profile.wxml
:
<view class="stats-section">
<stat-card
title="Posts"
value="{{userStats.posts}}"
icon="📝"
bind:tap="onStatTap"
/>
<stat-card
title="Followers"
value="{{userStats.followers}}"
icon="👥"
bind:tap="onStatTap"
/>
<stat-card
title="Following"
value="{{userStats.following}}"
icon="➕"
bind:tap="onStatTap"
/>
</view>
🎨 Styling Your App
Global Styles (app.wxss)
/* Global styles */
page {
background-color: #f5f5f5;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
.container {
padding: 20rpx;
}
/* Button styles */
.btn-primary {
background-color: #007aff;
color: white;
border-radius: 8rpx;
border: none;
padding: 20rpx 40rpx;
font-size: 28rpx;
}
.btn-secondary {
background-color: #f0f0f0;
color: #333;
border-radius: 8rpx;
border: none;
padding: 20rpx 40rpx;
font-size: 28rpx;
}
/* Card styles */
.card {
background-color: white;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
}
/* Text styles */
.text-primary {
color: #007aff;
}
.text-secondary {
color: #666;
}
.text-large {
font-size: 32rpx;
}
.text-small {
font-size: 24rpx;
}
Theme Configuration
Create a theme system:
utils/theme.js
const themes = {
light: {
backgroundColor: '#ffffff',
textColor: '#333333',
primaryColor: '#007aff',
secondaryColor: '#f0f0f0'
},
dark: {
backgroundColor: '#1a1a1a',
textColor: '#ffffff',
primaryColor: '#0a84ff',
secondaryColor: '#2a2a2a'
}
}
class ThemeManager {
constructor() {
this.currentTheme = wx.getStorageSync('theme') || 'light'
}
getTheme() {
return themes[this.currentTheme]
}
setTheme(themeName) {
if (themes[themeName]) {
this.currentTheme = themeName
wx.setStorageSync('theme', themeName)
// Notify all pages to update
const pages = getCurrentPages()
pages.forEach(page => {
if (page.onThemeChange) {
page.onThemeChange(this.getTheme())
}
})
}
}
toggleTheme() {
const newTheme = this.currentTheme === 'light' ? 'dark' : 'light'
this.setTheme(newTheme)
}
}
module.exports = new ThemeManager()
⚡ Adding Functionality
Data Management
Create a simple data service:
utils/api.js
const BASE_URL = 'https://api.example.com'
class ApiService {
static request(options) {
return new Promise((resolve, reject) => {
wx.request({
url: BASE_URL + options.url,
method: options.method || 'GET',
data: options.data,
header: {
'Content-Type': 'application/json',
...options.header
},
success: (res) => {
if (res.statusCode === 200) {
resolve(res.data)
} else {
reject(new Error(`HTTP ${res.statusCode}`))
}
},
fail: reject
})
})
}
static get(url, data) {
return this.request({ url, method: 'GET', data })
}
static post(url, data) {
return this.request({ url, method: 'POST', data })
}
static put(url, data) {
return this.request({ url, method: 'PUT', data })
}
static delete(url) {
return this.request({ url, method: 'DELETE' })
}
}
module.exports = ApiService
Local Storage Helper
utils/storage.js
class StorageHelper {
static set(key, value) {
try {
wx.setStorageSync(key, value)
return true
} catch (error) {
console.error('Storage set error:', error)
return false
}
}
static get(key, defaultValue = null) {
try {
const value = wx.getStorageSync(key)
return value !== '' ? value : defaultValue
} catch (error) {
console.error('Storage get error:', error)
return defaultValue
}
}
static remove(key) {
try {
wx.removeStorageSync(key)
return true
} catch (error) {
console.error('Storage remove error:', error)
return false
}
}
static clear() {
try {
wx.clearStorageSync()
return true
} catch (error) {
console.error('Storage clear error:', error)
return false
}
}
}
module.exports = StorageHelper
🧪 Testing Your App
Manual Testing Checklist
- [ ] App launches successfully
- [ ] All pages load correctly
- [ ] Navigation works between pages
- [ ] User interactions respond properly
- [ ] Data displays correctly
- [ ] Error handling works
- [ ] Performance is acceptable
- [ ] Works on different screen sizes
Debugging Tips
- Use Console Logs: Add
console.log()
statements to track data flow - Check Network Tab: Monitor API requests in developer tools
- Use Debugger: Set breakpoints in the developer tools
- Test on Real Device: Use the preview feature to test on actual devices
Common Issues and Solutions
Issue: Page not found
// Solution: Check app.json pages array
{
"pages": [
"pages/index/index",
"pages/profile/profile" // Make sure path is correct
]
}
Issue: Component not displaying
// Solution: Check component registration in page.json
{
"usingComponents": {
"my-component": "/components/my-component/my-component"
}
}
Issue: Data not updating
// Solution: Use setData to update page data
this.setData({
userInfo: newUserInfo
})
🚀 Deployment
Step 1: Build for Production
- Click "Upload" in WeChat Developer Tools
- Enter version number (e.g., "1.0.0")
- Add version description
- Click "Upload"
Step 2: Submit for Review
- Go to WeChat Mini Program Admin Panel
- Navigate to "Development" → "Version Management"
- Find your uploaded version
- Click "Submit for Review"
- Fill in review information
- Submit
Step 3: Release
After review approval:
- Go to "Version Management"
- Click "Release" on the approved version
- Your mini program is now live!
🎯 Next Steps
Congratulations! You've created your first mini program. Here are some ideas for enhancement:
- Add More Pages: Create additional pages like settings, about, etc.
- Implement Navigation: Add tab bar or custom navigation
- Add Animations: Use CSS animations or mini program animation APIs
- Integrate APIs: Connect to real backend services
- Add Sharing: Implement share functionality
- Optimize Performance: Implement lazy loading and caching
- Add Testing: Write unit tests for your components
- Implement State Management: Use a state management solution for complex apps
Useful Resources
You've successfully created your first mini program! This foundation will help you build more complex and feature-rich applications. Keep experimenting and learning to master mini program development.