Swap out the complicated canary stuff for serial execution

Fixes https://github.com/vector-im/riot-web/issues/7386
pull/7355/head
Travis Ralston 4 years ago
parent 27c23058dc
commit 91304e70a1
  1. 2
      README.md
  2. 20
      package.json
  3. 46
      scripts/block-on-sdk-build.js
  4. 99
      scripts/build-watch-sdk.js
  5. 21
      scripts/npm-sub.js

@ -256,6 +256,8 @@ First clone and build `matrix-js-sdk`:
1. `git clone https://github.com/matrix-org/matrix-js-sdk.git`
1. `pushd matrix-js-sdk`
1. `git checkout develop`
1. `npm install`
1. `npm install source-map-loader` # because webpack is made of fail (https://github.com/webpack/webpack/issues/1472)
1. `popd`
Then similarly with `matrix-react-sdk`:

@ -36,22 +36,22 @@
"build:bundle": "cross-env NODE_ENV=production webpack -p --progress --bail",
"build:bundle:dev": "webpack --optimize-occurence-order --progress --bail",
"build:electron": "npm run clean && npm run build && npm run install:electron && build -wml --ia32 --x64",
"build:react-sdk": "node scripts/build-watch-sdk.js build react",
"build:js-sdk": "node scripts//build-watch-sdk.js build js",
"build:react-sdk": "node scripts/npm-sub.js matrix-react-sdk run start:init",
"build:js-sdk": "node scripts/npm-sub.js matrix-js-sdk run start:init",
"build": "npm run build:js-sdk && npm run build:react-sdk && npm run reskindex && npm run build:res && npm run build:bundle",
"build:dev": "npm run build:js-sdk && npm run build:react-sdk && npm run reskindex && npm run build:res && npm run build:bundle:dev",
"dist": "scripts/package.sh",
"install:electron": "install-app-deps",
"electron": "npm run install:electron && electron .",
"start:res": "node scripts/copy-res.js -w",
"start:js": "node scripts/block-on-sdk-build.js js && node scripts/block-on-sdk-build.js react && webpack-dev-server --output-filename=bundles/_dev_/[name].js --output-chunk-file=bundles/_dev_/[name].js -w --progress",
"start:js:prod": "cross-env NODE_ENV=production node scripts/block-on-sdk-build.js js && node scripts/block-on-sdk-build.js react && webpack-dev-server -w --progress",
"start:js-sdk": "node scripts/build-watch-sdk.js watch js",
"start:js-sdk:prod": "cross-env NODE_ENV=production node && scripts/build-watch-sdk.js watch js",
"start:react-sdk": "node scripts/block-on-sdk-build.js js && node scripts/build-watch-sdk.js watch react",
"start:react-sdk:prod": "cross-env NODE_ENV=production node && scripts/block-on-sdk-build.js js && node scripts//build-watch-sdk.js watch react",
"start": "concurrently --kill-others-on-fail --prefix \"{time} [{name}]\" -n js-sdk,react-sdk,reskindex,res,riot-js \"npm run start:js-sdk\" \"npm run start:react-sdk\" \"npm run reskindex:watch\" \"npm run start:res\" \"npm run start:js\"",
"start:prod": "concurrently --kill-others-on-fail --prefix \"{time} [{name}]\" -n js-sdk,react-sdk,reskindex,res,riot-js \"npm run start:js-sdk:prod\" \"npm run start:react-sdk:prod\" \"npm run reskindex:watch\" \"npm run start:res\" \"npm run start:js:prod\"",
"start:js": "webpack-dev-server --output-filename=bundles/_dev_/[name].js --output-chunk-file=bundles/_dev_/[name].js -w --progress",
"start:js:prod": "cross-env NODE_ENV=production webpack-dev-server -w --progress",
"start:js-sdk": "node scripts/npm-sub.js matrix-js-sdk run start:watch",
"start:js-sdk:prod": "cross-env NODE_ENV=production node scripts/npm-sub.js matrix-js-sdk run start:watch",
"start:react-sdk": "node scripts/npm-sub.js matrix-react-sdk run start:all",
"start:react-sdk:prod": "cross-env NODE_ENV=production node scripts/npm-sub.js matrix-react-sdk run start:all",
"start": "npm run build:js-sdk && npm run build:react-sdk && concurrently --kill-others-on-fail --prefix \"{time} [{name}]\" -n js-sdk,react-sdk,reskindex,res,riot-js \"npm run start:js-sdk\" \"npm run start:react-sdk\" \"npm run reskindex:watch\" \"npm run start:res\" \"npm run start:js\"",
"start:prod": "npm run build:js-sdk && npm run build:react-sdk && concurrently --kill-others-on-fail --prefix \"{time} [{name}]\" -n js-sdk,react-sdk,reskindex,res,riot-js \"npm run start:js-sdk:prod\" \"npm run start:react-sdk:prod\" \"npm run reskindex:watch\" \"npm run start:res\" \"npm run start:js:prod\"",
"lint": "eslint src/",
"lintall": "eslint src/ test/",
"clean": "rimraf lib webapp electron_app/dist",

