From 9c055fb165a9da91207f06a32cab7036f67e7136 Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Thu, 11 May 2017 15:37:45 -0400 Subject: [PATCH] fix(CLI): workaround absolute paths in Browserify bundles (#1409) For some strange reason, Browserify will hardcode absolute paths from the machine that generated the bundle to be able to resolve `__dirname` and `__filename` calls. This makes no sense, given that it means that the Browserify bundle will not work when we move it to another machine, which went undetected probably for months. The Browserify community apparently makes modules to fix this particular issue (like `bundle-collapser`, and `intreq`), however none of this seem to solve the problem for the Etcher CLI bundle. I also gave https://github.com/zeit/pkg a go, however I gave up after not being able to make use of native modules (nothing seems to work; the packager result will simply not find the addons). Finally, I ended up making the following workarounds: - Edit the Browserify bundle file to use its own `__dirname` to dynamically resolve the values of `__dirname` and `__filename` of the files it contains - Patch `lzma-native` to statically require its add-on rather than relying on dynamic requires from `node-pre-gyp`, which makes it impossible to resolve on the final bundle See: https://github.com/resin-io/etcher/issues/355 See: http://stackoverflow.com/questions/21993073/browserify-with-paths-to-folders-in-my-system Signed-off-by: Juan Cruz Viotti --- .gitattributes | 1 + Makefile | 3 +- ...ma-native-index-static-addon-require.patch | 17 ++++++++++ scripts/build/concatenate-javascript.sh | 33 +++++++++++++++++-- .../build/dependencies-npm-extract-addons.sh | 1 + 5 files changed, 51 insertions(+), 4 deletions(-) create mode 100644 patches/cli/lzma-native-index-static-addon-require.patch diff --git a/.gitattributes b/.gitattributes index 0984c995..ad33d3a1 100644 --- a/.gitattributes +++ b/.gitattributes @@ -23,6 +23,7 @@ Makefile text *.bat text *.svg text *.yml text +*.patch text # Binary files (no line-ending conversions) *.bz2 binary diff=hex diff --git a/Makefile b/Makefile index 3bc4b2d7..b3456918 100644 --- a/Makefile +++ b/Makefile @@ -197,6 +197,7 @@ $(BUILD_DIRECTORY)/node-$(TARGET_PLATFORM)-$(TARGET_ARCH)-dependencies: package. -x $@ \ -t node \ -s "$(TARGET_PLATFORM)" + git apply --directory $@/node_modules/lzma-native patches/cli/lzma-native-index-static-addon-require.patch $(BUILD_DIRECTORY)/electron-$(TARGET_PLATFORM)-$(APPLICATION_VERSION)-$(TARGET_ARCH)-app: \ $(BUILD_DIRECTORY)/electron-$(TARGET_PLATFORM)-$(TARGET_ARCH)-dependencies \ @@ -247,7 +248,7 @@ $(BUILD_DIRECTORY)/$(APPLICATION_NAME)-cli-$(TARGET_PLATFORM)-$(APPLICATION_VERS $(BUILD_DIRECTORY)/$(APPLICATION_NAME)-cli-$(TARGET_PLATFORM)-$(APPLICATION_VERSION)-$(TARGET_ARCH).js: \ $(BUILD_DIRECTORY)/$(APPLICATION_NAME)-cli-$(TARGET_PLATFORM)-$(APPLICATION_VERSION)-$(TARGET_ARCH)-app \ | $(BUILD_DIRECTORY) - ./scripts/build/concatenate-javascript.sh -e $" + echo " -b " echo " -o " echo " -m minify" exit 1 } ARGV_ENTRY_POINT="" +ARGV_BASE_DIRECTORY="" ARGV_OUTPUT="" ARGV_MINIFY=false -while getopts ":e:o:m" option; do +while getopts ":e:b:o:m" option; do case $option in e) ARGV_ENTRY_POINT=$OPTARG ;; + b) ARGV_BASE_DIRECTORY=$OPTARG ;; o) ARGV_OUTPUT=$OPTARG ;; m) ARGV_MINIFY=true ;; *) usage ;; esac done -if [ -z "$ARGV_ENTRY_POINT" ] || [ -z "$ARGV_OUTPUT" ]; then +if [ -z "$ARGV_ENTRY_POINT" ] || + [ -z "$ARGV_BASE_DIRECTORY" ] || + [ -z "$ARGV_OUTPUT" ]; then usage fi -"$BROWSERIFY" "$ARGV_ENTRY_POINT" --node --outfile "$ARGV_OUTPUT" +"$BROWSERIFY" "$ARGV_BASE_DIRECTORY/$ARGV_ENTRY_POINT" --node --outfile "$ARGV_OUTPUT" + +# This hack workarounds the fact the Browserify stores absolute paths +# of the machine that was used to produce the bundle, giving "not found" +# module errors when executing it in another computer. +# The fix is to replace absolute paths with `__dirname` +node < "$ARGV_OUTPUT.TMP" +const separator = process.platform === 'win32' ? '\\\\\\\\\\\\\\\\' : '\\/'; +const baseDirectory = process.platform === 'win32' + ? "$ARGV_BASE_DIRECTORY".replace(/\//g, separator) + : "$ARGV_BASE_DIRECTORY"; + +const regex = new RegExp('"(.)+' + baseDirectory.replace(/\+/g, '\\\\+') + separator, 'g'); +const contents = require('fs').readFileSync("$ARGV_OUTPUT", { encoding: 'utf8' }); + +console.log(contents.split('\n').map((line) => { + if (!regex.test(line)) return line; + return line + .replace(regex, 'require("path").join(__dirname,"') + .replace(new RegExp(separator, 'g'), '","') + ')'; +}).join('\n')); +EOF +mv "$ARGV_OUTPUT.TMP" "$ARGV_OUTPUT" if [ "$ARGV_MINIFY" == "true" ]; then uglifyjs --compress --output "$ARGV_OUTPUT.MIN" -- "$ARGV_OUTPUT" diff --git a/scripts/build/dependencies-npm-extract-addons.sh b/scripts/build/dependencies-npm-extract-addons.sh index 831368a0..2c88f505 100755 --- a/scripts/build/dependencies-npm-extract-addons.sh +++ b/scripts/build/dependencies-npm-extract-addons.sh @@ -51,6 +51,7 @@ rsync \ --prune-empty-dirs \ --progress \ --include='*.node' \ + --include='*.dll' \ --include='*/' \ --exclude='*' \ "$ARGV_NODE_MODULES" "$ARGV_OUTPUT_DIRECTORY"