Compare commits
22 Commits
v3.0.1
...
esm-asar-e
| Author | SHA1 | Date | |
|---|---|---|---|
| 75309d0945 | |||
| 6f0968cdce | |||
|
|
bf1269fe21 | ||
|
|
ca53e14488 | ||
|
|
1b9f5eb340 | ||
|
|
53c72d8c47 | ||
|
|
b61638598d | ||
|
|
0a0b41d115 | ||
|
|
ed0459457f | ||
|
|
0939980564 | ||
|
|
2e087ef6c8 | ||
|
|
355fd7c6e8 | ||
|
|
7a73b7793e | ||
|
|
436b2abeff | ||
|
|
01eec61200 | ||
|
|
9a2c19c940 | ||
|
|
4eb37fab7b | ||
|
|
b3059564b7 | ||
|
|
f7d15b8d34 | ||
|
|
1c55526cdb | ||
|
|
e9a5812213 | ||
|
|
ed1efe60a0 |
9
.github/workflows/docs.yml
vendored
9
.github/workflows/docs.yml
vendored
@@ -14,12 +14,13 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
environment: docs-publish
|
environment: docs-publish
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
|
cache: 'yarn'
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: yarn --frozen-lockfile
|
run: yarn --immutable
|
||||||
- name: Build API documentation
|
- name: Build API documentation
|
||||||
run: yarn build:docs
|
run: yarn build:docs
|
||||||
- name: Azure login
|
- name: Azure login
|
||||||
@@ -29,7 +30,7 @@ jobs:
|
|||||||
tenant-id: ${{ secrets.AZURE_OIDC_TENANT_ID }}
|
tenant-id: ${{ secrets.AZURE_OIDC_TENANT_ID }}
|
||||||
subscription-id: ${{ secrets.AZURE_OIDC_SUBSCRIPTION_ID }}
|
subscription-id: ${{ secrets.AZURE_OIDC_SUBSCRIPTION_ID }}
|
||||||
- name: Upload to Azure Blob Storage
|
- name: Upload to Azure Blob Storage
|
||||||
uses: azure/cli@089eac9d8cc39f5d003e94f8b65efc51076c9cbd # v2.1.0
|
uses: azure/cli@9f7ce6f37c31b777ec6c6b6d1dfe7db79f497956 # v2.2.0
|
||||||
with:
|
with:
|
||||||
inlineScript: |
|
inlineScript: |
|
||||||
az storage blob upload-batch --account-name ${{ secrets.AZURE_ECOSYSTEM_PACKAGES_STORAGE_ACCOUNT_NAME }} -d '$web/${{ github.event.repository.name }}/${{ github.ref_name }}' -s ./docs --overwrite --auth-mode login
|
az storage blob upload-batch --account-name ${{ secrets.AZURE_ECOSYSTEM_PACKAGES_STORAGE_ACCOUNT_NAME }} -d '$web/${{ github.event.repository.name }}/${{ github.ref_name }}' -s ./docs --overwrite --auth-mode login
|
||||||
|
|||||||
21
.github/workflows/release.yml
vendored
21
.github/workflows/release.yml
vendored
@@ -13,24 +13,25 @@ jobs:
|
|||||||
name: Release
|
name: Release
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: test
|
needs: test
|
||||||
environment: npm
|
environment: npm-trusted-publisher
|
||||||
permissions:
|
permissions:
|
||||||
id-token: write # for CFA and npm provenance
|
id-token: write # for publishing releases
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
- name: Install
|
- name: Install
|
||||||
run: yarn install --frozen-lockfile
|
run: yarn install --immutable
|
||||||
- uses: continuousauth/action@4e8a2573eeb706f6d7300d6a9f3ca6322740b72d # v1.0.5
|
- name: Get GitHub App Token
|
||||||
timeout-minutes: 60
|
id: secret-service
|
||||||
|
uses: electron/secret-service-action@3476425e8b30555aac15b1b7096938e254b0e155 # v1.0.0
|
||||||
|
- name: Run Semantic Release
|
||||||
|
uses: electron/semantic-trusted-release@5eceb399ac8de8863205cf6e34109bce473ba566 # v1.0.1
|
||||||
with:
|
with:
|
||||||
project-id: ${{ secrets.CFA_PROJECT_ID }}
|
github-token: ${{ fromJSON(steps.secret-service.outputs.secrets).GITHUB_TOKEN }}
|
||||||
secret: ${{ secrets.CFA_SECRET }}
|
|
||||||
npm-token: ${{ secrets.NPM_TOKEN }}
|
|
||||||
|
|||||||
2
.github/workflows/semantic.yml
vendored
2
.github/workflows/semantic.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: semantic-pull-request
|
- name: semantic-pull-request
|
||||||
uses: amannn/action-semantic-pull-request@0723387faaf9b38adef4775cd42cfd5155ed6017 # v5.5.3
|
uses: amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50 # v6.1.1
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
|
|||||||
6
.github/workflows/test.yml
vendored
6
.github/workflows/test.yml
vendored
@@ -22,14 +22,14 @@ jobs:
|
|||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||||
with:
|
with:
|
||||||
node-version: "${{ matrix.node-version }}"
|
node-version: "${{ matrix.node-version }}"
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
- name: Install
|
- name: Install
|
||||||
run: yarn install --frozen-lockfile
|
run: yarn install --immutable
|
||||||
- name: Build
|
- name: Build
|
||||||
run: yarn build
|
run: yarn build
|
||||||
- name: Lint
|
- name: Lint
|
||||||
|
|||||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1,9 +1,12 @@
|
|||||||
node_modules
|
node_modules
|
||||||
dist
|
dist
|
||||||
entry-asar/*.js*
|
entry-asar/cjs/*.js*
|
||||||
entry-asar/*.ts
|
entry-asar/cjs/*.d.ts
|
||||||
|
entry-asar/esm/*.?js*
|
||||||
|
entry-asar/esm/*.d.?ts
|
||||||
*.app
|
*.app
|
||||||
test/fixtures/apps
|
test/fixtures/apps
|
||||||
coverage
|
coverage
|
||||||
docs
|
docs
|
||||||
.vscode
|
.vscode
|
||||||
|
.yarn/install-state.gz
|
||||||
|
|||||||
5
.npmignore
Normal file
5
.npmignore
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# npmignore overrides .gitignore for yarn pack
|
||||||
|
# Only exclude source files, not built files
|
||||||
|
entry-asar/**/*.mts
|
||||||
|
entry-asar/**/*.ts
|
||||||
|
entry-asar/**/tsconfig.json
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
"plugins": [
|
"plugins": [
|
||||||
"@semantic-release/commit-analyzer",
|
"@semantic-release/commit-analyzer",
|
||||||
"@semantic-release/release-notes-generator",
|
"@semantic-release/release-notes-generator",
|
||||||
"@continuous-auth/semantic-release-npm",
|
"@semantic-release/npm",
|
||||||
"@semantic-release/github"
|
"@semantic-release/github"
|
||||||
],
|
],
|
||||||
"branches": [ "main" ]
|
"branches": [ "main" ]
|
||||||
|
|||||||
942
.yarn/releases/yarn-4.10.3.cjs
vendored
Executable file
942
.yarn/releases/yarn-4.10.3.cjs
vendored
Executable file
File diff suppressed because one or more lines are too long
10
.yarnrc.yml
Normal file
10
.yarnrc.yml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
enableScripts: false
|
||||||
|
|
||||||
|
nodeLinker: node-modules
|
||||||
|
|
||||||
|
npmMinimalAgeGate: 10080
|
||||||
|
|
||||||
|
npmPreapprovedPackages:
|
||||||
|
- "@electron/*"
|
||||||
|
|
||||||
|
yarnPath: .yarn/releases/yarn-4.10.3.cjs
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
[](https://github.com/electron/universal/actions/workflows/test.yml)
|
[](https://github.com/electron/universal/actions/workflows/test.yml)
|
||||||
[](https://npm.im/@electron/universal)
|
[](https://npm.im/@electron/universal)
|
||||||
|
[](https://packages.electronjs.org/universal)
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
@@ -22,6 +23,8 @@ await makeUniversalApp({
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
For full API usage, see the [API documentation](https://packages.electronjs.org/universal).
|
||||||
|
|
||||||
## Advanced configuration
|
## Advanced configuration
|
||||||
|
|
||||||
The basic usage patterns will work for most apps out of the box. Additional configuration
|
The basic usage patterns will work for most apps out of the box. Additional configuration
|
||||||
@@ -118,8 +121,4 @@ Note that if you are using `mergeASARs`, you may need to add architecture-specif
|
|||||||
binary resources to the `singleArchFiles` pattern.
|
binary resources to the `singleArchFiles` pattern.
|
||||||
See [Merging ASARs usage](#merging-asar-archives-to-reduce-app-size) for an example.
|
See [Merging ASARs usage](#merging-asar-archives-to-reduce-app-size) for an example.
|
||||||
|
|
||||||
#### How do I build my app for Apple silicon in the first place?
|
|
||||||
|
|
||||||
Check out the [Electron Apple silicon blog post](https://www.electronjs.org/blog/apple-silicon).
|
|
||||||
|
|
||||||
[`minimatch`]: https://github.com/isaacs/minimatch?tab=readme-ov-file#features
|
[`minimatch`]: https://github.com/isaacs/minimatch?tab=readme-ov-file#features
|
||||||
|
|||||||
11
entry-asar/cjs/tsconfig.json
Normal file
11
entry-asar/cjs/tsconfig.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": ".",
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
".",
|
||||||
|
"../ambient.d.ts"
|
||||||
|
],
|
||||||
|
"exclude": []
|
||||||
|
}
|
||||||
28
entry-asar/esm/has-asar.mts
Normal file
28
entry-asar/esm/has-asar.mts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import { app } from 'electron';
|
||||||
|
import { createRequire } from 'node:module';
|
||||||
|
import path from 'node:path';
|
||||||
|
|
||||||
|
if (process.arch === 'arm64') {
|
||||||
|
await setPaths('arm64');
|
||||||
|
} else {
|
||||||
|
await setPaths('x64');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setPaths(platform: string) {
|
||||||
|
// This should return the full path, ending in something like
|
||||||
|
// Notion.app/Contents/Resources/app.asar
|
||||||
|
const appPath = app.getAppPath();
|
||||||
|
const asarFile = `app-${platform}.asar`;
|
||||||
|
|
||||||
|
// Maybe we'll handle this in Electron one day
|
||||||
|
if (path.basename(appPath) === 'app.asar') {
|
||||||
|
const platformAppPath = path.join(path.dirname(appPath), asarFile);
|
||||||
|
|
||||||
|
// This is an undocumented API. It exists.
|
||||||
|
app.setAppPath(platformAppPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
const require = createRequire(import.meta.url);
|
||||||
|
process._archPath = require.resolve(`../${asarFile}`);
|
||||||
|
await import(process._archPath);
|
||||||
|
}
|
||||||
29
entry-asar/esm/no-asar.mts
Normal file
29
entry-asar/esm/no-asar.mts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { app } from 'electron';
|
||||||
|
import { createRequire } from 'node:module';
|
||||||
|
import path from 'node:path';
|
||||||
|
|
||||||
|
if (process.arch === 'arm64') {
|
||||||
|
await setPaths('arm64');
|
||||||
|
} else {
|
||||||
|
await setPaths('x64');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setPaths(platform: string) {
|
||||||
|
// This should return the full path, ending in something like
|
||||||
|
// Notion.app/Contents/Resources/app
|
||||||
|
const appPath = app.getAppPath();
|
||||||
|
const appFolder = `app-${platform}`;
|
||||||
|
|
||||||
|
// Maybe we'll handle this in Electron one day
|
||||||
|
if (path.basename(appPath) === 'app') {
|
||||||
|
const platformAppPath = path.join(path.dirname(appPath), appFolder);
|
||||||
|
|
||||||
|
// This is an undocumented private API. It exists.
|
||||||
|
app.setAppPath(platformAppPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
const require = createRequire(import.meta.url);
|
||||||
|
process._archPath = require.resolve(`../${appFolder}`);
|
||||||
|
|
||||||
|
await import(process._archPath);
|
||||||
|
}
|
||||||
14
entry-asar/esm/tsconfig.json
Normal file
14
entry-asar/esm/tsconfig.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "ESNext",
|
||||||
|
"target":"ESNext",
|
||||||
|
"outDir": ".",
|
||||||
|
"moduleResolution": "bundler"
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
".",
|
||||||
|
"../ambient.d.ts"
|
||||||
|
],
|
||||||
|
"exclude": []
|
||||||
|
}
|
||||||
16
package.json
16
package.json
@@ -19,8 +19,12 @@
|
|||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"dist/*",
|
"dist/*",
|
||||||
"entry-asar/*",
|
"entry-asar/**/*",
|
||||||
"!entry-asar/**/*.ts",
|
"!entry-asar/**/has-asar.ts",
|
||||||
|
"!entry-asar/**/no-asar.ts",
|
||||||
|
"!entry-asar/**/has-asar.mts",
|
||||||
|
"!entry-asar/**/no-asar.mts",
|
||||||
|
"!entry-asar/**/tsconfig.json",
|
||||||
"README.md"
|
"README.md"
|
||||||
],
|
],
|
||||||
"author": "Samuel Attard",
|
"author": "Samuel Attard",
|
||||||
@@ -28,12 +32,11 @@
|
|||||||
"provenance": true
|
"provenance": true
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc -p tsconfig.json && tsc -p tsconfig.entry-asar.json",
|
"build": "tsc -p tsconfig.json && tsc -p entry-asar/esm/tsconfig.json && tsc -p entry-asar/cjs/tsconfig.json",
|
||||||
"build:docs": "npx typedoc",
|
"build:docs": "npx typedoc",
|
||||||
"lint": "prettier --check \"{src,entry-asar,test}/**/*.ts\" \"*.ts\"",
|
"lint": "prettier --check \"{src,entry-asar,test}/**/*.ts\" \"*.ts\"",
|
||||||
"prettier:write": "prettier --write \"{src,entry-asar,test}/**/*.ts\" \"*.ts\"",
|
"prettier:write": "prettier --write \"{src,entry-asar,test}/**/*.ts\" \"*.ts\"",
|
||||||
"prepublishOnly": "npm run build",
|
"prepack": "npm run build",
|
||||||
"pretest": "npm run build",
|
|
||||||
"test": "vitest run",
|
"test": "vitest run",
|
||||||
"prepare": "husky"
|
"prepare": "husky"
|
||||||
},
|
},
|
||||||
@@ -65,5 +68,6 @@
|
|||||||
"*.ts": [
|
"*.ts": [
|
||||||
"prettier --write"
|
"prettier --write"
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
"packageManager": "yarn@4.10.3+sha512.c38cafb5c7bb273f3926d04e55e1d8c9dfa7d9c3ea1f36a4868fa028b9e5f72298f0b7f401ad5eb921749eb012eb1c3bb74bf7503df3ee43fd600d14a018266f"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,15 +3,19 @@ import path from 'node:path';
|
|||||||
import { promises as stream } from 'node:stream';
|
import { promises as stream } from 'node:stream';
|
||||||
|
|
||||||
import { spawn, ExitCodeError } from '@malept/cross-spawn-promise';
|
import { spawn, ExitCodeError } from '@malept/cross-spawn-promise';
|
||||||
|
import { minimatch } from 'minimatch';
|
||||||
|
|
||||||
const MACHO_PREFIX = 'Mach-O ';
|
const MACHO_PREFIX = 'Mach-O ';
|
||||||
|
|
||||||
|
const UNPACKED_ASAR_PATH = path.join('Contents', 'Resources', 'app.asar.unpacked');
|
||||||
|
|
||||||
export enum AppFileType {
|
export enum AppFileType {
|
||||||
MACHO,
|
MACHO,
|
||||||
PLAIN,
|
PLAIN,
|
||||||
INFO_PLIST,
|
INFO_PLIST,
|
||||||
SNAPSHOT,
|
SNAPSHOT,
|
||||||
APP_CODE,
|
APP_CODE,
|
||||||
|
SINGLE_ARCH,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AppFile = {
|
export type AppFile = {
|
||||||
@@ -19,11 +23,37 @@ export type AppFile = {
|
|||||||
type: AppFileType;
|
type: AppFileType;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type GetAllAppFilesOpts = {
|
||||||
|
singleArchFiles?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const isSingleArchFile = (relativePath: string, opts: GetAllAppFilesOpts): boolean => {
|
||||||
|
if (opts.singleArchFiles === undefined) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unpackedPath = path.relative(UNPACKED_ASAR_PATH, relativePath);
|
||||||
|
|
||||||
|
// Outside of app.asar.unpacked
|
||||||
|
if (unpackedPath.startsWith('..')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return minimatch(unpackedPath, opts.singleArchFiles, {
|
||||||
|
matchBase: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param appPath Path to the application
|
* @param appPath Path to the application
|
||||||
*/
|
*/
|
||||||
export const getAllAppFiles = async (appPath: string): Promise<AppFile[]> => {
|
export const getAllAppFiles = async (
|
||||||
|
appPath: string,
|
||||||
|
opts: GetAllAppFilesOpts,
|
||||||
|
): Promise<AppFile[]> => {
|
||||||
|
const unpackedPath = path.join('Contents', 'Resources', 'app.asar.unpacked');
|
||||||
|
|
||||||
const files: AppFile[] = [];
|
const files: AppFile[] = [];
|
||||||
|
|
||||||
const visited = new Set<string>();
|
const visited = new Set<string>();
|
||||||
@@ -35,6 +65,8 @@ export const getAllAppFiles = async (appPath: string): Promise<AppFile[]> => {
|
|||||||
const info = await fs.promises.stat(p);
|
const info = await fs.promises.stat(p);
|
||||||
if (info.isSymbolicLink()) return;
|
if (info.isSymbolicLink()) return;
|
||||||
if (info.isFile()) {
|
if (info.isFile()) {
|
||||||
|
const relativePath = path.relative(appPath, p);
|
||||||
|
|
||||||
let fileType = AppFileType.PLAIN;
|
let fileType = AppFileType.PLAIN;
|
||||||
|
|
||||||
var fileOutput = '';
|
var fileOutput = '';
|
||||||
@@ -49,6 +81,8 @@ export const getAllAppFiles = async (appPath: string): Promise<AppFile[]> => {
|
|||||||
}
|
}
|
||||||
if (p.endsWith('.asar')) {
|
if (p.endsWith('.asar')) {
|
||||||
fileType = AppFileType.APP_CODE;
|
fileType = AppFileType.APP_CODE;
|
||||||
|
} else if (isSingleArchFile(relativePath, opts)) {
|
||||||
|
fileType = AppFileType.SINGLE_ARCH;
|
||||||
} else if (fileOutput.startsWith(MACHO_PREFIX)) {
|
} else if (fileOutput.startsWith(MACHO_PREFIX)) {
|
||||||
fileType = AppFileType.MACHO;
|
fileType = AppFileType.MACHO;
|
||||||
} else if (p.endsWith('.bin')) {
|
} else if (p.endsWith('.bin')) {
|
||||||
@@ -58,7 +92,7 @@ export const getAllAppFiles = async (appPath: string): Promise<AppFile[]> => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
files.push({
|
files.push({
|
||||||
relativePath: path.relative(appPath, p),
|
relativePath,
|
||||||
type: fileType,
|
type: fileType,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
66
src/index.ts
66
src/index.ts
@@ -75,7 +75,12 @@ export type MakeUniversalOpts = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const dupedFiles = (files: AppFile[]) =>
|
const dupedFiles = (files: AppFile[]) =>
|
||||||
files.filter((f) => f.type !== AppFileType.SNAPSHOT && f.type !== AppFileType.APP_CODE);
|
files.filter(
|
||||||
|
(f) =>
|
||||||
|
f.type !== AppFileType.SNAPSHOT &&
|
||||||
|
f.type !== AppFileType.APP_CODE &&
|
||||||
|
f.type !== AppFileType.SINGLE_ARCH,
|
||||||
|
);
|
||||||
|
|
||||||
export const makeUniversalApp = async (opts: MakeUniversalOpts): Promise<void> => {
|
export const makeUniversalApp = async (opts: MakeUniversalOpts): Promise<void> => {
|
||||||
d('making a universal app with options', opts);
|
d('making a universal app with options', opts);
|
||||||
@@ -121,8 +126,8 @@ export const makeUniversalApp = async (opts: MakeUniversalOpts): Promise<void> =
|
|||||||
|
|
||||||
const uniqueToX64: string[] = [];
|
const uniqueToX64: string[] = [];
|
||||||
const uniqueToArm64: string[] = [];
|
const uniqueToArm64: string[] = [];
|
||||||
const x64Files = await getAllAppFiles(await fs.promises.realpath(tmpApp));
|
const x64Files = await getAllAppFiles(await fs.promises.realpath(tmpApp), opts);
|
||||||
const arm64Files = await getAllAppFiles(await fs.promises.realpath(opts.arm64AppPath));
|
const arm64Files = await getAllAppFiles(await fs.promises.realpath(opts.arm64AppPath), opts);
|
||||||
|
|
||||||
for (const file of dupedFiles(x64Files)) {
|
for (const file of dupedFiles(x64Files)) {
|
||||||
if (!arm64Files.some((f) => f.relativePath === file.relativePath))
|
if (!arm64Files.some((f) => f.relativePath === file.relativePath))
|
||||||
@@ -143,7 +148,9 @@ export const makeUniversalApp = async (opts: MakeUniversalOpts): Promise<void> =
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const file of x64Files.filter((f) => f.type === AppFileType.PLAIN)) {
|
// Single Arch files are copied as is without processing.
|
||||||
|
const multiArchFiles = x64Files.filter((f) => f.type !== AppFileType.SINGLE_ARCH);
|
||||||
|
for (const file of multiArchFiles.filter((f) => f.type === AppFileType.PLAIN)) {
|
||||||
const x64Sha = await sha(path.resolve(opts.x64AppPath, file.relativePath));
|
const x64Sha = await sha(path.resolve(opts.x64AppPath, file.relativePath));
|
||||||
const arm64Sha = await sha(path.resolve(opts.arm64AppPath, file.relativePath));
|
const arm64Sha = await sha(path.resolve(opts.arm64AppPath, file.relativePath));
|
||||||
if (x64Sha !== arm64Sha) {
|
if (x64Sha !== arm64Sha) {
|
||||||
@@ -159,7 +166,7 @@ export const makeUniversalApp = async (opts: MakeUniversalOpts): Promise<void> =
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const knownMergedMachOFiles = new Set();
|
const knownMergedMachOFiles = new Set();
|
||||||
for (const machOFile of x64Files.filter((f) => f.type === AppFileType.MACHO)) {
|
for (const machOFile of multiArchFiles.filter((f) => f.type === AppFileType.MACHO)) {
|
||||||
const first = await fs.promises.realpath(path.resolve(tmpApp, machOFile.relativePath));
|
const first = await fs.promises.realpath(path.resolve(tmpApp, machOFile.relativePath));
|
||||||
const second = await fs.promises.realpath(
|
const second = await fs.promises.realpath(
|
||||||
path.resolve(opts.arm64AppPath, machOFile.relativePath),
|
path.resolve(opts.arm64AppPath, machOFile.relativePath),
|
||||||
@@ -247,17 +254,30 @@ export const makeUniversalApp = async (opts: MakeUniversalOpts): Promise<void> =
|
|||||||
|
|
||||||
const entryAsar = path.resolve(tmpDir, 'entry-asar');
|
const entryAsar = path.resolve(tmpDir, 'entry-asar');
|
||||||
await fs.promises.mkdir(entryAsar, { recursive: true });
|
await fs.promises.mkdir(entryAsar, { recursive: true });
|
||||||
await fs.promises.cp(
|
|
||||||
path.resolve(import.meta.dirname, '..', 'entry-asar', 'no-asar.js'),
|
|
||||||
path.resolve(entryAsar, 'index.js'),
|
|
||||||
);
|
|
||||||
let pj = JSON.parse(
|
let pj = JSON.parse(
|
||||||
await fs.promises.readFile(
|
await fs.promises.readFile(
|
||||||
path.resolve(opts.x64AppPath, 'Contents', 'Resources', 'app', 'package.json'),
|
path.resolve(opts.x64AppPath, 'Contents', 'Resources', 'app', 'package.json'),
|
||||||
'utf8',
|
'utf8',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
pj.main = 'index.js';
|
|
||||||
|
// Load a shim that redirects to the correct folder for the architecture.
|
||||||
|
// This needs to be a different file depending on if the app entrypoint is CommonJS or ESM.
|
||||||
|
if (pj.type === 'module' || pj.main.endsWith('.mjs')) {
|
||||||
|
await fs.promises.cp(
|
||||||
|
path.resolve(import.meta.dirname, '..', 'entry-asar', 'esm', 'no-asar.mjs'),
|
||||||
|
path.resolve(entryAsar, 'index.mjs'),
|
||||||
|
);
|
||||||
|
pj.main = 'index.mjs';
|
||||||
|
} else {
|
||||||
|
await fs.promises.cp(
|
||||||
|
path.resolve(import.meta.dirname, '..', 'entry-asar', 'cjs', 'no-asar.js'),
|
||||||
|
path.resolve(entryAsar, 'index.js'),
|
||||||
|
);
|
||||||
|
pj.main = 'index.js';
|
||||||
|
}
|
||||||
|
|
||||||
await fs.promises.writeFile(
|
await fs.promises.writeFile(
|
||||||
path.resolve(entryAsar, 'package.json'),
|
path.resolve(entryAsar, 'package.json'),
|
||||||
JSON.stringify(pj) + '\n',
|
JSON.stringify(pj) + '\n',
|
||||||
@@ -330,10 +350,6 @@ export const makeUniversalApp = async (opts: MakeUniversalOpts): Promise<void> =
|
|||||||
|
|
||||||
const entryAsar = path.resolve(tmpDir, 'entry-asar');
|
const entryAsar = path.resolve(tmpDir, 'entry-asar');
|
||||||
await fs.promises.mkdir(entryAsar, { recursive: true });
|
await fs.promises.mkdir(entryAsar, { recursive: true });
|
||||||
await fs.promises.cp(
|
|
||||||
path.resolve(import.meta.dirname, '..', 'entry-asar', 'has-asar.js'),
|
|
||||||
path.resolve(entryAsar, 'index.js'),
|
|
||||||
);
|
|
||||||
let pj = JSON.parse(
|
let pj = JSON.parse(
|
||||||
(
|
(
|
||||||
await asar.extractFile(
|
await asar.extractFile(
|
||||||
@@ -342,7 +358,23 @@ export const makeUniversalApp = async (opts: MakeUniversalOpts): Promise<void> =
|
|||||||
)
|
)
|
||||||
).toString('utf8'),
|
).toString('utf8'),
|
||||||
);
|
);
|
||||||
pj.main = 'index.js';
|
|
||||||
|
// Load a shim that redirects to the correct `app.asar` for the architecture.
|
||||||
|
// This needs to be a different file depending on if the app entrypoint is CommonJS or ESM.
|
||||||
|
if (pj.type === 'module' || pj.main.endsWith('.mjs')) {
|
||||||
|
await fs.promises.cp(
|
||||||
|
path.resolve(import.meta.dirname, '..', 'entry-asar', 'esm', 'has-asar.mjs'),
|
||||||
|
path.resolve(entryAsar, 'index.mjs'),
|
||||||
|
);
|
||||||
|
pj.main = 'index.mjs';
|
||||||
|
} else {
|
||||||
|
await fs.promises.cp(
|
||||||
|
path.resolve(import.meta.dirname, '..', 'entry-asar', 'cjs', 'has-asar.js'),
|
||||||
|
path.resolve(entryAsar, 'index.js'),
|
||||||
|
);
|
||||||
|
pj.main = 'index.js';
|
||||||
|
}
|
||||||
|
|
||||||
await fs.promises.writeFile(
|
await fs.promises.writeFile(
|
||||||
path.resolve(entryAsar, 'package.json'),
|
path.resolve(entryAsar, 'package.json'),
|
||||||
JSON.stringify(pj) + '\n',
|
JSON.stringify(pj) + '\n',
|
||||||
@@ -355,9 +387,9 @@ export const makeUniversalApp = async (opts: MakeUniversalOpts): Promise<void> =
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const generatedIntegrity = await computeIntegrityData(path.join(tmpApp, 'Contents'));
|
const generatedIntegrity = await computeIntegrityData(path.join(tmpApp, 'Contents'), opts);
|
||||||
|
|
||||||
const plistFiles = x64Files.filter((f) => f.type === AppFileType.INFO_PLIST);
|
const plistFiles = multiArchFiles.filter((f) => f.type === AppFileType.INFO_PLIST);
|
||||||
for (const plistFile of plistFiles) {
|
for (const plistFile of plistFiles) {
|
||||||
const x64PlistPath = path.resolve(opts.x64AppPath, plistFile.relativePath);
|
const x64PlistPath = path.resolve(opts.x64AppPath, plistFile.relativePath);
|
||||||
const arm64PlistPath = path.resolve(opts.arm64AppPath, plistFile.relativePath);
|
const arm64PlistPath = path.resolve(opts.arm64AppPath, plistFile.relativePath);
|
||||||
|
|||||||
@@ -17,13 +17,20 @@ export interface AsarIntegrity {
|
|||||||
[key: string]: HeaderHash;
|
[key: string]: HeaderHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function computeIntegrityData(contentsPath: string): Promise<AsarIntegrity> {
|
export type ComputeIntegrityDataOpts = {
|
||||||
|
singleArchFiles?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function computeIntegrityData(
|
||||||
|
contentsPath: string,
|
||||||
|
opts: ComputeIntegrityDataOpts,
|
||||||
|
): Promise<AsarIntegrity> {
|
||||||
const root = await fs.promises.realpath(contentsPath);
|
const root = await fs.promises.realpath(contentsPath);
|
||||||
|
|
||||||
const resourcesRelativePath = 'Resources';
|
const resourcesRelativePath = 'Resources';
|
||||||
const resourcesPath = path.resolve(root, resourcesRelativePath);
|
const resourcesPath = path.resolve(root, resourcesRelativePath);
|
||||||
|
|
||||||
const resources = await getAllAppFiles(resourcesPath);
|
const resources = await getAllAppFiles(resourcesPath, opts);
|
||||||
const resourceAsars = resources
|
const resourceAsars = resources
|
||||||
.filter((file) => file.type === AppFileType.APP_CODE)
|
.filter((file) => file.type === AppFileType.APP_CODE)
|
||||||
.reduce<IntegrityMap>(
|
.reduce<IntegrityMap>(
|
||||||
|
|||||||
@@ -339,6 +339,86 @@ exports[`makeUniversalApp > asar mode > should merge two different asars when \`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`makeUniversalApp > asar mode > should merge two different asars with native files when \`mergeASARs\` is enabled 1`] = `
|
||||||
|
{
|
||||||
|
"files": {
|
||||||
|
"hello-world-arm64": "<stripped>",
|
||||||
|
"hello-world-x64": "<stripped>",
|
||||||
|
"index.js": {
|
||||||
|
"integrity": {
|
||||||
|
"algorithm": "SHA256",
|
||||||
|
"blockSize": 4194304,
|
||||||
|
"blocks": [
|
||||||
|
"0f6311dac07f0876c436ce2be042eb88c96e17eaf140b39627cf720dd87ad5b8",
|
||||||
|
],
|
||||||
|
"hash": "0f6311dac07f0876c436ce2be042eb88c96e17eaf140b39627cf720dd87ad5b8",
|
||||||
|
},
|
||||||
|
"size": 66,
|
||||||
|
},
|
||||||
|
"package.json": {
|
||||||
|
"integrity": {
|
||||||
|
"algorithm": "SHA256",
|
||||||
|
"blockSize": 4194304,
|
||||||
|
"blocks": [
|
||||||
|
"d6226276d47adc7aa20e6c46e842e258f5157313074a035051a89612acdd6be3",
|
||||||
|
],
|
||||||
|
"hash": "d6226276d47adc7aa20e6c46e842e258f5157313074a035051a89612acdd6be3",
|
||||||
|
},
|
||||||
|
"size": 41,
|
||||||
|
},
|
||||||
|
"private": {
|
||||||
|
"files": {
|
||||||
|
"var": {
|
||||||
|
"files": {
|
||||||
|
"app": {
|
||||||
|
"files": {
|
||||||
|
"file.txt": {
|
||||||
|
"link": "private/var/file.txt",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"file.txt": {
|
||||||
|
"integrity": {
|
||||||
|
"algorithm": "SHA256",
|
||||||
|
"blockSize": 4194304,
|
||||||
|
"blocks": [
|
||||||
|
"b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9",
|
||||||
|
],
|
||||||
|
"hash": "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9",
|
||||||
|
},
|
||||||
|
"size": 11,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"var": {
|
||||||
|
"link": "private/var",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`makeUniversalApp > asar mode > should merge two different asars with native files when \`mergeASARs\` is enabled 2`] = `[]`;
|
||||||
|
|
||||||
|
exports[`makeUniversalApp > asar mode > should merge two different asars with native files when \`mergeASARs\` is enabled 3`] = `
|
||||||
|
[
|
||||||
|
"hello-world-arm64",
|
||||||
|
"hello-world-x64",
|
||||||
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`makeUniversalApp > asar mode > should merge two different asars with native files when \`mergeASARs\` is enabled 4`] = `
|
||||||
|
{
|
||||||
|
"Contents/Info.plist": {
|
||||||
|
"Resources/app.asar": {
|
||||||
|
"algorithm": "SHA256",
|
||||||
|
"hash": "<stripped>",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`makeUniversalApp > asar mode > should not inject ElectronAsarIntegrity into \`infoPlistsToIgnore\` 1`] = `
|
exports[`makeUniversalApp > asar mode > should not inject ElectronAsarIntegrity into \`infoPlistsToIgnore\` 1`] = `
|
||||||
{
|
{
|
||||||
"files": {
|
"files": {
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ describe('file-utils', () => {
|
|||||||
let noAsarFiles: AppFile[];
|
let noAsarFiles: AppFile[];
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
asarFiles = await getAllAppFiles(path.resolve(appsPath, 'Arm64Asar.app'));
|
asarFiles = await getAllAppFiles(path.resolve(appsPath, 'Arm64Asar.app'), {});
|
||||||
noAsarFiles = await getAllAppFiles(path.resolve(appsPath, 'Arm64NoAsar.app'));
|
noAsarFiles = await getAllAppFiles(path.resolve(appsPath, 'Arm64NoAsar.app'), {});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly identify plist files', async () => {
|
it('should correctly identify plist files', async () => {
|
||||||
|
|||||||
@@ -142,6 +142,65 @@ describe('makeUniversalApp', () => {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
it(
|
||||||
|
'should merge two different asars with native files when `mergeASARs` is enabled',
|
||||||
|
{ timeout: VERIFY_APP_TIMEOUT },
|
||||||
|
async () => {
|
||||||
|
const x64AppPath = await generateNativeApp({
|
||||||
|
appNameWithExtension: 'SingleArchFiles-x64.app',
|
||||||
|
arch: 'x64',
|
||||||
|
createAsar: true,
|
||||||
|
singleArchBindings: true,
|
||||||
|
});
|
||||||
|
const arm64AppPath = await generateNativeApp({
|
||||||
|
appNameWithExtension: 'SingleArchFiles-arm64.app',
|
||||||
|
arch: 'arm64',
|
||||||
|
createAsar: true,
|
||||||
|
singleArchBindings: true,
|
||||||
|
});
|
||||||
|
const out = path.resolve(appsOutPath, 'SingleArchFiles.app');
|
||||||
|
await makeUniversalApp({
|
||||||
|
x64AppPath,
|
||||||
|
arm64AppPath,
|
||||||
|
outAppPath: out,
|
||||||
|
mergeASARs: true,
|
||||||
|
singleArchFiles: 'hello-world-*',
|
||||||
|
});
|
||||||
|
await verifyApp(out, true);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
it(
|
||||||
|
'throws an error if `mergeASARs` is enabled and `singleArchFiles` is missing a unique native file',
|
||||||
|
{ timeout: VERIFY_APP_TIMEOUT },
|
||||||
|
async () => {
|
||||||
|
const x64AppPath = await generateNativeApp({
|
||||||
|
appNameWithExtension: 'SingleArchFiles-2-x64.app',
|
||||||
|
arch: 'x64',
|
||||||
|
createAsar: true,
|
||||||
|
singleArchBindings: true,
|
||||||
|
});
|
||||||
|
const arm64AppPath = await generateNativeApp({
|
||||||
|
appNameWithExtension: 'SingleArchFiles-2-arm64.app',
|
||||||
|
arch: 'arm64',
|
||||||
|
createAsar: true,
|
||||||
|
singleArchBindings: true,
|
||||||
|
});
|
||||||
|
const out = path.resolve(appsOutPath, 'SingleArchFiles-2.app');
|
||||||
|
await expect(
|
||||||
|
makeUniversalApp({
|
||||||
|
x64AppPath,
|
||||||
|
arm64AppPath,
|
||||||
|
outAppPath: out,
|
||||||
|
mergeASARs: true,
|
||||||
|
singleArchFiles: 'bad-rule',
|
||||||
|
}),
|
||||||
|
).rejects.toThrow(
|
||||||
|
/the number of mach-o files is not the same between the arm64 and x64 builds/,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
it(
|
it(
|
||||||
'should not inject ElectronAsarIntegrity into `infoPlistsToIgnore`',
|
'should not inject ElectronAsarIntegrity into `infoPlistsToIgnore`',
|
||||||
{ timeout: VERIFY_APP_TIMEOUT },
|
{ timeout: VERIFY_APP_TIMEOUT },
|
||||||
|
|||||||
30
test/util.ts
30
test/util.ts
@@ -33,7 +33,12 @@ export const verifyApp = async (appPath: string, containsRuntimeGeneratedMacho =
|
|||||||
// verify header
|
// verify header
|
||||||
const asarFs = getRawHeader(path.resolve(resourcesDir, asar));
|
const asarFs = getRawHeader(path.resolve(resourcesDir, asar));
|
||||||
expect(
|
expect(
|
||||||
removeUnstableProperties(asarFs.header, containsRuntimeGeneratedMacho ? ['hello-world'] : []),
|
removeUnstableProperties(
|
||||||
|
asarFs.header,
|
||||||
|
containsRuntimeGeneratedMacho
|
||||||
|
? ['hello-world', 'hello-world-arm64', 'hello-world-x64']
|
||||||
|
: [],
|
||||||
|
),
|
||||||
).toMatchSnapshot();
|
).toMatchSnapshot();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,7 +58,7 @@ export const verifyApp = async (appPath: string, containsRuntimeGeneratedMacho =
|
|||||||
await verifyFileTree(path.resolve(resourcesDir, dir));
|
await verifyFileTree(path.resolve(resourcesDir, dir));
|
||||||
}
|
}
|
||||||
|
|
||||||
const allFiles = await fileUtils.getAllAppFiles(appPath);
|
const allFiles = await fileUtils.getAllAppFiles(appPath, {});
|
||||||
const infoPlists = allFiles
|
const infoPlists = allFiles
|
||||||
.filter(
|
.filter(
|
||||||
(appFile) =>
|
(appFile) =>
|
||||||
@@ -89,7 +94,7 @@ const extractAsarIntegrity = async (infoPlist: string) => {
|
|||||||
export const verifyFileTree = async (dirPath: string) => {
|
export const verifyFileTree = async (dirPath: string) => {
|
||||||
const { expect } = await import('vitest');
|
const { expect } = await import('vitest');
|
||||||
|
|
||||||
const dirFiles = await fileUtils.getAllAppFiles(dirPath);
|
const dirFiles = await fileUtils.getAllAppFiles(dirPath, {});
|
||||||
const files = dirFiles.map((file) => {
|
const files = dirFiles.map((file) => {
|
||||||
const it = path.join(dirPath, file.relativePath);
|
const it = path.join(dirPath, file.relativePath);
|
||||||
const name = toSystemIndependentPath(file.relativePath);
|
const name = toSystemIndependentPath(file.relativePath);
|
||||||
@@ -229,6 +234,7 @@ export const generateNativeApp = async (options: {
|
|||||||
createAsar: boolean;
|
createAsar: boolean;
|
||||||
nativeModuleArch?: string;
|
nativeModuleArch?: string;
|
||||||
additionalFiles?: Record<string, string>;
|
additionalFiles?: Record<string, string>;
|
||||||
|
singleArchBindings?: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
appNameWithExtension,
|
appNameWithExtension,
|
||||||
@@ -236,6 +242,7 @@ export const generateNativeApp = async (options: {
|
|||||||
createAsar,
|
createAsar,
|
||||||
nativeModuleArch = arch,
|
nativeModuleArch = arch,
|
||||||
additionalFiles,
|
additionalFiles,
|
||||||
|
singleArchBindings,
|
||||||
} = options;
|
} = options;
|
||||||
const appPath = await templateApp(appNameWithExtension, arch, async (appPath) => {
|
const appPath = await templateApp(appNameWithExtension, arch, async (appPath) => {
|
||||||
const resources = path.join(appPath, 'Contents', 'Resources');
|
const resources = path.join(appPath, 'Contents', 'Resources');
|
||||||
@@ -247,14 +254,19 @@ export const generateNativeApp = async (options: {
|
|||||||
path.basename(appNameWithExtension, '.app'),
|
path.basename(appNameWithExtension, '.app'),
|
||||||
additionalFiles,
|
additionalFiles,
|
||||||
);
|
);
|
||||||
await fs.promises.cp(
|
let targetBinding: string;
|
||||||
path.join(appsDir, `hello-world-${nativeModuleArch}`),
|
if (singleArchBindings) {
|
||||||
path.join(testPath, 'hello-world'),
|
targetBinding = path.join(testPath, `hello-world-${nativeModuleArch}`);
|
||||||
{ recursive: true, verbatimSymlinks: true },
|
} else {
|
||||||
);
|
targetBinding = path.join(testPath, 'hello-world');
|
||||||
|
}
|
||||||
|
await fs.promises.cp(path.join(appsDir, `hello-world-${nativeModuleArch}`), targetBinding, {
|
||||||
|
recursive: true,
|
||||||
|
verbatimSymlinks: true,
|
||||||
|
});
|
||||||
if (createAsar) {
|
if (createAsar) {
|
||||||
await createPackageWithOptions(testPath, path.resolve(resources, 'app.asar'), {
|
await createPackageWithOptions(testPath, path.resolve(resources, 'app.asar'), {
|
||||||
unpack: '**/hello-world',
|
unpack: '**/hello-world*',
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
await fs.promises.cp(testPath, resourcesApp, { recursive: true, verbatimSymlinks: true });
|
await fs.promises.cp(testPath, resourcesApp, { recursive: true, verbatimSymlinks: true });
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"module": "commonjs",
|
|
||||||
"target": "es2017",
|
|
||||||
"lib": [
|
|
||||||
"es2017"
|
|
||||||
],
|
|
||||||
"sourceMap": true,
|
|
||||||
"strict": true,
|
|
||||||
"outDir": "entry-asar",
|
|
||||||
"types": [
|
|
||||||
"node",
|
|
||||||
],
|
|
||||||
"allowSyntheticDefaultImports": true,
|
|
||||||
"moduleResolution": "node",
|
|
||||||
"esModuleInterop": true,
|
|
||||||
"declaration": false
|
|
||||||
},
|
|
||||||
"include": [
|
|
||||||
"entry-asar"
|
|
||||||
],
|
|
||||||
"exclude": []
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user