mirror of
https://github.com/status-im/metro.git
synced 2025-03-02 03:30:53 +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');
|
||||
|
||||
import type {AssetDescriptor} from '.';
|
||||
import type {ModuleTransportLike} from '../../../local-cli/bundle/types.flow';
|
||||
import type {ModuleTransportLike} from '../shared/types.flow';
|
||||
|
||||
type SubTree<T: ModuleTransportLike> = (
|
||||
moduleTransport: T,
|
||||
|
@ -10,11 +10,11 @@
|
||||
*/
|
||||
'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 {buildTableAndContents, createModuleGroups} = require('../../../../local-cli/bundle/output/unbundle/as-indexed-file');
|
||||
const {createRamBundleGroups} = require('../../Bundler/util');
|
||||
const {buildTableAndContents, createModuleGroups} = require('../../shared/output/unbundle/as-indexed-file');
|
||||
const {concat} = require('./util');
|
||||
|
||||
import type {FBIndexMap} from '../../lib/SourceMap.js';
|
||||
|
@ -10,7 +10,7 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const meta = require('../../../../local-cli/bundle/output/meta');
|
||||
const meta = require('../../shared/output/meta');
|
||||
|
||||
const {createIndexMap} = require('./source-map');
|
||||
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