Skip to content

Commit

Permalink
build(android): include common bundle in snapshot
Browse files Browse the repository at this point in the history
  • Loading branch information
Gary Mathews committed Jul 16, 2019
1 parent ee0812f commit 35aaaab
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 89 deletions.
4 changes: 4 additions & 0 deletions android/cli/commands/_build.js
Original file line number Diff line number Diff line change
Expand Up @@ -2589,6 +2589,10 @@ AndroidBuilder.prototype.copyResources = function copyResources(next) {
const tasks = [
// First copy all of the Titanium SDK's core JS files shared by all platforms.
function (cb) {
// Do not copy 'common' bundle over as it is included in our snapshot
if (fs.existsSync(path.join(this.platformPath, 'native', 'include', 'V8Snapshots.h'))) {
return cb();
}
const src = path.join(this.titaniumSdkPath, 'common', 'Resources');
warnDupeDrawableFolders.call(this, src);
_t.logger.debug(__('Copying %s', src.cyan));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,11 @@ protected void loadScript()
{
try {
String fullUrl = resolveUrl(this.url);
KrollRuntime.getInstance().runModule(KrollAssetHelper.readAsset(fullUrl), fullUrl, activityProxy);
if (KrollAssetHelper.assetExists(fullUrl)) {
KrollRuntime.getInstance().runModule(KrollAssetHelper.readAsset(fullUrl), fullUrl, activityProxy);
} else {
KrollRuntime.getInstance().runModule("global._startup(global)", fullUrl, activityProxy);
}
} finally {
Log.d(TAG, "Signal JS loaded", Log.DEBUG_MODE);
}
Expand Down
3 changes: 3 additions & 0 deletions build/lib/android/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ const copyFiles = utils.copyFiles;
const copyAndModifyFile = utils.copyAndModifyFile;
const globCopy = utils.globCopy;

const DIST_DIR = path.join(__dirname, '../../../dist');
const TMP_DIR = path.join(DIST_DIR, 'tmp'); // eslint-disable-line no-unused-vars

const ANDROID_BUILD_XML = path.join(__dirname, '../../../android/build.xml');

class Android {
Expand Down
14 changes: 13 additions & 1 deletion build/lib/android/snapshot.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ const path = require('path');
const ejs = require('ejs');

const ROOT_DIR = path.join(__dirname, '..', '..', '..');
const DIST_DIR = path.join(ROOT_DIR, 'dist');
const TMP_DIR = path.join(DIST_DIR, 'tmp');
const ANDROID_DIR = path.join(ROOT_DIR, 'android');
const ANDROID_PROPS = require(path.join(ANDROID_DIR, 'package.json')); // eslint-disable-line security/detect-non-literal-require
const V8_PROPS = ANDROID_PROPS.v8;
Expand All @@ -34,10 +36,20 @@ async function generateBlob(target) {
const V8_LIB_TARGET_DIR = path.resolve(V8_LIB_DIR, target);
const MKSNAPSHOT_PATH = path.join(V8_LIB_TARGET_DIR, 'mksnapshot');
const BLOB_PATH = path.join(V8_LIB_TARGET_DIR, 'blob.bin');
const STARTUP_PATH = path.join(TMP_DIR, 'startup.js');
const args = [
'--startup_blob=' + BLOB_PATH
'--startup_blob=' + BLOB_PATH,
STARTUP_PATH,
'--print-all-exceptions'
];

// Load 'common' bundle
const commonBundle = await fs.readFile(path.join(TMP_DIR, 'ti.main.js'));

// Generate 'startup.js'
const output = await promisify(ejs.renderFile)(path.join(__dirname, 'startup.ejs'), { script: commonBundle }, {});
await fs.writeFile(STARTUP_PATH, output);

// Snapshot already exists, skip...
if (await fs.exists(BLOB_PATH)) {
console.warn(`Snapshot blob for ${target} already exists, skipping...`);
Expand Down
3 changes: 3 additions & 0 deletions build/lib/android/startup.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
this._startup = function (global) {
<%- script %>
}
86 changes: 85 additions & 1 deletion build/lib/builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,23 @@
const os = require('os');
const path = require('path');
const fs = require('fs-extra');
const appc = require('node-appc');
const version = appc.version;
const rollup = require('rollup').rollup;
const babel = require('rollup-plugin-babel');
const resolve = require('rollup-plugin-node-resolve');
const commonjs = require('rollup-plugin-commonjs');

const git = require('./git');
const utils = require('./utils');
const copyPackageAndDependencies = utils.copyPackageAndDependencies;
const Packager = require('./packager');

const ROOT_DIR = path.join(__dirname, '../..');
const ROOT_DIR = path.join(__dirname, '..', '..');
const DIST_DIR = path.join(ROOT_DIR, 'dist');
const TMP_DIR = path.join(DIST_DIR, 'tmp');

const V8_STRING_VERSION_REGEXP = /(\d+)\.(\d+)\.\d+\.\d+/;

// platforms/OS mappings
const ALL_OSES = [ 'win32', 'linux', 'osx' ];
Expand All @@ -28,6 +38,38 @@ function thisOS() {
return osName;
}

function determineBabelOptions() {
// Pull out android's V8 target (and transform into equivalent chrome version)
// eslint-disable-next-line security/detect-non-literal-require
const v8Version = require(path.join(ROOT_DIR, 'android/package.json')).v8.version;
const found = v8Version.match(V8_STRING_VERSION_REGEXP);
const chromeVersion = parseInt(found[1] + found[2]); // concat the first two numbers as string, then turn to int
// Now pull out min IOS target
// eslint-disable-next-line security/detect-non-literal-require
const minSupportedIosSdk = version.parseMin(require(path.join(ROOT_DIR, 'iphone/package.json')).vendorDependencies['ios sdk']);
// TODO: filter to only targets relevant for platforms we're building?
const options = {
targets: {
chrome: chromeVersion,
ios: minSupportedIosSdk
},
useBuiltIns: 'entry',
// DO NOT include web polyfills!
exclude: [ 'web.dom.iterable', 'web.immediate', 'web.timers' ],
corejs: 2
};
// pull out windows target (if it exists)
if (fs.pathExistsSync(path.join(ROOT_DIR, 'windows/package.json'))) {
// eslint-disable-next-line security/detect-non-literal-require
const windowsSafariVersion = require(path.join(ROOT_DIR, 'windows/package.json')).safari;
options.targets.safari = windowsSafariVersion;
}
return {
presets: [ [ '@babel/env', options ] ],
exclude: 'node_modules/**'
};
}

class Builder {
constructor(program) {
this.hostOS = thisOS();
Expand Down Expand Up @@ -82,9 +124,51 @@ class Builder {
this.program.gitHash = hash || 'n/a';
}

async transpile() {
// Copy over common dir, @babel/polyfill, etc into some temp dir
// Then run rollup/babel on it, then just copy the resulting bundle to our real destination!
// The temporary location we'll assembled the transpiled bundle
const tmpCommonDir = path.join(TMP_DIR, '_common');

console.log(`Creating temporary 'common' directory...`); // eslint-disable-line quotes
await fs.copy(path.join(ROOT_DIR, 'common'), tmpCommonDir);

// copy over polyfill and its dependencies
console.log('Copying polyfills...');
const modulesDir = path.join(tmpCommonDir, 'Resources/node_modules');
// make sure our 'node_modules' directory exists
await fs.ensureDir(modulesDir);
copyPackageAndDependencies('@babel/polyfill', modulesDir);

// create a bundle
console.log('Transpile and run rollup...');
const babelOptions = determineBabelOptions();
const bundle = await rollup({
input: `${tmpCommonDir}/Resources/ti.main.js`,
plugins: [
resolve(),
commonjs(),
babel(babelOptions)
],
external: [ './app', 'com.appcelerator.aca' ]
});

console.log(`Writing 'common' bundle...`); // eslint-disable-line quotes
await bundle.write({ format: 'cjs', file: `${TMP_DIR}/ti.main.js` });

// We used to have to copy over ti.internal, but it is now bundled into ti.main.js
// if we ever have files there that cannot be bundled or are not hooked up properly, we'll need to copy them here manually.

console.log(`Removing temporary 'common' directory...`); // eslint-disable-line quotes
await fs.remove(tmpCommonDir);
}

async build() {
await this.ensureGitHash();
console.log('Building MobileSDK version %s, githash %s', this.program.sdkVersion, this.program.gitHash);

await this.transpile();

// TODO: build platforms in parallel
for (const item of this.platforms) {
const Platform = require(`./${item}`); // eslint-disable-line security/detect-non-literal-require
Expand Down
90 changes: 4 additions & 86 deletions build/lib/packager.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,15 @@ const os = require('os');
const exec = promisify(require('child_process').exec); // eslint-disable-line security/detect-child-process
const spawn = require('child_process').spawn; // eslint-disable-line security/detect-child-process
const fs = require('fs-extra');
const rollup = require('rollup').rollup;
const babel = require('rollup-plugin-babel');
const resolve = require('rollup-plugin-node-resolve');
const commonjs = require('rollup-plugin-commonjs');
const appc = require('node-appc');
const version = appc.version;
const packageJSON = require('../../package.json');
const utils = require('./utils');
const copyFile = utils.copyFile;
const copyFiles = utils.copyFiles;
const copyPackageAndDependencies = utils.copyPackageAndDependencies;
const moduleCopier = require('./module-copier');

const ROOT_DIR = path.join(__dirname, '../..');
const TMP_DIR = path.join(ROOT_DIR, 'dist', 'tmp');
const SUPPORT_DIR = path.join(ROOT_DIR, 'support');
const V8_STRING_VERSION_REGEXP = /(\d+)\.(\d+)\.\d+\.\d+/;

const TITANIUM_PREP_LOCATIONS = [
'android/titanium_prep.linux32',
Expand Down Expand Up @@ -77,38 +70,6 @@ async function unzip(zipfile, dest) {
});
}

function determineBabelOptions() {
// Pull out android's V8 target (and transform into equivalent chrome version)
// eslint-disable-next-line security/detect-non-literal-require
const v8Version = require(path.join(ROOT_DIR, 'android/package.json')).v8.version;
const found = v8Version.match(V8_STRING_VERSION_REGEXP);
const chromeVersion = parseInt(found[1] + found[2]); // concat the first two numbers as string, then turn to int
// Now pull out min IOS target
// eslint-disable-next-line security/detect-non-literal-require
const minSupportedIosSdk = version.parseMin(require(path.join(ROOT_DIR, 'iphone/package.json')).vendorDependencies['ios sdk']);
// TODO: filter to only targets relevant for platforms we're building?
const options = {
targets: {
chrome: chromeVersion,
ios: minSupportedIosSdk
},
useBuiltIns: 'entry',
// DO NOT include web polyfills!
exclude: [ 'web.dom.iterable', 'web.immediate', 'web.timers' ],
corejs: 2
};
// pull out windows target (if it exists)
if (fs.pathExistsSync(path.join(ROOT_DIR, 'windows/package.json'))) {
// eslint-disable-next-line security/detect-non-literal-require
const windowsSafariVersion = require(path.join(ROOT_DIR, 'windows/package.json')).safari;
options.targets.safari = windowsSafariVersion;
}
return {
presets: [ [ '@babel/env', options ] ],
exclude: 'node_modules/**'
};
}

class Packager {
/**
* @param {String} outputDir path to place the temp files and zipfile
Expand Down Expand Up @@ -152,8 +113,9 @@ class Packager {
this.generateManifestJSON(),
// copy misc dirs/files over
this.copy([ 'CREDITS', 'README.md', 'package.json', 'cli', 'templates' ]),
// transpile/bundle and copy common/ JS files
this.transpile(),
// copy over 'common' bundle
fs.ensureDir(path.join(this.zipSDKDir, 'common', 'Resources')),
fs.copy(path.join(TMP_DIR, 'ti.main.js'), path.join(this.zipSDKDir, 'common', 'Resources', 'ti.main.js')),
// grab down and unzip the native modules
this.includePackagedModules(),
// copy over support/
Expand Down Expand Up @@ -249,50 +211,6 @@ class Packager {
return copyFiles(this.srcDir, this.zipSDKDir, files);
}

async transpile() {
// Copy over common dir, @babel/polyfill, etc into some temp dir
// Then run rollup/babel on it, then just copy the resulting bundle to our real destination!
// The temporary location we'll assembled the transpiled bundle
const tmpBundleDir = path.join(this.zipSDKDir, 'common_temp');

console.log('Copying common SDK JS over');
await fs.copy(path.join(this.srcDir, 'common'), tmpBundleDir);

// copy over polyfill and its dependencies
console.log('Copying JS polyfills over');
const modulesDir = path.join(tmpBundleDir, 'Resources/node_modules');
// make sure our 'node_modules' directory exists
await fs.ensureDir(modulesDir);
copyPackageAndDependencies('@babel/polyfill', modulesDir);

console.log('Transpiling and bundling common SDK JS');
// the ultimate destinatio for our common SDK JS
const destDir = path.join(this.zipSDKDir, 'common');
// create a bundle
console.log('running rollup');
const babelOptions = determineBabelOptions();
const bundle = await rollup({
input: `${tmpBundleDir}/Resources/ti.main.js`,
plugins: [
resolve(),
commonjs(),
babel(babelOptions)
],
external: [ './app', 'com.appcelerator.aca' ]
});

// write the bundle to disk
console.log('Writing common SDK JS bundle to disk');
await bundle.write({ format: 'cjs', file: `${destDir}/Resources/ti.main.js` });

// We used to have to copy over ti.internal, but it is now bundled into ti.main.js
// if we ever have files there that cannot be bundled or are not hooked up properly, we'll need to copy them here manually.

// Remove the temp dir we assembled the parts inside!
console.log('Removing temporary common SDK JS bundle directory');
await fs.remove(tmpBundleDir);
}

async hackTitaniumSDKModule() {
// FIXME Remove these hacks for titanium-sdk when titanium-cli has been released and the tisdk3fixes.js hook is gone!
// Now copy over hacked titanium-sdk fake node_module
Expand Down

0 comments on commit 35aaaab

Please sign in to comment.