Replies: 1 comment 2 replies
-
I did some recent work to try to simplify our jbrowse CLI, so that it can even be distributed using a single JS file (currently can access it via e.g. unpkg here wget https://unpkg.com/@jbrowse/cli/bundle/index.js -O jbrowse.js) to go even further and not even require node.js the SEA system can be used I asked claude AI to help me create a script to make this SEA executable and it might have worked at least to create a linux binary node_executable_script.sh #!/bin/bash
# Node.js Single Executable Application Builder
# Converts a single JavaScript file into a standalone executable
set -e # Exit on any error
# Function to display usage
show_usage() {
echo "Usage: $0 <input.js> [output_name]"
echo ""
echo "Arguments:"
echo " input.js - Path to the JavaScript file to convert"
echo " output_name - Name for the output executable (optional, defaults to input filename without extension)"
echo ""
echo "Examples:"
echo " $0 hello.js"
echo " $0 myapp.js myapp"
echo ""
exit 1
}
# Check if input file is provided
if [ $# -eq 0 ]; then
echo "Error: No input file specified."
show_usage
fi
INPUT_FILE="$1"
# Check if input file exists
if [ ! -f "$INPUT_FILE" ]; then
echo "Error: Input file '$INPUT_FILE' does not exist."
exit 1
fi
# Determine output name
if [ $# -eq 2 ]; then
OUTPUT_NAME="$2"
else
# Extract filename without extension
OUTPUT_NAME=$(basename "$INPUT_FILE" .js)
fi
# Detect platform
PLATFORM=$(uname)
case "$PLATFORM" in
"Darwin")
PLATFORM_TYPE="macos"
EXECUTABLE_EXT=""
;;
"Linux")
PLATFORM_TYPE="linux"
EXECUTABLE_EXT=""
;;
"MINGW"*|"CYGWIN"*|"MSYS"*)
PLATFORM_TYPE="windows"
EXECUTABLE_EXT=".exe"
OUTPUT_NAME="${OUTPUT_NAME}${EXECUTABLE_EXT}"
;;
*)
echo "Error: Unsupported platform: $PLATFORM"
exit 1
;;
esac
echo "Building single executable application..."
echo "Input file: $INPUT_FILE"
echo "Output name: $OUTPUT_NAME"
echo "Platform: $PLATFORM_TYPE"
echo ""
# Step 1: Create configuration file
CONFIG_FILE="sea-config.json"
BLOB_FILE="sea-prep.blob"
echo "Step 1: Creating configuration file..."
cat > "$CONFIG_FILE" << EOF
{
"main": "$INPUT_FILE",
"output": "$BLOB_FILE",
"disableExperimentalSEAWarning": true
}
EOF
# Step 2: Generate the blob
echo "Step 2: Generating preparation blob..."
node --experimental-sea-config "$CONFIG_FILE"
# Step 3: Create a copy of the node executable
echo "Step 3: Creating copy of Node.js executable..."
if [ "$PLATFORM_TYPE" = "windows" ]; then
node -e "require('fs').copyFileSync(process.execPath, '$OUTPUT_NAME')"
else
cp "$(command -v node)" "$OUTPUT_NAME"
fi
# Step 4: Remove signature (macOS and Windows only)
echo "Step 4: Removing signature..."
if [ "$PLATFORM_TYPE" = "macos" ]; then
if command -v codesign >/dev/null 2>&1; then
codesign --remove-signature "$OUTPUT_NAME"
else
echo "Warning: codesign not found. Signature removal skipped."
fi
elif [ "$PLATFORM_TYPE" = "windows" ]; then
if command -v signtool >/dev/null 2>&1; then
signtool remove /s "$OUTPUT_NAME" 2>/dev/null || echo "Note: signtool signature removal failed or not needed"
else
echo "Note: signtool not found. Signature removal skipped."
fi
fi
# Step 5: Install postject if not available
echo "Step 5: Checking for postject..."
if ! command -v npx >/dev/null 2>&1; then
echo "Error: npx not found. Please install Node.js and npm."
exit 1
fi
# Step 6: Inject the blob
echo "Step 6: Injecting blob into executable..."
SENTINEL_FUSE="NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2"
case "$PLATFORM_TYPE" in
"linux")
npx postject "$OUTPUT_NAME" NODE_SEA_BLOB "$BLOB_FILE" \
--sentinel-fuse "$SENTINEL_FUSE"
;;
"macos")
npx postject "$OUTPUT_NAME" NODE_SEA_BLOB "$BLOB_FILE" \
--sentinel-fuse "$SENTINEL_FUSE" \
--macho-segment-name NODE_SEA
;;
"windows")
npx postject "$OUTPUT_NAME" NODE_SEA_BLOB "$BLOB_FILE" \
--sentinel-fuse "$SENTINEL_FUSE"
;;
esac
# Step 7: Sign the binary (macOS and Windows only)
echo "Step 7: Signing binary..."
if [ "$PLATFORM_TYPE" = "macos" ]; then
if command -v codesign >/dev/null 2>&1; then
codesign --sign - "$OUTPUT_NAME"
else
echo "Warning: codesign not found. Binary signing skipped."
fi
elif [ "$PLATFORM_TYPE" = "windows" ]; then
if command -v signtool >/dev/null 2>&1; then
signtool sign /fd SHA256 "$OUTPUT_NAME" 2>/dev/null || echo "Note: Binary signing skipped (no certificate or signtool failed)"
else
echo "Note: signtool not found. Binary signing skipped."
fi
fi
# Step 8: Make executable (Unix systems)
if [ "$PLATFORM_TYPE" != "windows" ]; then
chmod +x "$OUTPUT_NAME"
fi
# Clean up temporary files
echo "Step 8: Cleaning up temporary files..."
rm -f "$CONFIG_FILE" "$BLOB_FILE"
echo ""
echo "✅ Success! Single executable application created: $OUTPUT_NAME"
echo ""
echo "To run your executable:"
if [ "$PLATFORM_TYPE" = "windows" ]; then
echo " .\\$OUTPUT_NAME"
else
echo " ./$OUTPUT_NAME"
fi
echo ""
# Test if the executable works
echo "Testing executable..."
if [ "$PLATFORM_TYPE" = "windows" ]; then
"./$OUTPUT_NAME" --version 2>/dev/null || echo "Note: Unable to test executable automatically on Windows"
else
"./$OUTPUT_NAME" --version 2>/dev/null || echo "Note: Executable created but may need additional setup"
fi creating the exe
result
|
Beta Was this translation helpful? Give feedback.
2 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
Hello,
For a while we've been using pkg to build the JBrowse CLI tools into standalone executables that we can package with our application, allowing them to be run on any OS without dependencies. pkg is no longer being developed and we've been stuck to using an old version of jbrowse-cli, although this has not really been a limitation.
Does your team have any experience using the native nodejs SEA (https://nodejs.org/api/single-executable-applications.html) or anything else more modern to build portable executables? I see a couple mentions of this in the repo, but no usages I can find.
Beta Was this translation helpful? Give feedback.
All reactions