Skip to content

Development Environment ​

Setting up an efficient development environment is crucial for productive mini program development. This guide covers essential tools, configurations, and best practices.

Development Tools ​

WeChat Developer Tools ​

Installation and Setup

  1. Download and Install

    • Download from WeChat Developer Tools
    • Install the appropriate version for your operating system
    • Sign in with your WeChat account
  2. Basic Configuration

javascript
// project.config.json - Project configuration
{
  "description": "Mini Program Project",
  "packOptions": {
    "ignore": [
      {
        "type": "file",
        "value": ".eslintrc.js"
      },
      {
        "type": "folder",
        "value": "node_modules"
      }
    ]
  },
  "setting": {
    "urlCheck": false,
    "es6": true,
    "enhance": true,
    "postcss": true,
    "preloadBackgroundData": false,
    "minified": true,
    "newFeature": false,
    "coverView": true,
    "nodeModules": false,
    "autoAudits": false,
    "showShadowRootInWxmlPanel": true,
    "scopeDataCheck": false,
    "uglifyFileName": false,
    "checkInvalidKey": true,
    "checkSiteMap": true,
    "uploadWithSourceMap": true,
    "compileHotReLoad": false,
    "lazyloadPlaceholderEnable": false,
    "useMultiFrameRuntime": true,
    "useApiHook": true,
    "useApiHostProcess": true,
    "babelSetting": {
      "ignore": [],
      "disablePlugins": [],
      "outputPath": ""
    },
    "enableEngineNative": false,
    "useIsolateContext": false,
    "userConfirmedBundleSwitch": false,
    "packNpmManually": false,
    "packNpmRelationList": [],
    "minifyWXSS": true,
    "disableUseStrict": false,
    "minifyWXML": true,
    "showES6CompileOption": false,
    "useCompilerPlugins": false
  },
  "compileType": "miniprogram",
  "libVersion": "2.19.4",
  "appid": "your-app-id",
  "projectname": "mini-program",
  "debugOptions": {
    "hidedInDevtools": []
  },
  "scripts": {},
  "staticServerOptions": {
    "baseURL": "",
    "servePath": ""
  },
  "isGameTourist": false,
  "condition": {
    "search": {
      "list": []
    },
    "conversation": {
      "list": []
    },
    "game": {
      "list": []
    },
    "plugin": {
      "list": []
    },
    "gamePlugin": {
      "list": []
    },
    "miniprogram": {
      "list": []
    }
  }
}
  1. Useful Features
    • Simulator: Test on different device sizes and orientations
    • Debugger: Debug JavaScript, inspect elements, monitor network
    • Performance: Analyze performance metrics and memory usage
    • Audits: Automated code quality and performance checks

Code Editor Setup ​

VS Code Configuration

  1. Essential Extensions
json
// .vscode/extensions.json
{
  "recommendations": [
    "ms-vscode.vscode-wxml",
    "qiu8310.minapp-vscode",
    "bradlc.vscode-tailwindcss",
    "esbenp.prettier-vscode",
    "dbaeumer.vscode-eslint",
    "formulahendry.auto-rename-tag",
    "christian-kohler.path-intellisense",
    "ms-vscode.vscode-json"
  ]
}
  1. Workspace Settings
json
// .vscode/settings.json
{
  "files.associations": {
    "*.wxml": "html",
    "*.wxss": "css",
    "*.wxs": "javascript"
  },
  "emmet.includeLanguages": {
    "wxml": "html"
  },
  "minapp-vscode.disableAutoConfig": true,
  "minapp-vscode.wxmlFormatter": "prettier",
  "minapp-vscode.prettier": {
    "parser": "html"
  },
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  },
  "files.exclude": {
    "**/node_modules": true,
    "**/miniprogram_npm": true
  }
}
  1. Code Snippets
json
// .vscode/snippets.json
{
  "Page Template": {
    "prefix": "page",
    "body": [
      "Page({",
      "  data: {",
      "    $1",
      "  },",
      "",
      "  onLoad(options) {",
      "    $2",
      "  },",
      "",
      "  onReady() {",
      "    $3",
      "  },",
      "",
      "  onShow() {",
      "    $4",
      "  },",
      "",
      "  onHide() {",
      "    $5",
      "  },",
      "",
      "  onUnload() {",
      "    $6",
      "  }",
      "})"
    ],
    "description": "Create a new page"
  },
  "Component Template": {
    "prefix": "component",
    "body": [
      "Component({",
      "  properties: {",
      "    $1",
      "  },",
      "",
      "  data: {",
      "    $2",
      "  },",
      "",
      "  methods: {",
      "    $3",
      "  },",
      "",
      "  lifetimes: {",
      "    attached() {",
      "      $4",
      "    },",
      "",
      "    detached() {",
      "      $5",
      "    }",
      "  }",
      "})"
    ],
    "description": "Create a new component"
  }
}

