rn打包原來是packager,後來獨立出一個專門的打包工具metro,構建工具的大致思路跟前端構建工具差很少,都會有一個啓動文件,而後根據模塊依賴關係把對應文件找到。前端
在開發中打包,咱們訪問的是一個index.bundle,這個時候跟其餘的前端構建工具一致,都是會啓動一個node 服務,metro提供了一個createServer方法,這個方法結合http(s)模塊構建出一個能夠提供bundle文件的服務器,固然能夠其餘的node框架,好比express:node
const express = require('express'); const app = express(); app.use( metroBundlerServer.processRequest.bind(metroBundlerServer), ); app.listen(8081);
咱們能夠在瀏覽器中輸入http://localhost:8081/index.bundle?platform=ios&dev=true
那麼這個bundle文件就會被返回,而metroServer會提供幾個方法來提供返回內容,能夠是bundle也能夠是其餘靜態資源,這裏咱們訪問的是bundle,那麼就會使用processRequestBundle方法,這個方法會根據訪問的url去找對應的js文件,而後打包成bundle文件
因此這裏的虛擬目錄根目錄就是項目根目錄,咱們能夠獨立的去訪問某個目錄下js文件,都會爲咱們打包成bundle文件返回。react
這裏簡單分析下bundle文件,咱們簡單的翻一下整個文件,就能夠發現,前面除了第一行是設置環境變量,其餘都是一些自執行函數,後面的全是_d函數,大體也能夠猜出來,_d函數就是模塊定義函數。咱們看前面的函數,第一個自執行函數裏面有個很熟悉的東東,_d函數找到了,它被掛在到global下,在這個函數中把模塊加載相關作了定義。
模塊的id是一個createModuleIdFactory方法,而後咱們看到第一個定義的模塊id是從11開始的,這是由於以前的polyfill文件生成也在調用這個函數。ios
function createModuleIdFactory() { const fileToIdMap = new Map(); let nextId = 0; return path => { let id = fileToIdMap.get(path); if (typeof id !== 'number') { id = nextId++; fileToIdMap.set(path, id); } return id; }; }
然後面的幾個函數咱們能夠看到都是各類es6語法的polyfill,其中有個函數很特別,先是定義了一個inspect函數,裏邊大量的數據類型判斷,以後從新定義了console方法,這裏實際上是對console作了polyfill,可是因爲rn的打印錯誤信息跟瀏覽器有不一致,因此前面會有不少數據類型判斷,來保持跟瀏覽器控制檯中打印的一致。
以後的緊接着就是咱們的項目啓動模塊,可是以後的就是rn、react以及其餘依賴項目的模塊,一致到全部的公共模塊加載完纔是咱們的業務模塊。
es6
本地打包也就是打包出實實在在的bundle文件,而不是虛擬目錄下,命令使用這裏就不說了,這裏要注意的一點就是,若是你想在某個目錄下存放你的bundle文件,這個目錄必定要存在,metro不會幫你去建立目錄。這個時候調用依然會是metro的server,只不過最終會輸出bundle文件到指定目錄。
打包後的bundle文件跟開發中的結構是一致的,可是咱們仔細看就會發現模塊id變少了,前面的polyfill文件同樣的,都是第一個模塊ID都是11,也就是啓動文件,那麼就是中間的模塊便少了,其實就是一些公共模塊作了合併,因此看起來少了。express
基原本說只要rn和react等基礎包版本不變,那麼打包出來的bundle文件公共部分就是相同的,這裏也利於咱們進行基礎包也業務包的分離。瀏覽器