Skip to content

手动安装

说明

新项目必须使用脚手架 @ifanrx/scaffolder 创建,其中已经默认包含了下述配置,无需从头开始。

以下内容仅针对需要在现有项目中接入相关工具,或需要了解并修改项目配置等细节的情况。

小程序

安装

bash
pnpm install @ifanrx/uni-mp

配置 .npmrc

默认项目通过 pnpm 的 workspace 进行组织,项目根目录 .npmrc 必须包含以下配置:

yaml
save-prefix=~
enable-pre-post-scripts=true

注册插件

@ifanrx/uni-mp 依赖 pinia 和 vue-query,请务必安装好依赖。

js
import {createSSRApp} from 'vue'
import {VueQueryPlugin, vueQueryPluginOptions} from '@ifanrx/uni-mp'
import {createPinia} from 'pinia'

import App from './App.vue'

export function createApp() {
  const app = createSSRApp(App)
  const pinia = createPinia()

  app.use(pinia)
  app.use(VueQueryPlugin, vueQueryPluginOptions)

  return {
    app,
  }
}

注册全局组件

使用 uni-app 的 easycom 将 @ifanrx/uni-mp 和 uni-ui 组件全局注册,在 manifest.json 中添加如下配置:

json
"easycom": {
  "autoscan": true,
  "custom": {
    // 注意:缺一不可
    "^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue",
    "^mp-(.*)": "@ifanrx/uni-mp/components/mp-$1/mp-$1.vue",
  }
},

使用方式

vue
<script setup>
// 所有模块均可从 @ifanrx/uni-mp 中具名导入
import {message, router, device} from '@ifanrx/uni-mp'
</script>

<template>
  <!-- 全局注册过的组件无需引入,直接在页面中使用 uni-ui 和 uni-mp 的组件 -->
  <mp-nav-bar title="首页" />
</template>

统一 Vite 开发构建流程

此为基础,所有 uni-app 项目必须采用统一的开发构建流程

许多项目的开发构建流程以及 Vite 配置都大同小异,因此我们引入了 defineViteConfig 方法。

这个方法旨在提供一个标准化和简化的方式来处理 Vite 配置。

defineViteConfig 的优势

  • 内置默认配置defineViteConfig 包含了一套预设的配置,这些配置适用于多数项目。
  • 自定义与合并:它允许你根据项目的具体需求添加或修改配置,这些自定义配置将与默认配置合并。
  • 易于维护:使用 defineViteConfig 可以减少重复代码,使项目配置更加清晰、易于维护。

标准开发构建流程

首先 defineViteConfig 依赖于统一的 npm script,需要在项目中写入:

json
{
  "scripts": {
    "dev": "uni -p mp-weixin -- --BAAS_DEV", // 开发模式,知晓云测试环境
    "dev:prod": "uni -p mp-weixin", // 开发模式,知晓云 QA 服务器
    "dev:qa": "uni -p mp-weixin -- --BAAS_QA", // 开发模式,知晓云生产环境
    "build": "uni build -p mp-weixin" // 构建模式,知晓云生产环境,用于发版
  }
}

DANGER

请不要使用 dev:prod 命令进行发版。若通过此命令构建的版本发布,会在小程序首页出现警告弹窗。

声明 Vite 配置

应使用 defineViteConfig 方法进行 Vite 配置,你只需要将项目特定的配置作为参数传入。该方法会自动将传入的配置与默认配置合并,生成最终的 Vite 配置。

js
import defineViteConfig from '@ifanrx/uni-mp/define-vite-config'

export default defineViteConfig(() => {
  // 项目特定的配置
  return {
    plugins: [bar()],
    resolve: {
      alias: {
        '@bar': 'bar',
      },
    },
  }
})

默认配置内容

以下是 defineViteConfig 方法中已包含的默认配置:

Click me to view the code
js
/* eslint-disable import/no-extraneous-dependencies */
import fs from 'node:fs'
import path from 'node:path'