Build Tools and Workflow ​

Package Management ​

npm Configuration

json
// package.json
{
  "name": "mini-program",
  "version": "1.0.0",
  "description": "Mini Program Project",
  "main": "app.js",
  "scripts": {
    "dev": "npm run build:npm",
    "build": "npm run build:npm && npm run build:prod",
    "build:npm": "npm install --production=false",
    "build:prod": "node scripts/build.js",
    "lint": "eslint . --ext .js",
    "lint:fix": "eslint . --ext .js --fix",
    "format": "prettier --write \"**/*.{js,json,wxml,wxss}\"",
    "test": "jest",
    "test:watch": "jest --watch",
    "test:coverage": "jest --coverage"
  },
  "dependencies": {
    "@vant/weapp": "^1.10.4",
    "dayjs": "^1.11.7",
    "lodash": "^4.17.21"
  },
  "devDependencies": {
    "@babel/core": "^7.21.0",
    "@babel/preset-env": "^7.20.2",
    "eslint": "^8.36.0",
    "eslint-config-standard": "^17.0.0",
    "eslint-plugin-import": "^2.27.5",
    "eslint-plugin-node": "^11.1.0",
    "eslint-plugin-promise": "^6.1.1",
    "jest": "^29.5.0",
    "prettier": "^2.8.4"
  }
}

Code Quality Tools ​

ESLint Configuration

javascript
// .eslintrc.js
module.exports = {
  env: {
    browser: true,
    es6: true,
    node: true
  },
  extends: [
    'standard'
  ],
  globals: {
    wx: 'readonly',
    App: 'readonly',
    Page: 'readonly',
    Component: 'readonly',
    Behavior: 'readonly',
    getApp: 'readonly',
    getCurrentPages: 'readonly'
  },
  parserOptions: {
    ecmaVersion: 2020,
    sourceType: 'module'
  },
  rules: {
    'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    'space-before-function-paren': ['error', 'never'],
    'comma-dangle': ['error', 'never']
  }
}

Prettier Configuration

json
// .prettierrc
{
  "semi": false,
  "singleQuote": true,
  "trailingComma": "none",
  "tabWidth": 2,
  "useTabs": false,
  "printWidth": 100,
  "bracketSpacing": true,
  "arrowParens": "avoid",
  "endOfLine": "lf"
}

Git Hooks with Husky

json
// package.json (additional scripts)
{
  "scripts": {
    "prepare": "husky install"
  },
  "devDependencies": {
    "husky": "^8.0.3",
    "lint-staged": "^13.2.0"
  },
  "lint-staged": {
    "*.js": [
      "eslint --fix",
      "prettier --write"
    ],
    "*.{json,wxml,wxss}": [
      "prettier --write"
    ]
  }
}
bash
# .husky/pre-commit
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npx lint-staged

Build Scripts ​

Custom Build Script

javascript
// scripts/build.js
const fs = require('fs')
const path = require('path')
const { execSync } = require('child_process')

class BuildTool {
  constructor() {
    this.rootDir = process.cwd()
    this.distDir = path.join(this.rootDir, 'dist')
  }

  // Clean dist directory
  clean() {
    console.log('🧹 Cleaning dist directory...')
    if (fs.existsSync(this.distDir)) {
      fs.rmSync(this.distDir, { recursive: true })
    }
    fs.mkdirSync(this.distDir, { recursive: true })
  }

  // Copy source files
  copyFiles() {
    console.log('📁 Copying source files...')
    const filesToCopy = [
      'app.js',
      'app.json',
      'app.wxss',
      'sitemap.json',
      'pages',
      'components',
      'utils',
      'images',
      'miniprogram_npm'
    ]

    filesToCopy.forEach(file => {
      const srcPath = path.join(this.rootDir, file)
      const destPath = path.join(this.distDir, file)

      if (fs.existsSync(srcPath)) {
        this.copyRecursive(srcPath, destPath)
      }
    })
  }

  copyRecursive(src, dest) {
    const stat = fs.statSync(src)
    
    if (stat.isDirectory()) {
      fs.mkdirSync(dest, { recursive: true })
      const files = fs.readdirSync(src)
      
      files.forEach(file => {
        this.copyRecursive(
          path.join(src, file),
          path.join(dest, file)
        )
      })
    } else {
      fs.copyFileSync(src, dest)
    }
  }

  // Minify files
  minify() {
    console.log('🗜️  Minifying files...')
    // Add minification logic here
    // You can use tools like UglifyJS, CleanCSS, etc.
  }

