欧美三级国产三级日韩三级_亚洲熟妇丰满大屁股熟妇_欧美亚洲成人一区二区三区_国产精品久久久久久模特

聊聊如何給一個(gè)小程序歷史老項(xiàng)目“減壓” - 新聞資訊 - 云南小程序開(kāi)發(fā)|云南軟件開(kāi)發(fā)|云南網(wǎng)站建設(shè)-昆明葵宇信息科技有限公司

159-8711-8523

云南網(wǎng)建設(shè)/小程序開(kāi)發(fā)/軟件開(kāi)發(fā)

知識(shí)

不管是網(wǎng)站,軟件還是小程序,都要直接或間接能為您產(chǎn)生價(jià)值,我們?cè)谧非笃湟曈X(jué)表現(xiàn)的同時(shí),更側(cè)重于功能的便捷,營(yíng)銷的便利,運(yùn)營(yíng)的高效,讓網(wǎng)站成為營(yíng)銷工具,讓軟件能切實(shí)提升企業(yè)內(nèi)部管理水平和效率。優(yōu)秀的程序?yàn)楹笃谏?jí)提供便捷的支持!

您當(dāng)前位置>首頁(yè) » 新聞資訊 » 小程序相關(guān) >

聊聊如何給一個(gè)小程序歷史老項(xiàng)目“減壓”

發(fā)表時(shí)間:2021-2-28

發(fā)布人:葵宇科技

瀏覽次數(shù):60

前言

在日常的工作中,由于業(yè)務(wù)或者工作安排的需要,有時(shí)候需要我們參與到一些曾經(jīng)沒(méi)有接觸過(guò)卻 歷史悠久 的項(xiàng)目當(dāng)中,如果這個(gè)項(xiàng)目創(chuàng)建初期,創(chuàng)建者有很好的 前瞻性,并且嚴(yán)格遵循 code preview 等項(xiàng)目開(kāi)發(fā)工作流,那代碼看上去就會(huì)像是同一個(gè)人寫(xiě)出來(lái)一樣,十分規(guī)范;否則,將會(huì)逐漸淪為一個(gè) 茅坑代碼集合。

接下來(lái)我想分享一下近期對(duì)公司的一個(gè)小程序項(xiàng)目做的一些優(yōu)化工作,會(huì)分別從以下幾個(gè)方面進(jìn)行闡述:

  1. 項(xiàng)目現(xiàn)狀
  2. 項(xiàng)目拆解
  3. 搭建工具平臺(tái)
  4. 項(xiàng)目地址

項(xiàng)目現(xiàn)狀

1. 子模塊分包不完全,存在子包內(nèi)文件相互引用的情況

2. 個(gè)別沒(méi)有用到的圖片等靜態(tài)資源文件沒(méi)有及時(shí)刪除,導(dǎo)致包體積過(guò)大,無(wú)法生成預(yù)覽碼

3. 測(cè)試同學(xué)反饋小程序測(cè)試流程過(guò)于繁瑣,復(fù)雜,加大測(cè)試工作量和小程序的出錯(cuò)率

項(xiàng)目拆解

因此,需要針對(duì)以上提到的三個(gè)問(wèn)題對(duì)這個(gè)項(xiàng)目進(jìn)行初步的基于項(xiàng)目目錄結(jié)構(gòu)層面上的優(yōu)化(不涉及到項(xiàng)目里面的業(yè)務(wù)代碼,組件等冗余代碼的優(yōu)化)

其實(shí)也很容易理解,當(dāng)你剛接手一個(gè)項(xiàng)目的時(shí)候,想必是先對(duì)這個(gè)項(xiàng)目的目錄結(jié)構(gòu)有一個(gè)總體初步的認(rèn)識(shí)。

一、 “子模塊分包不完全,存在子包內(nèi)文件相互引用的情況”

1. 分析

如果是微信小程序項(xiàng)目,我們可以通過(guò)以下兩種方法去快速了解一個(gè)項(xiàng)目的模塊分包情況:

  • 打開(kāi)根目錄下的 app.json 文件,找到 subPackages 字段,這就是當(dāng)前項(xiàng)目的所有子模塊數(shù)組集合;(缺點(diǎn):人工肉眼查找,不智能)