import deepmerge from 'deepmerge'
import minimist from 'minimist'
import copy from 'rollup-plugin-copy'
import uni from '@dcloudio/vite-plugin-uni'
import {input} from '@inquirer/prompts'
import {isBool, isNum, isStr} from 'licia'
import usePluginImport from '@ifanrx/vite-plugin-importer'
import {nodeResolve} from '@rollup/plugin-node-resolve'
import {viteCommonjs} from '@originjs/vite-plugin-commonjs'

import projectConfigJSONPlugin from './vite-plugin-project-config-json.js'

/**
 * @typedef {object} ExtendConfigFnEnv
 * @prop {boolean} DEV 是否 dev 开发模式
 * @prop {boolean} BAAS_DEV 是否知晓云测试环境
 * @prop {boolean} BAAS_QA 是否知晓云 QA 服务器
 * @prop {string} BAAS_QA_SERVICE 知晓云 QA 服务器多环境
 * @prop {object} defaultViteConfig 默认配置
 * @prop {object} commandArgs
 */

/**
 * @typedef {ExtendConfigFnEnv & import('vite').ConfigEnv} ConfigFnEnv
 */

/**
 * @typedef {(env:ConfigFnEnv)=>ReturnType<import('vite').UserConfigFn>} ConfigFn
 */

/**
 * 定义 Vite 配置,该配置已经集成了项目的通用配置项。
 * 该函数允许传入一个配置函数,用于生成特定的配置对象。
 * 传入的配置将与内置的通用配置合并,以形成最终的配置对象。
 * @param {ConfigFn} configFn
 * @return
 */
export default function defineViteConfig(configFn = () => ({})) {
  /**
   * @param {import('vite').ConfigEnv} options
   */
  return async ({mode, ...rest}) => {
    const argv = process.argv.slice(process.argv.findIndex(item => item === '--') + 1)
    const args = minimist(argv)

    const DEV = mode === 'development' // 是否 dev 开发模式

    let {BAAS_DEV, BAAS_QA, s: qaService, ...restArgs} = args // 是否知晓云测试环境,是否知晓云 QA 服务器

    qaService = isStr(qaService) || isNum(qaService) ? String(qaService) : ''

    const isInvalidQAService = !qaService || isBool(qaService) || !qaService.trim()

    if (BAAS_QA && isInvalidQAService) {
      const answer = await Promise.race([
        input({message: 'QA 服务器环境(选填)'}),
        // eslint-disable-next-line no-promise-executor-return
        new Promise(resolve => setTimeout(() => resolve(''), 5000)),
      ])

      qaService = answer.trim()
    }

    const defaultAlias = {
      '@': path.resolve(process.cwd(), 'src'),
    }

    if (fs.existsSync(path.resolve(process.cwd(), '../shared-constants'))) {
      defaultAlias['shared-constants'] = path.resolve(process.cwd(), '../shared-constants')
    }

    const defaultViteConfig = {
      plugins: [
        uni.default(),
        uniPolyfill(),
        nodeResolve(),
        usePluginImport({
          licia: {
            // eslint-disable-next-line no-template-curly-in-string
            transform: 'licia/${member}',
            preventFullImport: true,
          },
        }),
        // 开发模式关闭微信开发者工具的 es6 转 es5,提高编译速度
        DEV &&
          projectConfigJSONPlugin(config => {
            const {setting} = config
            setting.es6 = false
            return config
          }),
        // pnpm build 时,将构建产物从 dist/build 复制到 dist/dev 目录
        // 不切换微信开发者工具的项目也能进行发版
        !DEV && {
          ...copy({
            targets: [{src: 'dist/build/mp-weixin/', dest: 'dist/dev/'}],
            hook: 'closeBundle',
          }),
          enforce: 'post',
        },
        process.env.UNI_PLATFORM === 'h5' ? viteCommonjs() : null,
      ].filter(Boolean),
      // 必须是 es2017~2019 之间,超出范围会产生编译问题
      build: {
        target: 'es2017',
      },
      define: {
        VITE_DEV: DEV,
        VITE_BAAS_DEV: BAAS_DEV,
        VITE_BAAS_QA: BAAS_QA,
        VITE_BAAS_QA_SERVICE: JSON.stringify(qaService),
      },
      resolve: {
        alias: defaultAlias,
      },
    }

    const customViteConfig = configFn({
      DEV,
      BAAS_DEV,
      BAAS_QA,
      BAAS_QA_SERVICE: JSON.stringify(qaService),
      mode,
      defaultViteConfig,
      commandArgs: restArgs,
      ...rest,
    })

    return deepmerge(defaultViteConfig, customViteConfig, {
      arrayMerge: (target, source) => target.concat(source),
    })
  }
}