  // Generate build info
  generateBuildInfo() {
    console.log('📝 Generating build info...')
    const buildInfo = {
      version: require('../package.json').version,
      buildTime: new Date().toISOString(),
      gitCommit: this.getGitCommit(),
      environment: process.env.NODE_ENV || 'production'
    }

    fs.writeFileSync(
      path.join(this.distDir, 'build-info.json'),
      JSON.stringify(buildInfo, null, 2)
    )
  }

  getGitCommit() {
    try {
      return execSync('git rev-parse HEAD').toString().trim()
    } catch (error) {
      return 'unknown'
    }
  }

  // Main build process
  build() {
    console.log('🚀 Starting build process...')
    
    this.clean()
    this.copyFiles()
    this.minify()
    this.generateBuildInfo()
    
    console.log('✅ Build completed successfully!')
  }
}

// Run build
const builder = new BuildTool()
builder.build()

Environment Configuration ​

Environment Variables ​

javascript
// config/env.js
const environments = {
  development: {
    API_BASE_URL: 'https://dev-api.example.com',
    DEBUG: true,
    LOG_LEVEL: 'debug'
  },
  staging: {
    API_BASE_URL: 'https://staging-api.example.com',
    DEBUG: true,
    LOG_LEVEL: 'info'
  },
  production: {
    API_BASE_URL: 'https://api.example.com',
    DEBUG: false,
    LOG_LEVEL: 'error'
  }
}

const currentEnv = process.env.NODE_ENV || 'development'
const config = environments[currentEnv]

module.exports = config

Usage in Code

javascript
// utils/config.js
const config = require('../config/env')

class Config {
  static get(key) {
    return config[key]
  }

  static getApiUrl(endpoint) {
    return `${config.API_BASE_URL}${endpoint}`
  }

  static isDebug() {
    return config.DEBUG
  }

  static shouldLog(level) {
    const levels = ['debug', 'info', 'warn', 'error']
    const currentLevel = levels.indexOf(config.LOG_LEVEL)
    const messageLevel = levels.indexOf(level)
    
    return messageLevel >= currentLevel
  }
}

module.exports = Config

Multi-Platform Configuration ​

javascript
// utils/platform.js
class PlatformConfig {
  constructor() {
    this.platform = this.detectPlatform()
  }

  detectPlatform() {
    const systemInfo = wx.getSystemInfoSync()
    
    if (systemInfo.platform === 'ios') {
      return 'ios'
    } else if (systemInfo.platform === 'android') {
      return 'android'
    } else {
      return 'unknown'
    }
  }

  getConfig() {
    const baseConfig = {
      appName: 'Mini Program',
      version: '1.0.0'
    }

    const platformConfigs = {
      ios: {
        ...baseConfig,
        statusBarHeight: 44,
        navigationBarHeight: 44
      },
      android: {
        ...baseConfig,
        statusBarHeight: 24,
        navigationBarHeight: 48
      },
      unknown: {
        ...baseConfig,
        statusBarHeight: 24,
        navigationBarHeight: 44
      }
    }

    return platformConfigs[this.platform]
  }

  isPlatform(platform) {
    return this.platform === platform
  }
}

module.exports = new PlatformConfig()

Testing Setup ​

Unit Testing with Jest ​

javascript
// jest.config.js
module.exports = {
  testEnvironment: 'jsdom',
  setupFilesAfterEnv: ['<rootDir>/tests/setup.js'],
  testMatch: [
    '<rootDir>/tests/**/*.test.js',
    '<rootDir>/utils/**/*.test.js'
  ],
  collectCoverageFrom: [
    'utils/**/*.js',
    'pages/**/*.js',
    'components/**/*.js',
    '!**/node_modules/**',
    '!**/miniprogram_npm/**'
  ],
  coverageThreshold: {
    global: {
      branches: 80,
      functions: 80,
      lines: 80,
      statements: 80
    }
  },
  globals: {
    wx: {},
    App: jest.fn(),
    Page: jest.fn(),
    Component: jest.fn(),
    getApp: jest.fn(),
    getCurrentPages: jest.fn()
  }
}

Test Setup

javascript
// tests/setup.js
// Mock WeChat APIs
global.wx = {
  request: jest.fn(),
  showToast: jest.fn(),
  showModal: jest.fn(),
  navigateTo: jest.fn(),
  redirectTo: jest.fn(),
  setStorageSync: jest.fn(),
  getStorageSync: jest.fn(),
  removeStorageSync: jest.fn(),
  getSystemInfoSync: jest.fn(() => ({
    platform: 'ios',
    system: 'iOS 15.0',
    windowWidth: 375,
    windowHeight: 812
  }))
}

