mirror of
https://github.com/Llewellynvdm/nativefier.git
synced 2025-04-02 21:01:50 +00:00
- Docker builds for Windows are fixed (fixes #997) - Switched over to use Alpine (as was indicated as desired in https://github.com/nativefier/nativefier/issues/375#issuecomment-304247033) - which may mean #375 is fixed as well. - Fixed bug where Docker has the wrong line endings when copying from a Windows host - Fixed the invalid `arm` arch to `armv7l` - Add `npm t` to the docker build to ensure tests pass before we start trying to do builds - Add a message to help the user when trying to build Mac apps on Windows as a non-Admin (currently an unhelpful exception) Co-authored-by: Ronan Jouchet <ronan@jouchet.fr>
This commit is contained in:
parent
cbb4380583
commit
8f9135312b
@ -41,6 +41,7 @@ build/Release
|
|||||||
# Dependency directory
|
# Dependency directory
|
||||||
# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
|
# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
|
||||||
node_modules
|
node_modules
|
||||||
|
app/node_modules
|
||||||
|
|
||||||
# IntelliJ project files
|
# IntelliJ project files
|
||||||
.idea
|
.idea
|
||||||
|
42
Dockerfile
42
Dockerfile
@ -1,34 +1,46 @@
|
|||||||
FROM node:12-stretch
|
FROM node:12-alpine
|
||||||
LABEL description="Debian image to build nativefier apps"
|
LABEL description="Alpine image to build Nativefier apps"
|
||||||
|
|
||||||
# Get wine32, not 64, to work around binary incompatibility with rcedit.
|
|
||||||
# https://github.com/nativefier/nativefier/issues/375#issuecomment-304247033
|
|
||||||
# Forced us to use Debian rather than Alpine, which doesn't do multiarch.
|
|
||||||
RUN dpkg --add-architecture i386
|
|
||||||
|
|
||||||
# Install dependencies
|
# Install dependencies
|
||||||
RUN apt-get update \
|
RUN apk update \
|
||||||
&& apt-get --yes install wine32 imagemagick \
|
&& apk add bash wine imagemagick dos2unix \
|
||||||
&& apt-get clean && rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/cache/apk/*
|
||||||
|
|
||||||
|
WORKDIR /nativefier
|
||||||
|
|
||||||
# Add sources
|
# Add sources
|
||||||
COPY . /nativefier
|
COPY . .
|
||||||
|
|
||||||
|
# Fix line endings that may have gotten mangled in Windows
|
||||||
|
RUN find ./icon-scripts ./src ./app -type f -print0 | xargs -0 dos2unix
|
||||||
|
|
||||||
# Build nativefier and link globally
|
# Build nativefier and link globally
|
||||||
WORKDIR /nativefier/app
|
WORKDIR /nativefier/app
|
||||||
RUN npm install
|
RUN npm install
|
||||||
WORKDIR /nativefier
|
WORKDIR /nativefier
|
||||||
RUN npm install && npm run build && npm link
|
|
||||||
|
# Install (note that we had to manually install in `app` before, as `prepare` won't run as root)
|
||||||
|
# Also, running tests, to ensure we don't Docker build & publish broken stuff
|
||||||
|
RUN npm install && npm run build && npm test && npm link
|
||||||
|
|
||||||
|
# Cleanup test artifacts
|
||||||
|
RUN rm -rf /tmp/nativefier*
|
||||||
|
|
||||||
# Use 1000 as default user not root
|
# Use 1000 as default user not root
|
||||||
USER 1000
|
USER 1000
|
||||||
|
|
||||||
# Run a {lin,mac,win} build: 1. to check installation was sucessful,
|
# Run a {lin,mac,win} build
|
||||||
# 2. to cache electron distributables and avoid downloads at runtime.
|
# 1. to check installation was sucessful
|
||||||
|
# 2. to cache electron distributables and avoid downloads at runtime
|
||||||
RUN nativefier https://github.com/nativefier/nativefier /tmp/nativefier \
|
RUN nativefier https://github.com/nativefier/nativefier /tmp/nativefier \
|
||||||
&& nativefier -p osx https://github.com/nativefier/nativefier /tmp/nativefier \
|
&& nativefier -p osx https://github.com/nativefier/nativefier /tmp/nativefier \
|
||||||
&& nativefier -p windows https://github.com/nativefier/nativefier /tmp/nativefier \
|
&& nativefier -p windows https://github.com/nativefier/nativefier /tmp/nativefier
|
||||||
&& rm -rf /tmp/nativefier
|
|
||||||
|
|
||||||
|
RUN echo Generated Electron cache size: $(du -sh ~/.cache/electron) \
|
||||||
|
&& rm -rf /tmp/nativefier \
|
||||||
|
&& echo Final image size: $(du -sh / 2>/dev/null)
|
||||||
|
|
||||||
ENTRYPOINT ["nativefier"]
|
ENTRYPOINT ["nativefier"]
|
||||||
CMD ["--help"]
|
CMD ["--help"]
|
||||||
|
34
docs/api.md
34
docs/api.md
@ -70,12 +70,12 @@
|
|||||||
- [[browserwindow-options]](#browserwindow-options)
|
- [[browserwindow-options]](#browserwindow-options)
|
||||||
- [[darwin-dark-mode-support]](#darwin-dark-mode-support)
|
- [[darwin-dark-mode-support]](#darwin-dark-mode-support)
|
||||||
- [[background-color]](#background-color)
|
- [[background-color]](#background-color)
|
||||||
- [[disable-old-build-warning-yesiknowitisinsecure]](#disable-old-build-warning-yesiknowitisinsecure)
|
|
||||||
- [Programmatic API](#programmatic-api)
|
- [Programmatic API](#programmatic-api)
|
||||||
- [Addition packaging options for Windows](#addition-packaging-options-for-windows)
|
- [Addition packaging options for Windows](#addition-packaging-options-for-windows)
|
||||||
- [[version-string]](#version-string)
|
- [[version-string]](#version-string)
|
||||||
- [[win32metadata]](#win32metadata)
|
- [[win32metadata]](#win32metadata)
|
||||||
- [Programmatic API](#programmatic-api)
|
- [Programmatic API](#programmatic-api-1)
|
||||||
|
- [[disable-old-build-warning-yesiknowitisinsecure]](#disable-old-build-warning-yesiknowitisinsecure)
|
||||||
|
|
||||||
## Packaging Squirrel-based installers
|
## Packaging Squirrel-based installers
|
||||||
|
|
||||||
@ -129,7 +129,13 @@ The name of the application, which will affect strings in titles and the icon.
|
|||||||
-p, --platform <value>
|
-p, --platform <value>
|
||||||
```
|
```
|
||||||
|
|
||||||
Automatically determined based on the current OS. Can be overwritten by specifying either `linux`, `windows`, `osx` or `mas` for a Mac App Store specific build.
|
- Default: current operating system.
|
||||||
|
- To test your default platform you can run
|
||||||
|
```
|
||||||
|
node -p "process.platform"
|
||||||
|
```
|
||||||
|
(See https://nodejs.org/api/os.html#os_os_platform)
|
||||||
|
- Can be overwritten by specifying either `linux`, `windows`, `osx` or `mas` for a Mac App Store specific build.
|
||||||
|
|
||||||
The alternative values `win32` (for Windows) or `darwin`, `mac` (for macOS) can also be used.
|
The alternative values `win32` (for Windows) or `darwin`, `mac` (for macOS) can also be used.
|
||||||
|
|
||||||
@ -141,8 +147,14 @@ The alternative values `win32` (for Windows) or `darwin`, `mac` (for macOS) can
|
|||||||
|
|
||||||
The processor architecture to target when building.
|
The processor architecture to target when building.
|
||||||
|
|
||||||
- Automatically set to the build-time machine architecture...
|
- Default: the architecture of the installed version of node (usually the architecture of the build-time machine).
|
||||||
- ... or can be overridden by specifying one of: `x64`, `arm`, `arm64`, `ia32`.
|
- To test your default architecture you can run
|
||||||
|
```
|
||||||
|
node -p "process.arch"
|
||||||
|
```
|
||||||
|
(See https://nodejs.org/api/os.html#os_os_arch)
|
||||||
|
- Please note: On M1 Macs, unless an arm64 version of brew is used to install nodejs, the version installed will be an `x64` version run through Rosetta, and will result in an `x64` app being generated. If this is not desired, either specify `-a arm64` to build for M1, or re-install node with an arm64 version of brew. See https://github.com/nativefier/nativefier/issues/1089
|
||||||
|
- Can be overridden by specifying one of: `ia32`, `x64`, `armv7l`, `arm64`.
|
||||||
|
|
||||||
#### [app-copyright]
|
#### [app-copyright]
|
||||||
|
|
||||||
@ -858,12 +870,6 @@ Example:
|
|||||||
nativefier <your-geolocation-enabled-website> --win32metadata '{"ProductName": "Your Product Name", "InternalName", "Your Internal Name", "FileDescription": "Your File Description"}'
|
nativefier <your-geolocation-enabled-website> --win32metadata '{"ProductName": "Your Product Name", "InternalName", "Your Internal Name", "FileDescription": "Your File Description"}'
|
||||||
```
|
```
|
||||||
|
|
||||||
#### [disable-old-build-warning-yesiknowitisinsecure]
|
|
||||||
|
|
||||||
Disables the warning shown when opening a Nativefier app made a long time ago, using an old and probably insecure Electron. Nativefier uses the Chrome browser (through Electron), and remaining on an old version is A. performance sub-optimal and B. dangerous.
|
|
||||||
|
|
||||||
However, there are legitimate use cases to disable such a warning. For example, if you are using Nativefier to ship a kiosk app exposing an internal site (over which you have control). Under those circumstances, it is reasonable to disable this warning that you definitely don't want end-users to see.
|
|
||||||
|
|
||||||
##### Programmatic API
|
##### Programmatic API
|
||||||
|
|
||||||
_Object_
|
_Object_
|
||||||
@ -893,4 +899,10 @@ var options = {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### [disable-old-build-warning-yesiknowitisinsecure]
|
||||||
|
|
||||||
|
Disables the warning shown when opening a Nativefier app made a long time ago, using an old and probably insecure Electron. Nativefier uses the Chrome browser (through Electron), and remaining on an old version is A. performance sub-optimal and B. dangerous.
|
||||||
|
|
||||||
|
However, there are legitimate use cases to disable such a warning. For example, if you are using Nativefier to ship a kiosk app exposing an internal site (over which you have control). Under those circumstances, it is reasonable to disable this warning that you definitely don't want end-users to see.
|
||||||
|
|
||||||
More description about the options for `nativefier` can be found at the above [section](#command-line).
|
More description about the options for `nativefier` can be found at the above [section](#command-line).
|
||||||
|
@ -5,11 +5,16 @@ import * as electronPackager from 'electron-packager';
|
|||||||
import * as hasbin from 'hasbin';
|
import * as hasbin from 'hasbin';
|
||||||
import * as log from 'loglevel';
|
import * as log from 'loglevel';
|
||||||
|
|
||||||
import { isWindows, getTempDir, copyFileOrDir } from '../helpers/helpers';
|
import { convertIconIfNecessary } from './buildIcon';
|
||||||
|
import {
|
||||||
|
copyFileOrDir,
|
||||||
|
getTempDir,
|
||||||
|
isWindows,
|
||||||
|
isWindowsAdmin,
|
||||||
|
} from '../helpers/helpers';
|
||||||
|
import { AppOptions, NativefierOptions } from '../options/model';
|
||||||
import { getOptions } from '../options/optionsMain';
|
import { getOptions } from '../options/optionsMain';
|
||||||
import { prepareElectronApp } from './prepareElectronApp';
|
import { prepareElectronApp } from './prepareElectronApp';
|
||||||
import { convertIconIfNecessary } from './buildIcon';
|
|
||||||
import { AppOptions, NativefierOptions } from '../options/model';
|
|
||||||
|
|
||||||
const OPTIONS_REQUIRING_WINDOWS_FOR_WINDOWS_BUILD = [
|
const OPTIONS_REQUIRING_WINDOWS_FOR_WINDOWS_BUILD = [
|
||||||
'icon',
|
'icon',
|
||||||
@ -106,6 +111,22 @@ export async function buildNativefierApp(
|
|||||||
log.info('Processing options...');
|
log.info('Processing options...');
|
||||||
const options = await getOptions(rawOptions);
|
const options = await getOptions(rawOptions);
|
||||||
|
|
||||||
|
if (options.packager.platform === 'darwin' && isWindows()) {
|
||||||
|
// electron-packager has to extract the desired electron package for the target platform.
|
||||||
|
// For a target platform of Mac, this zip file contains symlinks. And on Windows, extracting
|
||||||
|
// files that are symlinks need Admin permissions. So we'll check if the user is an admin, and
|
||||||
|
// fail early if not.
|
||||||
|
// For reference
|
||||||
|
// https://github.com/electron/electron-packager/issues/933
|
||||||
|
// https://github.com/electron/electron-packager/issues/1194
|
||||||
|
// https://github.com/electron/electron/issues/11094
|
||||||
|
if (!isWindowsAdmin()) {
|
||||||
|
throw new Error(
|
||||||
|
'Building an app with a target platform of Mac on a Windows machine requires admin priveleges to perform. Please rerun this command in an admin command prompt.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
log.info('\nPreparing Electron app...');
|
log.info('\nPreparing Electron app...');
|
||||||
const tmpPath = getTempDir('app', 0o755);
|
const tmpPath = getTempDir('app', 0o755);
|
||||||
await prepareElectronApp(options.packager.dir, tmpPath, options);
|
await prepareElectronApp(options.packager.dir, tmpPath, options);
|
||||||
@ -135,7 +156,7 @@ export async function buildNativefierApp(
|
|||||||
osRunHelp = `the app bundle.`;
|
osRunHelp = `the app bundle.`;
|
||||||
}
|
}
|
||||||
log.info(
|
log.info(
|
||||||
`App built to ${appPath} , move it wherever it makes sense for you and run ${osRunHelp}`,
|
`App built to ${appPath}, move to wherever it makes sense for you and run ${osRunHelp}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return appPath;
|
return appPath;
|
||||||
|
17
src/cli.ts
17
src/cli.ts
@ -1,13 +1,14 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
import 'source-map-support/register';
|
import 'source-map-support/register';
|
||||||
|
|
||||||
import * as commander from 'commander';
|
|
||||||
import * as dns from 'dns';
|
import * as dns from 'dns';
|
||||||
|
|
||||||
|
import * as commander from 'commander';
|
||||||
import * as log from 'loglevel';
|
import * as log from 'loglevel';
|
||||||
|
|
||||||
|
import { isArgFormatInvalid, isWindows } from './helpers/helpers';
|
||||||
|
import { supportedArchs, supportedPlatforms } from './infer/inferOs';
|
||||||
import { buildNativefierApp } from './main';
|
import { buildNativefierApp } from './main';
|
||||||
import { isArgFormatInvalid } from './helpers/helpers';
|
|
||||||
import { isWindows } from './helpers/helpers';
|
|
||||||
|
|
||||||
// package.json is `require`d to let tsc strip the `src` folder by determining
|
// package.json is `require`d to let tsc strip the `src` folder by determining
|
||||||
// baseUrl=src. A static import would prevent that and cause an ugly extra "src" folder
|
// baseUrl=src. A static import would prevent that and cause an ugly extra "src" folder
|
||||||
@ -102,8 +103,14 @@ if (require.main === module) {
|
|||||||
positionalOptions.out = outputDirectory;
|
positionalOptions.out = outputDirectory;
|
||||||
})
|
})
|
||||||
.option('-n, --name <value>', 'app name')
|
.option('-n, --name <value>', 'app name')
|
||||||
.option('-p, --platform <value>', "'mac', 'mas', 'linux' or 'windows'")
|
.addOption(
|
||||||
.option('-a, --arch <value>', "'ia32' or 'x64' or 'arm' or 'arm64'")
|
new commander.Option('-p, --platform <value>').choices(
|
||||||
|
supportedPlatforms,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.addOption(
|
||||||
|
new commander.Option('-a, --arch <value>').choices(supportedArchs),
|
||||||
|
)
|
||||||
.option(
|
.option(
|
||||||
'--app-version <value>',
|
'--app-version <value>',
|
||||||
'(macOS, windows only) the version of the app. Maps to the `ProductVersion` metadata property on Windows, and `CFBundleShortVersionString` on macOS.',
|
'(macOS, windows only) the version of the app. Maps to the `ProductVersion` metadata property on Windows, and `CFBundleShortVersionString` on macOS.',
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
|
import { spawnSync } from 'child_process';
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import * as hasbin from 'hasbin';
|
import * as hasbin from 'hasbin';
|
||||||
import { ncp } from 'ncp';
|
|
||||||
import * as log from 'loglevel';
|
import * as log from 'loglevel';
|
||||||
|
import { ncp } from 'ncp';
|
||||||
import * as tmp from 'tmp';
|
import * as tmp from 'tmp';
|
||||||
|
|
||||||
tmp.setGracefulCleanup(); // cleanup temp dirs even when an uncaught exception occurs
|
tmp.setGracefulCleanup(); // cleanup temp dirs even when an uncaught exception occurs
|
||||||
|
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
@ -24,6 +26,16 @@ export function isWindows(): boolean {
|
|||||||
return os.platform() === 'win32';
|
return os.platform() === 'win32';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isWindowsAdmin(): boolean {
|
||||||
|
if (process.platform !== 'win32') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://stackoverflow.com/questions/4051883/batch-script-how-to-check-for-admin-rights
|
||||||
|
// https://stackoverflow.com/questions/57009374/check-admin-or-non-admin-users-in-nodejs-or-javascript
|
||||||
|
return spawnSync('fltmc').status === 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a temp directory with a debug-friendly name, and return its path.
|
* Create a temp directory with a debug-friendly name, and return its path.
|
||||||
* Will be automatically deleted on exit.
|
* Will be automatically deleted on exit.
|
||||||
|
@ -1,6 +1,22 @@
|
|||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
|
|
||||||
import * as log from 'loglevel';
|
import * as log from 'loglevel';
|
||||||
|
|
||||||
|
// Ideally we'd get this list directly from electron-packager, but it's not
|
||||||
|
// accessible in the package without importing its private js files, which felt
|
||||||
|
// dirty. So if those change, we'll update these as well.
|
||||||
|
// https://electron.github.io/electron-packager/master/interfaces/electronpackager.options.html#platform
|
||||||
|
// https://electron.github.io/electron-packager/master/interfaces/electronpackager.options.html#arch
|
||||||
|
export const supportedArchs = ['ia32', 'x64', 'armv7l', 'arm64'];
|
||||||
|
export const supportedPlatforms = [
|
||||||
|
'darwin',
|
||||||
|
'linux',
|
||||||
|
'mac',
|
||||||
|
'mas',
|
||||||
|
'osx',
|
||||||
|
'windows',
|
||||||
|
];
|
||||||
|
|
||||||
export function inferPlatform(): string {
|
export function inferPlatform(): string {
|
||||||
const platform = os.platform();
|
const platform = os.platform();
|
||||||
if (
|
if (
|
||||||
@ -19,7 +35,7 @@ export function inferPlatform(): string {
|
|||||||
|
|
||||||
export function inferArch(): string {
|
export function inferArch(): string {
|
||||||
const arch = os.arch();
|
const arch = os.arch();
|
||||||
if (arch !== 'ia32' && arch !== 'x64' && arch !== 'arm' && arch !== 'arm64') {
|
if (!supportedArchs.includes(arch)) {
|
||||||
throw new Error(`Incompatible architecture ${arch} detected`);
|
throw new Error(`Incompatible architecture ${arch} detected`);
|
||||||
}
|
}
|
||||||
log.debug('Inferred arch', arch);
|
log.debug('Inferred arch', arch);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user