/**
 * @see https://github.com/dcloudio/uni-app/issues/4604
 * @see https://github.com/vuejs/pinia/issues/2210#issuecomment-1868843572
 */
export function uniPolyfill() {
  return {
    name: 'vite-plugin-uni-polyfill',
    transform(code, id) {
      if (id.endsWith('@dcloudio/uni-mp-vue/dist/vue.runtime.esm.js')) {
        // eslint-disable-next-line no-param-reassign
        code += `
          // polyfill for @vueuse/core
          export const render = () => {}
          export const TransitionGroup = {}
        `

        if (!code.includes('hasInjectionContext')) {
          // eslint-disable-next-line no-param-reassign
          code += `
          // polyfill for @pinia, @tanstack/vue-query
          export function hasInjectionContext() {return !!getCurrentInstance()}
          `
        }
      }

      if (
        id.endsWith('@dcloudio/uni-h5-vue/dist/vue.runtime.esm.js') &&
        !code.includes('hasInjectionContext')
      ) {
        // eslint-disable-next-line no-param-reassign
        code += `
          // polyfill for @pinia, @tanstack/vue-query
          export function hasInjectionContext() {return !!getCurrentInstance()}
          `
      }

      return code
    },
  }
}

区分环境

我们的 Vite 配置中定义了三个关键的全局变量,你可以使用它们来区分不同的运行环境。

为提供代码提示,我们建议将这三个变量集成到项目的常量定义中,方便在代码中显式引用:

js
export const DEV = VITE_DEV // 是否 dev 开发模式
export const BAAS_DEV = VITE_BAAS_DEV // 是否知晓云测试环境
export const BAAS_QA = VITE_BAAS_QA // 是否知晓云 QA 服务器

自定义参数

如果需要自定义启动命令参数,比如:可以通过 --SCREENSHOTS 参数表示当前环境用于截图,就可以通过 commandArgs 获取自定义参数:

json
"scripts": {
  "dev:screenshots": "uni -p mp-weixin -- --BAAS_QA --SCREENSHOTS",
}
js
import defineViteConfig from '@ifanrx/uni-mp/define-vite-config'

export default defineViteConfig(({commandArgs}) => {
  const {SCREENSHOTS} = commandArgs

  return {
    define: {
      VITE_SCREENSHOTS: SCREENSHOTS,
    },
  }
})

提升微信开发者工具编译速度

WARNING

已集成到 defineViteConfig,无需重复引入

微信开发者工具默认开启「将 JS 编译至 ES5」,这会导致修改代码后重新编译时间较长。然而,关闭此选项可能会导致线上部分机型运行异常。因此,解决方案是仅在本地开发时关闭该选项。

Click me to view the code

如下所示,可以使用 Vite 插件,在编译代码后关闭该选项。

js
import projectConfigJSONPlugin from '@ifanrx/uni-mp/vite-plugin-project-config-json'

export default defineConfig(({mode}) => {
  const DEV = mode === 'development'

  return {
    // ...
    plugins: [
      DEV &&
        projectConfigJSONPlugin(config => {
          const {setting} = config
          setting.es6 = false
          return config
        }),
    ].filter(Boolean),
    // ...
  }
})

优化 console 响应式变量输出

推荐启用此功能

此功能必须启用微信开发者工具的 「Enable custom formatters」。

启用方式:打开微信开发者工具调试器右上角小齿轮 「Settings」,在 「Preferences」中找到 「Console」分组,勾选 「Enable custom formatters」。

uni-mp 内部会自动挂载 initDevToolsCustomFormatter,可对 ref/reactive 响应式变量的 console 输出进行格式优化。

initDevToolsCustomFormatter

运营后台

详见《运营后台 —— 快速开始》

云函数

详见《云函数 —— 快速开始》