mirror of
https://github.com/status-im/metro.git
synced 2025-03-03 12:10:30 +00:00
Move packager core logic from local-cli
to packager
Summary: Moves packager core logic to `packager/...` to prepare the open source split. Reviewed By: cpojer Differential Revision: D5116162 fbshipit-source-id: 06ee2406026686789f67acc88df41773866c3cd3
This commit is contained in:
parent
3e8991548b
commit
f0e629b8bf
@ -16,7 +16,7 @@ const babelGenerate = require('babel-generator').default;
|
|||||||
const babylon = require('babylon');
|
const babylon = require('babylon');
|
||||||
|
|
||||||
import type {AssetDescriptor} from '.';
|
import type {AssetDescriptor} from '.';
|
||||||
import type {ModuleTransportLike} from '../../../local-cli/bundle/types.flow';
|
import type {ModuleTransportLike} from '../shared/types.flow';
|
||||||
|
|
||||||
type SubTree<T: ModuleTransportLike> = (
|
type SubTree<T: ModuleTransportLike> = (
|
||||||
moduleTransport: T,
|
moduleTransport: T,
|
||||||
|
@ -10,11 +10,11 @@
|
|||||||
*/
|
*/
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const buildSourceMapWithMetaData = require('../../../../local-cli/bundle/output/unbundle/build-unbundle-sourcemap-with-metadata.js');
|
const buildSourceMapWithMetaData = require('../../shared/output/unbundle/build-unbundle-sourcemap-with-metadata.js');
|
||||||
const nullthrows = require('fbjs/lib/nullthrows');
|
const nullthrows = require('fbjs/lib/nullthrows');
|
||||||
|
|
||||||
const {buildTableAndContents, createModuleGroups} = require('../../../../local-cli/bundle/output/unbundle/as-indexed-file');
|
|
||||||
const {createRamBundleGroups} = require('../../Bundler/util');
|
const {createRamBundleGroups} = require('../../Bundler/util');
|
||||||
|
const {buildTableAndContents, createModuleGroups} = require('../../shared/output/unbundle/as-indexed-file');
|
||||||
const {concat} = require('./util');
|
const {concat} = require('./util');
|
||||||
|
|
||||||
import type {FBIndexMap} from '../../lib/SourceMap.js';
|
import type {FBIndexMap} from '../../lib/SourceMap.js';
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*/
|
*/
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const meta = require('../../../../local-cli/bundle/output/meta');
|
const meta = require('../../shared/output/meta');
|
||||||
|
|
||||||
const {createIndexMap} = require('./source-map');
|
const {createIndexMap} = require('./source-map');
|
||||||
const {addModuleIdsToModuleWrapper, concat} = require('./util');
|
const {addModuleIdsToModuleWrapper, concat} = require('./util');
|
||||||
|
83
packages/metro-bundler/src/shared/output/bundle.js
Normal file
83
packages/metro-bundler/src/shared/output/bundle.js
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015-present, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*
|
||||||
|
* @flow
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const Server = require('../../Server');
|
||||||
|
|
||||||
|
const meta = require('./meta');
|
||||||
|
const relativizeSourceMap = require('../../lib/relativizeSourceMap');
|
||||||
|
const writeFile = require('./writeFile');
|
||||||
|
|
||||||
|
import type Bundle from '../../Bundler/Bundle';
|
||||||
|
import type {SourceMap} from '../../lib/SourceMap';
|
||||||
|
import type {OutputOptions, RequestOptions} from '../types.flow';
|
||||||
|
|
||||||
|
function buildBundle(packagerClient: Server, requestOptions: RequestOptions) {
|
||||||
|
return packagerClient.buildBundle({
|
||||||
|
...Server.DEFAULT_BUNDLE_OPTIONS,
|
||||||
|
...requestOptions,
|
||||||
|
isolateModuleIDs: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function createCodeWithMap(bundle: Bundle, dev: boolean, sourceMapSourcesRoot?: string): * {
|
||||||
|
const map = bundle.getSourceMap({dev});
|
||||||
|
const sourceMap = relativizeSourceMap(
|
||||||
|
typeof map === 'string' ? (JSON.parse(map): SourceMap) : map,
|
||||||
|
sourceMapSourcesRoot);
|
||||||
|
return {
|
||||||
|
code: bundle.getSource({dev}),
|
||||||
|
map: JSON.stringify(sourceMap),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveBundleAndMap(
|
||||||
|
bundle: Bundle,
|
||||||
|
options: OutputOptions,
|
||||||
|
log: (...args: Array<string>) => {},
|
||||||
|
): Promise<> {
|
||||||
|
const {
|
||||||
|
bundleOutput,
|
||||||
|
bundleEncoding: encoding,
|
||||||
|
dev,
|
||||||
|
sourcemapOutput,
|
||||||
|
sourcemapSourcesRoot
|
||||||
|
} = options;
|
||||||
|
|
||||||
|
log('start');
|
||||||
|
const codeWithMap = createCodeWithMap(bundle, !!dev, sourcemapSourcesRoot);
|
||||||
|
log('finish');
|
||||||
|
|
||||||
|
log('Writing bundle output to:', bundleOutput);
|
||||||
|
|
||||||
|
const {code} = codeWithMap;
|
||||||
|
const writeBundle = writeFile(bundleOutput, code, encoding);
|
||||||
|
const writeMetadata = writeFile(
|
||||||
|
bundleOutput + '.meta',
|
||||||
|
meta(code, encoding),
|
||||||
|
'binary');
|
||||||
|
Promise.all([writeBundle, writeMetadata])
|
||||||
|
.then(() => log('Done writing bundle output'));
|
||||||
|
|
||||||
|
if (sourcemapOutput) {
|
||||||
|
log('Writing sourcemap output to:', sourcemapOutput);
|
||||||
|
const writeMap = writeFile(sourcemapOutput, codeWithMap.map, null);
|
||||||
|
writeMap.then(() => log('Done writing sourcemap output'));
|
||||||
|
return Promise.all([writeBundle, writeMetadata, writeMap]);
|
||||||
|
} else {
|
||||||
|
return writeBundle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.build = buildBundle;
|
||||||
|
exports.save = saveBundleAndMap;
|
||||||
|
exports.formatName = 'bundle';
|
46
packages/metro-bundler/src/shared/output/meta.js
Normal file
46
packages/metro-bundler/src/shared/output/meta.js
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015-present, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*
|
||||||
|
* @flow
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/* global Buffer: true */
|
||||||
|
|
||||||
|
const crypto = require('crypto');
|
||||||
|
|
||||||
|
const isUTF8 = encoding => /^utf-?8$/i.test(encoding);
|
||||||
|
|
||||||
|
const constantFor = encoding =>
|
||||||
|
/^ascii$/i.test(encoding) ? 1 :
|
||||||
|
isUTF8(encoding) ? 2 :
|
||||||
|
/^(?:utf-?16(?:le)?|ucs-?2)$/.test(encoding) ? 3 : 0;
|
||||||
|
|
||||||
|
module.exports = function(
|
||||||
|
code: string,
|
||||||
|
encoding: 'ascii' | 'utf8' | 'utf16le' = 'utf8',
|
||||||
|
): Buffer {
|
||||||
|
const hash = crypto.createHash('sha1');
|
||||||
|
// remove `new Buffer` calls when RN drops support for Node 4
|
||||||
|
hash.update(Buffer.from ? Buffer.from(code, encoding) : new Buffer(code, encoding));
|
||||||
|
const digest = hash.digest();
|
||||||
|
const signature = Buffer.alloc ? Buffer.alloc(digest.length + 1) : new Buffer(digest.length + 1);
|
||||||
|
digest.copy(signature);
|
||||||
|
signature.writeUInt8(
|
||||||
|
constantFor(tryAsciiPromotion(code, encoding)),
|
||||||
|
signature.length - 1);
|
||||||
|
return signature;
|
||||||
|
};
|
||||||
|
|
||||||
|
function tryAsciiPromotion(string, encoding) {
|
||||||
|
if (!isUTF8(encoding)) { return encoding; }
|
||||||
|
for (let i = 0, n = string.length; i < n; i++) {
|
||||||
|
if (string.charCodeAt(i) > 0x7f) { return encoding; }
|
||||||
|
}
|
||||||
|
return 'ascii';
|
||||||
|
}
|
108
packages/metro-bundler/src/shared/output/unbundle/as-assets.js
Normal file
108
packages/metro-bundler/src/shared/output/unbundle/as-assets.js
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015-present, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*
|
||||||
|
* @flow
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const MAGIC_UNBUNDLE_NUMBER = require('./magic-number');
|
||||||
|
|
||||||
|
const buildSourceMapWithMetaData = require('./build-unbundle-sourcemap-with-metadata');
|
||||||
|
const mkdirp = require('mkdirp');
|
||||||
|
const path = require('path');
|
||||||
|
const relativizeSourceMap = require('../../../lib/relativizeSourceMap');
|
||||||
|
const writeFile = require('../writeFile');
|
||||||
|
const writeSourceMap = require('./write-sourcemap');
|
||||||
|
|
||||||
|
const {joinModules} = require('./util');
|
||||||
|
|
||||||
|
import type Bundle from '../../../Bundler/Bundle';
|
||||||
|
import type {OutputOptions} from '../../types.flow';
|
||||||
|
|
||||||
|
// must not start with a dot, as that won't go into the apk
|
||||||
|
const MAGIC_UNBUNDLE_FILENAME = 'UNBUNDLE';
|
||||||
|
const MODULES_DIR = 'js-modules';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves all JS modules of an app as single files
|
||||||
|
* The startup code (prelude, polyfills etc.) are written to the file
|
||||||
|
* designated by the `bundleOuput` option.
|
||||||
|
* All other modules go into a 'js-modules' folder that in the same parent
|
||||||
|
* directory as the startup file.
|
||||||
|
*/
|
||||||
|
function saveAsAssets(
|
||||||
|
bundle: Bundle,
|
||||||
|
options: OutputOptions,
|
||||||
|
log: (...args: Array<string>) => void,
|
||||||
|
): Promise<mixed> {
|
||||||
|
const {
|
||||||
|
bundleOutput,
|
||||||
|
bundleEncoding: encoding,
|
||||||
|
sourcemapOutput,
|
||||||
|
sourcemapSourcesRoot,
|
||||||
|
} = options;
|
||||||
|
|
||||||
|
log('start');
|
||||||
|
const {startupModules, lazyModules} = bundle.getUnbundle();
|
||||||
|
log('finish');
|
||||||
|
const startupCode = joinModules(startupModules);
|
||||||
|
|
||||||
|
log('Writing bundle output to:', bundleOutput);
|
||||||
|
const modulesDir = path.join(path.dirname(bundleOutput), MODULES_DIR);
|
||||||
|
const writeUnbundle =
|
||||||
|
createDir(modulesDir).then( // create the modules directory first
|
||||||
|
() => Promise.all([
|
||||||
|
writeModules(lazyModules, modulesDir, encoding),
|
||||||
|
writeFile(bundleOutput, startupCode, encoding),
|
||||||
|
writeMagicFlagFile(modulesDir),
|
||||||
|
])
|
||||||
|
);
|
||||||
|
writeUnbundle.then(() => log('Done writing unbundle output'));
|
||||||
|
|
||||||
|
const sourceMap =
|
||||||
|
relativizeSourceMap(
|
||||||
|
buildSourceMapWithMetaData({
|
||||||
|
fixWrapperOffset: true,
|
||||||
|
lazyModules: lazyModules.concat(),
|
||||||
|
moduleGroups: null,
|
||||||
|
startupModules: startupModules.concat(),
|
||||||
|
}),
|
||||||
|
sourcemapSourcesRoot
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
return Promise.all([
|
||||||
|
writeUnbundle,
|
||||||
|
sourcemapOutput && writeSourceMap(sourcemapOutput, JSON.stringify(sourceMap), log)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createDir(dirName) {
|
||||||
|
return new Promise((resolve, reject) =>
|
||||||
|
mkdirp(dirName, error => error ? reject(error) : resolve()));
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeModuleFile(module, modulesDir, encoding) {
|
||||||
|
const {code, id} = module;
|
||||||
|
return writeFile(path.join(modulesDir, id + '.js'), code, encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeModules(modules, modulesDir, encoding) {
|
||||||
|
const writeFiles =
|
||||||
|
modules.map(module => writeModuleFile(module, modulesDir, encoding));
|
||||||
|
return Promise.all(writeFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeMagicFlagFile(outputDir) {
|
||||||
|
/* global Buffer: true */
|
||||||
|
const buffer = new Buffer(4);
|
||||||
|
buffer.writeUInt32LE(MAGIC_UNBUNDLE_NUMBER, 0);
|
||||||
|
return writeFile(path.join(outputDir, MAGIC_UNBUNDLE_FILENAME), buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = saveAsAssets;
|
@ -0,0 +1,216 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015-present, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*
|
||||||
|
* @flow
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const MAGIC_UNBUNDLE_FILE_HEADER = require('./magic-number');
|
||||||
|
|
||||||
|
const buildSourceMapWithMetaData = require('./build-unbundle-sourcemap-with-metadata');
|
||||||
|
const fs = require('fs');
|
||||||
|
const relativizeSourceMap = require('../../../lib/relativizeSourceMap');
|
||||||
|
const writeSourceMap = require('./write-sourcemap');
|
||||||
|
|
||||||
|
const {joinModules} = require('./util');
|
||||||
|
|
||||||
|
import type Bundle from '../../../Bundler/Bundle';
|
||||||
|
import type {ModuleGroups, ModuleTransportLike, OutputOptions} from '../../types.flow';
|
||||||
|
|
||||||
|
const SIZEOF_UINT32 = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves all JS modules of an app as a single file, separated with null bytes.
|
||||||
|
* The file begins with an offset table that contains module ids and their
|
||||||
|
* lengths/offsets.
|
||||||
|
* The module id for the startup code (prelude, polyfills etc.) is the
|
||||||
|
* empty string.
|
||||||
|
*/
|
||||||
|
function saveAsIndexedFile(
|
||||||
|
bundle: Bundle,
|
||||||
|
options: OutputOptions,
|
||||||
|
log: (...args: Array<string>) => void,
|
||||||
|
): Promise<> {
|
||||||
|
const {
|
||||||
|
bundleOutput,
|
||||||
|
bundleEncoding: encoding,
|
||||||
|
sourcemapOutput,
|
||||||
|
sourcemapSourcesRoot,
|
||||||
|
} = options;
|
||||||
|
|
||||||
|
log('start');
|
||||||
|
const {startupModules, lazyModules, groups} = bundle.getUnbundle();
|
||||||
|
log('finish');
|
||||||
|
|
||||||
|
const moduleGroups = createModuleGroups(groups, lazyModules);
|
||||||
|
const startupCode = joinModules(startupModules);
|
||||||
|
|
||||||
|
log('Writing unbundle output to:', bundleOutput);
|
||||||
|
const writeUnbundle = writeBuffers(
|
||||||
|
fs.createWriteStream(bundleOutput),
|
||||||
|
buildTableAndContents(startupCode, lazyModules, moduleGroups, encoding)
|
||||||
|
).then(() => log('Done writing unbundle output'));
|
||||||
|
|
||||||
|
const sourceMap =
|
||||||
|
relativizeSourceMap(
|
||||||
|
buildSourceMapWithMetaData({
|
||||||
|
startupModules: startupModules.concat(),
|
||||||
|
lazyModules: lazyModules.concat(),
|
||||||
|
moduleGroups,
|
||||||
|
fixWrapperOffset: true,
|
||||||
|
}),
|
||||||
|
sourcemapSourcesRoot
|
||||||
|
);
|
||||||
|
|
||||||
|
return Promise.all([
|
||||||
|
writeUnbundle,
|
||||||
|
sourcemapOutput && writeSourceMap(sourcemapOutput, JSON.stringify(sourceMap), log),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* global Buffer: true */
|
||||||
|
|
||||||
|
const fileHeader = new Buffer(4);
|
||||||
|
fileHeader.writeUInt32LE(MAGIC_UNBUNDLE_FILE_HEADER, 0);
|
||||||
|
const nullByteBuffer: Buffer = new Buffer(1).fill(0);
|
||||||
|
|
||||||
|
function writeBuffers(stream, buffers: Array<Buffer>) {
|
||||||
|
buffers.forEach(buffer => stream.write(buffer));
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
stream.on('error', reject);
|
||||||
|
stream.on('finish', () => resolve());
|
||||||
|
stream.end();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function nullTerminatedBuffer(contents, encoding) {
|
||||||
|
return Buffer.concat([new Buffer(contents, encoding), nullByteBuffer]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function moduleToBuffer(id, code, encoding) {
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
buffer: nullTerminatedBuffer(code, encoding),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function entryOffset(n) {
|
||||||
|
// 2: num_entries + startup_code_len
|
||||||
|
// n * 2: each entry consists of two uint32s
|
||||||
|
return (2 + n * 2) * SIZEOF_UINT32;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildModuleTable(startupCode, moduleBuffers, moduleGroups) {
|
||||||
|
// table format:
|
||||||
|
// - num_entries: uint_32 number of entries
|
||||||
|
// - startup_code_len: uint_32 length of the startup section
|
||||||
|
// - entries: entry...
|
||||||
|
//
|
||||||
|
// entry:
|
||||||
|
// - module_offset: uint_32 offset into the modules blob
|
||||||
|
// - module_length: uint_32 length of the module code in bytes
|
||||||
|
|
||||||
|
const moduleIds = Array.from(moduleGroups.modulesById.keys());
|
||||||
|
const maxId = moduleIds.reduce((max, id) => Math.max(max, id));
|
||||||
|
const numEntries = maxId + 1;
|
||||||
|
const table: Buffer = new Buffer(entryOffset(numEntries)).fill(0);
|
||||||
|
|
||||||
|
// num_entries
|
||||||
|
table.writeUInt32LE(numEntries, 0);
|
||||||
|
|
||||||
|
// startup_code_len
|
||||||
|
table.writeUInt32LE(startupCode.length, SIZEOF_UINT32);
|
||||||
|
|
||||||
|
// entries
|
||||||
|
let codeOffset = startupCode.length;
|
||||||
|
moduleBuffers.forEach(({id, buffer}) => {
|
||||||
|
const group = moduleGroups.groups.get(id);
|
||||||
|
const idsInGroup = group ? [id].concat(Array.from(group)) : [id];
|
||||||
|
|
||||||
|
idsInGroup.forEach(moduleId => {
|
||||||
|
const offset = entryOffset(moduleId);
|
||||||
|
// module_offset
|
||||||
|
table.writeUInt32LE(codeOffset, offset);
|
||||||
|
// module_length
|
||||||
|
table.writeUInt32LE(buffer.length, offset + SIZEOF_UINT32);
|
||||||
|
});
|
||||||
|
codeOffset += buffer.length;
|
||||||
|
});
|
||||||
|
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
function groupCode(rootCode, moduleGroup, modulesById) {
|
||||||
|
if (!moduleGroup || !moduleGroup.size) {
|
||||||
|
return rootCode;
|
||||||
|
}
|
||||||
|
const code = [rootCode];
|
||||||
|
for (const id of moduleGroup) {
|
||||||
|
code.push((modulesById.get(id) || {}).code);
|
||||||
|
}
|
||||||
|
|
||||||
|
return code.join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildModuleBuffers(modules, moduleGroups, encoding) {
|
||||||
|
return modules
|
||||||
|
.filter(m => !moduleGroups.modulesInGroups.has(m.id))
|
||||||
|
.map(({id, code}) => moduleToBuffer(
|
||||||
|
id,
|
||||||
|
groupCode(
|
||||||
|
code,
|
||||||
|
moduleGroups.groups.get(id),
|
||||||
|
moduleGroups.modulesById,
|
||||||
|
),
|
||||||
|
encoding
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildTableAndContents(
|
||||||
|
startupCode: string,
|
||||||
|
modules: $ReadOnlyArray<ModuleTransportLike>,
|
||||||
|
moduleGroups: ModuleGroups,
|
||||||
|
encoding?: 'utf8' | 'utf16le' | 'ascii',
|
||||||
|
) {
|
||||||
|
// file contents layout:
|
||||||
|
// - magic number char[4] 0xE5 0xD1 0x0B 0xFB (0xFB0BD1E5 uint32 LE)
|
||||||
|
// - offset table table see `buildModuleTables`
|
||||||
|
// - code blob char[] null-terminated code strings, starting with
|
||||||
|
// the startup code
|
||||||
|
|
||||||
|
const startupCodeBuffer = nullTerminatedBuffer(startupCode, encoding);
|
||||||
|
const moduleBuffers = buildModuleBuffers(modules, moduleGroups, encoding);
|
||||||
|
const table = buildModuleTable(startupCodeBuffer, moduleBuffers, moduleGroups);
|
||||||
|
|
||||||
|
return [
|
||||||
|
fileHeader,
|
||||||
|
table,
|
||||||
|
startupCodeBuffer
|
||||||
|
].concat(moduleBuffers.map(({buffer}) => buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
function createModuleGroups(
|
||||||
|
groups: Map<number, Set<number>>,
|
||||||
|
modules: $ReadOnlyArray<ModuleTransportLike>,
|
||||||
|
): ModuleGroups {
|
||||||
|
return {
|
||||||
|
groups,
|
||||||
|
modulesById: new Map(modules.map(m => [m.id, m])),
|
||||||
|
modulesInGroups: new Set(concat(groups.values())),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function * concat(iterators) {
|
||||||
|
for (const it of iterators) {
|
||||||
|
yield * it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.save = saveAsIndexedFile;
|
||||||
|
exports.buildTableAndContents = buildTableAndContents;
|
||||||
|
exports.createModuleGroups = createModuleGroups;
|
@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015-present, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*
|
||||||
|
* @flow
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const {combineSourceMaps, combineSourceMapsAddingOffsets, joinModules} = require('./util');
|
||||||
|
|
||||||
|
import type {ModuleGroups, ModuleTransportLike} from '../../types.flow';
|
||||||
|
|
||||||
|
type Params = {|
|
||||||
|
fixWrapperOffset: boolean,
|
||||||
|
lazyModules: $ReadOnlyArray<ModuleTransportLike>,
|
||||||
|
moduleGroups: ?ModuleGroups,
|
||||||
|
startupModules: $ReadOnlyArray<ModuleTransportLike>,
|
||||||
|
|};
|
||||||
|
|
||||||
|
module.exports = ({fixWrapperOffset, lazyModules, moduleGroups, startupModules}: Params) => {
|
||||||
|
const options = fixWrapperOffset ? {fixWrapperOffset: true} : undefined;
|
||||||
|
const startupModule: ModuleTransportLike = {
|
||||||
|
code: joinModules(startupModules),
|
||||||
|
id: Number.MIN_SAFE_INTEGER,
|
||||||
|
map: combineSourceMaps(startupModules, undefined, options),
|
||||||
|
sourcePath: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
const map = combineSourceMapsAddingOffsets(
|
||||||
|
[startupModule].concat(lazyModules),
|
||||||
|
moduleGroups,
|
||||||
|
options,
|
||||||
|
);
|
||||||
|
delete map.x_facebook_offsets[Number.MIN_SAFE_INTEGER];
|
||||||
|
return map;
|
||||||
|
};
|
46
packages/metro-bundler/src/shared/output/unbundle/index.js
Normal file
46
packages/metro-bundler/src/shared/output/unbundle/index.js
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015-present, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*
|
||||||
|
* @flow
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const Server = require('../../../Server');
|
||||||
|
|
||||||
|
const asAssets = require('./as-assets');
|
||||||
|
const asIndexedFile = require('./as-indexed-file').save;
|
||||||
|
|
||||||
|
import type Bundle from '../../../Bundler/Bundle';
|
||||||
|
import type {OutputOptions, RequestOptions} from '../../types.flow';
|
||||||
|
|
||||||
|
function buildBundle(packagerClient: Server, requestOptions: RequestOptions) {
|
||||||
|
return packagerClient.buildBundle({
|
||||||
|
...Server.DEFAULT_BUNDLE_OPTIONS,
|
||||||
|
...requestOptions,
|
||||||
|
unbundle: true,
|
||||||
|
isolateModuleIDs: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveUnbundle(
|
||||||
|
bundle: Bundle,
|
||||||
|
options: OutputOptions,
|
||||||
|
log: (x: string) => void,
|
||||||
|
): Promise<mixed> {
|
||||||
|
// we fork here depending on the platform:
|
||||||
|
// while android is pretty good at loading individual assets, ios has a large
|
||||||
|
// overhead when reading hundreds pf assets from disk
|
||||||
|
return options.platform === 'android' && !options.indexedUnbundle ?
|
||||||
|
asAssets(bundle, options, log) :
|
||||||
|
asIndexedFile(bundle, options, log);
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.build = buildBundle;
|
||||||
|
exports.save = saveUnbundle;
|
||||||
|
exports.formatName = 'bundle';
|
@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015-present, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*
|
||||||
|
* @flow
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = 0xFB0BD1E5;
|
128
packages/metro-bundler/src/shared/output/unbundle/util.js
Normal file
128
packages/metro-bundler/src/shared/output/unbundle/util.js
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2016-present, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*
|
||||||
|
* @flow
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const invariant = require('fbjs/lib/invariant');
|
||||||
|
|
||||||
|
import type {FBIndexMap, IndexMap, MappingsMap, SourceMap} from '../../../lib/SourceMap';
|
||||||
|
import type {ModuleGroups, ModuleTransportLike} from '../../types.flow';
|
||||||
|
|
||||||
|
const newline = /\r\n?|\n|\u2028|\u2029/g;
|
||||||
|
// fastest implementation
|
||||||
|
const countLines = (string: string) => (string.match(newline) || []).length + 1;
|
||||||
|
|
||||||
|
|
||||||
|
function lineToLineSourceMap(source: string, filename: string = ''): MappingsMap {
|
||||||
|
// The first line mapping in our package is the base64vlq code for zeros (A).
|
||||||
|
const firstLine = 'AAAA;';
|
||||||
|
|
||||||
|
// Most other lines in our mappings are all zeros (for module, column etc)
|
||||||
|
// except for the lineno mapping: curLineno - prevLineno = 1; Which is C.
|
||||||
|
const line = 'AACA;';
|
||||||
|
|
||||||
|
return {
|
||||||
|
file: filename,
|
||||||
|
mappings: firstLine + Array(countLines(source)).join(line),
|
||||||
|
sources: [filename],
|
||||||
|
names: [],
|
||||||
|
version: 3,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const wrapperEnd = wrappedCode => wrappedCode.indexOf('{') + 1;
|
||||||
|
|
||||||
|
const Section =
|
||||||
|
(line: number, column: number, map: SourceMap) =>
|
||||||
|
({map, offset: {line, column}});
|
||||||
|
|
||||||
|
type CombineOptions = {fixWrapperOffset: boolean};
|
||||||
|
|
||||||
|
function combineSourceMaps(
|
||||||
|
modules: $ReadOnlyArray<ModuleTransportLike>,
|
||||||
|
moduleGroups?: ModuleGroups,
|
||||||
|
options?: ?CombineOptions,
|
||||||
|
): IndexMap {
|
||||||
|
const sections = combineMaps(modules, null, moduleGroups, options);
|
||||||
|
return {sections, version: 3};
|
||||||
|
}
|
||||||
|
|
||||||
|
function combineSourceMapsAddingOffsets(
|
||||||
|
modules: $ReadOnlyArray<ModuleTransportLike>,
|
||||||
|
moduleGroups?: ?ModuleGroups,
|
||||||
|
options?: ?CombineOptions,
|
||||||
|
): FBIndexMap {
|
||||||
|
const x_facebook_offsets = [];
|
||||||
|
const sections = combineMaps(modules, x_facebook_offsets, moduleGroups, options);
|
||||||
|
return {sections, version: 3, x_facebook_offsets};
|
||||||
|
}
|
||||||
|
|
||||||
|
function combineMaps(modules, offsets: ?Array<number>, moduleGroups, options) {
|
||||||
|
const sections = [];
|
||||||
|
|
||||||
|
let line = 0;
|
||||||
|
modules.forEach(moduleTransport => {
|
||||||
|
const {code, id, name} = moduleTransport;
|
||||||
|
let column = 0;
|
||||||
|
let group;
|
||||||
|
let groupLines = 0;
|
||||||
|
let {map} = moduleTransport;
|
||||||
|
|
||||||
|
if (moduleGroups && moduleGroups.modulesInGroups.has(id)) {
|
||||||
|
// this is a module appended to another module
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (offsets != null) {
|
||||||
|
group = moduleGroups && moduleGroups.groups.get(id);
|
||||||
|
if (group && moduleGroups) {
|
||||||
|
const {modulesById} = moduleGroups;
|
||||||
|
const otherModules: $ReadOnlyArray<ModuleTransportLike> =
|
||||||
|
Array.from(group || [])
|
||||||
|
.map(moduleId => modulesById.get(moduleId))
|
||||||
|
.filter(Boolean); // needed to appease flow
|
||||||
|
otherModules.forEach(m => {
|
||||||
|
groupLines += countLines(m.code);
|
||||||
|
});
|
||||||
|
map = combineSourceMaps([moduleTransport].concat(otherModules));
|
||||||
|
}
|
||||||
|
|
||||||
|
column = options && options.fixWrapperOffset ? wrapperEnd(code) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
invariant(
|
||||||
|
!Array.isArray(map),
|
||||||
|
'Random Access Bundle source maps cannot be built from raw mappings',
|
||||||
|
);
|
||||||
|
sections.push(Section(line, column, map || lineToLineSourceMap(code, name)));
|
||||||
|
if (offsets != null && id != null) {
|
||||||
|
offsets[id] = line;
|
||||||
|
for (const moduleId of group || []) {
|
||||||
|
offsets[moduleId] = line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
line += countLines(code) + groupLines;
|
||||||
|
});
|
||||||
|
|
||||||
|
return sections;
|
||||||
|
}
|
||||||
|
|
||||||
|
const joinModules =
|
||||||
|
(modules: $ReadOnlyArray<{+code: string}>): string =>
|
||||||
|
modules.map(m => m.code).join('\n');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
combineSourceMaps,
|
||||||
|
combineSourceMapsAddingOffsets,
|
||||||
|
countLines,
|
||||||
|
joinModules,
|
||||||
|
lineToLineSourceMap,
|
||||||
|
};
|
@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015-present, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*
|
||||||
|
* @flow
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const writeFile = require('../writeFile');
|
||||||
|
|
||||||
|
function writeSourcemap(
|
||||||
|
fileName: string,
|
||||||
|
contents: string,
|
||||||
|
log: (...args: Array<string>) => void,
|
||||||
|
): Promise<> {
|
||||||
|
if (!fileName) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
log('Writing sourcemap output to:', fileName);
|
||||||
|
const writeMap = writeFile(fileName, contents, null);
|
||||||
|
writeMap.then(() => log('Done writing sourcemap output'));
|
||||||
|
return writeMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = writeSourcemap;
|
20
packages/metro-bundler/src/shared/output/writeFile.js
Normal file
20
packages/metro-bundler/src/shared/output/writeFile.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015-present, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*
|
||||||
|
* @flow
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const denodeify = require('denodeify');
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
type WriteFn =
|
||||||
|
(file: string, data: string | Buffer, encoding?: ?string) => Promise<mixed>;
|
||||||
|
const writeFile: WriteFn = denodeify(fs.writeFile);
|
||||||
|
|
||||||
|
module.exports = writeFile;
|
44
packages/metro-bundler/src/shared/types.flow.js
Normal file
44
packages/metro-bundler/src/shared/types.flow.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015-present, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*
|
||||||
|
* @flow
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
import type {SourceMapOrMappings} from '../lib/ModuleTransport';
|
||||||
|
|
||||||
|
export type ModuleGroups = {|
|
||||||
|
groups: Map<number, Set<number>>,
|
||||||
|
modulesById: Map<number, ModuleTransportLike>,
|
||||||
|
modulesInGroups: Set<number>,
|
||||||
|
|};
|
||||||
|
|
||||||
|
export type ModuleTransportLike = {
|
||||||
|
+code: string,
|
||||||
|
+id: number,
|
||||||
|
+map: ?SourceMapOrMappings,
|
||||||
|
+name?: string,
|
||||||
|
+sourcePath: string,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type OutputOptions = {
|
||||||
|
bundleOutput: string,
|
||||||
|
bundleEncoding?: 'utf8' | 'utf16le' | 'ascii',
|
||||||
|
dev?: boolean,
|
||||||
|
platform: string,
|
||||||
|
sourcemapOutput?: string,
|
||||||
|
sourcemapSourcesRoot?: string,
|
||||||
|
sourcemapUseAbsolutePath?: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type RequestOptions = {|
|
||||||
|
entryFile: string,
|
||||||
|
sourceMapUrl?: string,
|
||||||
|
dev?: boolean,
|
||||||
|
minify: boolean,
|
||||||
|
platform: string,
|
||||||
|
|};
|
Loading…
x
Reference in New Issue
Block a user