Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,17 @@ jobs:
working-directory: server
run: npm pack

- name: Build standalone binary
working-directory: server
run: npm run build:standalone

- name: Stage server release files
run: |
mkdir server-release
cp server/openmodelica-modelica-language-server-*.tgz server-release/
cp server/src/tree-sitter-modelica.wasm server-release/
cp server/out/modelica-language-server server-release/modelica-language-server-linux-x64
cp server/out/web-tree-sitter.wasm server-release/

- name: Archive server release files
uses: actions/upload-artifact@v7
Expand Down Expand Up @@ -107,6 +113,8 @@ jobs:
modelica-language-server-*.vsix
server-release/openmodelica-modelica-language-server-*.tgz
server-release/tree-sitter-modelica.wasm
server-release/web-tree-sitter.wasm
server-release/modelica-language-server-linux-x64
fail_on_unmatched_files: true
generate_release_notes: true
append_body: true
Expand Down
27 changes: 27 additions & 0 deletions server/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,14 @@
"scripts": {
"build": "node esbuild.config.js",
"build:watch": "node esbuild.config.js --watch",
"build:standalone": "npm run build && node scripts/build-standalone.js",
"prepack": "npm run build",
"prepublishOnly": "npm run build"
},
"devDependencies": {
"@types/node": "^25.9.1",
"esbuild": "^0.28.0",
"postject": "^1.0.0-alpha.6",
"tsx": "^4.19.0",
"typescript": "^6.0.0"
},
Expand Down
70 changes: 70 additions & 0 deletions server/scripts/build-standalone.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/usr/bin/env node
/**
* Build a Node.js Single Executable Application (SEA) for the language server.
* Produces out/modelica-language-server[.exe] alongside the existing WASM files.
* Requires Node.js >= 20 and postject (dev dependency).
*
* Usage: node scripts/build-standalone.js
*/

'use strict';

const { execFileSync, execSync } = require('child_process');
const fs = require('fs');
const path = require('path');

const OUT_DIR = path.join(__dirname, '..', 'out');
const SEA_CONFIG = path.join(__dirname, '..', 'sea-config.json');
const BLOB = path.join(OUT_DIR, 'sea-prep.blob');
const IS_WIN = process.platform === 'win32';
const IS_MAC = process.platform === 'darwin';
const BINARY_NAME = IS_WIN ? 'modelica-language-server.exe' : 'modelica-language-server';
const OUT_BINARY = path.join(OUT_DIR, BINARY_NAME);
const POSTJECT = path.join(__dirname, '..', 'node_modules', '.bin', 'postject');

function run(cmd, args, opts) {
console.log(` $ ${cmd} ${args.join(' ')}`);
execFileSync(cmd, args, { stdio: 'inherit', ...opts });
}

// 1. Generate the SEA preparation blob.
console.log('\n[1/4] Generating SEA blob...');
run(process.execPath, ['--experimental-sea-config', SEA_CONFIG]);

// 2. Copy the current node binary as the carrier.
console.log('\n[2/4] Copying node binary...');
fs.copyFileSync(process.execPath, OUT_BINARY);
fs.chmodSync(OUT_BINARY, 0o755);

// 3. Remove existing code signature on macOS (required before injection).
if (IS_MAC) {
console.log('\n[2b] Removing macOS code signature...');
run('codesign', ['--remove-signature', OUT_BINARY]);
}

// 4. Inject the blob.
console.log('\n[3/4] Injecting SEA blob with postject...');
const postjectArgs = [
OUT_BINARY,
'NODE_SEA_BLOB',
BLOB,
'--sentinel-fuse', 'NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2',
];
if (IS_MAC) {
postjectArgs.push('--macho-segment-name', 'NODE_SEA');
}
run(POSTJECT, postjectArgs);

// 4. Re-sign on macOS (ad-hoc, sufficient for local use; CI can use a real identity).
if (IS_MAC) {
console.log('\n[4/4] Ad-hoc re-signing for macOS...');
run('codesign', ['--sign', '-', OUT_BINARY]);
} else {
console.log('\n[4/4] Done.');
}

const size = (fs.statSync(OUT_BINARY).size / 1024 / 1024).toFixed(1);
console.log(`\nStandalone binary: ${OUT_BINARY} (${size} MB)`);
console.log('WASM files must remain alongside the binary:');
console.log(' tree-sitter-modelica.wasm');
console.log(' web-tree-sitter.wasm');
5 changes: 5 additions & 0 deletions server/sea-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"main": "out/server.js",
"output": "out/sea-prep.blob",
"disableExperimentalSEAWarning": true
}
Loading