-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
248 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import { test } from 'node:test' | ||
import assert from 'node:assert/strict' | ||
|
||
test('webview', () => { | ||
assert.equal(1, 1) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import { execSync } from 'node:child_process'; | ||
import { copyFileSync, constants, writeFileSync, existsSync, mkdirSync, readFileSync } from 'node:fs'; | ||
import { dirname, join, sep } from 'node:path'; | ||
import { execPath } from 'node:process' | ||
|
||
const isWindows = process.platform === 'win32'; | ||
const isMac = process.platform === 'darwin'; | ||
const NODE_SEA_FUSE = 'NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2'; | ||
|
||
const filename = (path) => path.split(sep).pop(); | ||
|
||
function writeSeaConfig(main, dest, resources) { | ||
const config = { | ||
main, | ||
output: join(dirname(dest), 'sea-prep.blob'), | ||
disableExperimentalSEAWarning: true, | ||
assets: resources | ||
}; | ||
|
||
writeFileSync(dest, JSON.stringify(config, null, 2)); | ||
} | ||
|
||
function run(command, args) { | ||
const cmd = !args?.length ? command : `${command} ${args.join(' ')}`; | ||
execSync(cmd, { stdio: 'inherit' }); | ||
} | ||
|
||
function generateBlob(configPath) { | ||
run('node', ['--experimental-sea-config', configPath]) | ||
|
||
return join(dirname(configPath), 'sea-prep.blob'); | ||
} | ||
|
||
function copyNode(output, name) { | ||
const ext = isWindows ? '.exe' : ''; | ||
const f = join(output, name + ext); | ||
copyFileSync(execPath, f, constants.COPYFILE_FICLONE); | ||
|
||
return f; | ||
} | ||
|
||
function removeSignature(path) { | ||
if (!isWindows && !isMac) return; | ||
|
||
if (isWindows) { | ||
try { | ||
run('signtool remove /s ' + path) | ||
} catch (e) { | ||
console.warn(`Failed to remove signature: ${e.message}`) | ||
} | ||
} else { | ||
run('codesign --remove-signature ' + path) | ||
} | ||
} | ||
|
||
function injectFuse(target, blob) { | ||
let args; | ||
|
||
if (isMac) { | ||
args = [`"${target}"`, 'NODE_SEA_BLOB', blob, '--sentinel-fuse', NODE_SEA_FUSE, '--macho-segment-name', 'NODE_SEA']; | ||
} else { | ||
args = [target, 'NODE_SEA_BLOB', blob, '--sentinel-fuse', NODE_SEA_FUSE]; | ||
} | ||
|
||
run('npx', ['--yes', 'postject', ...args]) | ||
} | ||
|
||
function sign(bin) { | ||
if (isWindows) { | ||
try { | ||
run('signtool', ['sign', '/fd', 'SHA256', bin]) | ||
} catch (e) { | ||
console.warn(`Failed to sign: ${e.message}`) | ||
} | ||
} else if (isMac) { | ||
run('codesign', ['--sign', '-', bin]) | ||
} | ||
} | ||
|
||
export function build(input, output, name, resources) { | ||
if (!existsSync(input)) { | ||
throw new Error('Input file does not exist'); | ||
} | ||
|
||
if (resources && !existsSync(resources)) { | ||
throw new Error('Resources file does not exist'); | ||
} | ||
|
||
if (!existsSync(output)) { | ||
mkdirSync(output, { recursive: true }); | ||
} | ||
|
||
const assets = JSON.parse(readFileSync(resources, 'utf-8')); | ||
const configPath = join(output, 'sea-config.json'); | ||
const execPath = copyNode(output, name); | ||
|
||
writeSeaConfig(input, configPath, assets); | ||
const blob = generateBlob(configPath); | ||
removeSignature(execPath); | ||
injectFuse(execPath, blob); | ||
sign(execPath); | ||
|
||
return execPath; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
#!/usr/bin/env node | ||
import { readFile } from 'node:fs/promises' | ||
import { parseArgs, styleText } from 'node:util' | ||
import { join } from 'node:path'; | ||
import { stripIndents } from './utils.mjs'; | ||
import { build } from './build.mjs'; | ||
|
||
async function readPackageJSON() { | ||
const packageJSON = await readFile(join(import.meta.dirname, '..', 'package.json'), 'utf-8'); | ||
return JSON.parse(packageJSON); | ||
} | ||
|
||
const { version, description, main } = await readPackageJSON(); | ||
|
||
const options = { | ||
help: { type: 'boolean', short: 'h', description: 'Show help' }, | ||
version: { type: 'boolean', short: 'v', description: 'Show version' }, | ||
build: { | ||
type: 'boolean', | ||
short: 'b', | ||
description: 'Build the project', | ||
}, | ||
name: { | ||
type: 'string', | ||
short: 'n', | ||
default: 'webviewjs', | ||
description: 'Project name', | ||
}, | ||
output: { | ||
type: 'string', | ||
short: 'o', | ||
default: join(process.cwd(), 'dist'), | ||
description: 'Output directory', | ||
}, | ||
input: { | ||
type: 'string', | ||
short: 'i', | ||
default: join(process.cwd(), main), | ||
description: 'Entry file', | ||
}, | ||
resources: { | ||
type: 'string', | ||
short: 'r', | ||
description: 'Resources mapping json file path' | ||
}, | ||
'dry-run': { | ||
type: 'boolean', | ||
short: 'd', | ||
description: 'Dry run', | ||
} | ||
}; | ||
|
||
const args = parseArgs({ | ||
strict: true, | ||
args: process.argv.slice(2), | ||
options | ||
}); | ||
|
||
let stdErr = false; | ||
|
||
|
||
const logger = (message) => { | ||
console.log(message); | ||
process.exit(+stdErr); | ||
} | ||
|
||
const defaultValuesOptionNames = new Set(Object.keys(options).filter(k => !!options[k].default)); | ||
|
||
if (!Object.keys(args.values).filter(k => !defaultValuesOptionNames.has(k)).length) { | ||
args.values.help = true; | ||
stdErr = true; | ||
} | ||
|
||
if (args.values.help) { | ||
const message = stripIndents`WebviewJS: ${styleText('greenBright', description)} | ||
${styleText('dim', 'Usage:')} ${styleText('greenBright', 'webview [options]')} | ||
${styleText('dim', 'Options:')} | ||
${Object.entries(options).map(([name, { short, default: defaultValue, type }]) => { | ||
const msg = ` ${styleText('greenBright', ` -${short}, --${name}`)} - ${styleText('dim', options[name].description || `${type} option`)}`; | ||
if (defaultValue) { | ||
return `${msg} (default: ${styleText('blueBright', defaultValue)})`; | ||
} | ||
return msg; | ||
}).join('\n')} | ||
`; | ||
|
||
logger(message); | ||
} else if (args.values.version) { | ||
logger(`- WebviewJS v${version}\n- Node.js ${process.version}\n- Operating System: ${process.platform} ${process.arch}`); | ||
} else if (args.values.build) { | ||
const isDry = !!args.values['dry-run']; | ||
const { output, input, resources } = args.values; | ||
|
||
if (isDry) { | ||
logger(`Dry run: building ${input} to ${output}`); | ||
} else { | ||
const projectName = args.values.name || 'webviewjs'; | ||
const target = build(input, output, prettify(projectName), resources); | ||
logger(styleText('greenBright', `\nBuilt ${input} to ${target}. You can now run the executable using ${styleText(['cyanBright', 'bold'], target)}`)); | ||
} | ||
} | ||
|
||
function prettify(str) { | ||
// remove stuff like @, /, whitespace, etc | ||
return str.replace(/[^a-zA-Z0-9]/g, ''); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
export function stripIndents(strings, ...values) { | ||
let str = ''; | ||
strings.forEach((string, i) => { | ||
str += string + (values[i] || ''); | ||
}); | ||
return str.replace(/(\t)+/g, ' ').trim(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,10 @@ | ||
{ | ||
"name": "@webviewjs/webview", | ||
"version": "0.1.0", | ||
"bin": { | ||
"webview": "./cli/index.mjs", | ||
"webviewjs": "./cli/index.mjs" | ||
}, | ||
"description": "Robust cross-platform webview library for Node.js written in Rust", | ||
"main": "index.js", | ||
"repository": "[email protected]:twlite/webview.git", | ||
|
@@ -48,7 +52,8 @@ | |
"format:rs": "cargo fmt", | ||
"lint": "oxlint .", | ||
"prepublishOnly": "napi prepublish -t npm", | ||
"version": "napi version" | ||
"version": "napi version", | ||
"test": "node --test './__test__/**/*.test.*'" | ||
}, | ||
"devDependencies": { | ||
"@napi-rs/cli": "^2.18.4", | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters