當前位置:
首頁 > 知識 > React Native官方拆包之metro bundle

React Native官方拆包之metro bundle

快速入門

安裝

安裝metro-core依賴主要有兩種方式:npm和yarn。npm安裝的命令如下:

npm install --save-dev metro metro-core

1

yarn方式的安裝命令如下:

yarn add --dev metro metro-core

1

運行

metro bundle支持使用CLI腳手架方式運行和通過程序的編程調用它來運行。

在程序中使用metro需要先導入它,導入的方式如下:

const Metro = require("metro");

1

方法

metro提供了很多有用的函數,這些函數包括:

runMetro(config)

此方法用於給定配置,請求特定的服務。此時,您可以使用processRequest方法來hook HTTP(S)請求。例如:

"use strict";

const http = require("http");

const Metro = require("metro");

// We first load the config from the file system

Metro.loadConfig().then(config => {

const metroBundlerServer = Metro.runMetro(config);

const httpServer = http.createServer(

metroBundlerServer.processRequest.bind(metroBundlerServer),

);

httpServer.listen(8081);

});

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

為了與Express apps兼容,當請求無法被Metro bundler處理時,processRequest也會調用它的第三個參數。這允許您將服務與現有服務集成,或者擴展一個新的服務。

const httpServer = http.createServer((req, res) => {

metroBundlerServer.processRequest(req, res, () => {

// Metro does not know how to handle the request.

});

});

1

2

3

4

5

如果您正在使用Express,可以將processRequest作為中間件進行使用。

const express = require("express");

const app = express();

app.use(

metroBundlerServer.processRequest.bind(metroBundlerServer),

);

app.listen(8081);

1

2

3

4

5

6

7

8

runServer(Config, Options)

runServer基於給定的配置和選項啟動開發服務,並返回服務。我們建議使用runMetro而不是runServer。runServer可選的參數有:

host (string):服務的host駐留地址。

onReady (Function):在服務已經準備好時服務請求時被調用。

secure (boolean):服務是否需要運行在https上,而不是http上。

secureKey (string):使用https訪問時secureKey。

secureCert (string):用於https訪問的安全證書。

hmrEnabled (boolean):是否開啟熱更新功能。

runBuild(Config, Options)

此函數用於,給定一個配置和一組通常傳遞給伺服器的選項,以及一組特定於包本身的選項,並用於構建一個包。runBuild支持的選項有:

dev (boolean):構建一個開發版本。例如,process.env.NODE_ENV = 『development』。

entry (string):指向要綁定的條目文件。

onBegin (Function):綁定開始時被調用。

onComplete (Function): 綁定完成後調用。

onProgress (Function):在包期間調用,每次有關於模塊計數/進度的新信息時被調用。

minify (boolean): 是否縮小bundle。

out (string):輸出包的路徑。

platform (『web』 | 『android』 | 『ios』): 指定打包的平台。

sourceMap (boolean):是否生成源映射。

sourceMapUrl (string): 源映射的URL匹配,它默認為與包相同的URL,只是將擴展名從.bundle更改為.map。

可用選項

有關配置選項的詳細信息,可用參考下面的連接:Configuring Metro

URL與 bundle 請求

Assets

為了獲取Assets資源,您可以使用require方法來獲取一個js文件,伺服器將根據特定的require請求返回js文件的路徑。當請求Assets資源時通常會原樣返回。

除此之外,伺服器還可以根據平台和請求的大小返回特定的Assets資源。指定平台的方法是通過點後綴(例如.ios)和at後綴(例如@2x)方式來進行的。

Bundle

任何js文件都可以作為bundle來請求根文件,這個文件將被看作是項目的根目錄,根目錄將包含所有遞歸在內的文件。為了請求bundle包,只需將擴展名從.js更改為.bundle即可。構建包的選項有:

dev: 是否以開發模式來構建包。

platform: 平台請求包,可以是ios或android。

minify: 代碼是否應該縮小。

excludeSource: 源碼是否應該包含在源映射中。

例如,請求http://localhost:8081/foo/bar/baz.bundle?dev=true&platform=ios將創建一個foo/bar/baz包,js為iOS開發模式。

Source maps

通過使用與包相同的URL為每個包構建源映射,只有當inlineSourceMap設置為false時才會工作。您傳遞給包的所有選項將被添加到源映射URL;否則,它們就不匹配。

JavaScript transformer

JavaScript transformer被用來進行JS代碼轉換,適用於訪問Babel。這個transformer可以導出兩種方法:

transform(module)

此方法主要用於轉換代碼。接收到的對象將會被轉換為包含一個ast鍵代碼。默認的轉換器僅能完成將代碼解析為AST,以此來完成最低限度的工作:

const babylon = require("@babel/parser");

module.exports.transform = (file: {filename: string, src: string}) => {

const ast = babylon.parse(code, {sourceType: "module"});

return {ast};

};

