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 <jviotti@openmailbox.org>
This commit is contained in:
Juan Cruz Viotti 2017-05-11 15:37:45 -04:00 committed by GitHub
parent b02da2d0cd
commit 9c055fb165
5 changed files with 51 additions and 4 deletions

1
.gitattributes vendored
View File

@ -23,6 +23,7 @@ Makefile text
*.bat text
*.svg text
*.yml text
*.patch text
# Binary files (no line-ending conversions)
*.bz2 binary diff=hex

View File

@ -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 $</lib/cli/etcher.js -o $@ -m
./scripts/build/concatenate-javascript.sh -e lib/cli/etcher.js -b $< -o $@ -m
$(BUILD_DIRECTORY)/$(APPLICATION_NAME)-cli-$(APPLICATION_VERSION)-$(TARGET_PLATFORM)-$(TARGET_ARCH): \
$(BUILD_DIRECTORY)/node-$(TARGET_PLATFORM)-$(TARGET_ARCH)-dependencies \

View File

@ -0,0 +1,17 @@
diff --git a/index.js b/index.js
index 1e7c766..e42c513 100644
--- a/index.js
+++ b/index.js
@@ -7,11 +7,8 @@ var extend = require('util-extend');
var assert = require('assert');
var fs = require('fs');
-// node-pre-gyp magic
-var nodePreGyp = require('node-pre-gyp');
var path = require('path');
-var binding_path = nodePreGyp.find(path.resolve(path.join(__dirname,'./package.json')));
-var native = require(binding_path);
+var native = require(path.join(__dirname, 'binding', 'lzma_native.node'));
extend(exports, native);

View File

@ -29,29 +29,56 @@ function usage() {
echo "Options"
echo ""
echo " -e <entry point (.js)>"
echo " -b <base directory>"
echo " -o <output>"
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 <<EOF > "$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"

View File

@ -51,6 +51,7 @@ rsync \
--prune-empty-dirs \
--progress \
--include='*.node' \
--include='*.dll' \
--include='*/' \
--exclude='*' \
"$ARGV_NODE_MODULES" "$ARGV_OUTPUT_DIRECTORY"