Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TIMOB-24610] Support transpiling user JS code to ES5, or minimum target OS/JS engine support #9512

Merged
merged 13 commits into from
Jan 29, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 8 additions & 1 deletion android/build/common.xml
Original file line number Diff line number Diff line change
Expand Up @@ -706,7 +706,14 @@ Common ant tasks and macros for building Android-based Titanium modules and proj
</target>

<target name="update.libv8">
<property file="${ti.build.dir}/libv8.properties"/>
<exec executable="node" dir="${ti.build.dir}" outputproperty="libv8.version">
<arg value="-p"/>
<arg value="require('../package.json').v8.version"/>
</exec>
<exec executable="node" dir="${ti.build.dir}" outputproperty="libv8.mode">
<arg value="-p"/>
<arg value="require('../package.json').v8.mode"/>
</exec>
<property name="dist.libv8.dir" location="${dist.dir}/libv8/${libv8.version}/${libv8.mode}"/>
<property name="libv8.archive" value="libv8-${libv8.version}-${libv8.mode}.tar.bz2"/>
<mkdir dir="${dist.libv8.dir}"/>
Expand Down
2 changes: 0 additions & 2 deletions android/build/libv8.properties

This file was deleted.

51 changes: 34 additions & 17 deletions android/cli/commands/_build.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@ const ADB = require('node-titanium-sdk/lib/adb'),
appc = require('node-appc'),
archiver = require('archiver'),
async = require('async'),
babel = require('babel-core'),
Builder = require('../lib/base-builder.js'),
CleanCSS = require('clean-css'),
DOMParser = require('xmldom').DOMParser,
ejs = require('ejs'),
EmulatorManager = require('node-titanium-sdk/lib/emulator'),
env = require('babel-preset-env'),
fields = require('fields'),
fs = require('fs'),
i18n = require('node-titanium-sdk/lib/i18n'),
Expand All @@ -46,7 +48,8 @@ const ADB = require('node-titanium-sdk/lib/adb'),
i18nLib = appc.i18n(__dirname),
__ = i18nLib.__,
__n = i18nLib.__n,
version = appc.version;
version = appc.version,
V8_STRING_VERSION_REGEXP = /(\d+)\.(\d+)\.\d+\.\d+/;