// app.json
{
  "pages": [],
  "subPackages": [
    {
      "root": "A",
      "pages": [
        "pages/A-a",
        "pages/A-b",
        ....
      ]
    },
    {
      "root": "B",
      "pages": [
        "pages/B-a",
        "pages/B-b",
        ....
      ]
    }
  ]
}
復(fù)制代碼
  • 通過(guò)微信提供的 cli 命令行工具,查看當(dāng)前的分包情況;(優(yōu)點(diǎn):不僅智能,還能查看每個(gè)子模塊壓縮后的包大?。?/li>
cli preview --project f://workspace/rainbow-mp/xinyu
復(fù)制代碼

效果如下:

通過(guò)cli工具分析出來(lái)的結(jié)果,我們可以很明顯看出當(dāng)前項(xiàng)目總共分了哪幾個(gè)子模塊,以及這些子模塊經(jīng)過(guò)微信壓縮工具(實(shí)則微信開(kāi)發(fā)者工具編譯)之后的大小,由此得出的當(dāng)前項(xiàng)目存在的問(wèn)題有如下幾點(diǎn):

  • 主包(main)體積已經(jīng)超過(guò)了微信規(guī)定的 2MB最大值,無(wú)法生成預(yù)覽碼用于移動(dòng)端測(cè)試(問(wèn)題很嚴(yán)重)

  • 子包分包不合理,將子包的子目錄作為分包的入口(如:/daojia/pages, /deptstore/pages, /index/pages/userMaterial, /shopping/pages),而不是將子包根目錄本身作為拆包的入口,導(dǎo)致其余目錄下的文件統(tǒng)一打包到了主包中,造成主包體積變大;

2. 細(xì)分拆包

換句話說(shuō),如果我們把子包的分包不合理的問(wèn)題給解決了,主包(main)的體積過(guò)大的問(wèn)題自然而然也就解決了。

定位到問(wèn)題就相當(dāng)于解決了一半。

接下來(lái)就是想辦法把子包根目錄更改為模塊打包的入口,這時(shí)候有人會(huì)說(shuō)了,把 app.json文件下的subPackages模塊數(shù)組字段的每個(gè)模塊的root的值都改成子模塊的根目錄不就完事了嗎?

沒(méi)毛病,做法就是這樣

但是,在修改之前得保證拆出來(lái)子包根目錄下的其余子目錄下的文件并沒(méi)有被別的模塊引用,否則就會(huì)出現(xiàn)文件引用錯(cuò)誤的bug。

因此,大致有以下兩種做法可以參考一下,我采用的是第一種:

  1. 對(duì)當(dāng)前拆解子包外的其余模塊(包括主包main) 進(jìn)行全文件掃描,通過(guò)正則的方式過(guò)濾出 require引用到的文件路徑,進(jìn)而分析是否有子包下的文件被別的模塊引用;

  2. 復(fù)寫(xiě) require 方法(因?yàn)槲覀冺?xiàng)目中文件引入的方式是require方式);

這里簡(jiǎn)單說(shuō)明一下我不采用第二種方法的原因:

  • require方法沒(méi)有掛載在global全局下(因?yàn)榻酉聛?lái)我需要寫(xiě)腳本在node環(huán)境下運(yùn)行),因此需要重寫(xiě)一個(gè)如myRequire的自定義函數(shù),然后掛載到global對(duì)象下,接著全局匹配所有文件的require字符替換為myRequire;

  • require是動(dòng)態(tài)引入,也就是說(shuō),可以在js文件的任意處進(jìn)行引入,寫(xiě)在了小程序的業(yè)務(wù)代碼中,因?yàn)榻酉聛?lái)的腳本文件是運(yùn)行在微信開(kāi)發(fā)者工具以外的環(huán)境,缺失了微信小程序需要的模塊包,會(huì)導(dǎo)致編寫(xiě)的腳本分析文件報(bào)錯(cuò);

3. 編寫(xiě)腳本

接下來(lái)就正式步入編碼階段了,其實(shí)思路比較簡(jiǎn)單,我大致從以下幾點(diǎn)進(jìn)行這次腳本文件的編寫(xiě):

1. 獲取當(dāng)前項(xiàng)目的所有一級(jí)目錄:除去當(dāng)前需要拆解的子包以外的所有一級(jí)目錄都需要進(jìn)行全局文件掃描

 * 獲取當(dāng)前路徑下的第一層目錄
 * @param {*} path 項(xiàng)目路徑
 * @param {*} targetDir 子包的目錄名
 */
