uni-app踩坑+小改造

快狗叫車前端團隊發表於2020-02-13

背景

最近團隊內部一直在試點用uni-app去做一些小需求,但主要是先在H5上做試點,之後再按計劃編譯成小程式去釋出。這回分享幾個遇到的小問題和解決方案。

下面說到的問題主要在用uni-app開發H5平臺時才會遇到,非H5平臺可忽略。

跨域的問題

首先,在本地開發時,不同於直接用小程式IDE進行開發,在開發H5平臺時,需要使用瀏覽器進行除錯,而瀏覽器會有跨域的問題。比如直接通過本地IP地址去訪問開發中的頁面,同時這個頁面會調一些現有的介面時,就面臨著跨域的問題。

官方的解決方案

uni-app官方介紹了一些解決跨域問題的方法,比如服務端開啟CORS,給瀏覽器安裝跨域外掛等,詳見uni-app的H5版使用注意事項。但裡面並沒有提到(應該是很久未更新文件導致)的是,如果不想這麼麻煩去解決,還有個更方便的辦法,也就是用webpack-dev-server去代理即可解決。

更方便的解決方案

根據官方文件的描述,devServer配置被要求在manifest.json去配置,並且由於這個配置檔案是json格式的,所以只能對簡單型別進行配置。但對於proxy這項配置來說也是足夠了的。直接如下方式配置即可解決:

// manifest.json
{
    "h5": {
        "devServer": {
            "proxy": {
                "/prefix/api/user/list": {
                    "target": "https://api-remote.xxxx.com",
                    "pathRewrite": {
                        "^/prefix": ""
                    }
                }
            }
        }
    }
}

複製程式碼

另一種解決方案

直接建立一個vue.config.js檔案,並在裡面配置devServer,直接上程式碼

// vue.config.js
module.exports = {
  devServer: {
    proxy: {
      '/prefix/api/user/list': {
        target: 'https://api-remote.xxxx.com',
        pathRewrite: {
          '^/prefix': ''
        }
      }
    },
  }
}
複製程式碼

這種辦法的好處顯而易見,用js而非json去配置會更加的靈活,需要注意的是以上兩種方案不能同時使用,第一種會覆蓋第二種方案。

Mock的問題

這可能也不是什麼大問題,畢竟現在有很多像Easy Mock這樣的線上Mock平臺。但有時我們可能嫌麻煩,不想離開程式碼編輯視窗去註冊,編寫線上Mock資料,更想一切都用程式碼解決,那麼同樣可以用上面的第二種方案來搞定

解決方案

藉助mocker-apimockjs這兩個工具,直接配置devServerbefore選項即可,程式碼如下:

// vue.config.js
const webpackApiMocker = require('mocker-api')

module.exports = {
  devServer: {
    before (app) {
      webpackApiMocker(app, path.resolve('./mock/index.js'))
    }
  }
}

// mock/index.js
const Mock = require('mockjs')

const Random = Mock.Random
const mock = Mock.mock

const proxy = {
  'GET /api/user/list': mock({
    'array|3': [
      {
        id: 1,
        username: 'kenny',
        sex: 'male'
      }
    ]
  }),
  'POST /api/login/account': (req, res) => {
    return res.json({
      status: 'ok',
      data: {
        id: Random.id(),
        userName: Random.cname(),
        city: Random.city()
      }
    })
  }
}

module.exports = proxy
複製程式碼

publicPath的問題

到了測試階段,我們需要將程式碼部署到CDN上提測,不同的環境對應不同的CDN域名,官方通過manifest.json的方式配置publicPath顯然非常的不靈活,我們希望publicPath是動態的,與環境,倉庫,工程名甚至開發分支有關,而且不需要開發人員去關心。

解決方案

要解決這個問題就需要對腳手架做一些小改造了。

  • 首先,我們將publicPath這項配置拿出來單獨放在一個配置檔案中,比如project-config.js,並放在工程根目錄下
const projectName = 'xxx' // 當前工程名,此處自由發揮即可
const isDev = isDev() // 是否為本地開發環境,此處自由發揮即可
const CDN_HOST = process.env.CDN_HOST   // build時指定的CDN域名
const APP_ENV = process.env.APP_ENV // build時指定的自定義環境

module.exports = {
  publicPath: isDev
    ? '/'
    : `//${CDN_HOST}/static/${projectName}/${APP_ENV}/`,
}
複製程式碼
  • 其次,我們fork了一版官方的uni-app原始碼,並對@dcloudio/vue-cli-plugin-uni/index.js做了點改動
// @dcloudio/vue-cli-plugin-uni/index.js#L30
// 獲取本地的project-config配置
module.exports = (api, options) => {
    const projectConfig = require(api.resolve('project-config'))

    Object.assign(options, { 
        outputDir: process.env.UNI_OUTPUT_TMP_DIR || process.env.UNI_OUTPUT_DIR,
        assetsDir
    }, vueConfig, {
        // 重新對publicPath進行覆蓋
        publicPath: process.env.NODE_ENV === 'production' ? projectConfig.publicPath : '/'
    })
}
複製程式碼

這樣會使manifest.json中的配置失效,也就是如果使用HBuilder開發的話會受到點影響。

關注我們

關注公眾號前端論道

相關文章