function AndroidBuilder() {
Builder.apply(this, arguments);
Expand Down Expand Up @@ -2699,27 +2702,41 @@ AndroidBuilder.prototype.copyResources = function copyResources(next) {
try {
this.cli.createHook('build.android.copyResource', this, function (from, to, cb) {
// parse the AST
const r = jsanalyze.analyzeJsFile(from, { minify: this.minifyJS });
const originalContents = fs.readFileSync(from).toString();
const r = jsanalyze.analyzeJs(originalContents, { minify: this.minifyJS, filename: from });

// we want to sort by the "to" filename so that we correctly handle file overwriting
this.tiSymbols[to] = r.symbols;

const dir = path.dirname(to);
fs.existsSync(dir) || wrench.mkdirSyncRecursive(dir);

if (this.minifyJS) {
this.logger.debug(__('Copying and minifying %s => %s', from.cyan, to.cyan));
// Now transpile too!
this.cli.createHook('build.android.compileJsFile', this, function (r, from, to, cb2) {
const dir = path.dirname(to);
fs.existsSync(dir) || wrench.mkdirSyncRecursive(dir);
// We get a string here like 6.2.414.36, we need to convert it to 62 (integer)
const v8Version = this.packageJson.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
const result = babel.transform(r.contents, {
filename: from,
presets: [
[ env, {
'targets': {
'chrome': chromeVersion,
}
}]
]
});
const newContents = result.code;

this.cli.createHook('build.android.compileJsFile', this, function (r, from, to, cb2) {
fs.writeFile(to, r.contents, cb2);
})(r, from, to, cb);
} else if (symlinkFiles) {
copyFile.call(this, from, to, cb);
} else {
// we've already read in the file, so just write the original contents
this.logger.debug(__('Copying %s => %s', from.cyan, to.cyan));
fs.writeFile(to, r.contents, cb);
}
// If we're able to symlink and the contents didn't change, great let's just symlink
if (symlinkFiles && newContents === originalContents) {
copyFile.call(this, from, to, cb2);
} else {
// code changed or we can't symlink. Either way, write the file to dest
this.logger.debug(__('Copying %s => %s', from.cyan, to.cyan));
fs.writeFile(to, newContents, cb2);
}
})(r, from, to, cb);
})(from, to, done);
} catch (ex) {
ex.message.split('\n').forEach(this.logger.error);
Expand Down
4 changes: 4 additions & 0 deletions android/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
"Chris Barber <cbarber@appcelerator.com>"
],
"architectures": ["arm64-v8a", "armeabi-v7a", "x86"],
"v8": {
"version": "6.2.414.36",
"mode": "release"
},
"minSDKVersion": "16",
"compileSDKVersion": "26",
"vendorDependencies": {
Expand Down
11 changes: 7 additions & 4 deletions android/runtime/v8/src/ndk-modules/libv8/Android.mk
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@
# libv8 (for both ARMv5 and ARMv7a)
LOCAL_PATH := $(call my-dir)

define GetFromPkg
$(shell node -p "require('$(LOCAL_PATH)/../../../../../package.json').$(1)")
endef

include $(CLEAR_VARS)

# Read android/build/libv8.properties to get v8 version and mode (release or debug)
include $(LOCAL_PATH)/../../../../../build/libv8.properties
V8_VERSION=$(libv8.version)
LIBV8_MODE := $(libv8.mode)
# Read android/package.json to get v8 version and mode (release or debug)
V8_VERSION=$(call GetFromPkg,v8.version)
LIBV8_MODE := $(call GetFromPkg,v8.mode)
LIBV8_DIR := $(TI_DIST_DIR)/android/libv8/$(V8_VERSION)/$(LIBV8_MODE)

# https://jira.appcelerator.org/browse/TIMOB-15263
Expand Down
15 changes: 2 additions & 13 deletions build/android.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,6 @@ const path = require('path'),
copyAndModifyFile = utils.copyAndModifyFile,
globCopy = utils.globCopy;

function readProperties(filepath) {
var contents = fs.readFileSync(filepath).toString().replace(/\r\n/g, '\n'),
regexp = /^([^=]+)\s*=\s*(.+)$/gm,
matches,
result = {};
while ((matches = regexp.exec(contents))) {
result[matches[1]] = matches[2];
}
return result;
}

/**
* @param {Object} options options object
* @param {String} options.androidSdk path to the Android SDK to build with
Expand Down Expand Up @@ -89,8 +78,8 @@ Android.prototype.package = function (packager, next) {
globCopy('**/*.h', path.join(ANDROID_ROOT, 'runtime', 'v8', 'generated'), path.join(ANDROID_DEST, 'native', 'include'), cb);
},
function (cb) {
const v8Props = readProperties(path.join(ANDROID_ROOT, 'build', 'libv8.properties')),
src = path.join(DIST_ANDROID, 'libv8', v8Props['libv8.version'], v8Props['libv8.mode'], 'include');
const v8Props = require(path.join(ANDROID_ROOT, 'package.json')).v8, // eslint-disable-line security/detect-non-literal-require
src = path.join(DIST_ANDROID, 'libv8', v8Props.version, v8Props.mode, 'include');
globCopy('**/*.h', src, path.join(ANDROID_DEST, 'native', 'include'), cb);
},
// add js2c.py for js -> C embedding
Expand Down
83 changes: 51 additions & 32 deletions iphone/cli/commands/_build.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@

const appc = require('node-appc'),
async = require('async'),
babel = require('babel-core'),
bufferEqual = require('buffer-equal'),
Builder = require('node-titanium-sdk/lib/builder'),
CleanCSS = require('clean-css'),
crypto = require('crypto'),
cyan = require('colors').cyan,
DOMParser = require('xmldom').DOMParser,
env = require('babel-preset-env'),
ejs = require('ejs'),
fields = require('fields'),
fs = require('fs'),
Expand Down Expand Up @@ -5778,47 +5780,64 @@ iOSBuilder.prototype.copyResources = function copyResources(next) {
this.jsFilesToEncrypt.push(file);
}

this.cli.createHook('build.ios.copyResource', this, function (from, to, cb) {
let r;
try {
try {
this.cli.createHook('build.ios.copyResource', this, function (from, to, cb) {
const originalContents = fs.readFileSync(from).toString();
// parse the AST
r = jsanalyze.analyzeJsFile(from, { minify: this.minifyJS });
} catch (ex) {
ex.message.split('\n').forEach(this.logger.error);
this.logger.log();
process.exit(1);
}
const r = jsanalyze.analyzeJs(originalContents, { minify: this.minifyJS, filename: from });

// we want to sort by the "to" filename so that we correctly handle file overwriting
this.tiSymbols[to] = r.symbols;
// we want to sort by the "to" filename so that we correctly handle file overwriting
this.tiSymbols[to] = r.symbols;

const dir = path.dirname(to);
fs.existsSync(dir) || wrench.mkdirSyncRecursive(dir);
// Now transpile too!
this.cli.createHook('build.ios.compileJsFile', this, function (r, from, to, cb2) {
const dir = path.dirname(to);
fs.existsSync(dir) || wrench.mkdirSyncRecursive(dir);

this.unmarkBuildDirFile(to);
this.unmarkBuildDirFile(to);

if (this.minifyJS) {
this.cli.createHook('build.ios.compileJsFile', this, function (r, from, to, cb2) {
const exists = fs.existsSync(to);
if (!exists || r.contents !== fs.readFileSync(to).toString()) {
this.logger.debug(__('Copying and minifying %s => %s', from.cyan, to.cyan));
exists && fs.unlinkSync(to);
fs.writeFileSync(to, r.contents);
this.jsFilesChanged = true;
// generate our transpile target based on tijscore/jscore
const presets = this.useJSCore ? [[ env, {
'targets': {
'ios': this.minSupportedIosSdk // if using jscore, target our min ios version
}
}]] : [ env ]; // if not jscore, just transpile everything down (no target)
const result = babel.transform(r.contents, {
filename: from,
presets: presets
});
const newContents = result.code;

// if we didn't change the contents any...
if (newContents === originalContents) {
if (this.copyFileSync(from, to)) { // copy/symlink if necessary
this.jsFilesChanged = true;
} else { // possibly no need to copy/change, so we skipped entirely!
this.logger.trace(__('No change, skipping %s', to.cyan));
}
} else {
this.logger.trace(__('No change, skipping %s', to.cyan));
// contents definitely changed from source file...
const exists = fs.existsSync(to);
// check if dest file already exists and has same modified contents
if (!exists || newContents !== fs.readFileSync(to).toString()) {
// dest doesn't exist or it's different, so let's write the new file
this.logger.debug(__('Copying and minifying %s => %s', from.cyan, to.cyan));
exists && fs.unlinkSync(to);
fs.writeFileSync(to, newContents);
this.jsFilesChanged = true;
} else {
// so we changed from the source file, but we already wrote teh modified contents before and that didn't change
this.logger.trace(__('No change, skipping %s', to.cyan));
}
}
cb2();
})(r, from, to, cb);
} else {
if (this.copyFileSync(from, to)) {
this.jsFilesChanged = true;
} else {
this.logger.trace(__('No change, skipping %s', to.cyan));
}
cb();
}
})(info.src, info.dest, next);
})(info.src, info.dest, next);
} catch (ex) {
ex.message.split('\n').forEach(this.logger.error);
this.logger.log();
process.exit(1);
}
}.bind(this));
}.bind(this), next);
},
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
"appc-tasks": "^1.0.1",
"archiver": "2.1.0",
"async": "2.3.0",
"babel-core": "^6.26.0",
"babel-preset-env": "^1.6.1",
"buffer-equal": "1.0.0",
"clean-css": "4.0.11",
"colors": "1.1.2",
Expand Down