const getOwnDirectorys = async(path, targetDir) => {
  const dir = await fs.promises.opendir(path)

  const result = []
  for await (const dirent of dir) {
    const isDir = await isDirectory(`${path}/${dirent.name}`)
    // 也就是說(shuō),除去子包以外的目錄都需要進(jìn)行全局文件掃描
    if (isDir && dirent.name !== targetDir) {
      result.push(`${path}/${dirent.name}`)
    }
  }
  return result
}
復(fù)制代碼

2.過(guò)濾出每個(gè)一級(jí)目錄下所有js和json文件

讀取到目錄了,那接下來(lái)自然就是遍歷這些一級(jí)目錄,然后獲取到這些目錄下的所有資源文件,那為什么只是過(guò)濾其中的jsjson文件出來(lái)呢?

經(jīng)過(guò)一段時(shí)間的接觸之后,我發(fā)現(xiàn):

  • 子包的組件存在被別的模塊包引用的情況,而小程序的組件引入主要是通過(guò)json文件的usingComponents字段;

  • 子包的js文件也存在被別的模塊包引用的情況,多數(shù)發(fā)生在一些工具函數(shù),接口調(diào)用文件上;

因此,為了減少掃描文件的數(shù)量和提高效率,先針對(duì)項(xiàng)目中每個(gè)模塊的jsjson文件進(jìn)行掃描匹配。

const filterJsAndJsonFiles = async (dirItem, filterDirs) => {
  const subDir = await fs.promises.opendir(dirItem)
  const jsFiles = []
  const jsonFiles = []
  for await (const dirent of subDir) {
    // 不需要分析的目錄直接跳過(guò)
    if (!filterDirs.includes(dirent.name)) continue

    const currentFiles = getAllFiles(`${PROJECT_NAME}${dirItem}/${dirent.name}`)
    // 過(guò)濾若干不同類型的文件數(shù)組
    currentFiles.forEach(fileItem => {
      const extname = path.extname(fileItem)
      if (extname === '.json') {
        jsonFiles.push(fileItem)
      }
      if (extname === '.js') {
        jsFiles.push(fileItem)
      }
    })
  }
  return {
    jsFiles,
    jsonFiles,
  }
}
復(fù)制代碼

3. 文件查找 & 匹配

到這里,我們已經(jīng)拿到了每個(gè)模塊對(duì)應(yīng)下的所有js,json文件,接下來(lái)就需要針對(duì)這些文件進(jìn)行分析了,大致思路分為以下兩點(diǎn):

  • json文件分析:讀取文件內(nèi)容,將json字符串轉(zhuǎn)為json對(duì)象格式,過(guò)濾出usingComponents字段,查找匹配出拆解子包的組件;
{
  "usingComponents": {
    "a": "./A/a",
    "b": "../B/b",
    "c": "../C/c"
  }
}
復(fù)制代碼
  • js文件分析:讀取文件內(nèi)容,通過(guò)正則表達(dá)式過(guò)濾出require引入的文件字符數(shù)組,從中查找匹配出拆解子包內(nèi)的文件引用;
const a = require('../../a.js')
const b = require('./b.js')
....
復(fù)制代碼

腳本編寫(xiě):

json文件組件引入分析:

/**
 * 統(tǒng)計(jì)json文件引入到的組件數(shù)組
 * @param {*} jsonFile 
 */
const listComponents = (jsonFile) => {
  if (!jsonFile) return

  const jsonDataStr = fs.readFileSync(jsonFile)
  const jsonData = http://www.wxapp-union.com/JSON.parse(jsonDataStr)
  const componentList = []

  if (jsonData) {
    const { usingComponents } = jsonData

    for (let key in usingComponents) {
      componentList.push({
        name: key, 
        path: usingComponents[key],
        filePath: jsonFile,
      })
    }
  }
  return componentList
}
復(fù)制代碼

js文件require引入分析:

