Build js in obj and leave dist for the real build

Also make a couple of fixes to ./ui/run-dev-server.

Change-Id: Iff4c9b72c18840503f55f8c93b91c8db146ace87
diff --git a/ui/BUILD.gn b/ui/BUILD.gn
index d66f49b..960f426 100644
--- a/ui/BUILD.gn
+++ b/ui/BUILD.gn
@@ -16,7 +16,7 @@
 import("../gn/wasm.gni")
 import("../protos/perfetto/trace_processor/proto_files.gni")
 
-ui_dist_dir = "$root_build_dir/ui"
+ui_dir = "$root_build_dir/ui"
 nodejs_root = "../buildtools/nodejs"
 nodejs_bin = rebase_path("$nodejs_root/bin", root_build_dir)
 
@@ -25,9 +25,9 @@
 # +----------------------------------------------------------------------------+
 group("ui") {
   deps = [
-    ":bundle",
-    ":index",
-    ":wasm",
+    ":index_release",
+    ":main_bundle_release",
+    ":wasm_release",
   ]
 }
 
@@ -63,16 +63,16 @@
 
 # Bundle together all js sources into a bundle.js file, that will ultimately be
 # included by the .html files.
-node_bin("bundle") {
+node_bin("main_bundle") {
   deps = [
     ":transpile_all_ts",
   ]
   node_cmd = "browserify"
   inputs = [
-    "$ui_dist_dir/main.js",
+    "$target_out_dir/main.js",
   ]
   outputs = [
-    "$ui_dist_dir/bundle.js",
+    "$target_out_dir/bundle.js",
   ]
   args = [
     rebase_path(inputs[0], root_build_dir),
@@ -85,7 +85,7 @@
 # +----------------------------------------------------------------------------+
 # | Protobuf: gen rules to create .js and .d.ts files from protos.             |
 # +----------------------------------------------------------------------------+
-proto_gen_dir = "$ui_dist_dir/gen"
+proto_gen_dir = "$target_out_dir/gen"
 
 node_bin("protos_to_js") {
   inputs = []
@@ -145,7 +145,7 @@
   ]
   inputs = sources + [ "tsconfig.json" ]
   outputs = [
-    "$ui_dist_dir/main.js",
+    "$target_out_dir/main.js",
   ]
 
   # Find all *.ts files and pass them as input triggers. This does NOT affect
@@ -167,23 +167,35 @@
     "--project",
     rebase_path(".", root_build_dir),
     "--outDir",
-    rebase_path(ui_dist_dir, root_build_dir),
+    rebase_path(target_out_dir, root_build_dir),
   ]
 }
 
 # +----------------------------------------------------------------------------+
-# | Copy rules: copy assets into the dist directory.                           |
+# | Copy rules: create the final output directory.                             |
 # +----------------------------------------------------------------------------+
-copy("index") {
+copy("index_release") {
   sources = [
     "index.html",
   ]
   outputs = [
-    "$ui_dist_dir/index.html",
+    "$ui_dir/index.html",
   ]
 }
 
-copy("wasm") {
+copy("main_bundle_release") {
+  deps = [
+    ":main_bundle",
+  ]
+  sources = [
+    "$target_out_dir/bundle.js",
+  ]
+  outputs = [
+    "$ui_dir/bundle.js",
+  ]
+}
+
+copy("wasm_release") {
   deps = [
     "//src/trace_processor:trace_processor.js($wasm_toolchain)",
     "//src/trace_processor:trace_processor.wasm($wasm_toolchain)",
@@ -193,7 +205,7 @@
     "$root_build_dir/wasm/trace_processor.wasm",
   ]
   outputs = [
-    "$ui_dist_dir/wasm/{{source_file_part}}",
+    "$target_out_dir/wasm/{{source_file_part}}",
   ]
 }
 
@@ -224,13 +236,13 @@
     "node_modules",
   ]
   outputs = [
-    "$ui_dist_dir/node_modules",
+    "$target_out_dir/node_modules",
   ]
   script = "../gn/standalone/build_tool_wrapper.py"
   args = [
     "/bin/ln",
     "-fns",
-    rebase_path(inputs[0], ui_dist_dir),
+    rebase_path(inputs[0], target_out_dir),
     rebase_path(outputs[0], root_build_dir),
   ]
 }
@@ -238,7 +250,7 @@
 # Runs npm install.
 action("node_modules") {
   script = "../gn/standalone/build_tool_wrapper.py"
-  stamp_file = "$ui_dist_dir/.$target_name.stamp"
+  stamp_file = "$target_out_dir/.$target_name.stamp"
   args = [
     "--chdir",
     rebase_path(".", root_build_dir),
@@ -271,13 +283,13 @@
 # outDir to "./dist" and create a symlink on the first build.
 action("dist_symlink") {
   script = "../gn/standalone/build_tool_wrapper.py"
-  stamp_file = "$ui_dist_dir/.$target_name.stamp"
+  stamp_file = "$target_out_dir/.$target_name.stamp"
   args = [
     "--stamp",
     rebase_path(stamp_file, root_build_dir),
     "/bin/ln",
     "-fns",
-    rebase_path(ui_dist_dir, "."),
+    rebase_path(target_out_dir, "."),
     rebase_path("dist", root_build_dir),
   ]
   inputs = [
diff --git a/ui/README.md b/ui/README.md
index 5f51020..2830778 100644
--- a/ui/README.md
+++ b/ui/README.md
@@ -18,7 +18,7 @@
 Finally run:
 
 ```
-$ ./ui/run-dev-server
+$ ./ui/run-dev-server out/debug
 ```
 
 and navigate to `localhost:3000`.
diff --git a/ui/bs-config.js b/ui/bs-config.js
index f328b98..61a12e7 100644
--- a/ui/bs-config.js
+++ b/ui/bs-config.js
@@ -21,19 +21,31 @@
 'use strict';
 
 const { spawn } = require('child_process');
+const path = require('path');
 
 // Print without added new line.
 const print = data => process.stdout.write(data);
 const printErr = data => process.stderr.write(data);
 
-const ninjaOutDir = process.env.NINJA_OUT_DIR;
+const ninjaOutDir = process.env.OUT_DIR;
+const uiOutDir = path.join(ninjaOutDir, 'ui');
+const perfettoRoot = process.env.ROOT_DIR;
+const ninjaPath = path.join(perfettoRoot, 'tools', 'ninja');
 let ninjaRunning = false;
 
+function rebasePath(relative_path) {
+  return path.join(perfettoRoot, relative_path);
+}
+
 module.exports = function(bs) {
   return {
     files: [
       {
-        match: ["ui/**", "src/trace_processor/**", "protos/**"],
+        match: [
+          "ui/**",
+          "src/trace_processor/**",
+          "protos/**",
+        ].map(rebasePath),
         fn: function(event, file) {
           console.log(`Change detected on ${file}`);
           if (ninjaRunning) {
@@ -44,7 +56,7 @@
           ninjaRunning = true;
 
           console.log(`Executing: ninja -C ${ninjaOutDir} ui`);
-          const ninja = spawn('ninja', ['-C', ninjaOutDir, 'ui']);
+          const ninja = spawn(ninjaPath, ['-C', ninjaOutDir, 'ui']);
           ninja.stdout.on('data', data => print(data.toString()));
           ninja.stderr.on('data', data => printErr(data.toString()));
 
@@ -57,13 +69,17 @@
           });
         },
         options: {
-          ignored: ["ui/dist/", "ui/.git/", "ui/node_modules/"],
-          ignoreInitial: true
+          ignored: [
+            "ui/dist/",
+            "ui/.git/",
+            "ui/node_modules/",
+          ].map(rebasePath),
+          ignoreInitial: true,
         }
       }
     ],
     server: {
-      baseDir: "ui/dist"
+      baseDir: uiOutDir,
     },
   };
 };
diff --git a/ui/run-dev-server b/ui/run-dev-server
index 465bd76..e42a940 100755
--- a/ui/run-dev-server
+++ b/ui/run-dev-server
@@ -13,22 +13,34 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-CUR_DIR="$(cd -P ${BASH_SOURCE[0]%/*}; pwd)"
-NINJA_OUT_DIR=$(cd $CUR_DIR/$(dirname $(readlink $CUR_DIR/dist)); pwd)
+UI_DIR="$(cd -P ${BASH_SOURCE[0]%/*}; pwd)"
+ROOT_DIR=$(dirname "$UI_DIR")
+NODE=$ROOT_DIR/buildtools/nodejs/bin/node
+LITE="$UI_DIR/node_modules/.bin/lite-server"
 
-LITE_SERVER="$CUR_DIR/node_modules/.bin/lite-server"
-if [ ! -f "$LITE_SERVER" ]; then
+if [ ! -f "$LITE" ]; then
   echo "ERROR: cannot find lite-server. You need to run:"
   echo "  tools/install-build-deps --ui"
   echo "  ninja -C out/xxx ui"
   exit 127
 fi
-if [ ! -L "$CUR_DIR/dist" ]; then
-  echo "ERROR: cannot find the 'dist' symlink. Did you run ninja?"
+if [ -z "$1" ]; then
+  echo "ERROR: no output directory specified."
+  echo "Usage: $0 out/mac_debug"
+  exit 127
+fi
+OUT_DIR="$1"
+UI_OUT_DIR="$OUT_DIR/ui"
+if [ ! -d $OUT_DIR ]; then
+  echo "ERROR: cannot find the output directory (\"$OUT_DIR\")"
+  echo "Did you run ninja?"
+  exit 127
+fi
+if [ ! -d $UI_OUT_DIR ]; then
+  echo "ERROR: cannot find the UI output directory (\"$UI_OUT_DIR\")."
+  echo "Did you run ninja ui?"
   exit 127
 fi
 
-export PATH="$CUR_DIR/../buildtools/nodejs/bin/:$PATH"
-cd "$CUR_DIR/../"
-NINJA_OUT_DIR="$NINJA_OUT_DIR" \
-    node ui/node_modules/.bin/lite-server -c ui/bs-config.js
+OUT_DIR="$OUT_DIR" ROOT_DIR="$ROOT_DIR" $NODE $LITE -c $UI_DIR/bs-config.js
+