1. 指令參數解析:
react-native bundle --dev false --platform android --entry-file index.js --config bundle.main.js --bundle-output ./CodePush/index.android.bundle --assets-dest ./CodePush --sourcemap-output ./CodePush/index.android.bundle.map "
bundle檔案包含四層: 1.var聲明層,主要包含目前環境資訊、bundle啟動時間和目前程序相關資訊 2.Polyfill層,!(function(r)來頭部分代表polyfill層,定義了對 __define()、__require()和__clear()的支援,還有包含react-native和第三方的module 3.子產品定義層,包含 __define代碼塊、RN架構源碼js部分和自定義js部分以及圖檔資源資訊,供require引用 4.require層,引用require來執行define子產品的代碼 |
--dev : false: product包 true: dev包
--platform: 對應的平台
--entry-file:入口檔案
--config: 額外配置
--bundle-output:生成的bundle檔案輸出位置
--assets-dest: 圖檔等資源輸出的位置
--sourcemap-output: 映射檔案輸出的位置
2. metro 打包服務啟動:
在node_modules/react-native/node_modules/@react-native-community/cli/build/commands/bundle/buildBundle.js檔案中預設導出的 buildBundle 方法才是整個react-native bundle執行的入口。
在入口中主要做了如下幾件事情:
-合并 metro 預設配置和自定義配置,并設定 maxWorkers,resetCache
const config = await (0, _loadMetroConfig.default)(ctx, {
maxWorkers: args.maxWorkers,
resetCache: args.resetCache,
config: args.config,
});
-根據解析得到參數,建構 requestOptions,傳遞給打包函數
const requestOpts = {
entryFile: args.entryFile,
sourceMapUrl,
dev: args.dev,
minify: args.minify !== undefined ? args.minify : !args.dev,
platform: args.platform,
};
-執行個體化 metro Server
const server = new (_Server()).default(config);
-啟動 metro 建構 bundle
-處理資源檔案,解析
-關閉 Metro Server
try {
// 啟動打包
const bundle = await output.build(server, requestOpts);
// 将打包生成的bundle儲存到對應的目錄
await output.save(bundle, args, _cliTools().logger.info);
// 處理資源檔案,解析,并在下一步儲存在--assets-dest指定的位置
const outputAssets = await server.getAssets({
..._Server().default.DEFAULT_BUNDLE_OPTIONS,
...requestOpts,
bundleType: "todo",
});
// 儲存資源檔案到指定目錄
return await (0, _saveAssets.default)(
outputAssets,
args.platform,
args.assetsDest
);
} finally {
// 停止metro 打包服務
server.end();
}
為什麼用output.build啟動打包?
Output對象是“metro/src/shared/output/bundle”檔案中的buildBundle函數:
function buildBundle(packagerClient, requestOptions) {
return packagerClient.build(
_objectSpread({}, Server.DEFAULT_BUNDLE_OPTIONS, requestOptions, {
bundleType: "bundle",
})
)
packagerClient:是output.build(server, requestOpts)傳過來的serve對象
packagerClient.build的build函數: 是server的build函數:
1.将參過來的參數,按子產品拆分,用splitBundleOptions(options)函數拆分成四個部分:entryFile、transformOptions、serializerOptions、onProgress
2.解析和轉換,用buildGraph(entryFile,transformOptions, {onProgress})函數,最終生成prepend和graph對象
3.建構入口檔案路徑
const entryPoint = path.resolve(projectRoot, entryFile)
4.初始化建構參數,此處的參數來源于: 指令行和自定義metro.config.js配置
const bundle = baseJSBundle(entryPoint, prepend, graph, {
processModuleFilter: xxxxx,
createModuleId: xxxx, // createModuleIdFactory給每個module生成id;
getRunModuleStatement: xxxx, //給方法簽名
dev: transformOptions.dev,
projectRoot: _this2._config.projectRoot,
modulesOnly: serializerOptions.modulesOnly,
runBeforeMainModule: _this2._config.serializer.getModulesRunBeforeMainModule
(
path.relative(_this2._config.projectRoot, entryPoint)
), // 指定在主子產品前運作的子產品
runModule: serializerOptions.runModule,
sourceMapUrl: serializerOptions.sourceMapUrl,
sourceUrl: serializerOptions.sourceUrl,
inlineSourceMap: xxxx,
})
5.将js module進行排序和字元串拼接,生成最終代碼
bundleToString(bundle).code
更詳細:https://segmentfault.com/a/1190000038346994