Taro 2.2 全面插件化,支持拓展和定製個性化功能

来源:https://www.cnblogs.com/o2team/archive/2020/04/30/12807028.html
-Advertisement-
Play Games

自 2.2 開始,Taro 引入了插件化機制,允許開發者通過編寫插件的方式來為 Taro 拓展更多功能或者為自身業務定製個性化功能,歡迎大家進行嘗試,共同討論~ 當前版本 2.2.1 官方插件 Taro 提供了一些官方插件 "@tarojs/plugin mock" ,一個簡易的數據 mock 插件 ...


自 2.2 開始,Taro 引入了插件化機制,允許開發者通過編寫插件的方式來為 Taro 拓展更多功能或者為自身業務定製個性化功能,歡迎大家進行嘗試,共同討論~

當前版本 2.2.1

官方插件

Taro 提供了一些官方插件

如何引入插件

你可以從 npm 或者本地中引入插件,引入方式主要通過 編譯配置中的 pluginspresets,使用如下

plugins

插件在 Taro 中,一般通過編譯配置中的 plugins 欄位進行引入。

plugins 欄位取值為一個數組,配置方式如下:

const config = {
  plugins: [
    // 引入 npm 安裝的插件
    '@tarojs/plugin-mock',
    // 引入 npm 安裝的插件,並傳入插件參數
    ['@tarojs/plugin-mock', {
      mocks: {
        '/api/user/1': {
          name: 'judy',
          desc: 'Mental guy'
        }
      }
    }],
    // 從本地絕對路徑引入插件,同樣如果需要傳入參數也是如上
    '/absulute/path/plugin/filename',
  ]
}

presets

如果你有一系列插件需要配置,而他們通常是組合起來完成特定的事兒,那你可以通過插件集 presets 來進行配置。

配置編譯配置中的 presets 欄位,如下。

const config = {
  presets: [
    // 引入 npm 安裝的插件集
    '@tarojs/preset-sth',
    // 引入 npm 安裝的插件集,並傳入插件參數
    ['@tarojs/plugin-sth', {
      arg0: 'xxx'
    }],
    // 從本地絕對路徑引入插件集,同樣如果需要傳入參數也是如上
    '/absulute/path/preset/filename',
  ]
}

在瞭解完如何引入插件之後,我們來學習一下如何編寫一個插件。

如何編寫一個插件

一個 Taro 的插件都具有固定的代碼結構,通常由一個函數組成,示例如下:

export default (ctx, options) => {
  // plugin 主體
  ctx.onBuildStart(() => {
    console.log('編譯開始!')
  })
  ctx.onBuildFinish(() => {
    console.log('編譯結束!')
  })
}

插件函數可以接受兩個參數:

  • ctx:插件當前的運行環境信息,包含插件相關的 API、當前運行參數、輔助方法等等
  • options:為插件調用時傳入的參數

在插件主體代碼部分可以按照自己的需求編寫相應代碼,通常你可以實現以下功能。

Typings

建議使用 typescript 來編寫插件,這樣你就會獲得很棒的智能提示,使用方式如下:

import { IPluginContext } from '@tarojs/service'
export default (ctx: IPluginContext, pluginOpts) => {
  // 接下來使用 ctx 的時候就能獲得智能提示了
  ctx.onBuildStart(() => {
    console.log('編譯開始!')
  })
}

主要功能

命令行擴展

你可以通過編寫插件來為 Taro 拓展命令行的命令,在之前版本的 Taro 中,命令行的命令是固定的,如果你要進行擴展,那你得直接修改 Taro 源碼,而如今藉助插件功能,你可以任意拓展 Taro 的命令行。

這個功能主要通過 ctx.registerCommand API 來進行實現,例如,增加一個上傳的命令,將編譯後的代碼上傳到伺服器:

export default (ctx) => {
  ctx.registerCommand({
    // 命令名
    name: 'upload',
    // 執行 taro upload --help 時輸出的 options 信息
    optionsMap: {
      '--remote': '伺服器地址'
    },
    // 執行 taro upload --help 時輸出的使用例子的信息
    synopsisList: [
      'taro upload --remote xxx.xxx.xxx.xxx'
    ],
    async fn () {
      const { remote } = ctx.runOpts
      await uploadDist()
    }
  })
}

將這個插件配置到中項目之後,就可以通過 taro upload --remote xxx.xxx.xxx.xxx 命令將編譯後代碼上傳到目標伺服器。

編譯過程擴展

同時你也可以通過插件對代碼編譯過程進行拓展。

正如前面所述,針對編譯過程,有 onBuildStartonBuildFinish 兩個鉤子來分別表示編譯開始,編譯結束,而除此之外也有更多 API 來對編譯過程進行修改,如下:

  • ctx.onBuildStart(() => viod),編譯開始,接收一個回調函數
  • ctx.modifyWebpackChain(args: { chain: any }) => void),編譯中修改 webpack 配置,在這個鉤子中,你可以對 webpackChain 作出想要的調整,等同於配置 webpackChain
  • ctx.modifyBuildAssets(args: { assets: any }) => void),修改編譯後的結果
  • ctx.modifyBuildTempFileContent(args: { tempFiles: any }) => void),修改編譯過程中的中間文件,例如修改 app 或頁面的 config 配置
  • ctx.onBuildFinish(() => viod),編譯結束,接收一個回調函數

編譯平臺拓展

你也可以通過插件功能對編譯平臺進行拓展。

使用 API ctx.registerPlatform,Taro 中內置的平臺支持都是通過這個 API 來進行實現。

註意:這是未完工的功能,需要依賴代碼編譯器 @tarojs/transform-wx 的改造完成

API

通過以上內容,我們已經大致知道 Taro 插件可以實現哪些特性並且可以編寫一個簡單的 Taro 插件了,但是,為了能夠編寫更加複雜且標準的插件,我們需要瞭解 Taro 插件機制中的具體 API 用法。

插件環境變數

ctx.paths

包含當前執行命令的相關路徑,所有的路徑如下(並不是所有命令都會擁有以下所有路徑):

  • ctx.paths.appPath,當前命令執行的目錄,如果是 build 命令則為當前項目路徑
  • ctx.paths.configPath,當前項目配置目錄,如果 init 命令,則沒有此路徑
  • ctx.paths.sourcePath,當前項目源碼路徑
  • ctx.paths.outputPath,當前項目輸出代碼路徑
  • ctx.paths.nodeModulesPath,當前項目所用的 node_modules 路徑

ctx.runOpts

獲取當前執行命令所帶的參數,例如命令 taro upload --remote xxx.xxx.xxx.xxx,則 ctx.runOpts 值為:

{
  _: ['upload'],
  options: {
    remote: 'xxx.xxx.xxx.xxx'
  },
  isHelp: false
}

ctx.helper

為包 @tarojs/helper 的快捷使用方式,包含其所有 API。

ctx.initialConfig

獲取項目配置。

ctx.plugins

獲取當前所有掛載的插件。

插件方法

Taro 的插件架構基於 Tapable

ctx.register(hook: IHook)

註冊一個可供其他插件調用的鉤子,接收一個參數,即 Hook 對象。

一個 Hook 對象類型如下:

interface IHook {
  // Hook 名字,也會作為 Hook 標識
  name: string
  // Hook 所處的 plugin id,不需要指定,Hook 掛載的時候會自動識別
  plugin: string
  // Hook 回調
  fn: Function
  before?: string
  stage?: number
}

通過 ctx.register 註冊過的鉤子需要通過方法 ctx.applyPlugins 進行觸發。

我們約定,按照傳入的 Hook 對象的 name 來區分 Hook 類型,主要為以下三類:

  • 事件類型 Hook,Hook name 以 on 開頭,如 onStart,這種類型的 Hook 只管觸發而不關心 Hook 回調 fn 的值,Hook 的回調 fn 接收一個參數 opts ,為觸發鉤子時傳入的參數
  • 修改類型 Hook,Hook name 以 modify 開頭,如 modifyBuildAssets,這種類型的 Hook 觸發後會返回做出某項修改後的值,Hook 的回調 fn 接收兩個參數 optsarg ,分別為觸發鉤子時傳入的參數和上一個回調執行的結果
  • 添加類型 Hook,Hook name 以 add 開頭,如 addConfig,這種類型 Hook 會將所有回調的結果組合成數組最終返回,Hook 的回調 fn 接收兩個參數 optsarg ,分別為觸發鉤子時傳入的參數和上一個回調執行的結果

如果 Hook 對象的 name 不屬於以上三類,則該 Hook 表現情況類似事件類型 Hook。

鉤子回調可以是非同步也可以是同步,同一個 Hook 標識下一系列回調會藉助 Tapable 的 AsyncSeriesWaterfallHook 組織為非同步串列任務依次執行。

ctx.registerMethod(arg: string | { name: string, fn?: Function }, fn?: Function)

ctx 上掛載一個方法可供其他插件直接調用。

主要調用方式:


ctx.registerMethod('methodName')
ctx.registerMethod('methodName', () => {
  // callback
})
ctx.registerMethod({
  name: 'methodName'
})
ctx.registerMethod({
  name: 'methodName',
  fn: () => {
    // callback
  }
})

其中方法名必須指定,而對於回調函數則存在兩種情況。

指定回調函數

則直接往 ctx 上進行掛載方法,調用時 ctx.methodName 即執行 registerMethod 上指定的回調函數。

不指定回調函數

則相當於註冊了一個 methodName 鉤子,與 ctx.register 註冊鉤子一樣需要通過方法 ctx.applyPlugins 進行觸發,而具體要執行的鉤子回調則通過 ctx.methodName 進行指定,可以指定多個要執行的回調,最後會按照註冊順序依次執行。

內置的編譯過程中的 API 如 ctx.onBuildStart 等均是通過這種方式註冊。

ctx.registerCommand(hook: ICommand)

註冊一個自定義命令。

interface ICommand {
  // 命令別名
  alias?: string,
  // 執行 taro <command> --help 時輸出的 options 信息
  optionsMap?: {
    [key: string]: string
  },
  // 執行 taro <command> --help 時輸出的使用例子的信息
  synopsisList?: string[]
}

使用方式:

ctx.registerCommand({
  name: 'create',
  fn () {
    const {
      type,
      name,
      description
    } = ctx.runOpts
    const { chalk } = ctx.helper
    const { appPath } = ctx.paths
    if (typeof name !== 'string') {
      return console.log(chalk.red('請輸入需要創建的頁面名稱'))
    }
    if (type === 'page') {
      const Page = require('../../create/page').default
      const page = new Page({
        pageName: name,
        projectDir: appPath,
        description
      })

      page.create()
    }
  }
})

ctx.registerPlatform(hook: IPlatform)

註冊一個編譯平臺。

interface IFileType {
  templ: string
  style: string
  script: string
  config: string
}
interface IPlatform extends IHook {
  // 編譯後文件類型
  fileType: IFileType
  // 編譯時使用的配置參數名
  useConfigName: String
}

使用方式:

ctx.registerPlatform({
  name: 'alipay',
  useConfigName: 'mini',
  async fn ({ config }) {
    const { appPath, nodeModulesPath, outputPath } = ctx.paths
    const { npm, emptyDirectory } = ctx.helper
    emptyDirectory(outputPath)

    // 準備 miniRunner 參數
    const miniRunnerOpts = {
      ...config,
      nodeModulesPath,
      buildAdapter: config.platform,
      isBuildPlugin: false,
      globalObject: 'my',
      fileType: {
        templ: '.awml',
        style: '.acss',
        config: '.json',
        script: '.js'
      },
      isUseComponentBuildPage: false
    }

    ctx.modifyBuildTempFileContent(({ tempFiles }) => {
      const replaceKeyMap = {
        navigationBarTitleText: 'defaultTitle',
        navigationBarBackgroundColor: 'titleBarColor',
        enablePullDownRefresh: 'pullRefresh',
        list: 'items',
        text: 'name',
        iconPath: 'icon',
        selectedIconPath: 'activeIcon',
        color: 'textColor'
      }
      Object.keys(tempFiles).forEach(key => {
        const item = tempFiles[key]
        if (item.config) {
          recursiveReplaceObjectKeys(item.config, replaceKeyMap)
        }
      })
    })

    // build with webpack
    const miniRunner = await npm.getNpmPkg('@tarojs/mini-runner', appPath)
    await miniRunner(appPath, miniRunnerOpts)
  }
})

ctx.applyPlugins(args: string | { name: string, initialVal?: any, opts?: any })

觸發註冊的鉤子。

傳入的鉤子名為 ctx.registerctx.registerMethod 指定的名字。

這裡值得註意的是如果是修改類型添加類型的鉤子,則擁有返回結果,否則不用關心其返回結果。

使用方式:

ctx.applyPlugins('onStart')

const assets = await ctx.applyPlugins({
  name: 'modifyBuildAssets',
  initialVal: assets,
  opts: {
    assets
  }
})

ctx.addPluginOptsSchema(schema: Function)

為插件入參添加校驗,接受一個函數類型參數,函數入參為 joi 對象,返回值為 joi schema。

使用方式:

ctx.addPluginOptsSchema(joi => {
  return joi.object().keys({
    mocks: joi.object().pattern(
      joi.string(), joi.object()
    ),
    port: joi.number(),
    host: joi.string()
  })
})

ctx.writeFileToDist({ filePath: string, content: string })

向編譯結果目錄中寫入文件,參數:

  • filePath: 文件放入編譯結果目錄下的路徑
  • content: 文件內容

ctx.generateFrameworkInfo({ platform: string })

生成編譯信息文件 .frameworkinfo,參數:

  • platform: 平臺名

ctx.generateProjectConfig({ srcConfigName: string, distConfigName: string })

根據當前項目配置,生成最終項目配置,參數:

  • srcConfigName: 源碼中配置名
  • distConfigName: 最終生成的配置名

歡迎關註凹凸實驗室博客:aotu.io

或者關註凹凸實驗室公眾號(AOTULabs),不定時推送文章:

歡迎關註凹凸實驗室公眾號


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、視圖動畫標簽 0.概述 視圖動畫有5中類型組成: alpha:漸變透明度 scale:漸變尺寸伸縮 translate:畫面變換位置移動 rotate:畫面轉移旋轉移動 set:定義動畫集 1.scale標簽 scale_anim.xml pivotX有三種數值: 直接數字,則是以控制項為原點坐標 ...
  • VS Code寫Vue,每次按照eslint格式手動fix代碼很煩,Alt+Shift+f格式化代碼又會和prettier衝突,因此找了Ctrl+s保存代碼,自動按照eslint風格格式化代碼。 網上大多是早前修改方法,現在已經不適用,因此寫這個隨筆,避坑。 當前版本使用方式,使用編輯器提供的Cod ...
  • 解決方法:放在伺服器里打開。在 vscod e內安裝 Live Server 插件後,右擊使用 Live Server 打開。 其他說明(轉載): https://blog.csdn.net/qq_44163269/article/details/105116173 ...
  • 2018年開始各大互聯網公司對前端技術人才的需求缺口依然很大,然而公司招不到人和學生找不到工作的矛盾卻更加突出,這一切都與前端技術的飛速發展息息相關,公司對前端人才的開發經驗要求、技術要求逐漸提高。那麼企業到底需要什麼樣的人才呢?請看詳細分析: 一、2020年IT互聯網招聘需求是什麼? 我們先來看看 ...
  • 我看很多人都弄不清楚css的層級關係 自己也百度過很多網上的z-index的說法,比如 什麼是“層疊上下文” 層疊上下文(stacking context),是HTML中一個三維的概念。在CSS2.1規範中,每個盒模型的位置是三維的,分別是平面畫布上的X軸,Y軸以及表示層疊的Z軸。一般情況下,元素在 ...
  • 在中國互聯網行業崛起的大背景下,大家普遍對互聯網行業發展持樂觀態度。據今年第二季度招聘信息顯示,目前web前端工程師日均崗位缺口已經超過50000,隨著互聯網+的深入發展,html5作為前端展示技術,市場人才需求量將呈直線上漲。 一個好的Web前端工程師在知識體繫上既要有廣度,又要有深度,所以很多大 ...
  • jQuery 選擇器 | 選擇器 | 實例 | 選取 | | : | : | : | | | $(" ") | 所有元素 | | id | $(" lastname") | id="lastname" 的元素 | | . class | $(".intro") | 所有 class="intro" ...
  • css中相鄰元素的margin其實是會自動合併的,且取較大值。 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>test</title> <style> .div1 { width: 60px; height ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...