@ -1,46 +0,0 @@
const path = require('path');
const chokidar = require('chokidar');
// This script waits for a signal that an underlying SDK (js or react) has finished
// enough of the build process to be safe to rely on. In riot-web's case, this means
// that the underlying SDK has finished an initial build and is getting ready to watch
// for changes. This is done through use of a canary file that is deleted when it is
// safe to continue (see build-watch-sdk.js for why we listen for a delete event).
// Why do we block in the first place? Because if riot-web starts it's initial
// build (via webpack-dev-server) and the react-sdk or js-sdk are halfway through
// their initial builds, then riot-web's initial build fails out of the box. This
// can sometimes be corrected by waiting for the SDK build to complete and triggering
// a file change, thereby causing a cascading build, however it isn't great if the
// initial build of riot-web fails out of the box. We block at the js-sdk first so
// that the react-sdk build doesn't fall victim to the same problem, which also
// slows down the riot-web build. After the js-sdk completes, we start the react-sdk
// build which riot-web is waiting for. When complete, riot-web starts building as
// per normal.
function waitForCanary(canaryName) {
return new Promise((resolve, reject) => {
const filename = path.resolve(path.join(".tmp", canaryName + ".canary"));
// See build-watch-sdk.js for why we listen for 'unlink' specifically.
const watcher = chokidar.watch(filename).on('unlink', (path) => {
console.log("[block-on-build] Received signal to start watching for builds");
watcher.close();
resolve();
});
});
}
const sdkName = process.argv[2];
if (!sdkName) {
console.error("[block-on-build] No SDK name provided");
process.exit(1);
}
console.log("[block-on-build] Waiting for SDK: " + sdkName);
waitForCanary(sdkName).then(() => {
console.log("[block-on-build] Unblocked");
process.exit(0);
});

@ -1,99 +0,0 @@
const fs = require('fs');
const path = require('path');
const child_process = require('child_process');
const task = process.argv[2];
if (task !== "build" && task !== "watch") {
console.error("Expected a task of 'build' or 'watch'");
process.exit(1);
}
const sdkName = process.argv[3];
if (!sdkName) {
console.error("Missing SDK name");
process.exit(1);
}
const sdkPath = path.dirname(require.resolve(`matrix-${sdkName}-sdk/package.json`));
// Note: we intentionally create then delete the canary file to work
// around a file watching problem where if the file exists on startup it
// may fire a "created" event for the file. By having the behaviour be "do
// something on delete" we avoid accidentally firing the signal too early.
// We also need to ensure the create and delete events are not too close
// together, otherwise the filesystem may not fire the watcher. Therefore
// we create the canary as early as possible and delete it as late as possible.
prepareCanarySignal(sdkName);
// We only want to build the SDK if it looks like it was `npm link`ed
if (fs.existsSync(path.join(sdkPath, '.git'))) {
// Install the develop dependencies just in case they were forgotten by the developer.
console.log("Installing develop dependencies");
const devEnv = Object.assign({}, process.env, {NODE_ENV: "development"});
child_process.execSync("npm install --only=dev", {
env: devEnv,
cwd: sdkPath,
});
// Because webpack is made of fail
if (sdkName === "js") {
console.log("Installing source-map-loader");
child_process.execSync("npm install source-map-loader", {
env: devEnv,
cwd: sdkPath,
});
}
// Prepare an initial build of the SDK
child_process.execSync("npm run start:init", {
env: process.env,
cwd: sdkPath,
});
// Send a signal to unblock the build for other processes. Used by block-on-sdk-build.js
console.log("Sending signal that other processes may unblock");
triggerCanarySignal(sdkName);
// Actually start the watcher process for the SDK (without an initial build)
console.log("Performing task: " + task);
const watchTask = sdkName === 'js' ? "start:watch" : "start:all";
const buildTask = "build";
child_process.execSync(`npm run ${task === "build" ? buildTask : watchTask}`, {
env: process.env,
cwd: sdkPath,
});
} else triggerCanarySignal(sdkName);
function triggerCanarySignal(sdkName) {
fs.unlinkSync(getCanaryPath(sdkName));
}
function prepareCanarySignal(sdkName) {
const canaryPath = getCanaryPath(sdkName);
const canaryDir = path.dirname(canaryPath);
try {
console.log("Creating canary temp path...");
fs.mkdirSync(canaryDir);
} catch (e) {
if (e.code !== 'EEXIST') {
console.error(e);
throw "Failed to create temporary directory";
}
}
try {
console.log("Creating canary file: " + canaryPath);
fs.closeSync(fs.openSync(canaryPath, 'w'));
} catch (e) {
if (e.code !== 'EEXIST') {
console.error(e);
throw "Failed to create canary file";
}
}
}
function getCanaryPath(sdkName) {
return path.join(path.resolve(".tmp"), sdkName + ".canary");
}

@ -0,0 +1,21 @@
const path = require('path');
const child_process = require('child_process');
const moduleName = process.argv[2];
if (!moduleName) {
console.error("Expected module name");
process.exit(1);
}
const argString = process.argv.length > 3 ? process.argv.slice(3).join(" ") : "";
if (!argString) {
console.error("Expected an npm argument string to use");
process.exit(1);
}
const modulePath = path.dirname(require.resolve(`${moduleName}/package.json`));
child_process.execSync("npm " + argString, {
env: process.env,
cwd: modulePath,
});
Loading…
Cancel
Save