const lineReg = /require\s*\([\'\"][\w\W]*[\'\"]\)/g 
// 子模塊初始化
moduleResultMap[dirKey] = { 
  componentImport: [],
  fileImport: {},
}
jsFiles.forEach(filePath => {
  const fileContent = fs.readFileSync(filePath, 'utf8')
  // 為了避免無(wú)用查找,只針對(duì)前30行文本進(jìn)行內(nèi)容分析
  const lines = fileContent.split(/\r?\n/).splice(0, 30)
  // 初始化子包目錄文件名
  moduleResultMap[dirKey]['fileImport'][filePath] = 
    lines.reduce((acc, current) => {
      const matchArr = current.match(lineReg)
      return matchArr && matchArr.length > 0 && matchArr[0].indexOf('/daojia/') > -1 ? 
      [...acc, matchArr[0]] : acc}
    , [])
})
復(fù)制代碼

4. 效果展示

最后,我是將分析出來(lái)的結(jié)果導(dǎo)出到了csv文件中,以便于為我接下來(lái)的拆包提供一份相對(duì)有保障的可視化的支持:

因?yàn)槲疫@次主要是針對(duì)項(xiàng)目中daojia這個(gè)子模塊進(jìn)行一個(gè)拆包,因此分析的也是針對(duì)項(xiàng)目中其余子模塊對(duì)該模塊文件的一個(gè)引用情況做一個(gè)分析,表格中的每個(gè)字段所代表的意思我也大概說(shuō)明一下:

interface Table {
  module: string //子模塊
  type: string // 分析的文件類型
  name: string // 分析的文件名
  import: string // 引用的組件 || 引用的文件
  filePath: string // 分析的文件路徑
}
復(fù)制代碼

5. 終極展示

我們?cè)倩剡^(guò)頭來(lái)看這幅圖:

當(dāng)我們成功地都將以下幾個(gè)子包根目錄從項(xiàng)目中剝離抽身之后,才會(huì)真的有底氣地說(shuō):app.json文件下的subPackages改下就好了

/daojia/pages -> /daojia
/deptstore/pages -> /deptstore
/index/pages/userMaterial -> /index
/shopping/pages -> /shopping
復(fù)制代碼

再來(lái)看看現(xiàn)在的模塊包分析表:

結(jié)論:經(jīng)過(guò)合理化的分包之后,優(yōu)化后的主包體積比優(yōu)化前整整減少了35%

二、“個(gè)別沒(méi)有用到的圖片等靜態(tài)資源文件沒(méi)有及時(shí)刪除,導(dǎo)致包體積過(guò)大,無(wú)法生成預(yù)覽碼”

1. 分析

在上一節(jié)里,我的做法概括起來(lái):拆解子包,合理化模塊打包

由于各種原因,一是在當(dāng)前項(xiàng)目里面存在了過(guò)多的活動(dòng)圖片,重復(fù)的icon等等,但是當(dāng)活動(dòng)下架之后,這些圖片并沒(méi)有得到及時(shí)移除;二是組件引用混亂,相同組件的代碼會(huì)同時(shí)出現(xiàn)在各個(gè)子模塊里面;

這些無(wú)疑都是導(dǎo)致 項(xiàng)目體積過(guò)大 和造成 項(xiàng)目難以維護(hù) 的主要原因;

所以,在這一節(jié)里,也可以概括一句話:剔除無(wú)用資源,減少項(xiàng)目文件

2. 思路

總體來(lái)說(shuō),我也是通過(guò)寫(xiě)腳本來(lái)分析這些資源文件,思路如下:

  • 無(wú)用圖片資源查找

① 根據(jù)不同模塊配置信息,依次讀取當(dāng)前模塊圖片目錄下的所有圖片文件,過(guò)濾出圖片文件名,存儲(chǔ)在一個(gè)數(shù)組內(nèi);

② 然后全掃描這個(gè)項(xiàng)目?jī)?nèi)的所有文件,通過(guò)fs模塊讀取到文件的字符串內(nèi)容,遍歷圖片數(shù)組,根據(jù)字符串匹配indexOf,如果存在,則標(biāo)記圖片的引用路徑;文件全掃描之后,如果找不到,則在路徑一欄標(biāo)記為“沒(méi)有用到”;

③ 又或者匹配到的圖片,則從數(shù)組內(nèi)剔除出去,當(dāng)掃描完所有的文件之后,剩下的就是沒(méi)有引用到的圖片文件了;(以上方法很蠢,但是勝在簡(jiǎn)單粗暴,希望有更好方法的朋友可以給我留言,不勝感激。)

  • 組件引用分析

① 根據(jù)不同模塊的配置信息,依次讀取當(dāng)前模塊內(nèi)pagescomponents目錄下的json文件(組件引入的入口),實(shí)則一個(gè)JSON字符串的轉(zhuǎn)成JSON對(duì)象;JSON.parse(jsonstring)

{
  "usingComponents": {
    "a": "./A/a",
    "b": "../B/b",
    "c": "../C/c"
  }
}
復(fù)制代碼