1

2

3

4

5

6

7

如果您想要使用babel插件,您可以通過將代碼傳遞給它來實現:

const {transformSync} = require("@babel/core");

module.exports.transform = file => {

return transformSync(file.src, {

// Babel options...

});

};

1

2

3

4

5

6

7

getCacheKey()

此方法用於返迴轉換器緩存。當使用不同的轉換器時,這允許正確地將轉換後的文件綁定到轉換它的轉換器,且方法的結果必須是一個字元串。

概念

Metro是一個JavaScript的打包工具。它接收選項、一個條目文件,返回一個包含所有JavaScript的文件。Metro綁定程序主要涉及三個階段:

Resolution

Transformation

Serialization

Resolution

Metro需要從入口點構建所需的所有模塊的圖,要從另一個文件中找到所需的文件,需要使用Metro解析器。在現實開發中,這個階段與Transformation階段是並行的。

Transformation

所有模塊都要經過Transformation階段,Transformation負責將模塊轉換成目標平台可以理解的格式(如React Naitve)。模塊的轉換是基於擁有的核心數量來進行的。

Serialization

所有模塊一經轉換就會被序列化,Serialization會組合這些模塊來生成一個或多個包,包就是將模塊組合成一個JavaScript文件的包。

Modules

Metro被劃分為多個模塊,每個模塊對應於流程中的每個步驟,每個模塊都有自己的職責。這意味著我們每個模塊可以根據您的需要進行交換。

構建

綁定時,每個模塊都會被分配一個數字id,這意味著不支持動態需求。require通過數字版本更改、模塊以不同的格式存儲。支持三種不同的捆綁形式:

Plain bundle

這是一種標準的打包方式,在這種方式中,所有文件都用函數調用包裝,然後添加到全局文件中,這對於只需要JS包(例如瀏覽器)的環境非常有用。只需要具有.bundle擴展名的入口點就可以完成它的構建。

Indexed RAM bundle

這種打包方式會將包打包成二進位文件,其格式包括以下部分:

一組數字:用於驗證文件。uint32必須位於文件的開頭,值為0xFB0BD1E5。

偏移表:該表是一個由32對uint32對組成的序列,帶有一個表頭。

其他子模塊,由一個空位元組()完成。例如:

` 0 1 2 3 4 5 6

0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| Magic number | Header size |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| Startup code size | Module 0 offset |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| Module 0 length | |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +

| |

+ ... +

| |

+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| | Module n offset |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| Module n length | Module 0 code | Module 0 code | ... | |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| Module 1 code | Module 1 code | ... | | |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +

| |

+ ... +

| |

+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| | Module n code | Module n code | ... | |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+`

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

這種結構對於同時載入內存中所有代碼的環境來說是最優的:

通過使用偏移表,可以在固定的時間內載入任何模塊,其中模塊x的代碼位於文件[(x + 3) * sizeof(uint32)]。由於有一個空字元()分隔所有模塊,通常不需要使用長度,模塊可以直接作為ASCIIZ字元串載入。

啟動代碼總是可以在文件[sizeof(uint32)]中找到。

Indexed RAM bundle通常被用於iOS分包。

File RAM bundle

每個模塊都會被存儲為一個文件,例如,名稱為js-modules/${id},創建了一個名為UNBUNDLE的額外文件,它唯一的內容是一個數字0xFB0BD1E5。注意,解包文件是在根目錄下創建的。

Android通常使用這種方式分包,因為包內容是壓縮的,而且訪問壓縮文件要快得多。如果使用索引方式(Indexed RAM bundle),則應立即解壓縮所有綁定,以獲取對應模塊的代碼。

緩存

Metro具有多層緩存,您可以設置多個緩存供Metro使用,而不是一個緩存。下面來看看Motro的多層緩存是如何工作的。

為什麼要緩存

緩存提供了很大的性能優勢,它們可以將打包的速度提高十倍以上。然而,許多系統使用的是非持久緩存。對於Metro來說,我們有一種更複雜的層系統緩存方式。例如,我們可以在伺服器上存儲緩存,這樣,連接到同一伺服器的所有打包都可以使用共享緩存。因此,CI伺服器和本地開發的初始構建時間顯著降低。

我們希望將緩存存儲在多個位置,以便緩存可以執行回退操作。這就是為什麼有一個多層緩存系統。

緩存的請求與緩存

在Metro中,系統使用了一個排序機制來決定使用哪個緩存。為了檢索緩存,我們從上到下遍歷緩存,直到找到結果;為了保存緩存,我們同樣遍歷緩存,直到找到具有緩存的存儲。

假設您有兩個緩存存儲:一個在伺服器上,另一個在本地文件系統上。那麼,你可以這樣指定:

const config = {

cacheStores: [

new FileStore({/*opts*/}),

new NetworkStore({/*opts*/})

]

}

1

2

3

4

5

6

當我們檢索緩存時,Metro將首先查看本地文件存儲,如果不能找到緩存,它將檢查NetworkStore。最後,如果沒有緩存,它將生成一個新的緩存。一旦緩存生成,Metro將再次從上到下在所有存儲中存儲緩存。如果找到緩存,也會進行存儲。例如,如果Metro在NetworkStore中找到緩存,它也會將其存儲在FileStore中。

API

API

Methods

metro提供了如下一些方法:

loadConfig()

async runMetro(config)

async runBuild(config, )

async runServer(config, )

createConnectMiddleware(config, )

使用

編譯文件:

const config = await Metro.loadConfig();

await Metro.runBuild(config, {

entry: "index.js",

out: "bundle.js",

});

1

2

3

4

5

6

運行服務並監視文件系統的更改:

const config = await Metro.loadConfig();

await Metro.runServer(config, {

port: 8080,

});

1

2

3

4

5

Reference

下面公開的所有函數都會接受一個附加的配置選項,即metro.config.js,如意要使用它,你可以使用Metro.loadConfig來獲得它。

loadConfig()

Basic options: config, cwd

載入Metro配置,如果指定,可以從選項中的config載入,也可以從cwd到根目錄遍歷直到找到一個文件(默認metro.config.js)。返回的配置將與Metro的默認值合併。

async runMetro(config)

基於配置創建一個Metro伺服器並返回它,您可以將其用作現有伺服器中的中間件。

async runBuild(config, )

綁定給定平台的條目,並將其保存到外部位置。如果設置了sourceMap,還會生成一個源映射。源映射將被內聯,除非還定義了sourceMapUrl。在後一種情況下,將使用sourceMapUrl參數的basename生成一個新文件。

async runServer(config, )

啟動一個完整的Metro HTTP服務,它將偵聽指定的host:port,然後可以查詢它以檢索各種入口點的包。如果提供了安全系列選項,伺服器將通過HTTPS公開。如果設置了hmrEnabled,伺服器還將公開websocket伺服器內容,並將HMR客戶機注入生成的包中。

createConnectMiddleware(config, )

與其創建完整的伺服器不同,此函數用於創建一個連接中間件來響應包請求。然後可以將此中間件插入您自己的伺服器,埠參數是可選的,僅用於日誌記錄。

Metro配置

Metro配置可以通過以下三種方式創建:

metro.config.js

metro.config.json

The metro field in package.json

您還可以通過調用CLI時指定自定義文件,文件的格式為:

--config <path/to/config>

1

結構

每個模塊都有一個單獨的配置選項,Metro中常見的配置結構如下:

module.exports = {

resolver: {

/* resolver options */

},

transformer: {

/* transformer options */

},

serializer: {

/* serializer options */

},

server: {

/* server options */

}

/* general options */

};

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

可用的選項參數可以參考下面的鏈接:General Options

Option Type Description

cacheStores Array<CacheStore<TransformResult<>> 列出存儲緩存的位置

cacheVersion string 將使整個metro緩存生成一個鍵

projectRoot string 項目的根文件

watchFolders Array < string> 指定任何額外的監視文件夾

transformerPath string 轉換器路徑

watch boolean 是否監視所有文件

reporter {update: () => void} 是否監視打包過程中的狀態

resetCache boolean 是否在啟動構建時重置緩存

stickyWorkers boolean 創建的worker是否應該基於文件名

maxWorkers number 把序列化的包串聯起來

伺服器選項可以參考下面的鏈接:Server Options

Option Type Description

port number 監聽的埠

useGlobalHotkey boolean 是否打開熱更新快捷鍵,快捷鍵為CMD+R

enhanceMiddleware (Middleware, Server) => Middleware 添加自定義中間件

enableVisualizer boolean 啟用metro-visualizer中間件

Metro的轉化器選項如下:Transformer Options

Option Type Description

asyncRequireModulePath string 處理非同步請求模塊

babelTransformerPath string 使用自定義babel轉換器

dynamicDepsInPackages string (throwAtRuntime or reject) 發現動態依賴的處理動作

enableBabelRCLookup boolean (default: true) 是否使用.babelrc配置文件

enableBabelRuntime boolean (default: true) 是否使用@babel/transform/runtime插件

enableBabelRuntime boolean (default: true) 是否使用.babelrc配置文件

未完待續!!!!!

---------------------

作者:code_xzh

原文:https://blog.csdn.net/xiangzhihong8/article/details/85054279

React Native官方拆包之metro bundle

打開今日頭條,查看更多圖片
喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 程序員小新人學習 的精彩文章:

linux內核設計與實現筆記
為什麼去中心化存儲也能保證數據不丟失

TAG:程序員小新人學習 |