Skip to content
This repository has been archived by the owner on Aug 7, 2021. It is now read-only.

Commit

Permalink
Local snapshot support (#181)
Browse files Browse the repository at this point in the history
Introduce support for v8 heap snapshot generation
  • Loading branch information
ivanbuhov authored Jun 14, 2017
1 parent 46519ba commit 1b5dcdc
Show file tree
Hide file tree
Showing 39 changed files with 949 additions and 156 deletions.
6 changes: 6 additions & 0 deletions bin/generate-android-snapshot
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env node
const ProjectSnapshotGenerator = require("../snapshot/android/project-snapshot-generator");
const args = require("../snapshot/android/project-snapshot-generator-cli-ags-parser")();

const generator = new ProjectSnapshotGenerator(args);
generator.generate(args);
1 change: 1 addition & 0 deletions bin/generate-android-snapshot.cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@node %~dp0\generate-android-snapshot %*
31 changes: 23 additions & 8 deletions bin/ns-bundle
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const { spawn } = require("child_process");
const { resolve: pathResolve } = require("path");
const { existsSync } = require("fs");
const { getPackageJson } = require("../projectHelpers");
const { isVersionGte } = require("../utils");

const PROJECT_DIR = pathResolve(__dirname, "../../../");
const packageJson = getPackageJson(PROJECT_DIR);
Expand All @@ -15,6 +16,7 @@ if (!process.env.npm_config_argv) {
const escape = arg => `"${arg}"`;
const isTnsCommand = flag => flag.endsWith("-app");
const shouldUglify = () => process.env.npm_config_uglify;
const shouldSnapshot = (platform) => platform == "android" && require("os").type() != "Windows_NT" && process.env.npm_config_snapshot;

const npmArgs = JSON.parse(process.env.npm_config_argv).original;
const tnsArgs = getTnsArgs(npmArgs).map(escape);
Expand All @@ -28,6 +30,7 @@ function getTnsArgs(args) {
"--android",
"--ios",
"--uglify",
"--snapshot",
"--nobundle",
];

Expand All @@ -37,24 +40,29 @@ function getTnsArgs(args) {
execute(options);

function execute(options) {
let commands = [];
const platform = options.platform;
let commands = [
() => runTns("prepare", platform)
];

if (options.bundle) {
commands = [
...commands,
() => cleanApp(platform),
() => cleanSnapshotArtefacts(),
() => cleanBuildArtifacts(platform),
() => webpack(platform),
];
}

if (shouldSnapshot(platform)) {
commands.push(() => installSnapshotArtefacts());
}

// If "build-app" or "start-app" is specified,
// the respective command should be run last.
// Otherwise, the app should be just prepared.
if (options.command) {
commands.push(() => runTns(options.command, platform));
} else {
commands.shift(() => runTns("prepare", platform))
}
return commands.reduce((current, next) => current.then(next), Promise.resolve());
}
Expand All @@ -65,12 +73,10 @@ function cleanBuildArtifacts(platform) {
return resolve();
}

getTnsVersion().then(versionString => {
const version = versionToNumber(versionString);

getTnsVersion().then(version => {
// the android build artifacts should be cleaned manually
// for nativescript-cli v3.0.1 and below or if using uglify
if (version <= 301 || shouldUglify()) {
if (isVersionGte(version, "3.0.1") || shouldUglify()) {
gradlewClean().then(resolve).catch(throwError);
} else {
return resolve();
Expand All @@ -79,6 +85,14 @@ function cleanBuildArtifacts(platform) {
});
}

function cleanSnapshotArtefacts() {
require("../snapshot/android/project-snapshot-generator").cleanSnapshotArtefacts(PROJECT_DIR);
}

function installSnapshotArtefacts() {
require("../snapshot/android/project-snapshot-generator").installSnapshotArtefacts(PROJECT_DIR);
}

function gradlewClean() {
return new Promise((resolve, reject) => {
const platformsPath = pathResolve(PROJECT_DIR, "platforms", "android")
Expand Down Expand Up @@ -135,6 +149,7 @@ function webpack(platform) {
`--progress`,
`--env.${platform}`,
shouldUglify() && `--env.uglify`,
shouldSnapshot(platform) && `--env.snapshot`
];

spawnChildProcess(...args)
Expand Down
20 changes: 13 additions & 7 deletions bin/update-ns-webpack
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
#!/usr/bin/env node
const path = require("path");
const fs = require("fs");
const { resolve } = require("path");

const helpers = require("../projectHelpers");
const forceUpdateProjectDeps = require("../dependencyManager").forceUpdateProjectDeps;
const { getPackageJson, writePackageJson } = require("../projectHelpers");
const { forceUpdateProjectDeps } = require("../dependencyManager");
const { editExistingProjectFiles } = require("../projectFilesManager");

const PROJECT_DIR = path.resolve(__dirname, "../../../");
const packageJson = helpers.getPackageJson(PROJECT_DIR);
const PROJECT_DIR = resolve(__dirname, "../../../");

console.info("Updating dev dependencies...");
const packageJson = getPackageJson(PROJECT_DIR);
const { deps } = forceUpdateProjectDeps(packageJson);
packageJson.devDependencies = deps;
writePackageJson(packageJson, PROJECT_DIR);

console.info("\nUpdating configuration files...");
editExistingProjectFiles(PROJECT_DIR);

console.info("\nProject successfully updated! Don't forget to run `npm install`");

helpers.writePackageJson(packageJson, PROJECT_DIR);
122 changes: 20 additions & 102 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,84 +1,19 @@
var sources = require("webpack-sources");
var fs = require("fs");
var path = require("path");
const path = require("path");
const { existsSync } = require("fs");

var projectDir = path.dirname(path.dirname(__dirname));
var packageJsonPath = path.join(projectDir, "package.json");
var packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
const { getPackageJson, isAngular } = require("./projectHelpers");
const { sanitize } = require("./utils");

var isAngular = Object.keys(packageJson.dependencies).filter(function (dependency) {
return /^@angular\b/.test(dependency);
}).length > 0;
const PROJECT_DIR = path.dirname(path.dirname(__dirname));
const APP_DIR = path.join(PROJECT_DIR, "app");

Object.assign(exports, require('./plugins'));

if (isAngular) {
exports.UrlResolvePlugin = require("./resource-resolver-plugins/UrlResolvePlugin");
if (isAngular({projectDir: PROJECT_DIR})) {
Object.assign(exports, require('./plugins/angular'));
}

//HACK: changes the JSONP chunk eval function to `global["nativescriptJsonp"]`
// applied to tns-java-classes.js only
exports.NativeScriptJsonpPlugin = function () {
};

exports.NativeScriptJsonpPlugin.prototype.apply = function (compiler) {
compiler.plugin("compilation", function (compilation) {
compilation.plugin("optimize-chunk-assets", function (chunks, callback) {
chunks.forEach(function (chunk) {
chunk.files.forEach(function (file) {
if (file === "vendor.js") {
var src = compilation.assets[file];
var code = src.source();
var match = code.match(/window\["nativescriptJsonp"\]/);
if (match) {
compilation.assets[file] = new sources.ConcatSource(code.replace(/window\["nativescriptJsonp"\]/g, "global[\"nativescriptJsonp\"]"));
}
}
});
});
callback();
});
});
};

exports.GenerateBundleStarterPlugin = function (bundles) {
this.bundles = bundles;
};

exports.GenerateBundleStarterPlugin.prototype = {
apply: function (compiler) {
var plugin = this;
plugin.webpackContext = compiler.options.context;

compiler.plugin("emit", function (compilation, cb) {
compilation.assets["package.json"] = plugin.generatePackageJson();
compilation.assets["starter.js"] = plugin.generateStarterModule();
plugin.generateTnsJavaClasses(compilation);

cb();
});
},
generateTnsJavaClasses: function (compilation) {
const path = compilation.compiler.outputPath;
const isAndroid = path.indexOf("android") > -1;

if (isAndroid) {
compilation.assets["tns-java-classes.js"] = new sources.RawSource("");
}
},
generatePackageJson: function () {
var packageJsonPath = path.join(this.webpackContext, "package.json");
var packageData = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
packageData.main = "starter";

return new sources.RawSource(JSON.stringify(packageData, null, 4));
},
generateStarterModule: function () {
var moduleSource = this.bundles.map(function (bundle) {
return "require(\"" + bundle + "\");";
}).join("\n");
return new sources.RawSource(moduleSource);
},
};
exports.uglifyMangleExcludes = require("./mangle-excludes");

exports.getEntryModule = function () {
const maybePackageJsonEntry = getPackageJsonEntry();
Expand All @@ -90,46 +25,29 @@ exports.getEntryModule = function () {
return maybeAotEntry || maybePackageJsonEntry;
};

exports.getAppPath = function (platform) {
var projectDir = path.dirname(path.dirname(__dirname));

exports.getAppPath = platform => {
if (/ios/i.test(platform)) {
var appName = path.basename(projectDir);
var sanitizedName = appName.split("").filter(function (c) {
return /[a-zA-Z0-9]/.test(c);
}).join("");
return "platforms/ios/" + sanitizedName + "/app";
const appName = path.basename(PROJECT_DIR);
const sanitizedName = sanitize(appName);

return `platforms/ios/${sanitizedName}/app`;
} else if (/android/i.test(platform)) {
return path.join(projectDir, "platforms/android/src/main/assets/app");
return path.join(PROJECT_DIR, "platforms/android/src/main/assets/app");
} else {
throw new Error("Invalid platform: " + platform);
throw new Error(`Invalid platform: ${platform}`);
}
};

exports.uglifyMangleExcludes = require("./mangle-excludes");

function getPackageJsonEntry() {
const packageJsonSource = getAppPackageJsonSource();
const packageJsonSource = getPackageJson(APP_DIR);
const entry = packageJsonSource.main;

return entry ? entry.replace(/\.js$/i, "") : null;
}

function getAppPackageJsonSource() {
const projectDir = getProjectDir();
const appPackageJsonPath = path.join(projectDir, "app", "package.json");

return JSON.parse(fs.readFileSync(appPackageJsonPath, "utf8"));
}

function getAotEntry(entry) {
const aotEntry = `${entry}.aot.ts`;
const projectDir = getProjectDir();
const aotEntryPath = path.join(projectDir, "app", aotEntry);

return fs.existsSync(aotEntryPath) ? aotEntry : null;
}
const aotEntryPath = path.join(APP_DIR, aotEntry);

function getProjectDir() {
return path.dirname(path.dirname(__dirname));
return existsSync(aotEntryPath) ? aotEntry : null;
}
1 change: 0 additions & 1 deletion installer.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ function install() {
const packageJson = helpers.getPackageJson(PROJECT_DIR);

projectFilesManager.addProjectFiles(PROJECT_DIR, APP_DIR);
projectFilesManager.editExistingProjectFiles(PROJECT_DIR);

const scripts = packageJson.scripts || {};
npmScriptsManager.removeDeprecatedNpmScripts(scripts);
Expand Down
1 change: 1 addition & 0 deletions npmScriptsManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const SCRIPT_TEMPLATES = Object.freeze({
"start-[PLATFORM]-bundle": "npm run ns-bundle --[PLATFORM] --run-app",
"build-[PLATFORM]-bundle": "npm run ns-bundle --[PLATFORM] --build-app",
"publish-ios-bundle": "npm run ns-bundle --ios --publish-app",
"generate-android-snapshot": "generate-android-snapshot --projectRoot . --targetArchs arm,arm64 --install"
});

const DEPRECATED_SCRIPT_TEMPLATES = Object.freeze([
Expand Down
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,12 @@
"remove-ns-webpack": "./bin/remove-ns-webpack",
"update-ns-webpack": "./bin/update-ns-webpack",
"ns-bundle": "./bin/ns-bundle",
"ns-verify-bundle": "./bin/ns-verify-bundle"
"ns-verify-bundle": "./bin/ns-verify-bundle",
"generate-android-snapshot": "./bin/generate-android-snapshot"
},
"dependencies": {
"adm-zip": "^0.4.7",
"shelljs": "^0.6.0"
},
"dependencies": {},
"devDependencies": {}
}
47 changes: 47 additions & 0 deletions plugins/GenerateBundleStarterPlugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
const { RawSource } = require("webpack-sources");
const { getPackageJson } = require("../projectHelpers");

exports.GenerateBundleStarterPlugin = (function() {
function GenerateBundleStarterPlugin(bundles) {
this.bundles = bundles;
};

GenerateBundleStarterPlugin.prototype.apply = function(compiler) {
const plugin = this;
plugin.webpackContext = compiler.options.context;

compiler.plugin("emit", function (compilation, cb) {
compilation.assets["package.json"] = plugin.generatePackageJson();
compilation.assets["starter.js"] = plugin.generateStarterModule();
plugin.generateTnsJavaClasses(compilation);

cb();
});
}

GenerateBundleStarterPlugin.prototype.generateTnsJavaClasses = function (compilation) {
const path = compilation.compiler.outputPath;
const isAndroid = path.indexOf("android") > -1;

if (isAndroid && !compilation.assets["tns-java-classes.js"]) {
compilation.assets["tns-java-classes.js"] = new RawSource("");
}
}

GenerateBundleStarterPlugin.prototype.generatePackageJson = function () {
const packageJson = getPackageJson(this.webpackContext);
packageJson.main = "starter";

return new RawSource(JSON.stringify(packageJson, null, 4));
}

GenerateBundleStarterPlugin.prototype.generateStarterModule = function () {
const moduleSource = this.bundles
.map(bundle => `require("${bundle}")`)
.join("\n");

return new RawSource(moduleSource);
}

return GenerateBundleStarterPlugin;
})();
Loading

0 comments on commit 1b5dcdc

Please sign in to comment.