② 然后獲取其相同文件名的js文件(頁(yè)面或者組件的主體文件),通過(guò)fs模塊讀取文件內(nèi)容,注意,這時(shí)候是得將這些富文本字符串轉(zhuǎn)為DOM節(jié)點(diǎn)樹(shù)結(jié)構(gòu)對(duì)象,然后遍歷節(jié)點(diǎn)對(duì)象,去匹配解析出對(duì)應(yīng)的json組件引入入口文件下的json對(duì)象,然后分析出引用到的組件,實(shí)際就是節(jié)點(diǎn)標(biāo)簽名的匹配過(guò)程。

3. 腳本編寫(xiě)

這里就把一些核心代碼貼出來(lái)就好,大家看看就好,不做過(guò)多闡述了

  • 無(wú)用圖片資源查找腳本
  // 需要分析的圖片目錄地址
  const imgDirPath = path.resolve(__dirname + '/../..' + imagesEntry);
  const imgFiles = getAllFiles(imgDirPath)

  if (imgFiles.length === 0) return

  // 只保留圖片的文件名數(shù)組
  const allImageFiles = imgFiles.map(imgItem => path.basename(imgItem))

  // 查找所有的wxml, js文件
  const allWxmlFiles = targetEntrys.reduce((acc, targetEntry) => {
    const targetDirPath = path.resolve(__dirname + '/../..' + targetEntry)
    const targetAllFiles = getAllFiles(targetDirPath, true)
    const allWxmlFiles = targetAllFiles.filter(filePath => {
      const extname = path.extname(filePath)
      return ['.wxml', '.js'].indexOf(extname) > -1
    })
    return [...acc, ...allWxmlFiles]
  }, [])

  // 遍歷圖片集數(shù)組,查找文件是否有引入
  const result = allImageFiles.reduce((acc, imgName) => {
    const rowItems = allWxmlFiles.reduce((childAcc, filePath) => {
      const fileStr = fs.readFileSync(filePath, 'utf8')
      return fileStr.indexOf(imgName) === -1 ? childAcc : [...childAcc, {
        image: imgName,
        existPath: filePath,
      }]
    }, [])

    // 如果查找完畢數(shù)組為空,則說(shuō)明沒(méi)有引入到該圖片
    return rowItems.length === 0 ? [...acc, {
      image: imgName,
      existPath: '沒(méi)有用到'
    }] : [...acc, ...rowItems]
  }, [])

  // 導(dǎo)出csv文件
  const csv = new ObjectsToCsv(result)
  const exportPath = `${__dirname}${'/../..'}${BASE_EXPORT_IMG}/${imageReportFile}`
  await csv.toDisk(exportPath)
復(fù)制代碼
  • 組件引用分析腳本
  // 解析入口目錄
  const entryDir = path.resolve(__dirname + '/../..' + entry)
  const allFiles = getAllFiles(entryDir)

  if (allFiles.length === 0) return

  const filterFiles = getFilterFiles(allFiles, ['wxml', 'json'])

  // 組裝導(dǎo)出對(duì)象數(shù)組數(shù)據(jù)
  const pageWithComponents = filterFiles.reduce((acc, { jsonFile }) => {
    const current = path.basename(jsonFile, '.json')
    const currentDir = path.dirname(jsonFile)
    const components = listComponents(jsonFile) || []

    if (components.length == 0) {
      return [...acc, { 
        page: current, 
        directory: currentDir,
      }]
    } else {
      // 輸入wxml地址,轉(zhuǎn)化為json標(biāo)簽對(duì)象
      const fileJsonData = http://www.wxapp-union.com/getFileJsonData(currentDir + `/${current}.wxml`)
      const childs = components.reduce((childAcc, { name, path: compPath }) => {
        let used
        if (fileJsonData) {
          used = isWxmlImportComponent(fileJsonData, name)
          used = used ? 'true' : 'false'
        } else {
          used = '解析出錯(cuò)'
        }
        return [...childAcc, {
          page: current,
          directory: path.resolve(currentDir),
          component: name,
          componentPath: compPath,
          used,
        }]
      }, [])
      return [...acc, ...childs]
    }
  }, [])

  // 導(dǎo)出csv文件
  const csv = new ObjectsToCsv(pageWithComponents)
  const exportPath = `${__dirname}/../..${BASE_EXPORT_COMPONENT}/${exportFileName}`
  await csv.toDisk(exportPath)
復(fù)制代碼

結(jié)論:剔除沒(méi)有引入的圖片資源,減少項(xiàng)目體積;分析頁(yè)面的組件引入,為項(xiàng)目的組件庫(kù)的搭建提供數(shù)據(jù)支持。

三、“測(cè)試同學(xué)反饋小程序測(cè)試流程過(guò)于繁瑣,復(fù)雜,加大測(cè)試工作量和小程序的出錯(cuò)率”

1. 分析

小程序測(cè)試步驟如下:

  1. 開(kāi)發(fā)同學(xué)在功能提測(cè)階段,需提供功能分支名給到測(cè)試同學(xué),比如說(shuō):feature/monthcard
  2. 測(cè)試同學(xué)需要切換功能分支,并且拉取最新代碼,執(zhí)行
  • git checkout feature/montcard
  • git pull origin feature/monthcard
  1. 打開(kāi) 小程序開(kāi)發(fā)者工具,更改配置文件環(huán)境參數(shù),如:config.js,比如說(shuō)修改成 env = test/dev/pre/pro 等等,切換到對(duì)應(yīng)的接口環(huán)境進(jìn)行測(cè)試
  2. 如只需要本地測(cè)試,直接在工具上面測(cè)試即可,如需要移動(dòng)端測(cè)試,則需要點(diǎn)擊 編譯執(zhí)行 生成小程序預(yù)覽碼,手機(jī)掃碼測(cè)試
  3. 后期開(kāi)發(fā)同學(xué)推了代碼,需要同步測(cè)試同學(xué)定期去更新代碼,執(zhí)行:
  • git pull origin 分支名

上面就是我司的關(guān)于小程序提測(cè)時(shí)的做法,相信這也是一部分公司的關(guān)于小程序的測(cè)試流程,又或者一部分公司的做法如下:

  • 開(kāi)發(fā)同學(xué)在本地生成測(cè)試預(yù)覽碼,然后將預(yù)覽碼截圖發(fā)給測(cè)試同學(xué)進(jìn)行測(cè)試(測(cè)試預(yù)覽碼有時(shí)效限制,需要開(kāi)發(fā)每隔一段時(shí)間去重新生成一個(gè)新的預(yù)覽碼);

  • 開(kāi)發(fā)同學(xué)編寫(xiě)工具,將整個(gè)小程序代碼包壓縮放在內(nèi)網(wǎng)的一個(gè)網(wǎng)頁(yè)下,每次由測(cè)試下載到本地,解壓,然后用開(kāi)發(fā)者工具打開(kāi)測(cè)試(一定程度自動(dòng)化了測(cè)試流程和簡(jiǎn)化了測(cè)試同學(xué)的流程,但是依然很麻煩);

結(jié)論:總得來(lái)說(shuō),開(kāi)發(fā)和測(cè)試同學(xué)都沒(méi)有成功從上面的開(kāi)發(fā)工作流中解耦出來(lái)。

2. 解決方案

基于上述的一些問(wèn)題,我發(fā)現(xiàn)這一系列的測(cè)試步驟可以通過(guò)微信官方提供的ci命令行工具,是完全可以抽象出來(lái),做成一個(gè)可以簡(jiǎn)化測(cè)試工作流的工具平臺(tái),聽(tīng)著是不是很棒?

下面就是我的一些調(diào)研發(fā)現(xiàn):

miniprogram-ci 是從微信開(kāi)發(fā)者工具中抽離的關(guān)于小程序/小游戲項(xiàng)目代碼的編譯模塊。 開(kāi)發(fā)者可不打開(kāi)小程序開(kāi)發(fā)者工具,獨(dú)立使用 miniprogram-ci 進(jìn)行小程序代碼的上傳、預(yù)覽等操作。

搭建工具平臺(tái)

  • 前端(js)
  1. React 搭建前端骨架(借用facebook提供 create-react-app 腳手架即可)
  2. Bootstrap 作為前端界面布局的ui框架庫(kù)
  • 后端(nodejs)
  1. 采用 Express web應(yīng)用開(kāi)發(fā)框架搭建即可
  2. 安裝 miniprogram-ci 包(構(gòu)建預(yù)覽碼,提交發(fā)版等)
  3. 安裝 html2json, objects-to-csv 包(用于項(xiàng)目靜態(tài)資源使用分析等)

ps: 這里就不對(duì)里面的技術(shù)細(xì)節(jié)做過(guò)多闡述了,具體可以查看文末的項(xiàng)目地址,我已經(jīng)開(kāi)源出來(lái)了。

效果展示:


相關(guān)案例查看更多