// Mock global functions
global.getApp = jest.fn(() => ({
  globalData: {}
}))

global.getCurrentPages = jest.fn(() => [])

Example Test

javascript
// utils/format.test.js
const { formatPrice, formatDate } = require('./format')

describe('Format Utils', () => {
  describe('formatPrice', () => {
    test('should format price correctly', () => {
      expect(formatPrice(1234.56)).toBe('¥1,234.56')
      expect(formatPrice(0)).toBe('¥0.00')
      expect(formatPrice(null)).toBe('¥0.00')
    })
  })

  describe('formatDate', () => {
    test('should format date correctly', () => {
      const date = new Date('2023-03-15T10:30:00Z')
      expect(formatDate(date, 'YYYY-MM-DD')).toBe('2023-03-15')
    })
  })
})

Debugging and Development ​

Debug Configuration ​

javascript
// utils/debug.js
class Debug {
  constructor() {
    this.enabled = wx.getAccountInfoSync().miniProgram.envVersion !== 'release'
  }

  log(...args) {
    if (this.enabled) {
      console.log('[DEBUG]', ...args)
    }
  }

  warn(...args) {
    if (this.enabled) {
      console.warn('[WARN]', ...args)
    }
  }

  error(...args) {
    console.error('[ERROR]', ...args)
  }

  time(label) {
    if (this.enabled) {
      console.time(label)
    }
  }

  timeEnd(label) {
    if (this.enabled) {
      console.timeEnd(label)
    }
  }

  group(label) {
    if (this.enabled) {
      console.group(label)
    }
  }

  groupEnd() {
    if (this.enabled) {
      console.groupEnd()
    }
  }

  table(data) {
    if (this.enabled && console.table) {
      console.table(data)
    }
  }
}

module.exports = new Debug()

Development Utilities ​

javascript
// utils/dev-tools.js
class DevTools {
  static showPageInfo() {
    const pages = getCurrentPages()
    const currentPage = pages[pages.length - 1]
    
    console.group('📄 Page Info')
    console.log('Route:', currentPage.route)
    console.log('Options:', currentPage.options)
    console.log('Data:', currentPage.data)
    console.groupEnd()
  }

  static showSystemInfo() {
    const systemInfo = wx.getSystemInfoSync()
    
    console.group('📱 System Info')
    console.table(systemInfo)
    console.groupEnd()
  }

  static showNetworkInfo() {
    wx.getNetworkType({
      success: (res) => {
        console.group('🌐 Network Info')
        console.log('Network Type:', res.networkType)
        console.log('Is Connected:', res.networkType !== 'none')
        console.groupEnd()
      }
    })
  }

  static measurePerformance(name, fn) {
    return async (...args) => {
      const startTime = Date.now()
      
      try {
        const result = await fn(...args)
        const endTime = Date.now()
        
        console.log(`⏱️ ${name} took ${endTime - startTime}ms`)
        return result
      } catch (error) {
        const endTime = Date.now()
        console.error(`❌ ${name} failed after ${endTime - startTime}ms:`, error)
        throw error
      }
    }
  }
}

module.exports = DevTools

Best Practices ​

Project Structure ​

mini-program/
├── app.js                 # App entry point
├── app.json              # App configuration
├── app.wxss              # Global styles
├── sitemap.json          # Sitemap configuration
├── project.config.json   # Project configuration
├── package.json          # Dependencies
├── pages/                # Pages
│   ├── index/
│   │   ├── index.js
│   │   ├── index.json
│   │   ├── index.wxml
│   │   └── index.wxss
│   └── profile/
├── components/           # Reusable components
│   ├── common/
│   └── business/
├── utils/               # Utility functions
│   ├── api.js
│   ├── config.js
│   ├── format.js
│   └── storage.js
├── images/              # Static images
├── styles/              # Shared styles
├── config/              # Configuration files
├── scripts/             # Build scripts
├── tests/               # Test files
└── docs/                # Documentation

Development Workflow ​

  1. Setup Phase

    • Clone repository
    • Install dependencies: npm install
    • Configure development tools
    • Set up environment variables
  2. Development Phase

    • Start development: npm run dev
    • Use hot reload for rapid development
    • Write tests alongside features
    • Use debugging tools effectively
  3. Quality Assurance

    • Run linting: npm run lint
    • Run tests: npm test
    • Check code coverage
    • Review code before committing
  4. Build and Deploy

    • Build for production: npm run build
    • Test in WeChat Developer Tools
    • Upload to WeChat platform
    • Monitor performance and errors

A well-configured development environment significantly improves productivity and code quality. Invest time in setting up proper tooling and workflows for long-term benefits.

Connecting Multiple Platforms, Empowering Innovation