Add unbundling to packager

Reviewed By: tadeuzagallo

Differential Revision: D2707409

fb-gh-sync-id: 30216c36066dae68d83622dba2d598e9dc0a29db
This commit is contained in:
David Aurelio
2015-12-01 07:42:44 -08:00
committed by facebook-github-bot-7
parent b6f5c7fa04
commit cc4a5d39db
15 changed files with 318 additions and 19 deletions

View File

@@ -17,10 +17,18 @@ const outputPrepack = require('./output/prepack');
/**
* Builds the bundle starting to look for dependencies at the given entry path.
*/
function bundle(argv, config) {
function bundleWithOutput(argv, config, output) {
const args = parseCommandLine(bundleCommandLineArgs, argv);
const output = args.prepack ? outputPrepack : outputBundle;
if (!output) {
output = args.prepack ? outputPrepack : outputBundle;
}
return buildBundle(args, config, output);
}
function bundle(argv, config) {
return bundleWithOutput(argv, config);
}
module.exports = bundle;
module.exports.withOutput = bundleWithOutput;

View File

@@ -33,7 +33,7 @@ function saveBundleAndMap(bundle, options, log) {
'bundle-encoding': encoding,
dev,
'sourcemap-output': sourcemapOutput,
} = options;
} = options;
log('start');
const codeWithMap = createCodeWithMap(bundle, dev);

View File

@@ -0,0 +1,126 @@
/**
* 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.
*/
'use strict';
const fs = require('fs');
const Promise = require('promise');
const writeFile = require('./writeFile');
const MAGIC_STARTUP_MODULE_ID = '';
function buildBundle(packagerClient, requestOptions) {
return packagerClient.buildBundle({...requestOptions, unbundle: true});
}
function saveUnbundle(bundle, options, log) {
const {
'bundle-output': bundleOutput,
'bundle-encoding': encoding,
dev,
'sourcemap-output': sourcemapOutput,
} = options;
log('start');
const {startupCode, modules} = bundle.getUnbundle({minify: !dev});
log('finish');
log('Writing unbundle output to:', bundleOutput);
const writeUnbundle = writeBuffers(
fs.createWriteStream(bundleOutput),
buildTableAndContents(startupCode, modules, encoding)
);
writeUnbundle.then(() => log('Done writing unbundle output'));
if (sourcemapOutput) {
log('Writing sourcemap output to:', sourcemapOutput);
const writeMap = writeFile(sourcemapOutput, '', null);
writeMap.then(() => log('Done writing sourcemap output'));
return Promise.all([writeUnbundle, writeMap]);
} else {
return writeUnbundle;
}
}
/* global Buffer: true */
const nullByteBuffer = Buffer(1).fill(0);
const moduleToBuffer = ({name, code}, encoding) => ({
name,
buffer: Buffer.concat([
Buffer(code, encoding),
nullByteBuffer // create \0-terminated strings
])
});
function buildModuleBuffers(startupCode, modules, encoding) {
return (
[moduleToBuffer({name: '', code: startupCode}, encoding)]
.concat(modules.map(module => moduleToBuffer(module, encoding)))
);
}
function uInt32Buffer(n) {
const buffer = Buffer(4);
buffer.writeUInt32LE(n, 0); // let's assume LE for now :)
return buffer;
}
function buildModuleTable(buffers) {
// table format:
// - table_length: uint_32 length of all table entries in bytes
// - entries: entry...
//
// entry:
// - module_id: NUL terminated utf8 string
// - module_offset: uint_32 offset into the module string
// - module_length: uint_32 length of the module string, including terminating NUL byte
const numBuffers = buffers.length;
const tableLengthBuffer = uInt32Buffer(0);
let tableLength = 4; // the table length itself, 4 == tableLengthBuffer.length
let currentOffset = 0;
const offsetTable = [tableLengthBuffer];
for (let i = 0; i < numBuffers; i++) {
const {name, buffer: {length}} = buffers[i];
const entry = Buffer.concat([
Buffer(i === 0 ? MAGIC_STARTUP_MODULE_ID : name, 'utf8'),
nullByteBuffer,
uInt32Buffer(currentOffset),
uInt32Buffer(length)
]);
currentOffset += length;
tableLength += entry.length;
offsetTable.push(entry);
}
tableLengthBuffer.writeUInt32LE(tableLength, 0);
return Buffer.concat(offsetTable);
}
function buildTableAndContents(startupCode, modules, encoding) {
const buffers = buildModuleBuffers(startupCode, modules, encoding);
const table = buildModuleTable(buffers, encoding);
return [table].concat(buffers.map(({buffer}) => buffer));
}
function writeBuffers(stream, buffers) {
buffers.forEach(buffer => stream.write(buffer));
return new Promise((resolve, reject) => {
stream.on('error', reject);
stream.on('finish', () => resolve());
stream.end();
});
}
exports.build = buildBundle;
exports.save = saveUnbundle;
exports.formatName = 'bundle';

View File

@@ -0,0 +1,21 @@
/**
* 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.
*/
'use strict';
const bundleWithOutput = require('./bundle').withOutput;
const outputUnbundle = require('./output/unbundle');
/**
* Builds the bundle starting to look for dependencies at the given entry path.
*/
function unbundle(argv, config) {
return bundleWithOutput(argv, config, outputUnbundle);
}
module.exports = unbundle;

View File

@@ -28,6 +28,7 @@ var runAndroid = require('./runAndroid/runAndroid');
var server = require('./server/server');
var TerminalAdapter = require('yeoman-environment/lib/adapter.js');
var yeoman = require('yeoman-environment');
var unbundle = require('./bundle/unbundle');
var upgrade = require('./upgrade/upgrade');
var fs = require('fs');
@@ -40,6 +41,7 @@ gracefulFs.gracefulify(fs);
var documentedCommands = {
'start': [server, 'starts the webserver'],
'bundle': [bundle, 'builds the javascript bundle for offline use'],
'unbundle': [unbundle, 'builds javascript as "unbundle" for offline use'],
'new-library': [library, 'generates a native library bridge'],
'link': [link, 'Adds a third-party library to your project. Example: react-native link awesome-camera'],
'android': [generateWrapper, 'generates an Android project for your app'],