mirror of
https://github.com/electron/electron.git
synced 2026-04-10 03:01:51 -04:00
Compare commits
350 Commits
v10.0.0-ni
...
v11.0.0-ni
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a9eaebb7f4 | ||
|
|
01c9113e2b | ||
|
|
481b19bee6 | ||
|
|
433956ce4f | ||
|
|
b0ea1e14e1 | ||
|
|
4d50f3f62c | ||
|
|
2028492356 | ||
|
|
3fa250d6da | ||
|
|
854b74809a | ||
|
|
cbdfeb1979 | ||
|
|
2224d94c75 | ||
|
|
b6f8cd39e5 | ||
|
|
075a7adcc0 | ||
|
|
14256ee697 | ||
|
|
aaa971ff19 | ||
|
|
5bf423b646 | ||
|
|
4f4c383ec5 | ||
|
|
5ed8afbdb6 | ||
|
|
5f447e4b4f | ||
|
|
4523c90dcd | ||
|
|
6cb23e1d36 | ||
|
|
a2c82f2342 | ||
|
|
9274117e12 | ||
|
|
99874fd71f | ||
|
|
06c47c650a | ||
|
|
30cd9cdf2a | ||
|
|
9c234f3f3f | ||
|
|
01a2e23194 | ||
|
|
15ee34a1f2 | ||
|
|
f53aac97f5 | ||
|
|
1350dc46ed | ||
|
|
6fd302f745 | ||
|
|
e5c721eafc | ||
|
|
a342ab7ce7 | ||
|
|
c3258d6c4e | ||
|
|
b5cd9ce0b3 | ||
|
|
e7fc19c98e | ||
|
|
948cc08265 | ||
|
|
d93bb34ac4 | ||
|
|
01023435c0 | ||
|
|
06cb550c75 | ||
|
|
1b175a0609 | ||
|
|
75372e933f | ||
|
|
f859d4ce44 | ||
|
|
9c37e12e2d | ||
|
|
834408a50f | ||
|
|
b6321cc22d | ||
|
|
38fafe4986 | ||
|
|
e6cf5906f6 | ||
|
|
362da77c0a | ||
|
|
3f45fc24bb | ||
|
|
75c3a426ea | ||
|
|
4e15273b9f | ||
|
|
c6c986648f | ||
|
|
bac232689d | ||
|
|
76e3ee6fe6 | ||
|
|
4829b0f816 | ||
|
|
a612fb00c8 | ||
|
|
2f02a469f4 | ||
|
|
b39a5b71fe | ||
|
|
91f5837344 | ||
|
|
5fc354df73 | ||
|
|
ee31611e84 | ||
|
|
071c5930b9 | ||
|
|
5cfe956fe1 | ||
|
|
b500294c1d | ||
|
|
3b250b649b | ||
|
|
2162eeb609 | ||
|
|
00fc8066de | ||
|
|
6b1de271a7 | ||
|
|
ec838cfc11 | ||
|
|
6fa3406912 | ||
|
|
b57f5086ef | ||
|
|
734753dd7a | ||
|
|
10bf50e1fd | ||
|
|
5795e59352 | ||
|
|
2fb14f53fe | ||
|
|
d4a4269989 | ||
|
|
cd805544d1 | ||
|
|
95dd81bd68 | ||
|
|
a76e74ac3f | ||
|
|
74e7f2773f | ||
|
|
b43e601b83 | ||
|
|
589968f9fc | ||
|
|
a12602dbc3 | ||
|
|
77eea08a54 | ||
|
|
86b441d599 | ||
|
|
509740c357 | ||
|
|
bcba4baa85 | ||
|
|
f0953902db | ||
|
|
e5cb22b7f9 | ||
|
|
682f78b9a8 | ||
|
|
8f5280a821 | ||
|
|
fa1323d6cd | ||
|
|
f146a164af | ||
|
|
6f53457a17 | ||
|
|
45551f6bf2 | ||
|
|
14bbc07f1e | ||
|
|
3806f4cb64 | ||
|
|
eb7c04c7c4 | ||
|
|
f649e604be | ||
|
|
4c3da359fc | ||
|
|
3f37ff87d2 | ||
|
|
24fb498fd3 | ||
|
|
d8be385d4b | ||
|
|
e4180b3a3a | ||
|
|
eb550c57d3 | ||
|
|
cdd5bb1eba | ||
|
|
9c8cdd63fd | ||
|
|
3f54f240bd | ||
|
|
36900df7d9 | ||
|
|
ce87a7e69f | ||
|
|
990a6f8b6c | ||
|
|
e002f7315d | ||
|
|
8bbdc224ac | ||
|
|
36bd940bc3 | ||
|
|
f0a0e10bd1 | ||
|
|
b02748e607 | ||
|
|
1719f073c1 | ||
|
|
91cdedfea9 | ||
|
|
cbb47570bd | ||
|
|
e18f508e66 | ||
|
|
6c4017ff45 | ||
|
|
5737fda154 | ||
|
|
8847517798 | ||
|
|
c9aa68e32c | ||
|
|
42f716bbc6 | ||
|
|
ef9addcb92 | ||
|
|
dcb56923cb | ||
|
|
eb6616e4e9 | ||
|
|
9bd0fc5348 | ||
|
|
66d65a6d35 | ||
|
|
4305707ca8 | ||
|
|
8d25847318 | ||
|
|
ad16e6c647 | ||
|
|
80a6adb597 | ||
|
|
7dd365784d | ||
|
|
e59370f541 | ||
|
|
6cfbee9f34 | ||
|
|
2aeaca6f7b | ||
|
|
cadc142d05 | ||
|
|
446100cdfe | ||
|
|
7fd96cd188 | ||
|
|
25a36a43c1 | ||
|
|
b0be3fbb7f | ||
|
|
71a7e1b2e3 | ||
|
|
2a3437e5b5 | ||
|
|
cf74ee3d83 | ||
|
|
99079c3bc7 | ||
|
|
1f23807271 | ||
|
|
82af855579 | ||
|
|
f6e21d59e7 | ||
|
|
4398ecb6c8 | ||
|
|
9106d0c6d5 | ||
|
|
92d9de93a4 | ||
|
|
fd0eaf4507 | ||
|
|
2a6d6d6ea7 | ||
|
|
d330c6f9fe | ||
|
|
82ae18dd1c | ||
|
|
c157311373 | ||
|
|
354ea00f17 | ||
|
|
4c449fbc75 | ||
|
|
3cb833821a | ||
|
|
a69a655386 | ||
|
|
dc3905cef4 | ||
|
|
22e64dc328 | ||
|
|
6bd30bf09e | ||
|
|
c6db47182a | ||
|
|
451086d7f2 | ||
|
|
ee61eb9aa4 | ||
|
|
2cbd091e89 | ||
|
|
af4876296c | ||
|
|
d9d07c65b2 | ||
|
|
6e069a7df8 | ||
|
|
ef3579eae3 | ||
|
|
80e5007c47 | ||
|
|
1c49e4e376 | ||
|
|
8eb198bab4 | ||
|
|
16a3f41fd3 | ||
|
|
605e50269e | ||
|
|
9b4572de44 | ||
|
|
5b80556da2 | ||
|
|
4290555a0d | ||
|
|
1429a8961c | ||
|
|
46f58b28c3 | ||
|
|
6369748a2a | ||
|
|
abf2e9c93d | ||
|
|
b2b5a6a3de | ||
|
|
acb64a2d3c | ||
|
|
3853fd3e99 | ||
|
|
659e79fc08 | ||
|
|
4c77fe318d | ||
|
|
72a089262e | ||
|
|
61a05caa78 | ||
|
|
563a8c83ea | ||
|
|
046a05944a | ||
|
|
0629c6c2ea | ||
|
|
48d1a70b52 | ||
|
|
5c6d8c2b7d | ||
|
|
0f44682be0 | ||
|
|
2376c45443 | ||
|
|
b665eb6d43 | ||
|
|
4e66f1b2c6 | ||
|
|
a54fcde3f4 | ||
|
|
7cc780d077 | ||
|
|
59f9d75324 | ||
|
|
cb6476fd12 | ||
|
|
e1e73fa5f5 | ||
|
|
09c0ee8f87 | ||
|
|
cf284991d8 | ||
|
|
f9fe8a67b9 | ||
|
|
7bf0af7d96 | ||
|
|
7a216a8fab | ||
|
|
673169a7ba | ||
|
|
9c7d73c6d6 | ||
|
|
0b830ba9e5 | ||
|
|
c0182bca15 | ||
|
|
8412aae231 | ||
|
|
b9ac334efc | ||
|
|
379bb174e9 | ||
|
|
178e46cd23 | ||
|
|
66744ecb4d | ||
|
|
a7599a0838 | ||
|
|
d5f642938d | ||
|
|
7274467f73 | ||
|
|
7c7ea141f0 | ||
|
|
c66282a460 | ||
|
|
78fe545d18 | ||
|
|
81d09bea44 | ||
|
|
130b176796 | ||
|
|
2e2e9a3702 | ||
|
|
04be1ac4a1 | ||
|
|
a33c10c3ed | ||
|
|
ce042184de | ||
|
|
b1574f9e59 | ||
|
|
9554d063a5 | ||
|
|
3eade2c228 | ||
|
|
71e2b7151c | ||
|
|
d08cfce6cb | ||
|
|
b2ef299efc | ||
|
|
fc8b49485a | ||
|
|
aa32fbf1d6 | ||
|
|
980e592271 | ||
|
|
c6c022dc46 | ||
|
|
261f385b5e | ||
|
|
6e710a20a6 | ||
|
|
46c9e15182 | ||
|
|
5185501b85 | ||
|
|
27d629abb9 | ||
|
|
9d960e29eb | ||
|
|
a1c55a13e1 | ||
|
|
491caf59c1 | ||
|
|
2d47daa8c4 | ||
|
|
25e4a9431c | ||
|
|
3fa4299939 | ||
|
|
90caa5eac9 | ||
|
|
b1adbf7fd7 | ||
|
|
2fadb73032 | ||
|
|
ac81a39e09 | ||
|
|
83247c48c3 | ||
|
|
5de6adfb84 | ||
|
|
d8594f7a78 | ||
|
|
087567655a | ||
|
|
512e1541c6 | ||
|
|
c36981da8b | ||
|
|
d3fa5ed1e8 | ||
|
|
edc5050a2e | ||
|
|
a5efc387c7 | ||
|
|
0062b126b4 | ||
|
|
969f46a48f | ||
|
|
c6f4573a13 | ||
|
|
95037a7d2a | ||
|
|
5218a6e6ab | ||
|
|
5918dd6e65 | ||
|
|
fbf397e15d | ||
|
|
066b8c5ab3 | ||
|
|
634ab45095 | ||
|
|
a4de915b74 | ||
|
|
4a551bde16 | ||
|
|
b809d104d0 | ||
|
|
4133c71105 | ||
|
|
f67aff2704 | ||
|
|
aa8d81511f | ||
|
|
236c1334e3 | ||
|
|
9f21d09dfd | ||
|
|
9dec16d81e | ||
|
|
b086197968 | ||
|
|
e8ea007104 | ||
|
|
e5da2caa34 | ||
|
|
a1edf5cf94 | ||
|
|
6516110c70 | ||
|
|
3a7775fa73 | ||
|
|
5d88d0ee74 | ||
|
|
7b0a84477a | ||
|
|
f78504515b | ||
|
|
ca6a415626 | ||
|
|
f445e0a797 | ||
|
|
204f001c5d | ||
|
|
dc72f74020 | ||
|
|
2b39111e30 | ||
|
|
2bc85b2579 | ||
|
|
0a026cde0c | ||
|
|
db5cf816b4 | ||
|
|
08f288faf1 | ||
|
|
0dabd5e8c7 | ||
|
|
2029ff1903 | ||
|
|
9bc5e98238 | ||
|
|
762f7bcca2 | ||
|
|
75847a0c5b | ||
|
|
e3c2ec9f7c | ||
|
|
fdf40ce07a | ||
|
|
82924679fe | ||
|
|
f373cc770f | ||
|
|
78d74bf8b4 | ||
|
|
5ed2512881 | ||
|
|
ce77e3327c | ||
|
|
7b55a70a36 | ||
|
|
5bdf97e7ae | ||
|
|
3137d5f011 | ||
|
|
4114281b62 | ||
|
|
21a6062a31 | ||
|
|
df53816eea | ||
|
|
4b23a85475 | ||
|
|
33d6a99d40 | ||
|
|
9d851b8791 | ||
|
|
0a481242f0 | ||
|
|
84888bb1f1 | ||
|
|
8de06f0c57 | ||
|
|
bca071f428 | ||
|
|
de44d28c8e | ||
|
|
3f3a760a01 | ||
|
|
27d7eb3880 | ||
|
|
393b637e9e | ||
|
|
33bd218df9 | ||
|
|
82da234650 | ||
|
|
ce53c35e1d | ||
|
|
82f89c8206 | ||
|
|
38a04214e0 | ||
|
|
01579cc8ed | ||
|
|
c00103d274 | ||
|
|
89441caad4 | ||
|
|
7e841ceb5c | ||
|
|
8879a3db58 | ||
|
|
ee0f67d541 | ||
|
|
eb341b383d | ||
|
|
87a670f74d | ||
|
|
8bbb68be79 | ||
|
|
75fd9a3496 | ||
|
|
52b50e6b33 | ||
|
|
9d7ba98209 |
@@ -37,10 +37,18 @@ parameters:
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
run-osx-publish-arm64:
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
run-mas-publish:
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
run-mas-publish-arm64:
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
run-linux-publish:
|
||||
type: boolean
|
||||
default: false
|
||||
@@ -77,12 +85,17 @@ machine-linux-2xlarge: &machine-linux-2xlarge
|
||||
|
||||
machine-mac: &machine-mac
|
||||
macos:
|
||||
xcode: "11.1.0"
|
||||
xcode: "11.5.0"
|
||||
|
||||
machine-mac-large: &machine-mac-large
|
||||
resource_class: large
|
||||
macos:
|
||||
xcode: "11.1.0"
|
||||
xcode: "11.5.0"
|
||||
|
||||
machine-mac-large-arm: &machine-mac-large-arm
|
||||
resource_class: large
|
||||
macos:
|
||||
xcode: "12.0.0-UA"
|
||||
|
||||
# Build configurations options.
|
||||
env-testing-build: &env-testing-build
|
||||
@@ -123,6 +136,10 @@ env-arm: &env-arm
|
||||
BUILD_NATIVE_MKSNAPSHOT: 1
|
||||
TARGET_ARCH: arm
|
||||
|
||||
env-apple-silicon: &env-apple-silicon
|
||||
GN_EXTRA_ARGS: 'target_cpu = "arm64"'
|
||||
TARGET_ARCH: arm64
|
||||
|
||||
env-arm64: &env-arm64
|
||||
GN_EXTRA_ARGS: 'target_cpu = "arm64" fatal_linker_warnings = false enable_linux_installer = false'
|
||||
MKSNAPSHOT_TOOLCHAIN: //build/toolchain/linux:clang_arm64
|
||||
@@ -133,6 +150,11 @@ env-mas: &env-mas
|
||||
GN_EXTRA_ARGS: 'is_mas_build = true'
|
||||
MAS_BUILD: 'true'
|
||||
|
||||
env-mas-apple-silicon: &env-mas-apple-silicon
|
||||
GN_EXTRA_ARGS: 'target_cpu = "arm64" is_mas_build = true'
|
||||
MAS_BUILD: 'true'
|
||||
TARGET_ARCH: arm64
|
||||
|
||||
# Misc build configuration options.
|
||||
env-enable-sccache: &env-enable-sccache
|
||||
USE_SCCACHE: true
|
||||
@@ -312,14 +334,25 @@ step-get-more-space-on-mac: &step-get-more-space-on-mac
|
||||
name: Free up space on MacOS
|
||||
command: |
|
||||
if [ "`uname`" == "Darwin" ]; then
|
||||
sudo rm -rf /Library/Developer/CoreSimulator
|
||||
sudo rm -rf /Applications/Xcode.app/Contents/Developer/Platforms/AppleTVOS.platform
|
||||
sudo rm -rf /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform
|
||||
sudo rm -rf /Applications/Xcode.app/Contents/Developer/Platforms/WatchOS.platform
|
||||
sudo rm -rf /Applications/Xcode.app/Contents/Developer/Platforms/WatchSimulator.platform
|
||||
sudo rm -rf /Applications/Xcode.app/Contents/Developer/Platforms/AppleTVSimulator.platform
|
||||
sudo rm -rf /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform
|
||||
sudo mkdir -p $TMPDIR/del-target
|
||||
tmpify() {
|
||||
if [ -d "$1" ]; then
|
||||
sudo mv $1 $TMPDIR/del-target/$(echo $1|shasum -a 256|head -n1|cut -d " " -f1)
|
||||
fi
|
||||
}
|
||||
tmpify /Library/Developer/CoreSimulator
|
||||
tmpify $(xcode-select -p)/Platforms/AppleTVOS.platform
|
||||
tmpify $(xcode-select -p)/Platforms/iPhoneOS.platform
|
||||
tmpify $(xcode-select -p)/Platforms/WatchOS.platform
|
||||
tmpify $(xcode-select -p)/Platforms/WatchSimulator.platform
|
||||
tmpify $(xcode-select -p)/Platforms/AppleTVSimulator.platform
|
||||
tmpify $(xcode-select -p)/Platforms/iPhoneSimulator.platform
|
||||
tmpify ~/.rubies
|
||||
tmpify ~/Library/Caches/Homebrew
|
||||
tmpify /usr/local/Homebrew
|
||||
sudo rm -rf $TMPDIR/del-target
|
||||
fi
|
||||
background: true
|
||||
|
||||
# On macOS delete all .git directories under src/ expect for
|
||||
# third_party/angle/ because of build time generation of file
|
||||
@@ -418,6 +451,7 @@ step-electron-build: &step-electron-build
|
||||
fi
|
||||
cd src
|
||||
ninja -C out/Default electron -j $NUMBER_OF_NINJA_PROCESSES
|
||||
node electron/script/check-symlinks.js
|
||||
|
||||
step-native-unittests-build: &step-native-unittests-build
|
||||
run:
|
||||
@@ -706,12 +740,11 @@ step-hunspell-store: &step-hunspell-store
|
||||
step-maybe-generate-breakpad-symbols: &step-maybe-generate-breakpad-symbols
|
||||
run:
|
||||
name: Generate breakpad symbols
|
||||
no_output_timeout: 30m
|
||||
command: |
|
||||
if [ "$GENERATE_SYMBOLS" == "true" ]; then
|
||||
cd src
|
||||
ninja -C out/Default electron:electron_symbols
|
||||
cd out/Default/breakpad_symbols
|
||||
find . -name \*.sym -print0 | xargs -0 npx @sentry/cli@1.51.1 difutil bundle-sources
|
||||
fi
|
||||
|
||||
step-maybe-zip-symbols: &step-maybe-zip-symbols
|
||||
@@ -740,9 +773,13 @@ step-maybe-cross-arch-snapshot: &step-maybe-cross-arch-snapshot
|
||||
elif [ "$TARGET_ARCH" == "arm64" ]; then
|
||||
export MKSNAPSHOT_PATH="clang_x64_v8_arm64"
|
||||
fi
|
||||
cp "out/Default/$MKSNAPSHOT_PATH/mksnapshot" out/Default
|
||||
cp "out/Default/$MKSNAPSHOT_PATH/libffmpeg.so" out/Default
|
||||
cp "out/Default/$MKSNAPSHOT_PATH/mksnapshot" out/Default
|
||||
cp "out/Default/$MKSNAPSHOT_PATH/v8_context_snapshot_generator" out/Default
|
||||
if [ "`uname`" == "Linux" ]; then
|
||||
cp "out/Default/$MKSNAPSHOT_PATH/libffmpeg.so" out/Default
|
||||
elif [ "`uname`" == "Darwin" ]; then
|
||||
cp "out/Default/$MKSNAPSHOT_PATH/libffmpeg.dylib" out/Default
|
||||
fi
|
||||
python electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default --create-snapshot-only
|
||||
mkdir cross-arch-snapshots
|
||||
cp out/Default-mksnapshot-test/*.bin cross-arch-snapshots
|
||||
@@ -761,8 +798,13 @@ step-maybe-trigger-arm-test: &step-maybe-trigger-arm-test
|
||||
# Only run for non-fork prs
|
||||
if [ "$TRIGGER_ARM_TEST" == "true" ] && [ -z "$CIRCLE_PR_NUMBER" ]; then
|
||||
#Trigger VSTS job, passing along CircleCI job number and branch to build
|
||||
echo "Triggering electron-$TARGET_ARCH-testing build on VSTS"
|
||||
node electron/script/release/ci-release-build.js --job=electron-$TARGET_ARCH-testing --ci=VSTS --armTest --circleBuildNum=$CIRCLE_BUILD_NUM $CIRCLE_BRANCH
|
||||
if [ "`uname`" == "Darwin" ]; then
|
||||
echo "Triggering electron-arm2-testing build on Azure DevOps"
|
||||
node electron/script/release/ci-release-build.js --job=electron-arm2-testing --ci=DevOps --armTest --circleBuildNum=$CIRCLE_BUILD_NUM $CIRCLE_BRANCH
|
||||
else
|
||||
echo "Triggering electron-$TARGET_ARCH-testing build on VSTS"
|
||||
node electron/script/release/ci-release-build.js --job=electron-$TARGET_ARCH-testing --ci=VSTS --armTest --circleBuildNum=$CIRCLE_BUILD_NUM $CIRCLE_BRANCH
|
||||
fi
|
||||
fi
|
||||
|
||||
step-maybe-generate-typescript-defs: &step-maybe-generate-typescript-defs
|
||||
@@ -810,8 +852,13 @@ step-touch-sync-done: &step-touch-sync-done
|
||||
step-maybe-restore-src-cache: &step-maybe-restore-src-cache
|
||||
restore_cache:
|
||||
keys:
|
||||
- v7-src-cache-{{ checksum "src/electron/.depshash" }}
|
||||
- v8-src-cache-{{ checksum "src/electron/.depshash" }}
|
||||
name: Restoring src cache
|
||||
step-maybe-restore-src-cache-marker: &step-maybe-restore-src-cache-marker
|
||||
restore_cache:
|
||||
keys:
|
||||
- v1-src-cache-marker-{{ checksum "src/electron/.depshash" }}
|
||||
name: Restoring src cache marker
|
||||
|
||||
# Restore exact or closest git cache based on the hash of DEPS and .circle-sync-done
|
||||
# If the src cache was restored above then this will match an empty cache
|
||||
@@ -830,7 +877,7 @@ step-restore-out-cache: &step-restore-out-cache
|
||||
paths:
|
||||
- ./src/out/Default
|
||||
keys:
|
||||
- v7-out-cache-{{ checksum "src/electron/.depshash" }}-{{ checksum "src/electron/.depshash-target" }}
|
||||
- v9-out-cache-{{ checksum "src/electron/.depshash" }}-{{ checksum "src/electron/.depshash-target" }}
|
||||
name: Restoring out cache
|
||||
|
||||
step-set-git-cache-path: &step-set-git-cache-path
|
||||
@@ -854,7 +901,7 @@ step-save-out-cache: &step-save-out-cache
|
||||
save_cache:
|
||||
paths:
|
||||
- ./src/out/Default
|
||||
key: v7-out-cache-{{ checksum "src/electron/.depshash" }}-{{ checksum "src/electron/.depshash-target" }}
|
||||
key: v9-out-cache-{{ checksum "src/electron/.depshash" }}-{{ checksum "src/electron/.depshash-target" }}
|
||||
name: Persisting out cache
|
||||
|
||||
step-run-electron-only-hooks: &step-run-electron-only-hooks
|
||||
@@ -888,9 +935,18 @@ step-minimize-workspace-size-from-checkout: &step-minimize-workspace-size-from-c
|
||||
step-save-src-cache: &step-save-src-cache
|
||||
save_cache:
|
||||
paths:
|
||||
- /portal
|
||||
key: v7-src-cache-{{ checksum "/portal/src/electron/.depshash" }}
|
||||
- /var/portal
|
||||
key: v8-src-cache-{{ checksum "/var/portal/src/electron/.depshash" }}
|
||||
name: Persisting src cache
|
||||
step-make-src-cache-marker: &step-make-src-cache-marker
|
||||
run:
|
||||
name: Making src cache marker
|
||||
command: touch .src-cache-marker
|
||||
step-save-src-cache-marker: &step-save-src-cache-marker
|
||||
save_cache:
|
||||
paths:
|
||||
- .src-cache-marker
|
||||
key: v1-src-cache-marker-{{ checksum "/var/portal/src/electron/.depshash" }}
|
||||
|
||||
# Check for doc only change
|
||||
step-check-for-doc-only-change: &step-check-for-doc-only-change
|
||||
@@ -981,6 +1037,11 @@ steps-lint: &steps-lint
|
||||
cd src/electron
|
||||
node script/yarn install --frozen-lockfile
|
||||
node script/yarn lint
|
||||
- run:
|
||||
name: Run Script Typechecker
|
||||
command: |
|
||||
cd src/electron
|
||||
node script/yarn tsc -p tsconfig.script.json
|
||||
|
||||
steps-checkout-and-save-cache: &steps-checkout-and-save-cache
|
||||
steps:
|
||||
@@ -996,7 +1057,8 @@ steps-checkout-and-save-cache: &steps-checkout-and-save-cache
|
||||
|
||||
- *step-generate-deps-hash
|
||||
- *step-touch-sync-done
|
||||
- maybe-restore-portaled-src-cache
|
||||
- maybe-restore-portaled-src-cache:
|
||||
halt-if-successful: true
|
||||
- *step-maybe-restore-git-cache
|
||||
- *step-set-git-cache-path
|
||||
# This sync call only runs if .circle-sync-done is an EMPTY file
|
||||
@@ -1017,10 +1079,12 @@ steps-checkout-and-save-cache: &steps-checkout-and-save-cache
|
||||
- run:
|
||||
name: Move src folder to the cross-OS portal
|
||||
command: |
|
||||
sudo mkdir -p /portal
|
||||
sudo chown -R $(id -u):$(id -g) /portal
|
||||
mv ./src /portal
|
||||
sudo mkdir -p /var/portal
|
||||
sudo chown -R $(id -u):$(id -g) /var/portal
|
||||
mv ./src /var/portal
|
||||
- *step-save-src-cache
|
||||
- *step-make-src-cache-marker
|
||||
- *step-save-src-cache-marker
|
||||
|
||||
steps-electron-gn-check: &steps-electron-gn-check
|
||||
steps:
|
||||
@@ -1041,8 +1105,8 @@ steps-electron-ts-compile-for-doc-change: &steps-electron-ts-compile-for-doc-cha
|
||||
- *step-depot-tools-get
|
||||
- *step-depot-tools-add-to-path
|
||||
- *step-restore-brew-cache
|
||||
- *step-get-more-space-on-mac
|
||||
- *step-install-gnutar-on-mac
|
||||
- *step-get-more-space-on-mac
|
||||
- *step-generate-deps-hash
|
||||
- *step-touch-sync-done
|
||||
- maybe-restore-portaled-src-cache
|
||||
@@ -1164,8 +1228,8 @@ steps-tests: &steps-tests
|
||||
ELECTRON_DISABLE_SECURITY_WARNINGS: 1
|
||||
command: |
|
||||
cd src
|
||||
(cd electron && node script/yarn test --runners=main --enable-logging --files $(circleci tests glob spec-main/*-spec.ts | circleci tests split))
|
||||
(cd electron && node script/yarn test --runners=remote --enable-logging --files $(circleci tests glob spec/*-spec.js | circleci tests split))
|
||||
(cd electron && node script/yarn test --runners=main --trace-uncaught --enable-logging --files $(circleci tests glob spec-main/*-spec.ts | circleci tests split))
|
||||
(cd electron && node script/yarn test --runners=remote --trace-uncaught --enable-logging --files $(circleci tests glob spec/*-spec.js | circleci tests split))
|
||||
- run:
|
||||
name: Check test results existence
|
||||
command: |
|
||||
@@ -1224,20 +1288,34 @@ chromium-upgrade-branches: &chromium-upgrade-branches
|
||||
# Command Aliases
|
||||
commands:
|
||||
maybe-restore-portaled-src-cache:
|
||||
parameters:
|
||||
halt-if-successful:
|
||||
type: boolean
|
||||
default: false
|
||||
steps:
|
||||
- run:
|
||||
name: Prepare for cross-OS sync restore
|
||||
command: |
|
||||
sudo mkdir -p /portal
|
||||
sudo chown -R $(id -u):$(id -g) /portal
|
||||
sudo mkdir -p /var/portal
|
||||
sudo chown -R $(id -u):$(id -g) /var/portal
|
||||
- when:
|
||||
condition: << parameters.halt-if-successful >>
|
||||
steps:
|
||||
- *step-maybe-restore-src-cache-marker
|
||||
- run:
|
||||
name: Halt the job early if the src cache exists
|
||||
command: |
|
||||
if [ -f ".src-cache-marker" ]; then
|
||||
circleci-agent step halt
|
||||
fi
|
||||
- *step-maybe-restore-src-cache
|
||||
- run:
|
||||
name: Fix the src cache restore point on macOS
|
||||
command: |
|
||||
if [ -d "/portal/src" ]; then
|
||||
if [ -d "/var/portal/src" ]; then
|
||||
echo Relocating Cache
|
||||
rm -rf src
|
||||
mv /portal/src ./
|
||||
mv /var/portal/src ./
|
||||
fi
|
||||
checkout-from-cache:
|
||||
steps:
|
||||
@@ -1700,7 +1778,7 @@ jobs:
|
||||
<<: *env-enable-sccache
|
||||
UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >>
|
||||
steps:
|
||||
- electron-publish:
|
||||
- electron-publish:
|
||||
attach: false
|
||||
checkout: true
|
||||
|
||||
@@ -1712,7 +1790,7 @@ jobs:
|
||||
<<: *env-enable-sccache
|
||||
UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >>
|
||||
steps:
|
||||
- electron-publish:
|
||||
- electron-publish:
|
||||
attach: true
|
||||
checkout: false
|
||||
|
||||
@@ -1764,7 +1842,7 @@ jobs:
|
||||
<<: *env-32bit-release
|
||||
UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >>
|
||||
steps:
|
||||
- electron-publish:
|
||||
- electron-publish:
|
||||
attach: false
|
||||
checkout: true
|
||||
|
||||
@@ -1778,7 +1856,7 @@ jobs:
|
||||
<<: *env-32bit-release
|
||||
UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >>
|
||||
steps:
|
||||
- electron-publish:
|
||||
- electron-publish:
|
||||
attach: true
|
||||
checkout: false
|
||||
|
||||
@@ -1831,7 +1909,7 @@ jobs:
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_boto=True --custom-var=checkout_requests=True'
|
||||
UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >>
|
||||
steps:
|
||||
- electron-publish:
|
||||
- electron-publish:
|
||||
attach: false
|
||||
checkout: true
|
||||
|
||||
@@ -1845,7 +1923,7 @@ jobs:
|
||||
<<: *env-32bit-release
|
||||
UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >>
|
||||
steps:
|
||||
- electron-publish:
|
||||
- electron-publish:
|
||||
attach: true
|
||||
checkout: false
|
||||
|
||||
@@ -1905,7 +1983,7 @@ jobs:
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm64=True --custom-var=checkout_boto=True --custom-var=checkout_requests=True'
|
||||
UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >>
|
||||
steps:
|
||||
- electron-publish:
|
||||
- electron-publish:
|
||||
attach: false
|
||||
checkout: true
|
||||
|
||||
@@ -1918,11 +1996,11 @@ jobs:
|
||||
<<: *env-enable-sccache
|
||||
UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >>
|
||||
steps:
|
||||
- electron-publish:
|
||||
- electron-publish:
|
||||
attach: true
|
||||
checkout: false
|
||||
|
||||
osx-testing:
|
||||
osx-testing-x64:
|
||||
<<: *machine-mac-large
|
||||
environment:
|
||||
<<: *env-mac-large
|
||||
@@ -1937,22 +2015,14 @@ jobs:
|
||||
checkout-and-assume-cache: true
|
||||
attach: false
|
||||
|
||||
osx-testing-gn-check:
|
||||
osx-testing-x64-gn-check:
|
||||
<<: *machine-mac
|
||||
environment:
|
||||
<<: *env-machine-mac
|
||||
<<: *env-testing-build
|
||||
<<: *steps-electron-gn-check
|
||||
|
||||
osx-chromedriver:
|
||||
<<: *machine-mac
|
||||
environment:
|
||||
<<: *env-machine-mac
|
||||
<<: *env-release-build
|
||||
<<: *env-send-slack-notifications
|
||||
<<: *steps-chromedriver-build
|
||||
|
||||
osx-release:
|
||||
osx-release-x64:
|
||||
<<: *machine-mac-large
|
||||
environment:
|
||||
<<: *env-mac-large
|
||||
@@ -1966,7 +2036,7 @@ jobs:
|
||||
checkout-and-assume-cache: true
|
||||
attach: false
|
||||
|
||||
osx-publish:
|
||||
osx-publish-x64:
|
||||
<<: *machine-mac-large
|
||||
environment:
|
||||
<<: *env-mac-large-release
|
||||
@@ -1975,11 +2045,25 @@ jobs:
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_boto=True --custom-var=checkout_requests=True'
|
||||
UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >>
|
||||
steps:
|
||||
- electron-publish:
|
||||
- electron-publish:
|
||||
attach: false
|
||||
checkout: true
|
||||
|
||||
osx-publish-skip-checkout:
|
||||
osx-publish-arm64:
|
||||
<<: *machine-mac-large-arm
|
||||
environment:
|
||||
<<: *env-mac-large-release
|
||||
<<: *env-release-build
|
||||
<<: *env-enable-sccache
|
||||
<<: *env-apple-silicon
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_boto=True --custom-var=checkout_requests=True'
|
||||
UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >>
|
||||
steps:
|
||||
- electron-publish:
|
||||
attach: false
|
||||
checkout: true
|
||||
|
||||
osx-publish-x64-skip-checkout:
|
||||
<<: *machine-mac-large
|
||||
environment:
|
||||
<<: *env-mac-large-release
|
||||
@@ -1987,11 +2071,40 @@ jobs:
|
||||
<<: *env-enable-sccache
|
||||
UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >>
|
||||
steps:
|
||||
- electron-publish:
|
||||
- electron-publish:
|
||||
attach: true
|
||||
checkout: false
|
||||
|
||||
mas-testing:
|
||||
osx-publish-arm64-skip-checkout:
|
||||
<<: *machine-mac-large-arm
|
||||
environment:
|
||||
<<: *env-mac-large-release
|
||||
<<: *env-release-build
|
||||
<<: *env-enable-sccache
|
||||
<<: *env-apple-silicon
|
||||
UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >>
|
||||
steps:
|
||||
- electron-publish:
|
||||
attach: true
|
||||
checkout: false
|
||||
|
||||
osx-testing-arm64:
|
||||
<<: *machine-mac-large-arm
|
||||
environment:
|
||||
<<: *env-mac-large
|
||||
<<: *env-testing-build
|
||||
<<: *env-ninja-status
|
||||
<<: *env-macos-build
|
||||
<<: *env-apple-silicon
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac'
|
||||
steps:
|
||||
- electron-build:
|
||||
persist: true
|
||||
checkout: false
|
||||
checkout-and-assume-cache: true
|
||||
attach: false
|
||||
|
||||
mas-testing-x64:
|
||||
<<: *machine-mac-large
|
||||
environment:
|
||||
<<: *env-mac-large
|
||||
@@ -2007,7 +2120,7 @@ jobs:
|
||||
checkout-and-assume-cache: true
|
||||
attach: false
|
||||
|
||||
mas-testing-gn-check:
|
||||
mas-testing-x64-gn-check:
|
||||
<<: *machine-mac
|
||||
environment:
|
||||
<<: *env-machine-mac
|
||||
@@ -2040,11 +2153,25 @@ jobs:
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_boto=True --custom-var=checkout_requests=True'
|
||||
UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >>
|
||||
steps:
|
||||
- electron-publish:
|
||||
- electron-publish:
|
||||
attach: false
|
||||
checkout: true
|
||||
|
||||
mas-publish-skip-checkout:
|
||||
mas-publish-arm64:
|
||||
<<: *machine-mac-large-arm
|
||||
environment:
|
||||
<<: *env-mac-large-release
|
||||
<<: *env-mas-apple-silicon
|
||||
<<: *env-release-build
|
||||
<<: *env-enable-sccache
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_boto=True --custom-var=checkout_requests=True'
|
||||
UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >>
|
||||
steps:
|
||||
- electron-publish:
|
||||
attach: false
|
||||
checkout: true
|
||||
|
||||
mas-publish-x64-skip-checkout:
|
||||
<<: *machine-mac-large
|
||||
environment:
|
||||
<<: *env-mac-large-release
|
||||
@@ -2053,10 +2180,39 @@ jobs:
|
||||
<<: *env-enable-sccache
|
||||
UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >>
|
||||
steps:
|
||||
- electron-publish:
|
||||
- electron-publish:
|
||||
attach: true
|
||||
checkout: false
|
||||
|
||||
mas-publish-arm64-skip-checkout:
|
||||
<<: *machine-mac-large-arm
|
||||
environment:
|
||||
<<: *env-mac-large-release
|
||||
<<: *env-mas-apple-silicon
|
||||
<<: *env-release-build
|
||||
<<: *env-enable-sccache
|
||||
UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >>
|
||||
steps:
|
||||
- electron-publish:
|
||||
attach: true
|
||||
checkout: false
|
||||
|
||||
mas-testing-arm64:
|
||||
<<: *machine-mac-large-arm
|
||||
environment:
|
||||
<<: *env-mac-large
|
||||
<<: *env-testing-build
|
||||
<<: *env-ninja-status
|
||||
<<: *env-macos-build
|
||||
<<: *env-mas-apple-silicon
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac'
|
||||
steps:
|
||||
- electron-build:
|
||||
persist: true
|
||||
checkout: false
|
||||
checkout-and-assume-cache: true
|
||||
attach: false
|
||||
|
||||
# Layer 3: Tests.
|
||||
linux-x64-unittests:
|
||||
<<: *machine-linux-2xlarge
|
||||
@@ -2180,7 +2336,7 @@ jobs:
|
||||
<<: *env-send-slack-notifications
|
||||
<<: *steps-verify-ffmpeg
|
||||
|
||||
osx-testing-tests:
|
||||
osx-testing-x64-tests:
|
||||
<<: *machine-mac-large
|
||||
environment:
|
||||
<<: *env-mac-large
|
||||
@@ -2188,7 +2344,7 @@ jobs:
|
||||
parallelism: 2
|
||||
<<: *steps-tests
|
||||
|
||||
osx-release-tests:
|
||||
osx-release-x64-tests:
|
||||
<<: *machine-mac-large
|
||||
environment:
|
||||
<<: *env-mac-large
|
||||
@@ -2203,7 +2359,7 @@ jobs:
|
||||
<<: *env-send-slack-notifications
|
||||
<<: *steps-verify-ffmpeg
|
||||
|
||||
mas-testing-tests:
|
||||
mas-testing-x64-tests:
|
||||
<<: *machine-mac-large
|
||||
environment:
|
||||
<<: *env-mac-large
|
||||
@@ -2267,7 +2423,7 @@ jobs:
|
||||
steps:
|
||||
- *step-maybe-notify-slack-success
|
||||
|
||||
osx-release-summary:
|
||||
osx-release-x64-summary:
|
||||
<<: *machine-mac
|
||||
environment:
|
||||
<<: *env-machine-mac
|
||||
@@ -2332,7 +2488,7 @@ workflows:
|
||||
publish-osx:
|
||||
when: << pipeline.parameters.run-osx-publish >>
|
||||
jobs:
|
||||
- osx-publish:
|
||||
- osx-publish-x64:
|
||||
context: release-env
|
||||
|
||||
publish-mas:
|
||||
@@ -2341,14 +2497,32 @@ workflows:
|
||||
- mas-publish:
|
||||
context: release-env
|
||||
|
||||
publish-osx-arm64:
|
||||
when: << pipeline.parameters.run-osx-publish-arm64 >>
|
||||
jobs:
|
||||
- osx-publish-arm64:
|
||||
context: release-env
|
||||
|
||||
publish-mas-arm64:
|
||||
when: << pipeline.parameters.run-mas-publish-arm64 >>
|
||||
jobs:
|
||||
- mas-publish-arm64:
|
||||
context: release-env
|
||||
|
||||
publish-macos:
|
||||
when: << pipeline.parameters.run-macos-publish >>
|
||||
jobs:
|
||||
- mac-checkout
|
||||
- osx-publish-skip-checkout:
|
||||
- osx-publish-x64-skip-checkout:
|
||||
requires:
|
||||
- mac-checkout
|
||||
- mas-publish-skip-checkout:
|
||||
- mas-publish-x64-skip-checkout:
|
||||
requires:
|
||||
- mac-checkout
|
||||
- osx-publish-arm64-skip-checkout:
|
||||
requires:
|
||||
- mac-checkout
|
||||
- mas-publish-arm64-skip-checkout:
|
||||
requires:
|
||||
- mac-checkout
|
||||
|
||||
@@ -2403,29 +2577,37 @@ workflows:
|
||||
- mac-checkout-fast
|
||||
- mac-checkout-and-save-cache
|
||||
|
||||
- osx-testing:
|
||||
- osx-testing-x64:
|
||||
requires:
|
||||
- mac-checkout-and-save-cache
|
||||
|
||||
- osx-testing-gn-check:
|
||||
- osx-testing-x64-gn-check:
|
||||
requires:
|
||||
- mac-checkout-fast
|
||||
|
||||
- osx-testing-tests:
|
||||
- osx-testing-x64-tests:
|
||||
requires:
|
||||
- osx-testing
|
||||
- osx-testing-x64
|
||||
|
||||
- mas-testing:
|
||||
- osx-testing-arm64:
|
||||
requires:
|
||||
- mac-checkout-and-save-cache
|
||||
|
||||
- mas-testing-gn-check:
|
||||
- mas-testing-x64:
|
||||
requires:
|
||||
- mac-checkout-and-save-cache
|
||||
|
||||
- mas-testing-x64-gn-check:
|
||||
requires:
|
||||
- mac-checkout-fast
|
||||
|
||||
- mas-testing-tests:
|
||||
- mas-testing-x64-tests:
|
||||
requires:
|
||||
- mas-testing
|
||||
- mas-testing-x64
|
||||
|
||||
- mas-testing-arm64:
|
||||
requires:
|
||||
- mac-checkout-and-save-cache
|
||||
|
||||
nightly-linux-release-test:
|
||||
triggers:
|
||||
@@ -2489,19 +2671,19 @@ workflows:
|
||||
- mac-checkout-fast
|
||||
- mac-checkout-and-save-cache
|
||||
|
||||
- osx-release:
|
||||
- osx-release-x64:
|
||||
requires:
|
||||
- mac-checkout-and-save-cache
|
||||
- osx-release-tests:
|
||||
- osx-release-x64-tests:
|
||||
requires:
|
||||
- osx-release
|
||||
- osx-release-x64
|
||||
- osx-verify-ffmpeg:
|
||||
requires:
|
||||
- osx-release
|
||||
- osx-release-summary:
|
||||
- osx-release-x64
|
||||
- osx-release-x64-summary:
|
||||
requires:
|
||||
- osx-release
|
||||
- osx-release-tests
|
||||
- osx-release-x64
|
||||
- osx-release-x64-tests
|
||||
- osx-verify-ffmpeg
|
||||
|
||||
- mas-release:
|
||||
|
||||
@@ -28,10 +28,12 @@
|
||||
},
|
||||
"globals": {
|
||||
"standardScheme": "readonly",
|
||||
"globalThis": "readonly",
|
||||
"BUILDFLAG": "readonly",
|
||||
"ENABLE_DESKTOP_CAPTURER": "readonly",
|
||||
"ENABLE_REMOTE_MODULE": "readonly",
|
||||
"ENABLE_VIEWS_API": "readonly"
|
||||
"ENABLE_VIEWS_API": "readonly",
|
||||
"BigInt": "readonly"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
|
||||
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -15,6 +15,7 @@ Contributors guide: https://github.com/electron/electron/blob/master/CONTRIBUTIN
|
||||
- [ ] relevant documentation is changed or added
|
||||
- [ ] PR title follows semantic [commit guidelines](https://github.com/electron/electron/blob/master/docs/development/pull-requests.md#commit-message-guidelines)
|
||||
- [ ] [PR release notes](https://github.com/electron/clerk/blob/master/README.md) describe the change in a way relevant to app developers, and are [capitalized, punctuated, and past tense](https://github.com/electron/clerk/blob/master/README.md#examples).
|
||||
- [ ] This is **NOT A BREAKING CHANGE**. Breaking changes may not be merged to master until 11-x-y is branched.
|
||||
|
||||
#### Release Notes
|
||||
|
||||
|
||||
165
BUILD.gn
165
BUILD.gn
@@ -94,6 +94,15 @@ npm_action("build_electron_definitions") {
|
||||
outputs = [ "$target_gen_dir/tsc/typings/electron.d.ts" ]
|
||||
}
|
||||
|
||||
webpack_build("electron_asar_bundle") {
|
||||
deps = [ ":build_electron_definitions" ]
|
||||
|
||||
inputs = auto_filenames.asar_bundle_deps
|
||||
|
||||
config_file = "//electron/build/webpack/webpack.config.asar.js"
|
||||
out_file = "$target_gen_dir/js2c/asar_bundle.js"
|
||||
}
|
||||
|
||||
webpack_build("electron_browser_bundle") {
|
||||
deps = [ ":build_electron_definitions" ]
|
||||
|
||||
@@ -139,25 +148,18 @@ webpack_build("electron_isolated_renderer_bundle") {
|
||||
out_file = "$target_gen_dir/js2c/isolated_bundle.js"
|
||||
}
|
||||
|
||||
copy("electron_js2c_copy") {
|
||||
sources = [
|
||||
"lib/common/asar.js",
|
||||
"lib/common/asar_init.js",
|
||||
]
|
||||
outputs = [ "$target_gen_dir/js2c/{{source_file_part}}" ]
|
||||
}
|
||||
|
||||
action("electron_js2c") {
|
||||
deps = [
|
||||
":electron_asar_bundle",
|
||||
":electron_browser_bundle",
|
||||
":electron_isolated_renderer_bundle",
|
||||
":electron_js2c_copy",
|
||||
":electron_renderer_bundle",
|
||||
":electron_sandboxed_renderer_bundle",
|
||||
":electron_worker_bundle",
|
||||
]
|
||||
|
||||
webpack_sources = [
|
||||
sources = [
|
||||
"$target_gen_dir/js2c/asar_bundle.js",
|
||||
"$target_gen_dir/js2c/browser_init.js",
|
||||
"$target_gen_dir/js2c/isolated_bundle.js",
|
||||
"$target_gen_dir/js2c/renderer_init.js",
|
||||
@@ -165,15 +167,10 @@ action("electron_js2c") {
|
||||
"$target_gen_dir/js2c/worker_init.js",
|
||||
]
|
||||
|
||||
sources = webpack_sources + [
|
||||
"$target_gen_dir/js2c/asar.js",
|
||||
"$target_gen_dir/js2c/asar_init.js",
|
||||
]
|
||||
|
||||
inputs = sources + [ "//third_party/electron_node/tools/js2c.py" ]
|
||||
outputs = [ "$root_gen_dir/electron_natives.cc" ]
|
||||
|
||||
script = "tools/js2c.py"
|
||||
script = "build/js2c.py"
|
||||
args = [ rebase_path("//third_party/electron_node") ] +
|
||||
rebase_path(outputs, root_build_dir) +
|
||||
rebase_path(sources, root_build_dir)
|
||||
@@ -322,10 +319,10 @@ source_set("electron_lib") {
|
||||
"shell/common/api:mojo",
|
||||
"//base:base_static",
|
||||
"//base/allocator:buildflags",
|
||||
"//chrome/app:command_ids",
|
||||
"//chrome/app/resources:platform_locale_settings",
|
||||
"//chrome/services/printing/public/mojom",
|
||||
"//components/certificate_transparency",
|
||||
"//components/crash/core/app",
|
||||
"//components/language/core/browser",
|
||||
"//components/net_log",
|
||||
"//components/network_hints/browser",
|
||||
@@ -347,6 +344,7 @@ source_set("electron_lib") {
|
||||
"//device/bluetooth",
|
||||
"//device/bluetooth/public/cpp",
|
||||
"//gin",
|
||||
"//media/blink:blink",
|
||||
"//media/capture/mojom:video_capture",
|
||||
"//media/mojo/mojom",
|
||||
"//net:extras",
|
||||
@@ -432,6 +430,9 @@ source_set("electron_lib") {
|
||||
"*\bviews/*",
|
||||
]
|
||||
}
|
||||
if (!is_mas_build) {
|
||||
deps += [ "//components/crash/core/app" ]
|
||||
}
|
||||
|
||||
set_sources_assignment_filter(
|
||||
sources_assignment_filter + extra_source_filters)
|
||||
@@ -457,11 +458,14 @@ source_set("electron_lib") {
|
||||
deps += [
|
||||
"//components/remote_cocoa/app_shim",
|
||||
"//content/common:mac_helpers",
|
||||
"//third_party/crashpad/crashpad/client",
|
||||
"//ui/accelerated_widget_mac",
|
||||
]
|
||||
|
||||
libs = [
|
||||
if (!is_mas_build) {
|
||||
deps += [ "//third_party/crashpad/crashpad/client" ]
|
||||
}
|
||||
|
||||
frameworks = [
|
||||
"AVFoundation.framework",
|
||||
"Carbon.framework",
|
||||
"LocalAuthentication.framework",
|
||||
@@ -481,19 +485,26 @@ source_set("electron_lib") {
|
||||
sources += [ "shell/browser/api/electron_api_app_mas.mm" ]
|
||||
sources -= [ "shell/browser/auto_updater_mac.mm" ]
|
||||
defines += [ "MAS_BUILD" ]
|
||||
sources -= [
|
||||
"shell/app/electron_crash_reporter_client.cc",
|
||||
"shell/app/electron_crash_reporter_client.h",
|
||||
"shell/common/crash_keys.cc",
|
||||
"shell/common/crash_keys.h",
|
||||
]
|
||||
} else {
|
||||
libs += [
|
||||
frameworks += [
|
||||
"Squirrel.framework",
|
||||
"ReactiveCocoa.framework",
|
||||
"ReactiveObjC.framework",
|
||||
"Mantle.framework",
|
||||
]
|
||||
cflags_objcc = [
|
||||
"-F",
|
||||
rebase_path("external_binaries", root_build_dir),
|
||||
|
||||
deps += [
|
||||
"//third_party/squirrel.mac:reactiveobjc_framework+link",
|
||||
"//third_party/squirrel.mac:squirrel_framework+link",
|
||||
]
|
||||
|
||||
# ReactiveCocoa which is used by Squirrel requires using __weak.
|
||||
cflags_objcc += [ "-fobjc-weak" ]
|
||||
# ReactiveObjC which is used by Squirrel requires using __weak.
|
||||
cflags_objcc = [ "-fobjc-weak" ]
|
||||
}
|
||||
}
|
||||
if (is_linux) {
|
||||
@@ -523,6 +534,16 @@ source_set("electron_lib") {
|
||||
|
||||
sources += filenames.lib_sources_nss
|
||||
sources += [
|
||||
"shell/browser/ui/gtk/app_indicator_icon.cc",
|
||||
"shell/browser/ui/gtk/app_indicator_icon.h",
|
||||
"shell/browser/ui/gtk/app_indicator_icon_menu.cc",
|
||||
"shell/browser/ui/gtk/app_indicator_icon_menu.h",
|
||||
"shell/browser/ui/gtk/gtk_status_icon.cc",
|
||||
"shell/browser/ui/gtk/gtk_status_icon.h",
|
||||
"shell/browser/ui/gtk/menu_util.cc",
|
||||
"shell/browser/ui/gtk/menu_util.h",
|
||||
"shell/browser/ui/gtk/status_icon.cc",
|
||||
"shell/browser/ui/gtk/status_icon.h",
|
||||
"shell/browser/ui/gtk_util.cc",
|
||||
"shell/browser/ui/gtk_util.h",
|
||||
]
|
||||
@@ -579,15 +600,6 @@ source_set("electron_lib") {
|
||||
]
|
||||
}
|
||||
|
||||
if (enable_remote_module) {
|
||||
sources += [
|
||||
"shell/common/api/remote/remote_callback_freer.cc",
|
||||
"shell/common/api/remote/remote_callback_freer.h",
|
||||
"shell/common/api/remote/remote_object_freer.cc",
|
||||
"shell/common/api/remote/remote_object_freer.h",
|
||||
]
|
||||
}
|
||||
|
||||
if (enable_desktop_capturer) {
|
||||
if (is_component_build && !is_linux) {
|
||||
# On windows the implementation relies on unexported
|
||||
@@ -646,6 +658,7 @@ source_set("electron_lib") {
|
||||
deps += [
|
||||
"//components/pdf/browser",
|
||||
"//components/pdf/renderer",
|
||||
"//pdf:pdf_ppapi",
|
||||
]
|
||||
sources += [
|
||||
"shell/browser/electron_pdf_web_contents_helper_client.cc",
|
||||
@@ -763,8 +776,10 @@ if (is_mac) {
|
||||
framework_contents = [
|
||||
"Resources",
|
||||
"Libraries",
|
||||
"Helpers",
|
||||
]
|
||||
if (!is_mas_build) {
|
||||
framework_contents += [ "Helpers" ]
|
||||
}
|
||||
public_deps = [
|
||||
":electron_framework_libraries",
|
||||
":electron_lib",
|
||||
@@ -788,15 +803,13 @@ if (is_mac) {
|
||||
|
||||
include_dirs = [ "." ]
|
||||
sources = filenames.framework_sources
|
||||
libs = []
|
||||
frameworks = []
|
||||
|
||||
if (enable_osr) {
|
||||
libs += [ "IOSurface.framework" ]
|
||||
frameworks += [ "IOSurface.framework" ]
|
||||
}
|
||||
|
||||
ldflags = [
|
||||
"-F",
|
||||
rebase_path("external_binaries", root_build_dir),
|
||||
"-Wl,-install_name,@rpath/$output_name.framework/$output_name",
|
||||
"-rpath",
|
||||
"@loader_path/Libraries",
|
||||
@@ -847,17 +860,49 @@ if (is_mac) {
|
||||
}
|
||||
}
|
||||
|
||||
template("stripped_framework") {
|
||||
action(target_name) {
|
||||
assert(defined(invoker.framework))
|
||||
|
||||
script = "//electron/build/strip_framework.py"
|
||||
|
||||
forward_variables_from(invoker, [ "deps" ])
|
||||
inputs = [ "$root_out_dir/" + invoker.framework ]
|
||||
outputs = [ "$target_out_dir/stripped_frameworks/" + invoker.framework ]
|
||||
|
||||
args = rebase_path(inputs) + rebase_path(outputs)
|
||||
}
|
||||
}
|
||||
|
||||
stripped_framework("stripped_mantle_framework") {
|
||||
framework = "Mantle.framework"
|
||||
deps = [ "//third_party/squirrel.mac:mantle_framework" ]
|
||||
}
|
||||
|
||||
stripped_framework("stripped_reactiveobjc_framework") {
|
||||
framework = "ReactiveObjC.framework"
|
||||
deps = [ "//third_party/squirrel.mac:reactiveobjc_framework" ]
|
||||
}
|
||||
|
||||
stripped_framework("stripped_squirrel_framework") {
|
||||
framework = "Squirrel.framework"
|
||||
deps = [ "//third_party/squirrel.mac:squirrel_framework" ]
|
||||
}
|
||||
|
||||
bundle_data("electron_app_framework_bundle_data") {
|
||||
sources = [ "$root_out_dir/$electron_framework_name.framework" ]
|
||||
if (!is_mas_build) {
|
||||
sources += [
|
||||
"external_binaries/Mantle.framework",
|
||||
"external_binaries/ReactiveCocoa.framework",
|
||||
"external_binaries/Squirrel.framework",
|
||||
]
|
||||
sources += get_target_outputs(":stripped_mantle_framework") +
|
||||
get_target_outputs(":stripped_reactiveobjc_framework") +
|
||||
get_target_outputs(":stripped_squirrel_framework")
|
||||
}
|
||||
outputs = [ "{{bundle_contents_dir}}/Frameworks/{{source_file_part}}" ]
|
||||
public_deps = [ ":electron_framework+link" ]
|
||||
public_deps = [
|
||||
":electron_framework+link",
|
||||
":stripped_mantle_framework",
|
||||
":stripped_reactiveobjc_framework",
|
||||
":stripped_squirrel_framework",
|
||||
]
|
||||
|
||||
foreach(helper_params, content_mac_helpers) {
|
||||
sources +=
|
||||
@@ -870,7 +915,7 @@ if (is_mac) {
|
||||
output_name = electron_login_helper_name
|
||||
sources = filenames.login_helper_sources
|
||||
include_dirs = [ "." ]
|
||||
libs = [ "AppKit.framework" ]
|
||||
frameworks = [ "AppKit.framework" ]
|
||||
info_plist = "shell/app/resources/mac/loginhelper-Info.plist"
|
||||
extra_substitutions =
|
||||
[ "ELECTRON_BUNDLE_ID=$electron_mac_bundle_id.loginhelper" ]
|
||||
@@ -995,13 +1040,16 @@ if (is_mac) {
|
||||
|
||||
group("electron_symbols") {
|
||||
deps = [
|
||||
":crashpad_handler_syms",
|
||||
":electron_app_syms",
|
||||
":electron_framework_syms",
|
||||
":swiftshader_egl_syms",
|
||||
":swiftshader_gles_syms",
|
||||
]
|
||||
|
||||
if (!is_mas_build) {
|
||||
deps += [ ":crashpad_handler_syms" ]
|
||||
}
|
||||
|
||||
foreach(helper_params, content_mac_helpers) {
|
||||
_helper_target = helper_params[0]
|
||||
deps += [ ":electron_helper_syms_${_helper_target}" ]
|
||||
@@ -1052,7 +1100,9 @@ if (is_mac) {
|
||||
data += [ "$root_out_dir/resources/default_app.asar" ]
|
||||
}
|
||||
|
||||
public_deps = [ "//tools/v8_context_snapshot:v8_context_snapshot" ]
|
||||
if (use_v8_context_snapshot) {
|
||||
public_deps = [ "//tools/v8_context_snapshot:v8_context_snapshot" ]
|
||||
}
|
||||
|
||||
if (is_win) {
|
||||
sources += [
|
||||
@@ -1160,18 +1210,6 @@ test("shell_browser_ui_unittests") {
|
||||
"//ui/base",
|
||||
"//ui/strings",
|
||||
]
|
||||
|
||||
if (is_mac) {
|
||||
# Resolve paths owing to different test executable locations
|
||||
ldflags = [
|
||||
"-F",
|
||||
rebase_path("external_binaries", root_build_dir),
|
||||
"-rpath",
|
||||
"@loader_path",
|
||||
"-rpath",
|
||||
"@executable_path/" + rebase_path("external_binaries", root_build_dir),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
template("dist_zip") {
|
||||
@@ -1269,10 +1307,13 @@ dist_zip("electron_chromedriver_zip") {
|
||||
|
||||
mksnapshot_deps = [
|
||||
":licenses",
|
||||
"//tools/v8_context_snapshot:v8_context_snapshot_generator($v8_snapshot_toolchain)",
|
||||
"//v8:mksnapshot($v8_snapshot_toolchain)",
|
||||
]
|
||||
|
||||
if (use_v8_context_snapshot) {
|
||||
mksnapshot_deps += [ "//tools/v8_context_snapshot:v8_context_snapshot_generator($v8_snapshot_toolchain)" ]
|
||||
}
|
||||
|
||||
group("electron_mksnapshot") {
|
||||
public_deps = mksnapshot_deps
|
||||
}
|
||||
|
||||
35
DEPS
35
DEPS
@@ -5,18 +5,22 @@ gclient_gn_args = [
|
||||
'checkout_android_native_support',
|
||||
'checkout_libaom',
|
||||
'checkout_nacl',
|
||||
'checkout_pgo_profiles',
|
||||
'checkout_oculus_sdk',
|
||||
'checkout_openxr',
|
||||
'checkout_google_benchmark'
|
||||
'checkout_google_benchmark',
|
||||
'mac_xcode_version',
|
||||
]
|
||||
|
||||
vars = {
|
||||
'chromium_version':
|
||||
'17da1064b910f4170320ff37e971064916aed1dc',
|
||||
'93a6ebbe22f1a093e6a0cb5e72ba78990fe39824',
|
||||
'node_version':
|
||||
'v12.16.3',
|
||||
'v12.18.3',
|
||||
'nan_version':
|
||||
'2c4ee8a32a299eada3cd6e468bbd0a473bfea96d',
|
||||
'squirrel.mac_version':
|
||||
'44468f858ce0d25c27bd5e674abfa104e0119738',
|
||||
|
||||
'boto_version': 'f7574aa6cc2c819430c1f05e9a1a1a666ef8169b',
|
||||
'pyyaml_version': '3.12',
|
||||
@@ -28,6 +32,7 @@ vars = {
|
||||
'nodejs_git': 'https://github.com/nodejs',
|
||||
'requests_git': 'https://github.com/kennethreitz',
|
||||
'yaml_git': 'https://github.com/yaml',
|
||||
'squirrel_git': 'https://github.com/Squirrel',
|
||||
|
||||
# KEEP IN SYNC WITH utils.js FILE
|
||||
'yarn_version': '1.15.2',
|
||||
@@ -42,6 +47,7 @@ vars = {
|
||||
'checkout_chromium': True,
|
||||
'checkout_node': True,
|
||||
'checkout_nan': True,
|
||||
'checkout_pgo_profiles': True,
|
||||
|
||||
# It's only needed to parse the native tests configurations.
|
||||
'checkout_pyyaml': False,
|
||||
@@ -49,6 +55,8 @@ vars = {
|
||||
# Python "requests" module is used for releases only.
|
||||
'checkout_requests': False,
|
||||
|
||||
'mac_xcode_version': 'default',
|
||||
|
||||
# To allow running hooks without parsing the DEPS tree
|
||||
'process_deps': True,
|
||||
|
||||
@@ -99,6 +107,18 @@ deps = {
|
||||
'url': Var('requests_git') + '/requests.git' + '@' + Var('requests_version'),
|
||||
'condition': 'checkout_requests and process_deps',
|
||||
},
|
||||
'src/third_party/squirrel.mac': {
|
||||
'url': Var("squirrel_git") + '/Squirrel.Mac.git@' + Var("squirrel.mac_version"),
|
||||
'condition': 'process_deps',
|
||||
},
|
||||
'src/third_party/squirrel.mac/vendor/ReactiveObjC': {
|
||||
'url': 'https://github.com/ReactiveCocoa/ReactiveObjC.git@74ab5baccc6f7202c8ac69a8d1e152c29dc1ea76',
|
||||
'condition': 'process_deps'
|
||||
},
|
||||
'src/third_party/squirrel.mac/vendor/Mantle': {
|
||||
'url': 'https://github.com/Mantle/Mantle.git@78d3966b3c331292ea29ec38661b25df0a245948',
|
||||
'condition': 'process_deps',
|
||||
}
|
||||
}
|
||||
|
||||
hooks = [
|
||||
@@ -107,7 +127,7 @@ hooks = [
|
||||
'condition': '(checkout_chromium and apply_patches) and process_deps',
|
||||
'pattern': 'src/electron',
|
||||
'action': [
|
||||
'python',
|
||||
'python3',
|
||||
'src/electron/script/apply_all_patches.py',
|
||||
'src/electron/patches/config.json',
|
||||
],
|
||||
@@ -125,7 +145,7 @@ hooks = [
|
||||
'name': 'electron_npm_deps',
|
||||
'pattern': 'src/electron/package.json',
|
||||
'action': [
|
||||
'python',
|
||||
'python3',
|
||||
'-c',
|
||||
'import os, subprocess; os.chdir(os.path.join("src", "electron")); subprocess.check_call(["python", "script/lib/npx.py", "yarn@' + (Var("yarn_version")) + '", "install", "--frozen-lockfile"]);',
|
||||
],
|
||||
@@ -135,7 +155,7 @@ hooks = [
|
||||
'pattern': 'src/electron',
|
||||
'condition': 'checkout_boto and process_deps',
|
||||
'action': [
|
||||
'python',
|
||||
'python3',
|
||||
'-c',
|
||||
'import os, subprocess; os.chdir(os.path.join("src", "electron", "vendor", "boto")); subprocess.check_call(["python", "setup.py", "build"]);',
|
||||
],
|
||||
@@ -145,7 +165,7 @@ hooks = [
|
||||
'pattern': 'src/electron',
|
||||
'condition': 'checkout_requests and process_deps',
|
||||
'action': [
|
||||
'python',
|
||||
'python3',
|
||||
'-c',
|
||||
'import os, subprocess; os.chdir(os.path.join("src", "electron", "vendor", "requests")); subprocess.check_call(["python", "setup.py", "build"]);',
|
||||
],
|
||||
@@ -154,4 +174,5 @@ hooks = [
|
||||
|
||||
recursedeps = [
|
||||
'src',
|
||||
'src/third_party/squirrel.mac',
|
||||
]
|
||||
|
||||
@@ -1 +1 @@
|
||||
10.0.0-nightly.20200515
|
||||
11.0.0-nightly.20200810
|
||||
12
appveyor.yml
12
appveyor.yml
@@ -29,7 +29,7 @@
|
||||
|
||||
version: 1.0.{build}
|
||||
build_cloud: electron-16-core
|
||||
image: vs2019bt-16.4.0
|
||||
image: vs2019bt-16.6.2
|
||||
environment:
|
||||
GIT_CACHE_PATH: C:\Users\electron\libcc_cache
|
||||
ELECTRON_OUT_DIR: Default
|
||||
@@ -61,6 +61,7 @@ build_script:
|
||||
- git config --global core.longpaths true
|
||||
- cd ..
|
||||
- mkdir src
|
||||
- update_depot_tools.bat
|
||||
- ps: Move-Item $env:APPVEYOR_BUILD_FOLDER -Destination src\electron
|
||||
- ps: $env:CHROMIUM_BUILDTOOLS_PATH="$pwd\src\buildtools"
|
||||
- ps: $env:SCCACHE_PATH="$pwd\src\electron\external_binaries\sccache.exe"
|
||||
@@ -152,7 +153,11 @@ build_script:
|
||||
- ninja -C out/ffmpeg electron:electron_ffmpeg_zip
|
||||
- ninja -C out/Default electron:electron_dist_zip
|
||||
- ninja -C out/Default shell_browser_ui_unittests
|
||||
- gn desc out/Default v8:run_mksnapshot_default args > out/Default/mksnapshot_args
|
||||
- ninja -C out/Default electron:electron_mksnapshot_zip
|
||||
- cd out\Default
|
||||
- 7z a mksnapshot.zip mksnapshot_args gen\v8\embedded.S
|
||||
- cd ..\..
|
||||
- ninja -C out/Default electron:hunspell_dictionaries_zip
|
||||
- ninja -C out/Default electron:electron_chromedriver_zip
|
||||
- ninja -C out/Default third_party/electron_node:headers
|
||||
@@ -200,11 +205,10 @@ test_script:
|
||||
echo "Skipping tests for $env:GN_CONFIG build"
|
||||
}
|
||||
- cd electron
|
||||
- if "%RUN_TESTS%"=="true" ( echo Running test suite & node script/yarn test -- --enable-logging)
|
||||
- if "%RUN_TESTS%"=="true" ( echo Running test suite & node script/yarn test -- --trace-uncaught --enable-logging)
|
||||
- cd ..
|
||||
- if "%RUN_TESTS%"=="true" ( echo Verifying non proprietary ffmpeg & python electron\script\verify-ffmpeg.py --build-dir out\Default --source-root %cd% --ffmpeg-path out\ffmpeg )
|
||||
- echo "About to verify mksnapshot"
|
||||
- if "%RUN_TESTS%"=="true" ( gn desc out\Default v8:run_mksnapshot_default args > out\Default\mksnapshot_args )
|
||||
- echo "About to verify mksnapshot"
|
||||
- if "%RUN_TESTS%"=="true" ( echo Verifying mksnapshot & python electron\script\verify-mksnapshot.py --build-dir out\Default --source-root %cd% )
|
||||
- echo "Done verifying mksnapshot"
|
||||
- if "%RUN_TESTS%"=="true" ( echo Verifying chromedriver & python electron\script\verify-chromedriver.py --build-dir out\Default --source-root %cd% )
|
||||
|
||||
104
azure-pipelines-arm.yml
Normal file
104
azure-pipelines-arm.yml
Normal file
@@ -0,0 +1,104 @@
|
||||
steps:
|
||||
- task: CopyFiles@2
|
||||
displayName: 'Copy Files to: src/electron'
|
||||
inputs:
|
||||
TargetFolder: src/electron
|
||||
|
||||
- bash: |
|
||||
cd src/electron
|
||||
node script/yarn.js install --frozen-lockfile
|
||||
displayName: 'Yarn install'
|
||||
|
||||
- bash: |
|
||||
export ZIP_DEST=$PWD/src/out/Default
|
||||
echo "##vso[task.setvariable variable=ZIP_DEST]$ZIP_DEST"
|
||||
mkdir -p $ZIP_DEST
|
||||
cd src/electron
|
||||
node script/download-circleci-artifacts.js --buildNum=$CIRCLE_BUILD_NUM --name=dist.zip --dest=$ZIP_DEST
|
||||
cd $ZIP_DEST
|
||||
unzip -o dist.zip
|
||||
displayName: 'Download and unzip dist files for test'
|
||||
env:
|
||||
CIRCLE_TOKEN: $(CIRCLECI_TOKEN)
|
||||
|
||||
- bash: |
|
||||
export FFMPEG_ZIP_DEST=$PWD/src/out/ffmpeg
|
||||
mkdir -p $FFMPEG_ZIP_DEST
|
||||
cd src/electron
|
||||
node script/download-circleci-artifacts.js --buildNum=$CIRCLE_BUILD_NUM --name=ffmpeg.zip --dest=$FFMPEG_ZIP_DEST
|
||||
cd $FFMPEG_ZIP_DEST
|
||||
unzip -o ffmpeg.zip
|
||||
displayName: 'Download and unzip ffmpeg for test'
|
||||
env:
|
||||
CIRCLE_TOKEN: $(CIRCLECI_TOKEN)
|
||||
|
||||
- bash: |
|
||||
export NODE_HEADERS_DEST=$PWD/src/out/Default/gen
|
||||
mkdir -p $NODE_HEADERS_DEST
|
||||
cd src/electron
|
||||
node script/download-circleci-artifacts.js --buildNum=$CIRCLE_BUILD_NUM --name=node_headers.tar.gz --dest=$NODE_HEADERS_DEST
|
||||
cd $NODE_HEADERS_DEST
|
||||
tar xzf node_headers.tar.gz
|
||||
displayName: 'Download and untar node header files for test'
|
||||
env:
|
||||
CIRCLE_TOKEN: $(CIRCLECI_TOKEN)
|
||||
|
||||
- bash: |
|
||||
export CROSS_ARCH_SNAPSHOTS=$PWD/src/out/Default/cross-arch-snapshots
|
||||
mkdir -p $CROSS_ARCH_SNAPSHOTS
|
||||
cd src/electron
|
||||
node script/download-circleci-artifacts.js --buildNum=$CIRCLE_BUILD_NUM --name=cross-arch-snapshots/snapshot_blob.bin --dest=$CROSS_ARCH_SNAPSHOTS
|
||||
node script/download-circleci-artifacts.js --buildNum=$CIRCLE_BUILD_NUM --name=cross-arch-snapshots/v8_context_snapshot.bin --dest=$CROSS_ARCH_SNAPSHOTS
|
||||
displayName: 'Download cross arch snapshot files'
|
||||
env:
|
||||
CIRCLE_TOKEN: $(CIRCLECI_TOKEN)
|
||||
|
||||
- bash: |
|
||||
export NATIVE_UNITTESTS_DEST=$PWD/src/out/Default
|
||||
cd src/electron
|
||||
node script/download-circleci-artifacts.js --buildNum=$CIRCLE_BUILD_NUM --name=shell_browser_ui_unittests --dest=$NATIVE_UNITTESTS_DEST
|
||||
chmod +x $NATIVE_UNITTESTS_DEST/shell_browser_ui_unittests
|
||||
displayName: 'Download native unittest executables'
|
||||
env:
|
||||
CIRCLE_TOKEN: $(CIRCLECI_TOKEN)
|
||||
|
||||
- bash: |
|
||||
cd src
|
||||
export ELECTRON_OUT_DIR=Default
|
||||
set npm_config_arch=arm64
|
||||
(cd electron && node script/yarn test -- --enable-logging)
|
||||
displayName: 'Run Electron tests'
|
||||
timeoutInMinutes: 20
|
||||
env:
|
||||
ELECTRON_DISABLE_SECURITY_WARNINGS: 1
|
||||
IGNORE_YARN_INSTALL_ERROR: 1
|
||||
ELECTRON_TEST_RESULTS_DIR: junit
|
||||
|
||||
- bash: |
|
||||
cd src
|
||||
python electron/script/verify-ffmpeg.py --source-root "$PWD" --build-dir out/Default --ffmpeg-path out/ffmpeg
|
||||
displayName: Verify non proprietary ffmpeg
|
||||
timeoutInMinutes: 5
|
||||
condition: succeededOrFailed()
|
||||
|
||||
- bash: |
|
||||
cd src
|
||||
echo Verify cross arch snapshot
|
||||
python electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default --snapshot-files-dir $PWD/out/Default/cross-arch-snapshots
|
||||
displayName: Verify cross arch snapshot
|
||||
timeoutInMinutes: 5
|
||||
condition: succeededOrFailed()
|
||||
|
||||
- task: PublishTestResults@2
|
||||
displayName: 'Publish Test Results'
|
||||
inputs:
|
||||
testResultsFiles: '*.xml'
|
||||
|
||||
searchFolder: '$(System.DefaultWorkingDirectory)/src/junit/'
|
||||
|
||||
condition: succeededOrFailed()
|
||||
|
||||
- task: mspremier.PostBuildCleanup.PostBuildCleanup-task.PostBuildCleanup@3
|
||||
displayName: 'Clean Agent Directories'
|
||||
|
||||
condition: always()
|
||||
16
build/strip_framework.py
Executable file
16
build/strip_framework.py
Executable file
@@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env python
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
source = sys.argv[1]
|
||||
dest = sys.argv[2]
|
||||
|
||||
# Ensure any existing framework is removed
|
||||
subprocess.check_output(["rm", "-rf", dest])
|
||||
|
||||
subprocess.check_output(["cp", "-a", source, dest])
|
||||
|
||||
# Strip headers, we do not need to ship them
|
||||
subprocess.check_output(["rm", "-r", os.path.join(dest, 'Headers')])
|
||||
subprocess.check_output(["rm", "-r", os.path.join(dest, 'Versions', 'Current', 'Headers')])
|
||||
@@ -1,2 +1,2 @@
|
||||
process.env.PRINT_WEBPACK_GRAPH = true
|
||||
require('./run-compiler')
|
||||
process.env.PRINT_WEBPACK_GRAPH = true;
|
||||
require('./run-compiler');
|
||||
|
||||
@@ -1,22 +1,38 @@
|
||||
const path = require('path')
|
||||
const webpack = require('webpack')
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
|
||||
const configPath = process.argv[2]
|
||||
const outPath = path.resolve(process.argv[3])
|
||||
const config = require(configPath)
|
||||
const configPath = process.argv[2];
|
||||
const outPath = path.resolve(process.argv[3]);
|
||||
const config = require(configPath);
|
||||
config.output = {
|
||||
path: path.dirname(outPath),
|
||||
filename: path.basename(outPath)
|
||||
}
|
||||
};
|
||||
|
||||
const { wrapInitWithProfilingTimeout } = config;
|
||||
delete config.wrapInitWithProfilingTimeout;
|
||||
|
||||
webpack(config, (err, stats) => {
|
||||
if (err) {
|
||||
console.error(err)
|
||||
process.exit(1)
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
} else if (stats.hasErrors()) {
|
||||
console.error(stats.toString('normal'))
|
||||
process.exit(1)
|
||||
console.error(stats.toString('normal'));
|
||||
process.exit(1);
|
||||
} else {
|
||||
process.exit(0)
|
||||
if (wrapInitWithProfilingTimeout) {
|
||||
const contents = fs.readFileSync(outPath, 'utf8');
|
||||
const newContents = `function ___electron_webpack_init__() {
|
||||
${contents}
|
||||
};
|
||||
if ((globalThis.process || binding.process).argv.includes("--profile-electron-init")) {
|
||||
setTimeout(___electron_webpack_init__, 0);
|
||||
} else {
|
||||
___electron_webpack_init__();
|
||||
}`;
|
||||
fs.writeFileSync(outPath, newContents);
|
||||
}
|
||||
process.exit(0);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
5
build/webpack/webpack.config.asar.js
Normal file
5
build/webpack/webpack.config.asar.js
Normal file
@@ -0,0 +1,5 @@
|
||||
module.exports = require('./webpack.config.base')({
|
||||
target: 'asar',
|
||||
alwaysHasNode: true,
|
||||
targetDeletesNodeGlobals: true
|
||||
});
|
||||
@@ -1,110 +1,118 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const webpack = require('webpack')
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const TerserPlugin = require('terser-webpack-plugin');
|
||||
|
||||
const electronRoot = path.resolve(__dirname, '../..')
|
||||
const electronRoot = path.resolve(__dirname, '../..');
|
||||
|
||||
const onlyPrintingGraph = !!process.env.PRINT_WEBPACK_GRAPH
|
||||
const onlyPrintingGraph = !!process.env.PRINT_WEBPACK_GRAPH;
|
||||
|
||||
class AccessDependenciesPlugin {
|
||||
apply(compiler) {
|
||||
apply (compiler) {
|
||||
// Only hook into webpack when we are printing the dependency graph
|
||||
if (!onlyPrintingGraph) return
|
||||
if (!onlyPrintingGraph) return;
|
||||
|
||||
compiler.hooks.compilation.tap('AccessDependenciesPlugin', compilation => {
|
||||
compilation.hooks.finishModules.tap('AccessDependenciesPlugin', modules => {
|
||||
const filePaths = modules.map(m => m.resource).filter(p => p).map(p => path.relative(electronRoot, p))
|
||||
console.info(JSON.stringify(filePaths))
|
||||
})
|
||||
})
|
||||
const filePaths = modules.map(m => m.resource).filter(p => p).map(p => path.relative(electronRoot, p));
|
||||
console.info(JSON.stringify(filePaths));
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const defines = {
|
||||
BUILDFLAG: ''
|
||||
}
|
||||
BUILDFLAG: onlyPrintingGraph ? '(a => a)' : ''
|
||||
};
|
||||
|
||||
const buildFlagsPrefix = '--buildflags='
|
||||
const buildFlagsPrefix = '--buildflags=';
|
||||
const buildFlagArg = process.argv.find(arg => arg.startsWith(buildFlagsPrefix));
|
||||
|
||||
if (buildFlagArg) {
|
||||
const buildFlagPath = buildFlagArg.substr(buildFlagsPrefix.length)
|
||||
const buildFlagPath = buildFlagArg.substr(buildFlagsPrefix.length);
|
||||
|
||||
const flagFile = fs.readFileSync(buildFlagPath, 'utf8')
|
||||
const flagFile = fs.readFileSync(buildFlagPath, 'utf8');
|
||||
for (const line of flagFile.split(/(\r\n|\r|\n)/g)) {
|
||||
const flagMatch = line.match(/#define BUILDFLAG_INTERNAL_(.+?)\(\) \(([01])\)/)
|
||||
const flagMatch = line.match(/#define BUILDFLAG_INTERNAL_(.+?)\(\) \(([01])\)/);
|
||||
if (flagMatch) {
|
||||
const flagName = flagMatch[1];
|
||||
const flagValue = flagMatch[2];
|
||||
const [, flagName, flagValue] = flagMatch;
|
||||
defines[flagName] = JSON.stringify(Boolean(parseInt(flagValue, 10)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const ignoredModules = []
|
||||
const ignoredModules = [];
|
||||
|
||||
if (defines['ENABLE_DESKTOP_CAPTURER'] === 'false') {
|
||||
if (defines.ENABLE_DESKTOP_CAPTURER === 'false') {
|
||||
ignoredModules.push(
|
||||
'@electron/internal/browser/desktop-capturer',
|
||||
'@electron/internal/browser/api/desktop-capturer',
|
||||
'@electron/internal/renderer/api/desktop-capturer'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (defines['ENABLE_REMOTE_MODULE'] === 'false') {
|
||||
if (defines.ENABLE_REMOTE_MODULE === 'false') {
|
||||
ignoredModules.push(
|
||||
'@electron/internal/browser/remote/server',
|
||||
'@electron/internal/renderer/api/remote'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (defines['ENABLE_VIEWS_API'] === 'false') {
|
||||
if (defines.ENABLE_VIEWS_API === 'false') {
|
||||
ignoredModules.push(
|
||||
'@electron/internal/browser/api/views/image-view.js'
|
||||
)
|
||||
}
|
||||
|
||||
const alias = {}
|
||||
for (const ignoredModule of ignoredModules) {
|
||||
alias[ignoredModule] = path.resolve(electronRoot, 'lib/common/dummy.js')
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = ({
|
||||
alwaysHasNode,
|
||||
loadElectronFromAlternateTarget,
|
||||
targetDeletesNodeGlobals,
|
||||
target
|
||||
target,
|
||||
wrapInitWithProfilingTimeout
|
||||
}) => {
|
||||
let entry = path.resolve(electronRoot, 'lib', target, 'init.ts')
|
||||
let entry = path.resolve(electronRoot, 'lib', target, 'init.ts');
|
||||
if (!fs.existsSync(entry)) {
|
||||
entry = path.resolve(electronRoot, 'lib', target, 'init.js')
|
||||
entry = path.resolve(electronRoot, 'lib', target, 'init.js');
|
||||
}
|
||||
|
||||
const electronAPIFile = path.resolve(electronRoot, 'lib', loadElectronFromAlternateTarget || target, 'api', 'exports', 'electron.ts');
|
||||
|
||||
return ({
|
||||
mode: 'development',
|
||||
devtool: 'inline-source-map',
|
||||
devtool: false,
|
||||
entry,
|
||||
target: alwaysHasNode ? 'node' : 'web',
|
||||
output: {
|
||||
filename: `${target}.bundle.js`
|
||||
},
|
||||
wrapInitWithProfilingTimeout,
|
||||
resolve: {
|
||||
alias: {
|
||||
...alias,
|
||||
'@electron/internal': path.resolve(electronRoot, 'lib'),
|
||||
'electron': path.resolve(electronRoot, 'lib', loadElectronFromAlternateTarget || target, 'api', 'exports', 'electron.ts'),
|
||||
// Force timers to resolve to our dependency that doens't use window.postMessage
|
||||
'timers': path.resolve(electronRoot, 'node_modules', 'timers-browserify', 'main.js')
|
||||
electron$: electronAPIFile,
|
||||
'electron/main$': electronAPIFile,
|
||||
'electron/renderer$': electronAPIFile,
|
||||
'electron/common$': electronAPIFile,
|
||||
// Force timers to resolve to our dependency that doesn't use window.postMessage
|
||||
timers: path.resolve(electronRoot, 'node_modules', 'timers-browserify', 'main.js')
|
||||
},
|
||||
extensions: ['.ts', '.js']
|
||||
},
|
||||
module: {
|
||||
rules: [{
|
||||
test: (moduleName) => !onlyPrintingGraph && ignoredModules.includes(moduleName),
|
||||
loader: 'null-loader'
|
||||
}, {
|
||||
test: /\.ts$/,
|
||||
loader: 'ts-loader',
|
||||
options: {
|
||||
configFile: path.resolve(electronRoot, 'tsconfig.electron.json'),
|
||||
transpileOnly: onlyPrintingGraph,
|
||||
ignoreDiagnostics: [6059]
|
||||
ignoreDiagnostics: [
|
||||
// File '{0}' is not under 'rootDir' '{1}'.
|
||||
6059
|
||||
]
|
||||
}
|
||||
}]
|
||||
},
|
||||
@@ -113,21 +121,32 @@ module.exports = ({
|
||||
__filename: false,
|
||||
// We provide our own "timers" import above, any usage of setImmediate inside
|
||||
// one of our renderer bundles should import it from the 'timers' package
|
||||
setImmediate: false,
|
||||
setImmediate: false
|
||||
},
|
||||
optimization: {
|
||||
minimize: true,
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
terserOptions: {
|
||||
keep_classnames: true,
|
||||
keep_fnames: true
|
||||
}
|
||||
})
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
new AccessDependenciesPlugin(),
|
||||
...(targetDeletesNodeGlobals ? [
|
||||
new webpack.ProvidePlugin({
|
||||
process: ['@electron/internal/renderer/webpack-provider', 'process'],
|
||||
global: ['@electron/internal/renderer/webpack-provider', '_global'],
|
||||
Buffer: ['@electron/internal/renderer/webpack-provider', 'Buffer'],
|
||||
process: ['@electron/internal/common/webpack-provider', 'process'],
|
||||
global: ['@electron/internal/common/webpack-provider', '_global'],
|
||||
Buffer: ['@electron/internal/common/webpack-provider', 'Buffer']
|
||||
})
|
||||
] : []),
|
||||
new webpack.ProvidePlugin({
|
||||
Promise: ['@electron/internal/common/webpack-globals-provider', 'Promise'],
|
||||
Promise: ['@electron/internal/common/webpack-globals-provider', 'Promise']
|
||||
}),
|
||||
new webpack.DefinePlugin(defines),
|
||||
new webpack.DefinePlugin(defines)
|
||||
]
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module.exports = require('./webpack.config.base')({
|
||||
target: 'browser',
|
||||
alwaysHasNode: true
|
||||
})
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module.exports = require('./webpack.config.base')({
|
||||
target: 'isolated_renderer',
|
||||
alwaysHasNode: false
|
||||
})
|
||||
});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
module.exports = require('./webpack.config.base')({
|
||||
target: 'renderer',
|
||||
alwaysHasNode: true,
|
||||
targetDeletesNodeGlobals: true
|
||||
})
|
||||
targetDeletesNodeGlobals: true,
|
||||
wrapInitWithProfilingTimeout: true
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
module.exports = require('./webpack.config.base')({
|
||||
target: 'sandboxed_renderer',
|
||||
alwaysHasNode: false
|
||||
})
|
||||
alwaysHasNode: false,
|
||||
wrapInitWithProfilingTimeout: true
|
||||
});
|
||||
|
||||
@@ -3,4 +3,4 @@ module.exports = require('./webpack.config.base')({
|
||||
loadElectronFromAlternateTarget: 'renderer',
|
||||
alwaysHasNode: true,
|
||||
targetDeletesNodeGlobals: true
|
||||
})
|
||||
});
|
||||
|
||||
@@ -16,6 +16,7 @@ template("webpack_build") {
|
||||
inputs = [
|
||||
invoker.config_file,
|
||||
"//electron/build/webpack/webpack.config.base.js",
|
||||
"//electron/build/webpack/run-compiler.js",
|
||||
"//electron/tsconfig.json",
|
||||
"//electron/yarn.lock",
|
||||
"//electron/typings/internal-ambient.d.ts",
|
||||
|
||||
@@ -32,6 +32,8 @@ PATHS_TO_SKIP = [
|
||||
# On Linux, we don't use crashpad, but this binary is still built for some
|
||||
# reason. Exclude it from the zip.
|
||||
'./crashpad_handler',
|
||||
|
||||
'resources/inspector', #Skipping because these are outputs that we don't need
|
||||
]
|
||||
|
||||
def skip_path(dep, dist_zip, target_cpu):
|
||||
|
||||
@@ -12,6 +12,8 @@ import("//third_party/widevine/cdm/widevine.gni")
|
||||
static_library("chrome") {
|
||||
visibility = [ "//electron:electron_lib" ]
|
||||
sources = [
|
||||
"//chrome/browser/accessibility/accessibility_ui.cc",
|
||||
"//chrome/browser/accessibility/accessibility_ui.h",
|
||||
"//chrome/browser/browser_process.cc",
|
||||
"//chrome/browser/browser_process.h",
|
||||
"//chrome/browser/crash_upload_list/crash_upload_list_crashpad.cc",
|
||||
@@ -62,17 +64,20 @@ static_library("chrome") {
|
||||
"//extensions/browser/app_window/size_constraints.cc",
|
||||
"//extensions/browser/app_window/size_constraints.h",
|
||||
]
|
||||
|
||||
public_deps = [
|
||||
"//chrome/common",
|
||||
"//chrome/common:version_header",
|
||||
"//components/keyed_service/content",
|
||||
"//components/paint_preview/buildflags",
|
||||
"//components/proxy_config",
|
||||
"//components/security_state/content",
|
||||
"//content/public/browser",
|
||||
]
|
||||
|
||||
deps = [
|
||||
"//chrome/browser:resource_prefetch_predictor_proto",
|
||||
"//components/feature_engagement:buildflags",
|
||||
"//chrome/services/speech:buildflags",
|
||||
"//components/optimization_guide/proto:optimization_guide_proto",
|
||||
]
|
||||
|
||||
@@ -92,6 +97,14 @@ static_library("chrome") {
|
||||
]
|
||||
}
|
||||
|
||||
if (is_win) {
|
||||
sources += [
|
||||
"//chrome/browser/win/icon_reader_service.cc",
|
||||
"//chrome/browser/win/icon_reader_service.h",
|
||||
]
|
||||
public_deps += [ "//chrome/services/util_win:lib" ]
|
||||
}
|
||||
|
||||
if (enable_desktop_capturer) {
|
||||
sources += [
|
||||
"//chrome/browser/media/webrtc/desktop_media_list.h",
|
||||
@@ -152,13 +165,6 @@ static_library("chrome") {
|
||||
}
|
||||
}
|
||||
|
||||
if (enable_tts) {
|
||||
sources += [
|
||||
"//chrome/browser/speech/tts_controller_delegate_impl.cc",
|
||||
"//chrome/browser/speech/tts_controller_delegate_impl.h",
|
||||
]
|
||||
}
|
||||
|
||||
if (enable_widevine) {
|
||||
sources += [
|
||||
"//chrome/renderer/media/chrome_key_systems.cc",
|
||||
@@ -265,7 +271,7 @@ static_library("chrome") {
|
||||
source_set("plugins") {
|
||||
sources = []
|
||||
deps = []
|
||||
libs = []
|
||||
frameworks = []
|
||||
|
||||
# browser side
|
||||
sources += [
|
||||
@@ -299,7 +305,7 @@ source_set("plugins") {
|
||||
"//chrome/browser/renderer_host/pepper/monitor_finder_mac.h",
|
||||
"//chrome/browser/renderer_host/pepper/monitor_finder_mac.mm",
|
||||
]
|
||||
libs += [ "CoreGraphics.framework" ]
|
||||
frameworks += [ "CoreGraphics.framework" ]
|
||||
}
|
||||
if (is_linux) {
|
||||
deps += [ "//components/services/font/public/cpp" ]
|
||||
@@ -363,8 +369,8 @@ source_set("chrome_spellchecker") {
|
||||
"//chrome/browser/spellchecker/spellcheck_factory.h",
|
||||
"//chrome/browser/spellchecker/spellcheck_hunspell_dictionary.cc",
|
||||
"//chrome/browser/spellchecker/spellcheck_hunspell_dictionary.h",
|
||||
"//chrome/browser/spellchecker/spellcheck_language_blacklist_policy_handler.cc",
|
||||
"//chrome/browser/spellchecker/spellcheck_language_blacklist_policy_handler.h",
|
||||
"//chrome/browser/spellchecker/spellcheck_language_blocklist_policy_handler.cc",
|
||||
"//chrome/browser/spellchecker/spellcheck_language_blocklist_policy_handler.h",
|
||||
"//chrome/browser/spellchecker/spellcheck_language_policy_handler.cc",
|
||||
"//chrome/browser/spellchecker/spellcheck_language_policy_handler.h",
|
||||
"//chrome/browser/spellchecker/spellcheck_service.cc",
|
||||
|
||||
@@ -68,7 +68,6 @@
|
||||
#include "base/logging.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/message_loop/message_loop.h"
|
||||
#include "base/metrics/histogram_macros.h"
|
||||
#include "base/path_service.h"
|
||||
#include "base/posix/eintr_wrapper.h"
|
||||
|
||||
@@ -24,18 +24,18 @@ GlobalMenuBarRegistrarX11* GlobalMenuBarRegistrarX11::GetInstance() {
|
||||
return base::Singleton<GlobalMenuBarRegistrarX11>::get();
|
||||
}
|
||||
|
||||
void GlobalMenuBarRegistrarX11::OnWindowMapped(unsigned long xid) {
|
||||
live_xids_.insert(xid);
|
||||
void GlobalMenuBarRegistrarX11::OnWindowMapped(x11::Window window) {
|
||||
live_windows_.insert(window);
|
||||
|
||||
if (registrar_proxy_)
|
||||
RegisterXID(xid);
|
||||
RegisterXWindow(window);
|
||||
}
|
||||
|
||||
void GlobalMenuBarRegistrarX11::OnWindowUnmapped(unsigned long xid) {
|
||||
void GlobalMenuBarRegistrarX11::OnWindowUnmapped(x11::Window window) {
|
||||
if (registrar_proxy_)
|
||||
UnregisterXID(xid);
|
||||
UnregisterXWindow(window);
|
||||
|
||||
live_xids_.erase(xid);
|
||||
live_windows_.erase(window);
|
||||
}
|
||||
|
||||
GlobalMenuBarRegistrarX11::GlobalMenuBarRegistrarX11()
|
||||
@@ -63,9 +63,9 @@ GlobalMenuBarRegistrarX11::~GlobalMenuBarRegistrarX11() {
|
||||
}
|
||||
}
|
||||
|
||||
void GlobalMenuBarRegistrarX11::RegisterXID(unsigned long xid) {
|
||||
void GlobalMenuBarRegistrarX11::RegisterXWindow(x11::Window window) {
|
||||
DCHECK(registrar_proxy_);
|
||||
std::string path = electron::GlobalMenuBarX11::GetPathForWindow(xid);
|
||||
std::string path = electron::GlobalMenuBarX11::GetPathForWindow(window);
|
||||
|
||||
ANNOTATE_SCOPED_MEMORY_LEAK; // http://crbug.com/314087
|
||||
// TODO(erg): The mozilla implementation goes to a lot of callback trouble
|
||||
@@ -76,13 +76,13 @@ void GlobalMenuBarRegistrarX11::RegisterXID(unsigned long xid) {
|
||||
// I don't see any reason why we should care if "RegisterWindow" completes or
|
||||
// not.
|
||||
g_dbus_proxy_call(registrar_proxy_, "RegisterWindow",
|
||||
g_variant_new("(uo)", xid, path.c_str()),
|
||||
g_variant_new("(uo)", window, path.c_str()),
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
void GlobalMenuBarRegistrarX11::UnregisterXID(unsigned long xid) {
|
||||
void GlobalMenuBarRegistrarX11::UnregisterXWindow(x11::Window window) {
|
||||
DCHECK(registrar_proxy_);
|
||||
std::string path = electron::GlobalMenuBarX11::GetPathForWindow(xid);
|
||||
std::string path = electron::GlobalMenuBarX11::GetPathForWindow(window);
|
||||
|
||||
ANNOTATE_SCOPED_MEMORY_LEAK; // http://crbug.com/314087
|
||||
// TODO(erg): The mozilla implementation goes to a lot of callback trouble
|
||||
@@ -93,7 +93,7 @@ void GlobalMenuBarRegistrarX11::UnregisterXID(unsigned long xid) {
|
||||
// I don't see any reason why we should care if "UnregisterWindow" completes
|
||||
// or not.
|
||||
g_dbus_proxy_call(registrar_proxy_, "UnregisterWindow",
|
||||
g_variant_new("(u)", xid), G_DBUS_CALL_FLAGS_NONE, -1,
|
||||
g_variant_new("(u)", window), G_DBUS_CALL_FLAGS_NONE, -1,
|
||||
nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
@@ -120,10 +120,10 @@ void GlobalMenuBarRegistrarX11::OnProxyCreated(GObject* source,
|
||||
|
||||
void GlobalMenuBarRegistrarX11::OnNameOwnerChanged(GObject* /* ignored */,
|
||||
GParamSpec* /* ignored */) {
|
||||
// If the name owner changed, we need to reregister all the live xids with
|
||||
// the system.
|
||||
for (std::set<unsigned long>::const_iterator it = live_xids_.begin();
|
||||
it != live_xids_.end(); ++it) {
|
||||
RegisterXID(*it);
|
||||
// If the name owner changed, we need to reregister all the live x11::Window
|
||||
// with the system.
|
||||
for (std::set<x11::Window>::const_iterator it = live_windows_.begin();
|
||||
it != live_windows_.end(); ++it) {
|
||||
RegisterXWindow(*it);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,19 +12,20 @@
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/memory/singleton.h"
|
||||
#include "ui/base/glib/glib_signal.h"
|
||||
#include "ui/gfx/x/xproto.h"
|
||||
|
||||
// Advertises our menu bars to Unity.
|
||||
//
|
||||
// GlobalMenuBarX11 is responsible for managing the DbusmenuServer for each
|
||||
// XID. We need a separate object to own the dbus channel to
|
||||
// x11::Window. We need a separate object to own the dbus channel to
|
||||
// com.canonical.AppMenu.Registrar and to register/unregister the mapping
|
||||
// between a XID and the DbusmenuServer instance we are offering.
|
||||
// between a x11::Window and the DbusmenuServer instance we are offering.
|
||||
class GlobalMenuBarRegistrarX11 {
|
||||
public:
|
||||
static GlobalMenuBarRegistrarX11* GetInstance();
|
||||
|
||||
void OnWindowMapped(unsigned long xid);
|
||||
void OnWindowUnmapped(unsigned long xid);
|
||||
void OnWindowMapped(x11::Window window);
|
||||
void OnWindowUnmapped(x11::Window window);
|
||||
|
||||
private:
|
||||
friend struct base::DefaultSingletonTraits<GlobalMenuBarRegistrarX11>;
|
||||
@@ -33,8 +34,8 @@ class GlobalMenuBarRegistrarX11 {
|
||||
~GlobalMenuBarRegistrarX11();
|
||||
|
||||
// Sends the actual message.
|
||||
void RegisterXID(unsigned long xid);
|
||||
void UnregisterXID(unsigned long xid);
|
||||
void RegisterXWindow(x11::Window window);
|
||||
void UnregisterXWindow(x11::Window window);
|
||||
|
||||
CHROMEG_CALLBACK_1(GlobalMenuBarRegistrarX11,
|
||||
void,
|
||||
@@ -49,9 +50,9 @@ class GlobalMenuBarRegistrarX11 {
|
||||
|
||||
GDBusProxy* registrar_proxy_;
|
||||
|
||||
// Window XIDs which want to be registered, but haven't yet been because
|
||||
// x11::Window which want to be registered, but haven't yet been because
|
||||
// we're waiting for the proxy to become available.
|
||||
std::set<unsigned long> live_xids_;
|
||||
std::set<x11::Window> live_windows_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(GlobalMenuBarRegistrarX11);
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { app, dialog, BrowserWindow, shell, ipcMain } from 'electron';
|
||||
import * as path from 'path';
|
||||
import * as url from 'url';
|
||||
|
||||
let mainWindow: BrowserWindow | null = null;
|
||||
|
||||
@@ -29,12 +30,11 @@ function isTrustedSender (webContents: Electron.WebContents) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const parsedUrl = new URL(webContents.getURL());
|
||||
const urlPath = process.platform === 'win32'
|
||||
// Strip the prefixed "/" that occurs on windows
|
||||
? path.resolve(parsedUrl.pathname.substr(1))
|
||||
: parsedUrl.pathname;
|
||||
return parsedUrl.protocol === 'file:' && urlPath === indexPath;
|
||||
try {
|
||||
return url.fileURLToPath(webContents.getURL()) === indexPath;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ipcMain.handle('bootstrap', (event) => {
|
||||
|
||||
@@ -53,31 +53,31 @@
|
||||
<nav>
|
||||
<div class="linkcol">
|
||||
<a class="hero-link" target="_blank" href="https://electronjs.org/blog">
|
||||
<span class="octicon hero-octicon octicon-gist" aria-hidden="true"></span>
|
||||
<span class="octicon hero-octicon octicon-code-square-24" aria-hidden="true"></span>
|
||||
<h4>Blog</h4>
|
||||
</a>
|
||||
</div>
|
||||
<div class="linkcol">
|
||||
<a class="hero-link" target="_blank" href="https://github.com/electron/electron">
|
||||
<span class="octicon hero-octicon octicon-mark-github" aria-hidden="true"></span>
|
||||
<span class="octicon hero-octicon octicon-mark-github-16" aria-hidden="true"></span>
|
||||
<h4>Repository</h4>
|
||||
</a>
|
||||
</div>
|
||||
<div class="linkcol">
|
||||
<a class="hero-link" target="_blank" href="https://electronjs.org/docs">
|
||||
<span class="octicon hero-octicon octicon-gear" aria-hidden="true"></span>
|
||||
<span class="octicon hero-octicon octicon-book-24" aria-hidden="true"></span>
|
||||
<h4>Docs</h4>
|
||||
</a>
|
||||
</div>
|
||||
<div class="linkcol">
|
||||
<a class="hero-link" target="_blank" href="https://github.com/electron/electron-api-demos">
|
||||
<span class="octicon hero-octicon octicon-star" aria-hidden="true"></span>
|
||||
<span class="octicon hero-octicon octicon-star-fill-24" aria-hidden="true"></span>
|
||||
<h4>API Demos</h4>
|
||||
</a>
|
||||
</div>
|
||||
<div class="linkcol">
|
||||
<a class="hero-link" target="_blank" href="https://electronforge.io">
|
||||
<span class="octicon hero-octicon octicon-gift" aria-hidden="true"></span>
|
||||
<span class="octicon hero-octicon octicon-gift-24" aria-hidden="true"></span>
|
||||
<h4>Forge</h4>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { app, dialog } from 'electron';
|
||||
import * as electron from 'electron';
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as url from 'url';
|
||||
const { app, dialog } = electron;
|
||||
|
||||
type DefaultAppOptions = {
|
||||
file: null | string;
|
||||
@@ -145,13 +146,90 @@ function startRepl () {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// prevent quitting
|
||||
// Prevent quitting.
|
||||
app.on('window-all-closed', () => {});
|
||||
|
||||
const repl = require('repl');
|
||||
repl.start('> ').on('exit', () => {
|
||||
const GREEN = '32';
|
||||
const colorize = (color: string, s: string) => `\x1b[${color}m${s}\x1b[0m`;
|
||||
const electronVersion = colorize(GREEN, `v${process.versions.electron}`);
|
||||
const nodeVersion = colorize(GREEN, `v${process.versions.node}`);
|
||||
|
||||
console.info(`
|
||||
Welcome to the Electron.js REPL \\[._.]/
|
||||
|
||||
You can access all Electron.js modules here as well as Node.js modules.
|
||||
Using: Node.js ${nodeVersion} and Electron.js ${electronVersion}
|
||||
`);
|
||||
|
||||
const { REPLServer } = require('repl');
|
||||
const repl = new REPLServer({
|
||||
prompt: '> '
|
||||
}).on('exit', () => {
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
function defineBuiltin (context: any, name: string, getter: Function) {
|
||||
const setReal = (val: any) => {
|
||||
// Deleting the property before re-assigning it disables the
|
||||
// getter/setter mechanism.
|
||||
delete context[name];
|
||||
context[name] = val;
|
||||
};
|
||||
|
||||
Object.defineProperty(context, name, {
|
||||
get: () => {
|
||||
const lib = getter();
|
||||
|
||||
delete context[name];
|
||||
Object.defineProperty(context, name, {
|
||||
get: () => lib,
|
||||
set: setReal,
|
||||
configurable: true,
|
||||
enumerable: false
|
||||
});
|
||||
|
||||
return lib;
|
||||
},
|
||||
set: setReal,
|
||||
configurable: true,
|
||||
enumerable: false
|
||||
});
|
||||
}
|
||||
|
||||
defineBuiltin(repl.context, 'electron', () => electron);
|
||||
for (const api of Object.keys(electron) as (keyof typeof electron)[]) {
|
||||
defineBuiltin(repl.context, api, () => electron[api]);
|
||||
}
|
||||
|
||||
// Copied from node/lib/repl.js. For better DX, we don't want to
|
||||
// show e.g 'contentTracing' at a higher priority than 'const', so
|
||||
// we only trigger custom tab-completion when no common words are
|
||||
// potentially matches.
|
||||
const commonWords = [
|
||||
'async', 'await', 'break', 'case', 'catch', 'const', 'continue',
|
||||
'debugger', 'default', 'delete', 'do', 'else', 'export', 'false',
|
||||
'finally', 'for', 'function', 'if', 'import', 'in', 'instanceof', 'let',
|
||||
'new', 'null', 'return', 'switch', 'this', 'throw', 'true', 'try',
|
||||
'typeof', 'var', 'void', 'while', 'with', 'yield'
|
||||
];
|
||||
|
||||
const electronBuiltins = [...Object.keys(electron), 'original-fs', 'electron'];
|
||||
|
||||
const defaultComplete = repl.completer;
|
||||
repl.completer = (line: string, callback: Function) => {
|
||||
const lastSpace = line.lastIndexOf(' ');
|
||||
const currentSymbol = line.substring(lastSpace + 1, repl.cursor);
|
||||
|
||||
const filterFn = (c: string) => c.startsWith(currentSymbol);
|
||||
const ignores = commonWords.filter(filterFn);
|
||||
const hits = electronBuiltins.filter(filterFn);
|
||||
|
||||
if (!ignores.length && hits.length) {
|
||||
callback(null, [hits, currentSymbol]);
|
||||
} else {
|
||||
defaultComplete.apply(repl, [line, callback]);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Start the specified app if there is one specified in command line, otherwise
|
||||
|
||||
@@ -92,7 +92,6 @@ These individual tutorials expand on topics discussed in the guide above.
|
||||
* Electron Releases & Developer Feedback
|
||||
* [Versioning Policy](tutorial/electron-versioning.md)
|
||||
* [Release Timelines](tutorial/electron-timelines.md)
|
||||
* [App Feedback Program](tutorial/app-feedback-program.md)
|
||||
* [Packaging App Source Code with asar](tutorial/application-packaging.md)
|
||||
* [Generating asar Archives](tutorial/application-packaging.md#generating-asar-archives)
|
||||
* [Using asar Archives](tutorial/application-packaging.md#using-asar-archives)
|
||||
|
||||
142
docs/api/app.md
142
docs/api/app.md
@@ -140,6 +140,16 @@ this event, such as launching the application for the first time, attempting
|
||||
to re-launch the application when it's already running, or clicking on the
|
||||
application's dock or taskbar icon.
|
||||
|
||||
### Event: 'did-become-active' _macOS_
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
|
||||
Emitted when mac application become active. Difference from `activate` event is
|
||||
that `did-become-active` is emitted every time the app becomes active, not only
|
||||
when Dock icon is clicked or application is re-launched.
|
||||
|
||||
### Event: 'continue-activity' _macOS_
|
||||
|
||||
Returns:
|
||||
@@ -350,7 +360,7 @@ page.
|
||||
|
||||
Emitted whenever there is a GPU info update.
|
||||
|
||||
### Event: 'gpu-process-crashed'
|
||||
### Event: 'gpu-process-crashed' _Deprecated_
|
||||
|
||||
Returns:
|
||||
|
||||
@@ -359,7 +369,12 @@ Returns:
|
||||
|
||||
Emitted when the GPU process crashes or is killed.
|
||||
|
||||
### Event: 'renderer-process-crashed'
|
||||
**Deprecated:** This event is superceded by the `child-process-gone` event
|
||||
which contains more information about why the child process dissapeared. It
|
||||
isn't always because it crashed. The `killed` boolean can be replaced by
|
||||
checking `reason === 'killed'` when you switch to that event.
|
||||
|
||||
### Event: 'renderer-process-crashed' _Deprecated_
|
||||
|
||||
Returns:
|
||||
|
||||
@@ -369,6 +384,60 @@ Returns:
|
||||
|
||||
Emitted when the renderer process of `webContents` crashes or is killed.
|
||||
|
||||
**Deprecated:** This event is superceded by the `render-process-gone` event
|
||||
which contains more information about why the render process dissapeared. It
|
||||
isn't always because it crashed. The `killed` boolean can be replaced by
|
||||
checking `reason === 'killed'` when you switch to that event.
|
||||
|
||||
#### Event: 'render-process-gone'
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `webContents` [WebContents](web-contents.md)
|
||||
* `details` Object
|
||||
* `reason` String - The reason the render process is gone. Possible values:
|
||||
* `clean-exit` - Process exited with an exit code of zero
|
||||
* `abnormal-exit` - Process exited with a non-zero exit code
|
||||
* `killed` - Process was sent a SIGTERM or otherwise killed externally
|
||||
* `crashed` - Process crashed
|
||||
* `oom` - Process ran out of memory
|
||||
* `launch-failure` - Process never successfully launched
|
||||
* `integrity-failure` - Windows code integrity checks failed
|
||||
|
||||
Emitted when the renderer process unexpectedly dissapears. This is normally
|
||||
because it was crashed or killed.
|
||||
|
||||
#### Event: 'child-process-gone'
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `details` Object
|
||||
* `type` String - Process type. One of the following values:
|
||||
* `Utility`
|
||||
* `Zygote`
|
||||
* `Sandbox helper`
|
||||
* `GPU`
|
||||
* `Pepper Plugin`
|
||||
* `Pepper Plugin Broker`
|
||||
* `Unknown`
|
||||
* `reason` String - The reason the child process is gone. Possible values:
|
||||
* `clean-exit` - Process exited with an exit code of zero
|
||||
* `abnormal-exit` - Process exited with a non-zero exit code
|
||||
* `killed` - Process was sent a SIGTERM or otherwise killed externally
|
||||
* `crashed` - Process crashed
|
||||
* `oom` - Process ran out of memory
|
||||
* `launch-failure` - Process never successfully launched
|
||||
* `integrity-failure` - Windows code integrity checks failed
|
||||
* `exitCode` Number - The exit code for the process
|
||||
(e.g. status from waitpid if on posix, from GetExitCodeProcess on Windows).
|
||||
* `name` String (optional) - The name of the process. i.e. for plugins it might be Flash.
|
||||
Examples for utility: `Audio Service`, `Content Decryption Module Service`, `Network Service`, `Video Capture`, etc.
|
||||
|
||||
Emitted when the child process unexpectedly dissapears. This is normally
|
||||
because it was crashed or killed. It does not include renderer processes.
|
||||
|
||||
### Event: 'accessibility-support-changed' _macOS_ _Windows_
|
||||
|
||||
Returns:
|
||||
@@ -781,6 +850,20 @@ Returns `String` - Name of the application handling the protocol, or an empty
|
||||
This method returns the application name of the default handler for the protocol
|
||||
(aka URI scheme) of a URL.
|
||||
|
||||
### `app.getApplicationInfoForProtocol(url)` _macOS_ _Windows_
|
||||
|
||||
* `url` String - a URL with the protocol name to check. Unlike the other
|
||||
methods in this family, this accepts an entire URL, including `://` at a
|
||||
minimum (e.g. `https://`).
|
||||
|
||||
Returns `Promise<Object>` - Resolve with an object containing the following:
|
||||
* `icon` NativeImage - the display icon of the app handling the protocol.
|
||||
* `path` String - installation path of the app handling the protocol.
|
||||
* `name` String - display name of the app handling the protocol.
|
||||
|
||||
This method returns a promise that contains the application name, icon and path of the default handler for the protocol
|
||||
(aka URI scheme) of a URL.
|
||||
|
||||
### `app.setUserTasks(tasks)` _Windows_
|
||||
|
||||
* `tasks` [Task[]](structures/task.md) - Array of `Task` objects
|
||||
@@ -942,6 +1025,7 @@ if (!gotTheLock) {
|
||||
|
||||
// Create myWindow, load the rest of the app, etc...
|
||||
app.whenReady().then(() => {
|
||||
myWindow = createWindow()
|
||||
})
|
||||
}
|
||||
```
|
||||
@@ -1057,8 +1141,10 @@ For `infoType` equal to `complete`:
|
||||
For `infoType` equal to `basic`:
|
||||
Promise is fulfilled with `Object` containing fewer attributes than when requested with `complete`. Here's an example of basic response:
|
||||
```js
|
||||
{ auxAttributes:
|
||||
{ amdSwitchable: true,
|
||||
{
|
||||
auxAttributes:
|
||||
{
|
||||
amdSwitchable: true,
|
||||
canSupportThreadedTextureMailbox: false,
|
||||
directComposition: false,
|
||||
directRendering: true,
|
||||
@@ -1071,12 +1157,14 @@ For `infoType` equal to `basic`:
|
||||
sandboxed: false,
|
||||
softwareRendering: false,
|
||||
supportsOverlays: false,
|
||||
videoDecodeAcceleratorFlags: 0 },
|
||||
gpuDevice:
|
||||
[ { active: true, deviceId: 26657, vendorId: 4098 },
|
||||
{ active: false, deviceId: 3366, vendorId: 32902 } ],
|
||||
machineModelName: 'MacBookPro',
|
||||
machineModelVersion: '11.5' }
|
||||
videoDecodeAcceleratorFlags: 0
|
||||
},
|
||||
gpuDevice:
|
||||
[{ active: true, deviceId: 26657, vendorId: 4098 },
|
||||
{ active: false, deviceId: 3366, vendorId: 32902 }],
|
||||
machineModelName: 'MacBookPro',
|
||||
machineModelVersion: '11.5'
|
||||
}
|
||||
```
|
||||
|
||||
Using `basic` should be preferred if only basic information like `vendorId` or `driverId` is needed.
|
||||
@@ -1128,6 +1216,13 @@ Returns `Object`:
|
||||
should restore the state from the previous session. This indicates that the
|
||||
app should restore the windows that were open the last time the app was
|
||||
closed. This setting is not available on [MAS builds][mas-builds].
|
||||
* `executableWillLaunchAtLogin` Boolean _Windows_ - `true` if app is set to open at login and its run key is not deactivated. This differs from `openAtLogin` as it ignores the `args` option, this property will be true if the given executable would be launched at login with **any** arguments.
|
||||
* `launchItems` Object[] _Windows_
|
||||
* `name` String _Windows_ - name value of a registry entry.
|
||||
* `path` String _Windows_ - The executable to an app that corresponds to a registry entry.
|
||||
* `args` String[] _Windows_ - the command-line arguments to pass to the executable.
|
||||
* `scope` String _Windows_ - one of `user` or `machine`. Indicates whether the registry entry is under `HKEY_CURRENT USER` or `HKEY_LOCAL_MACHINE`.
|
||||
* `enabled` Boolean _Windows_ - `true` if the app registry key is startup approved and therfore shows as `enabled` in Task Manager and Windows settings.
|
||||
|
||||
### `app.setLoginItemSettings(settings)` _macOS_ _Windows_
|
||||
|
||||
@@ -1143,7 +1238,9 @@ Returns `Object`:
|
||||
* `args` String[] (optional) _Windows_ - The command-line arguments to pass to
|
||||
the executable. Defaults to an empty array. Take care to wrap paths in
|
||||
quotes.
|
||||
|
||||
* `enabled` Boolean (optional) _Windows_ - `true` will change the startup approved registry key and `enable / disable` the App in Task Manager and Windows Settings.
|
||||
Defaults to `true`.
|
||||
* `name` String (optional) _Windows_ - value name to write into registry. Defaults to the app's AppUserModelId().
|
||||
Set the app's login item settings.
|
||||
|
||||
To work with Electron's `autoUpdater` on Windows, which uses [Squirrel][Squirrel-Windows],
|
||||
@@ -1198,7 +1295,7 @@ Show the app's about panel options. These options can be overridden with `app.se
|
||||
* `credits` String (optional) _macOS_ _Windows_ - Credit information.
|
||||
* `authors` String[] (optional) _Linux_ - List of app authors.
|
||||
* `website` String (optional) _Linux_ - The app's website.
|
||||
* `iconPath` String (optional) _Linux_ _Windows_ - Path to the app's icon. On Linux, will be shown as 64x64 pixels while retaining aspect ratio.
|
||||
* `iconPath` String (optional) _Linux_ _Windows_ - Path to the app's icon in a JPEG or PNG file format. On Linux, will be shown as 64x64 pixels while retaining aspect ratio.
|
||||
|
||||
Set the about panel options. This will override the values defined in the app's `.plist` file on macOS. See the [Apple docs][about-panel-options] for more details. On Linux, values must be set in order to be shown; there are no defaults.
|
||||
|
||||
@@ -1280,6 +1377,25 @@ app.moveToApplicationsFolder({
|
||||
|
||||
Would mean that if an app already exists in the user directory, if the user chooses to 'Continue Move' then the function would continue with its default behavior and the existing app will be trashed and the active app moved into its place.
|
||||
|
||||
### `app.isSecureKeyboardEntryEnabled()` _macOS_
|
||||
|
||||
Returns `Boolean` - whether `Secure Keyboard Entry` is enabled.
|
||||
|
||||
By default this API will return `false`.
|
||||
|
||||
### `app.setSecureKeyboardEntryEnabled(enabled)` _macOS_
|
||||
|
||||
* `enabled` Boolean - Enable or disable `Secure Keyboard Entry`
|
||||
|
||||
Set the `Secure Keyboard Entry` is enabled in your application.
|
||||
|
||||
By using this API, important information such as password and other sensitive information can be prevented from being intercepted by other processes.
|
||||
|
||||
See [Apple's documentation](https://developer.apple.com/library/archive/technotes/tn2150/_index.html) for more
|
||||
details.
|
||||
|
||||
**Note:** Enable `Secure Keyboard Entry` only when it is needed and disable it when it is no longer needed.
|
||||
|
||||
## Properties
|
||||
|
||||
### `app.accessibilitySupportEnabled` _macOS_ _Windows_
|
||||
@@ -1360,7 +1476,7 @@ in your app's initialization to ensure that your overridden value is used.
|
||||
|
||||
A `Boolean` which when `true` disables the overrides that Electron has in place
|
||||
to ensure renderer processes are restarted on every navigation. The current
|
||||
default value for this property is `false`.
|
||||
default value for this property is `true`.
|
||||
|
||||
The intention is for these overrides to become disabled by default and then at
|
||||
some point in the future this property will be removed. This property impacts
|
||||
|
||||
@@ -104,7 +104,7 @@ The `autoUpdater` object has the following methods:
|
||||
* `options` Object
|
||||
* `url` String
|
||||
* `headers` Record<String, String> (optional) _macOS_ - HTTP request headers.
|
||||
* `serverType` String (optional) _macOS_ - Either `json` or `default`, see the [Squirrel.Mac][squirrel-mac]
|
||||
* `serverType` String (optional) _macOS_ - Can be `json` or `default`, see the [Squirrel.Mac][squirrel-mac]
|
||||
README for more information.
|
||||
|
||||
Sets the `url` and initialize the auto updater.
|
||||
|
||||
@@ -28,25 +28,6 @@ view.webContents.loadURL('https://electronjs.org')
|
||||
* `options` Object (optional)
|
||||
* `webPreferences` Object (optional) - See [BrowserWindow](browser-window.md).
|
||||
|
||||
### Static Methods
|
||||
|
||||
#### `BrowserView.getAllViews()`
|
||||
|
||||
Returns `BrowserView[]` - An array of all opened BrowserViews.
|
||||
|
||||
#### `BrowserView.fromWebContents(webContents)`
|
||||
|
||||
* `webContents` [WebContents](web-contents.md)
|
||||
|
||||
Returns `BrowserView | null` - The BrowserView that owns the given `webContents`
|
||||
or `null` if the contents are not owned by a BrowserView.
|
||||
|
||||
#### `BrowserView.fromId(id)`
|
||||
|
||||
* `id` Integer
|
||||
|
||||
Returns `BrowserView` - The view with the given `id`.
|
||||
|
||||
### Instance Properties
|
||||
|
||||
Objects created with `new BrowserView` have the following properties:
|
||||
@@ -55,10 +36,6 @@ Objects created with `new BrowserView` have the following properties:
|
||||
|
||||
A [`WebContents`](web-contents.md) object owned by this view.
|
||||
|
||||
#### `view.id` _Experimental_
|
||||
|
||||
A `Integer` representing the unique ID of the view.
|
||||
|
||||
### Instance Methods
|
||||
|
||||
Objects created with `new BrowserView` have the following instance methods:
|
||||
|
||||
@@ -38,7 +38,7 @@ the window after this event will have no visual flash:
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
let win = new BrowserWindow({ show: false })
|
||||
const win = new BrowserWindow({ show: false })
|
||||
win.once('ready-to-show', () => {
|
||||
win.show()
|
||||
})
|
||||
@@ -60,7 +60,7 @@ immediately, and use a `backgroundColor` close to your app's background:
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
|
||||
let win = new BrowserWindow({ backgroundColor: '#2e2c29' })
|
||||
const win = new BrowserWindow({ backgroundColor: '#2e2c29' })
|
||||
win.loadURL('https://github.com')
|
||||
```
|
||||
|
||||
@@ -74,8 +74,8 @@ By using `parent` option, you can create child windows:
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
|
||||
let top = new BrowserWindow()
|
||||
let child = new BrowserWindow({ parent: top })
|
||||
const top = new BrowserWindow()
|
||||
const child = new BrowserWindow({ parent: top })
|
||||
child.show()
|
||||
top.show()
|
||||
```
|
||||
@@ -90,7 +90,7 @@ window, you have to set both `parent` and `modal` options:
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
|
||||
let child = new BrowserWindow({ parent: top, modal: true, show: false })
|
||||
const child = new BrowserWindow({ parent: top, modal: true, show: false })
|
||||
child.loadURL('https://github.com')
|
||||
child.once('ready-to-show', () => {
|
||||
child.show()
|
||||
@@ -348,6 +348,9 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
||||
You can access this context in the dev tools by selecting the
|
||||
'Electron Isolated Context' entry in the combo box at the top of the
|
||||
Console tab.
|
||||
* `worldSafeExecuteJavaScript` Boolean (optional) - If true, values returned from `webFrame.executeJavaScript` will be sanitized to ensure JS values
|
||||
can't unsafely cross between worlds when using `contextIsolation`. The default
|
||||
is `false`. In Electron 12, the default will be changed to `true`. _Deprecated_
|
||||
* `nativeWindowOpen` Boolean (optional) - Whether to use native
|
||||
`window.open()`. Defaults to `false`. Child windows will always have node
|
||||
integration disabled unless `nodeIntegrationInSubFrames` is true. **Note:** This option is currently
|
||||
@@ -387,6 +390,13 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
||||
Default is `true`.
|
||||
* `enableWebSQL` Boolean (optional) - Whether to enable the [WebSQL api](https://www.w3.org/TR/webdatabase/).
|
||||
Default is `true`.
|
||||
* `v8CacheOptions` String (optional) - Enforces the v8 code caching policy
|
||||
used by blink. Accepted values are
|
||||
* `none` - Disables code caching
|
||||
* `code` - Heuristic based code caching
|
||||
* `bypassHeatCheck` - Bypass code caching heuristics but with lazy compilation
|
||||
* `bypassHeatCheckAndEagerCompile` - Same as above except compilation is eager.
|
||||
Default policy is `code`.
|
||||
|
||||
When setting minimum or maximum window size with `minWidth`/`maxWidth`/
|
||||
`minHeight`/`maxHeight`, it only constrains the users. It won't prevent you from
|
||||
@@ -590,7 +600,7 @@ e.g. `APPCOMMAND_BROWSER_BACKWARD` is emitted as `browser-backward`.
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
let win = new BrowserWindow()
|
||||
const win = new BrowserWindow()
|
||||
win.on('app-command', (e, cmd) => {
|
||||
// Navigate the window back when the user hits their mouse back button
|
||||
if (cmd === 'browser-backward' && win.webContents.canGoBack()) {
|
||||
@@ -685,7 +695,7 @@ Returns `BrowserWindow | null` - The window that owns the given `browserView`. I
|
||||
|
||||
* `id` Integer
|
||||
|
||||
Returns `BrowserWindow` - The window with the given `id`.
|
||||
Returns `BrowserWindow | null` - The window with the given `id`.
|
||||
|
||||
#### `BrowserWindow.addExtension(path)` _Deprecated_
|
||||
|
||||
@@ -765,7 +775,7 @@ To check if a DevTools extension is installed you can run the following:
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
|
||||
let installed = BrowserWindow.getDevToolsExtensions().hasOwnProperty('devtron')
|
||||
const installed = 'devtron' in BrowserWindow.getDevToolsExtensions()
|
||||
console.log(installed)
|
||||
```
|
||||
|
||||
@@ -782,7 +792,7 @@ Objects created with `new BrowserWindow` have the following properties:
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
// In this example `win` is our instance
|
||||
let win = new BrowserWindow({ width: 800, height: 600 })
|
||||
const win = new BrowserWindow({ width: 800, height: 600 })
|
||||
win.loadURL('https://github.com')
|
||||
```
|
||||
|
||||
@@ -1116,7 +1126,7 @@ Disable or enable the window.
|
||||
|
||||
#### `win.isEnabled()`
|
||||
|
||||
Returns Boolean - whether the window is enabled.
|
||||
Returns `Boolean` - whether the window is enabled.
|
||||
|
||||
#### `win.setSize(width, height[, animate])`
|
||||
|
||||
@@ -1307,9 +1317,9 @@ a HTML-rendered toolbar. For example:
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
let win = new BrowserWindow()
|
||||
const win = new BrowserWindow()
|
||||
|
||||
let toolbarRect = document.getElementById('toolbar').getBoundingClientRect()
|
||||
const toolbarRect = document.getElementById('toolbar').getBoundingClientRect()
|
||||
win.setSheetOffset(toolbarRect.height)
|
||||
```
|
||||
|
||||
@@ -1433,7 +1443,7 @@ Node's [`url.format`](https://nodejs.org/api/url.html#url_url_format_urlobject)
|
||||
method:
|
||||
|
||||
```javascript
|
||||
let url = require('url').format({
|
||||
const url = require('url').format({
|
||||
protocol: 'file',
|
||||
slashes: true,
|
||||
pathname: require('path').join(__dirname, 'index.html')
|
||||
|
||||
@@ -36,6 +36,10 @@ for integrated authentication. Without `*` prefix the URL has to match exactly.
|
||||
A comma-separated list of servers for which delegation of user credentials is required.
|
||||
Without `*` prefix the URL has to match exactly.
|
||||
|
||||
### --disable-ntlm-v2
|
||||
|
||||
Disables NTLM v2 for posix platforms, no effect elsewhere.
|
||||
|
||||
### --disable-http-cache
|
||||
|
||||
Disables the disk cache for HTTP requests.
|
||||
|
||||
@@ -83,4 +83,4 @@ Returns `Promise<Object>` - Resolves with an object containing the `value` and `
|
||||
Get the maximum usage across processes of trace buffer as a percentage of the
|
||||
full state.
|
||||
|
||||
[trace viewer]: https://github.com/catapult-project/catapult/blob/master/tracing
|
||||
[trace viewer]: https://chromium.googlesource.com/catapult/+/HEAD/tracing/README.md
|
||||
|
||||
@@ -58,9 +58,8 @@ The `crashReporter` module has the following methods:
|
||||
Default is `false`.
|
||||
* `rateLimit` Boolean (optional) _macOS_ _Windows_ - If true, limit the
|
||||
number of crashes uploaded to 1/hour. Default is `false`.
|
||||
* `compress` Boolean (optional) _macOS_ _Windows_ - If true, crash reports
|
||||
will be compressed and uploaded with `Content-Encoding: gzip`. Not all
|
||||
collection servers support compressed payloads. Default is `false`.
|
||||
* `compress` Boolean (optional) - If true, crash reports will be compressed
|
||||
and uploaded with `Content-Encoding: gzip`. Default is `false`.
|
||||
* `extra` Record<String, String> (optional) - Extra string key/value
|
||||
annotations that will be sent along with crash reports that are generated
|
||||
in the main process. Only string values are supported. Crashes generated in
|
||||
@@ -157,10 +156,16 @@ parameters in a renderer process will not result in those parameters being sent
|
||||
with crashes that occur in other renderer processes or in the main process.
|
||||
|
||||
**Note:** Parameters have limits on the length of the keys and values. Key
|
||||
names must be no longer than 39 bytes, and values must be no longer than 127
|
||||
names must be no longer than 39 bytes, and values must be no longer than 20320
|
||||
bytes. Keys with names longer than the maximum will be silently ignored. Key
|
||||
values longer than the maximum length will be truncated.
|
||||
|
||||
**Note:** On linux values that are longer than 127 bytes will be chunked into
|
||||
multiple keys, each 127 bytes in length. E.g. `addExtraParameter('foo', 'a'.repeat(130))`
|
||||
will result in two chunked keys `foo__1` and `foo__2`, the first will contain
|
||||
the first 127 bytes and the second will contain the remaining 3 bytes. On
|
||||
your crash reporting backend you should stitch together keys in this format.
|
||||
|
||||
### `crashReporter.removeExtraParameter(key)`
|
||||
|
||||
* `key` String - Parameter key, must be no longer than 39 bytes.
|
||||
|
||||
@@ -9,7 +9,7 @@ runtime that allows interacting with pages and instrumenting them.
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
let win = new BrowserWindow()
|
||||
const win = new BrowserWindow()
|
||||
|
||||
try {
|
||||
win.webContents.debugger.attach('1.1')
|
||||
@@ -52,6 +52,8 @@ Returns:
|
||||
* `method` String - Method name.
|
||||
* `params` any - Event parameters defined by the 'parameters'
|
||||
attribute in the remote debugging protocol.
|
||||
* `sessionId` String - Unique identifier of attached debugging session,
|
||||
will match the value sent from `debugger.sendCommand`.
|
||||
|
||||
Emitted whenever the debugging target issues an instrumentation event.
|
||||
|
||||
@@ -74,11 +76,16 @@ Returns `Boolean` - Whether a debugger is attached to the `webContents`.
|
||||
|
||||
Detaches the debugger from the `webContents`.
|
||||
|
||||
#### `debugger.sendCommand(method[, commandParams])`
|
||||
#### `debugger.sendCommand(method[, commandParams, sessionId])`
|
||||
|
||||
* `method` String - Method name, should be one of the methods defined by the
|
||||
[remote debugging protocol][rdp].
|
||||
* `commandParams` any (optional) - JSON object with request parameters.
|
||||
* `sessionId` String (optional) - send command to the target with associated
|
||||
debugging session id. The initial value can be obtained by sending
|
||||
[Target.attachToTarget][attachToTarget] message.
|
||||
|
||||
[attachToTarget]: https://chromedevtools.github.io/devtools-protocol/tot/Target/#method-attachToTarget
|
||||
|
||||
Returns `Promise<any>` - A promise that resolves with the response defined by
|
||||
the 'returns' attribute of the command description in the remote debugging protocol
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
> Access information about media sources that can be used to capture audio and
|
||||
> video from the desktop using the [`navigator.mediaDevices.getUserMedia`] API.
|
||||
|
||||
Process: [Renderer](../glossary.md#renderer-process)
|
||||
Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process)
|
||||
|
||||
The following example shows how to capture video from a desktop window whose
|
||||
title is `Electron`:
|
||||
@@ -72,6 +72,50 @@ const constraints = {
|
||||
}
|
||||
```
|
||||
|
||||
This example shows how to capture a video from a [WebContents](web-contents.md)
|
||||
|
||||
```javascript
|
||||
// In the renderer process.
|
||||
const { desktopCapturer, remote } = require('electron')
|
||||
|
||||
desktopCapturer.getMediaSourceIdForWebContents(remote.getCurrentWebContents().id).then(async mediaSourceId => {
|
||||
try {
|
||||
const stream = await navigator.mediaDevices.getUserMedia({
|
||||
audio: {
|
||||
mandatory: {
|
||||
chromeMediaSource: 'tab',
|
||||
chromeMediaSourceId: mediaSourceId
|
||||
}
|
||||
},
|
||||
video: {
|
||||
mandatory: {
|
||||
chromeMediaSource: 'tab',
|
||||
chromeMediaSourceId: mediaSourceId,
|
||||
minWidth: 1280,
|
||||
maxWidth: 1280,
|
||||
minHeight: 720,
|
||||
maxHeight: 720
|
||||
}
|
||||
}
|
||||
})
|
||||
handleStream(stream)
|
||||
} catch (e) {
|
||||
handleError(e)
|
||||
}
|
||||
})
|
||||
|
||||
function handleStream (stream) {
|
||||
const video = document.querySelector('video')
|
||||
video.srcObject = stream
|
||||
video.onloadedmetadata = (e) => video.play()
|
||||
}
|
||||
|
||||
function handleError (e) {
|
||||
console.log(e)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Methods
|
||||
|
||||
The `desktopCapturer` module has the following methods:
|
||||
@@ -94,6 +138,15 @@ Returns `Promise<DesktopCapturerSource[]>` - Resolves with an array of [`Desktop
|
||||
**Note** Capturing the screen contents requires user consent on macOS 10.15 Catalina or higher,
|
||||
which can detected by [`systemPreferences.getMediaAccessStatus`].
|
||||
|
||||
### `desktopCapturer.getMediaSourceIdForWebContents(webContentsId)`
|
||||
|
||||
* `webContentsId` number - Id of the WebContents to get stream of
|
||||
|
||||
Returns `Promise<string>` - Resolves with the identifier of a WebContents stream, this identifier can be
|
||||
used with [`navigator.mediaDevices.getUserMedia`].
|
||||
The identifier is **only valid for 10 seconds**.
|
||||
The identifier may be empty if not requested from a renderer process.
|
||||
|
||||
[`navigator.mediaDevices.getUserMedia`]: https://developer.mozilla.org/en/docs/Web/API/MediaDevices/getUserMedia
|
||||
[`systemPreferences.getMediaAccessStatus`]: system-preferences.md#systempreferencesgetmediaaccessstatusmediatype-macos
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ control the download item.
|
||||
```javascript
|
||||
// In the main process.
|
||||
const { BrowserWindow } = require('electron')
|
||||
let win = new BrowserWindow()
|
||||
const win = new BrowserWindow()
|
||||
win.webContents.session.on('will-download', (event, item, webContents) => {
|
||||
// Set the save path, making Electron not to prompt a save dialog.
|
||||
item.setSavePath('/tmp/save.pdf')
|
||||
|
||||
@@ -15,7 +15,7 @@ To create a frameless window, you need to set `frame` to `false` in
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
let win = new BrowserWindow({ width: 800, height: 600, frame: false })
|
||||
const win = new BrowserWindow({ width: 800, height: 600, frame: false })
|
||||
win.show()
|
||||
```
|
||||
|
||||
@@ -33,7 +33,7 @@ Results in a hidden title bar and a full size content window, yet the title bar
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
let win = new BrowserWindow({ titleBarStyle: 'hidden' })
|
||||
const win = new BrowserWindow({ titleBarStyle: 'hidden' })
|
||||
win.show()
|
||||
```
|
||||
|
||||
@@ -43,7 +43,7 @@ Results in a hidden title bar with an alternative look where the traffic light b
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
let win = new BrowserWindow({ titleBarStyle: 'hiddenInset' })
|
||||
const win = new BrowserWindow({ titleBarStyle: 'hiddenInset' })
|
||||
win.show()
|
||||
```
|
||||
|
||||
@@ -58,7 +58,7 @@ This option is only applicable for frameless windows.
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
let win = new BrowserWindow({ titleBarStyle: 'customButtonsOnHover', frame: false })
|
||||
const win = new BrowserWindow({ titleBarStyle: 'customButtonsOnHover', frame: false })
|
||||
win.show()
|
||||
```
|
||||
|
||||
@@ -69,7 +69,7 @@ window transparent:
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
let win = new BrowserWindow({ transparent: true, frame: false })
|
||||
const win = new BrowserWindow({ transparent: true, frame: false })
|
||||
win.show()
|
||||
```
|
||||
|
||||
@@ -100,7 +100,7 @@ API:
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
let win = new BrowserWindow()
|
||||
const win = new BrowserWindow()
|
||||
win.setIgnoreMouseEvents(true)
|
||||
```
|
||||
|
||||
@@ -112,8 +112,8 @@ optional parameter can be used to forward mouse move messages to the web page,
|
||||
allowing events such as `mouseleave` to be emitted:
|
||||
|
||||
```javascript
|
||||
let win = require('electron').remote.getCurrentWindow()
|
||||
let el = document.getElementById('clickThroughElement')
|
||||
const win = require('electron').remote.getCurrentWindow()
|
||||
const el = document.getElementById('clickThroughElement')
|
||||
el.addEventListener('mouseenter', () => {
|
||||
win.setIgnoreMouseEvents(true, { forward: true })
|
||||
})
|
||||
|
||||
@@ -148,4 +148,4 @@ found in the [`ipc-main-invoke-event`](structures/ipc-main-invoke-event.md)
|
||||
structure docs.
|
||||
|
||||
[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter
|
||||
[web-contents-send]: web-contents.md#contentssendchannel-arg1-arg2-
|
||||
[web-contents-send]: web-contents.md#contentssendchannel-args
|
||||
|
||||
@@ -12,7 +12,7 @@ See [`Menu`](menu.md) for examples.
|
||||
* `click` Function (optional) - Will be called with
|
||||
`click(menuItem, browserWindow, event)` when the menu item is clicked.
|
||||
* `menuItem` MenuItem
|
||||
* `browserWindow` [BrowserWindow](browser-window.md)
|
||||
* `browserWindow` [BrowserWindow](browser-window.md) | undefined - This will not be defined if no window is open.
|
||||
* `event` [KeyboardEvent](structures/keyboard-event.md)
|
||||
* `role` String (optional) - Can be `undo`, `redo`, `cut`, `copy`, `paste`, `pasteAndMatchStyle`, `delete`, `selectAll`, `reload`, `forceReload`, `toggleDevTools`, `resetZoom`, `zoomIn`, `zoomOut`, `togglefullscreen`, `window`, `minimize`, `close`, `help`, `about`, `services`, `hide`, `hideOthers`, `unhide`, `quit`, `startSpeaking`, `stopSpeaking`, `zoom`, `front`, `appMenu`, `fileMenu`, `editMenu`, `viewMenu`, `recentDocuments`, `toggleTabBar`, `selectNextTab`, `selectPreviousTab`, `mergeAllWindows`, `clearRecentDocuments`, `moveTabToNewWindow` or `windowMenu` - Define the action of the menu item, when specified the
|
||||
`click` property will be ignored. See [roles](#roles).
|
||||
@@ -69,6 +69,7 @@ a `type`.
|
||||
The `role` property can have following values:
|
||||
|
||||
* `undo`
|
||||
* `about` - Trigger a native about panel (custom message box on Window, which does not provide its own).
|
||||
* `redo`
|
||||
* `cut`
|
||||
* `copy`
|
||||
@@ -94,7 +95,6 @@ The `role` property can have following values:
|
||||
The following additional roles are available on _macOS_:
|
||||
|
||||
* `appMenu` - Whole default "App" menu (About, Services, etc.)
|
||||
* `about` - Map to the `orderFrontStandardAboutPanel` action.
|
||||
* `hide` - Map to the `hide` action.
|
||||
* `hideOthers` - Map to the `hideOtherApplications` action.
|
||||
* `unhide` - Map to the `unhideAllApplications` action.
|
||||
|
||||
@@ -96,7 +96,7 @@ Appends the `menuItem` to the menu.
|
||||
|
||||
* `id` String
|
||||
|
||||
Returns `MenuItem` the item with the specified `id`
|
||||
Returns `MenuItem | null` the item with the specified `id`
|
||||
|
||||
#### `menu.insert(pos, menuItem)`
|
||||
|
||||
@@ -195,8 +195,8 @@ const template = [
|
||||
{
|
||||
label: 'Speech',
|
||||
submenu: [
|
||||
{ role: 'startspeaking' },
|
||||
{ role: 'stopspeaking' }
|
||||
{ role: 'startSpeaking' },
|
||||
{ role: 'stopSpeaking' }
|
||||
]
|
||||
}
|
||||
] : [
|
||||
@@ -211,12 +211,12 @@ const template = [
|
||||
label: 'View',
|
||||
submenu: [
|
||||
{ role: 'reload' },
|
||||
{ role: 'forcereload' },
|
||||
{ role: 'toggledevtools' },
|
||||
{ role: 'forceReload' },
|
||||
{ role: 'toggleDevTools' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'resetzoom' },
|
||||
{ role: 'zoomin' },
|
||||
{ role: 'zoomout' },
|
||||
{ role: 'resetZoom' },
|
||||
{ role: 'zoomIn' },
|
||||
{ role: 'zoomOut' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'togglefullscreen' }
|
||||
]
|
||||
|
||||
@@ -266,9 +266,13 @@ image instead of a copy, so you _must_ ensure that the associated
|
||||
|
||||
Returns `Boolean` - Whether the image is empty.
|
||||
|
||||
#### `image.getSize()`
|
||||
#### `image.getSize([scaleFactor])`
|
||||
|
||||
Returns [`Size`](structures/size.md)
|
||||
* `scaleFactor` Double (optional) - Defaults to 1.0.
|
||||
|
||||
Returns [`Size`](structures/size.md).
|
||||
|
||||
If `scaleFactor` is passed, this will return the size corresponding to the image representation most closely matching the passed value.
|
||||
|
||||
#### `image.setTemplateImage(option)`
|
||||
|
||||
@@ -303,10 +307,18 @@ Returns `NativeImage` - The resized image.
|
||||
If only the `height` or the `width` are specified then the current aspect ratio
|
||||
will be preserved in the resized image.
|
||||
|
||||
#### `image.getAspectRatio()`
|
||||
#### `image.getAspectRatio([scaleFactor])`
|
||||
|
||||
* `scaleFactor` Double (optional) - Defaults to 1.0.
|
||||
|
||||
Returns `Float` - The image's aspect ratio.
|
||||
|
||||
If `scaleFactor` is passed, this will return the aspect ratio corresponding to the image representation most closely matching the passed value.
|
||||
|
||||
#### `image.getScaleFactors()`
|
||||
|
||||
Returns `Float[]` - An array of all scale factors corresponding to representations for a given nativeImage.
|
||||
|
||||
#### `image.addRepresentation(options)`
|
||||
|
||||
* `options` Object
|
||||
|
||||
@@ -1,309 +0,0 @@
|
||||
# protocol (NetworkService) (Draft)
|
||||
|
||||
This document describes the new protocol APIs based on the [NetworkService](https://www.chromium.org/servicification).
|
||||
|
||||
We don't currently have an estimate of when we will enable the `NetworkService` by
|
||||
default in Electron, but as Chromium is already removing non-`NetworkService`
|
||||
code, we will probably switch before Electron 10.
|
||||
|
||||
The content of this document should be moved to `protocol.md` after we have
|
||||
enabled the `NetworkService` by default in Electron.
|
||||
|
||||
> Register a custom protocol and intercept existing protocol requests.
|
||||
|
||||
Process: [Main](../glossary.md#main-process)
|
||||
|
||||
An example of implementing a protocol that has the same effect as the
|
||||
`file://` protocol:
|
||||
|
||||
```javascript
|
||||
const { app, protocol } = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
app.whenReady().then(() => {
|
||||
protocol.registerFileProtocol('atom', (request, callback) => {
|
||||
const url = request.url.substr(7)
|
||||
callback({ path: path.normalize(`${__dirname}/${url}`) })
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
**Note:** All methods unless specified can only be used after the `ready` event
|
||||
of the `app` module gets emitted.
|
||||
|
||||
## Using `protocol` with a custom `partition` or `session`
|
||||
|
||||
A protocol is registered to a specific Electron [`session`](./session.md)
|
||||
object. If you don't specify a session, then your `protocol` will be applied to
|
||||
the default session that Electron uses. However, if you define a `partition` or
|
||||
`session` on your `browserWindow`'s `webPreferences`, then that window will use
|
||||
a different session and your custom protocol will not work if you just use
|
||||
`electron.protocol.XXX`.
|
||||
|
||||
To have your custom protocol work in combination with a custom session, you need
|
||||
to register it to that session explicitly.
|
||||
|
||||
```javascript
|
||||
const { session, app, protocol } = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
app.whenReady().then(() => {
|
||||
const partition = 'persist:example'
|
||||
const ses = session.fromPartition(partition)
|
||||
|
||||
ses.protocol.registerFileProtocol('atom', (request, callback) => {
|
||||
const url = request.url.substr(7)
|
||||
callback({ path: path.normalize(`${__dirname}/${url}`) })
|
||||
})
|
||||
|
||||
mainWindow = new BrowserWindow({ webPreferences: { partition } })
|
||||
})
|
||||
```
|
||||
|
||||
## Methods
|
||||
|
||||
The `protocol` module has the following methods:
|
||||
|
||||
### `protocol.registerSchemesAsPrivileged(customSchemes)`
|
||||
|
||||
* `customSchemes` [CustomScheme[]](structures/custom-scheme.md)
|
||||
|
||||
**Note:** This method can only be used before the `ready` event of the `app`
|
||||
module gets emitted and can be called only once.
|
||||
|
||||
Registers the `scheme` as standard, secure, bypasses content security policy for
|
||||
resources, allows registering ServiceWorker and supports fetch API. Specify a
|
||||
privilege with the value of `true` to enable the capability.
|
||||
|
||||
An example of registering a privileged scheme, that bypasses Content Security
|
||||
Policy:
|
||||
|
||||
```javascript
|
||||
const { protocol } = require('electron')
|
||||
protocol.registerSchemesAsPrivileged([
|
||||
{ scheme: 'foo', privileges: { bypassCSP: true } }
|
||||
])
|
||||
```
|
||||
|
||||
A standard scheme adheres to what RFC 3986 calls [generic URI
|
||||
syntax](https://tools.ietf.org/html/rfc3986#section-3). For example `http` and
|
||||
`https` are standard schemes, while `file` is not.
|
||||
|
||||
Registering a scheme as standard allows relative and absolute resources to
|
||||
be resolved correctly when served. Otherwise the scheme will behave like the
|
||||
`file` protocol, but without the ability to resolve relative URLs.
|
||||
|
||||
For example when you load following page with custom protocol without
|
||||
registering it as standard scheme, the image will not be loaded because
|
||||
non-standard schemes can not recognize relative URLs:
|
||||
|
||||
```html
|
||||
<body>
|
||||
<img src='test.png'>
|
||||
</body>
|
||||
```
|
||||
|
||||
Registering a scheme as standard will allow access to files through the
|
||||
[FileSystem API][file-system-api]. Otherwise the renderer will throw a security
|
||||
error for the scheme.
|
||||
|
||||
By default web storage apis (localStorage, sessionStorage, webSQL, indexedDB,
|
||||
cookies) are disabled for non standard schemes. So in general if you want to
|
||||
register a custom protocol to replace the `http` protocol, you have to register
|
||||
it as a standard scheme.
|
||||
|
||||
### `protocol.registerFileProtocol(scheme, handler)`
|
||||
|
||||
* `scheme` String
|
||||
* `handler` Function
|
||||
* `request` ProtocolRequest
|
||||
* `callback` Function
|
||||
* `response` (String | [ProtocolResponse](structures/protocol-response.md))
|
||||
|
||||
Registers a protocol of `scheme` that will send a file as the response. The
|
||||
`handler` will be called with `request` and `callback` where `request` is
|
||||
an incoming request for the `scheme`.
|
||||
|
||||
To handle the `request`, the `callback` should be called with either the file's
|
||||
path or an object that has a `path` property, e.g. `callback(filePath)` or
|
||||
`callback({ path: filePath })`. The `filePath` must be an absolute path.
|
||||
|
||||
By default the `scheme` is treated like `http:`, which is parsed differently
|
||||
from protocols that follow the "generic URI syntax" like `file:`.
|
||||
|
||||
### `protocol.registerBufferProtocol(scheme, handler)`
|
||||
|
||||
* `scheme` String
|
||||
* `handler` Function
|
||||
* `request` ProtocolRequest
|
||||
* `callback` Function
|
||||
* `response` (Buffer | [ProtocolResponse](structures/protocol-response.md))
|
||||
|
||||
Registers a protocol of `scheme` that will send a `Buffer` as a response.
|
||||
|
||||
The usage is the same with `registerFileProtocol`, except that the `callback`
|
||||
should be called with either a `Buffer` object or an object that has the `data`
|
||||
property.
|
||||
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
protocol.registerBufferProtocol('atom', (request, callback) => {
|
||||
callback({ mimeType: 'text/html', data: Buffer.from('<h5>Response</h5>') })
|
||||
})
|
||||
```
|
||||
|
||||
### `protocol.registerStringProtocol(scheme, handler)`
|
||||
|
||||
* `scheme` String
|
||||
* `handler` Function
|
||||
* `request` ProtocolRequest
|
||||
* `callback` Function
|
||||
* `response` (String | [ProtocolResponse](structures/protocol-response.md))
|
||||
|
||||
Registers a protocol of `scheme` that will send a `String` as a response.
|
||||
|
||||
The usage is the same with `registerFileProtocol`, except that the `callback`
|
||||
should be called with either a `String` or an object that has the `data`
|
||||
property.
|
||||
|
||||
### `protocol.registerHttpProtocol(scheme, handler)`
|
||||
|
||||
* `scheme` String
|
||||
* `handler` Function
|
||||
* `request` ProtocolRequest
|
||||
* `callback` Function
|
||||
* `response` ProtocolResponse
|
||||
|
||||
Registers a protocol of `scheme` that will send an HTTP request as a response.
|
||||
|
||||
The usage is the same with `registerFileProtocol`, except that the `callback`
|
||||
should be called with an object that has the `url` property.
|
||||
|
||||
### `protocol.registerStreamProtocol(scheme, handler)`
|
||||
|
||||
* `scheme` String
|
||||
* `handler` Function
|
||||
* `request` ProtocolRequest
|
||||
* `callback` Function
|
||||
* `response` (ReadableStream | [ProtocolResponse](structures/protocol-response.md))
|
||||
|
||||
Registers a protocol of `scheme` that will send a stream as a response.
|
||||
|
||||
The usage is the same with `registerFileProtocol`, except that the
|
||||
`callback` should be called with either a [`ReadableStream`](https://nodejs.org/api/stream.html#stream_class_stream_readable) object or an object that
|
||||
has the `data` property.
|
||||
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
const { protocol } = require('electron')
|
||||
const { PassThrough } = require('stream')
|
||||
|
||||
function createStream (text) {
|
||||
const rv = new PassThrough() // PassThrough is also a Readable stream
|
||||
rv.push(text)
|
||||
rv.push(null)
|
||||
return rv
|
||||
}
|
||||
|
||||
protocol.registerStreamProtocol('atom', (request, callback) => {
|
||||
callback({
|
||||
statusCode: 200,
|
||||
headers: {
|
||||
'content-type': 'text/html'
|
||||
},
|
||||
data: createStream('<h5>Response</h5>')
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
It is possible to pass any object that implements the readable stream API (emits
|
||||
`data`/`end`/`error` events). For example, here's how a file could be returned:
|
||||
|
||||
```javascript
|
||||
protocol.registerStreamProtocol('atom', (request, callback) => {
|
||||
callback(fs.createReadStream('index.html'))
|
||||
})
|
||||
```
|
||||
|
||||
### `protocol.unregisterProtocol(scheme)`
|
||||
|
||||
* `scheme` String
|
||||
|
||||
Unregisters the custom protocol of `scheme`.
|
||||
|
||||
### `protocol.isProtocolRegistered(scheme)`
|
||||
|
||||
* `scheme` String
|
||||
|
||||
Returns `Boolean` - Whether `scheme` is already registered.
|
||||
|
||||
### `protocol.interceptFileProtocol(scheme, handler)`
|
||||
|
||||
* `scheme` String
|
||||
* `handler` Function
|
||||
* `request` ProtocolRequest
|
||||
* `callback` Function
|
||||
* `response` (String | [ProtocolResponse](structures/protocol-response.md))
|
||||
|
||||
Intercepts `scheme` protocol and uses `handler` as the protocol's new handler
|
||||
which sends a file as a response.
|
||||
|
||||
### `protocol.interceptStringProtocol(scheme, handler)`
|
||||
|
||||
* `scheme` String
|
||||
* `handler` Function
|
||||
* `request` ProtocolRequest
|
||||
* `callback` Function
|
||||
* `response` (String | [ProtocolResponse](structures/protocol-response.md))
|
||||
|
||||
Intercepts `scheme` protocol and uses `handler` as the protocol's new handler
|
||||
which sends a `String` as a response.
|
||||
|
||||
### `protocol.interceptBufferProtocol(scheme, handler)`
|
||||
|
||||
* `scheme` String
|
||||
* `handler` Function
|
||||
* `request` ProtocolRequest
|
||||
* `callback` Function
|
||||
* `response` (Buffer | [ProtocolResponse](structures/protocol-response.md))
|
||||
|
||||
Intercepts `scheme` protocol and uses `handler` as the protocol's new handler
|
||||
which sends a `Buffer` as a response.
|
||||
|
||||
### `protocol.interceptHttpProtocol(scheme, handler)`
|
||||
|
||||
* `scheme` String
|
||||
* `handler` Function
|
||||
* `request` ProtocolRequest
|
||||
* `callback` Function
|
||||
* `response` ProtocolResponse
|
||||
|
||||
Intercepts `scheme` protocol and uses `handler` as the protocol's new handler
|
||||
which sends a new HTTP request as a response.
|
||||
|
||||
### `protocol.interceptStreamProtocol(scheme, handler)`
|
||||
|
||||
* `scheme` String
|
||||
* `handler` Function
|
||||
* `request` ProtocolRequest
|
||||
* `callback` Function
|
||||
* `response` (ReadableStream | [ProtocolResponse](structures/protocol-response.md))
|
||||
|
||||
Same as `protocol.registerStreamProtocol`, except that it replaces an existing
|
||||
protocol handler.
|
||||
|
||||
### `protocol.uninterceptProtocol(scheme)`
|
||||
|
||||
* `scheme` String
|
||||
|
||||
Remove the interceptor installed for `scheme` and restore its original handler.
|
||||
|
||||
### `protocol.isProtocolIntercepted(scheme)`
|
||||
|
||||
* `scheme` String
|
||||
|
||||
Returns `Boolean` - Whether `scheme` is already intercepted.
|
||||
|
||||
[file-system-api]: https://developer.mozilla.org/en-US/docs/Web/API/LocalFileSystem
|
||||
@@ -15,8 +15,6 @@ app.whenReady().then(() => {
|
||||
protocol.registerFileProtocol('atom', (request, callback) => {
|
||||
const url = request.url.substr(7)
|
||||
callback({ path: path.normalize(`${__dirname}/${url}`) })
|
||||
}, (error) => {
|
||||
if (error) console.error('Failed to register protocol')
|
||||
})
|
||||
})
|
||||
```
|
||||
@@ -26,9 +24,15 @@ of the `app` module gets emitted.
|
||||
|
||||
## Using `protocol` with a custom `partition` or `session`
|
||||
|
||||
A protocol is registered to a specific Electron [`session`](./session.md) object. If you don't specify a session, then your `protocol` will be applied to the default session that Electron uses. However, if you define a `partition` or `session` on your `browserWindow`'s `webPreferences`, then that window will use a different session and your custom protocol will not work if you just use `electron.protocol.XXX`.
|
||||
A protocol is registered to a specific Electron [`session`](./session.md)
|
||||
object. If you don't specify a session, then your `protocol` will be applied to
|
||||
the default session that Electron uses. However, if you define a `partition` or
|
||||
`session` on your `browserWindow`'s `webPreferences`, then that window will use
|
||||
a different session and your custom protocol will not work if you just use
|
||||
`electron.protocol.XXX`.
|
||||
|
||||
To have your custom protocol work in combination with a custom session, you need to register it to that session explicitly.
|
||||
To have your custom protocol work in combination with a custom session, you need
|
||||
to register it to that session explicitly.
|
||||
|
||||
```javascript
|
||||
const { session, app, protocol } = require('electron')
|
||||
@@ -41,17 +45,9 @@ app.whenReady().then(() => {
|
||||
ses.protocol.registerFileProtocol('atom', (request, callback) => {
|
||||
const url = request.url.substr(7)
|
||||
callback({ path: path.normalize(`${__dirname}/${url}`) })
|
||||
}, (error) => {
|
||||
if (error) console.error('Failed to register protocol')
|
||||
})
|
||||
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
partition: partition
|
||||
}
|
||||
})
|
||||
mainWindow = new BrowserWindow({ webPreferences: { partition } })
|
||||
})
|
||||
```
|
||||
|
||||
@@ -63,15 +59,15 @@ The `protocol` module has the following methods:
|
||||
|
||||
* `customSchemes` [CustomScheme[]](structures/custom-scheme.md)
|
||||
|
||||
|
||||
**Note:** This method can only be used before the `ready` event of the `app`
|
||||
module gets emitted and can be called only once.
|
||||
|
||||
Registers the `scheme` as standard, secure, bypasses content security policy for resources,
|
||||
allows registering ServiceWorker and supports fetch API.
|
||||
Registers the `scheme` as standard, secure, bypasses content security policy for
|
||||
resources, allows registering ServiceWorker, supports fetch API, and streaming
|
||||
video/audio. Specify a privilege with the value of `true` to enable the capability.
|
||||
|
||||
Specify a privilege with the value of `true` to enable the capability.
|
||||
An example of registering a privileged scheme, with bypassing Content Security Policy:
|
||||
An example of registering a privileged scheme, that bypasses Content Security
|
||||
Policy:
|
||||
|
||||
```javascript
|
||||
const { protocol } = require('electron')
|
||||
@@ -84,7 +80,7 @@ A standard scheme adheres to what RFC 3986 calls [generic URI
|
||||
syntax](https://tools.ietf.org/html/rfc3986#section-3). For example `http` and
|
||||
`https` are standard schemes, while `file` is not.
|
||||
|
||||
Registering a scheme as standard, will allow relative and absolute resources to
|
||||
Registering a scheme as standard allows relative and absolute resources to
|
||||
be resolved correctly when served. Otherwise the scheme will behave like the
|
||||
`file` protocol, but without the ability to resolve relative URLs.
|
||||
|
||||
@@ -102,168 +98,107 @@ Registering a scheme as standard will allow access to files through the
|
||||
[FileSystem API][file-system-api]. Otherwise the renderer will throw a security
|
||||
error for the scheme.
|
||||
|
||||
By default web storage apis (localStorage, sessionStorage, webSQL, indexedDB, cookies)
|
||||
are disabled for non standard schemes. So in general if you want to register a
|
||||
custom protocol to replace the `http` protocol, you have to register it as a standard scheme.
|
||||
By default web storage apis (localStorage, sessionStorage, webSQL, indexedDB,
|
||||
cookies) are disabled for non standard schemes. So in general if you want to
|
||||
register a custom protocol to replace the `http` protocol, you have to register
|
||||
it as a standard scheme.
|
||||
|
||||
`protocol.registerSchemesAsPrivileged` can be used to replicate the functionality of the previous `protocol.registerStandardSchemes`, `webFrame.registerURLSchemeAs*` and `protocol.registerServiceWorkerSchemes` functions that existed prior to Electron 5.0.0, for example:
|
||||
Protocols that use streams (http and stream protocols) should set `stream: true`.
|
||||
The `<video>` and `<audio>` HTML elements expect protocols to buffer their
|
||||
responses by default. The `stream` flag configures those elements to correctly
|
||||
expect streaming responses.
|
||||
|
||||
**before (<= v4.x)**
|
||||
```javascript
|
||||
// Main
|
||||
protocol.registerStandardSchemes(['scheme1', 'scheme2'], { secure: true })
|
||||
// Renderer
|
||||
webFrame.registerURLSchemeAsPrivileged('scheme1', { secure: true })
|
||||
webFrame.registerURLSchemeAsPrivileged('scheme2', { secure: true })
|
||||
```
|
||||
|
||||
**after (>= v5.x)**
|
||||
```javascript
|
||||
protocol.registerSchemesAsPrivileged([
|
||||
{ scheme: 'scheme1', privileges: { standard: true, secure: true } },
|
||||
{ scheme: 'scheme2', privileges: { standard: true, secure: true } }
|
||||
])
|
||||
```
|
||||
|
||||
### `protocol.registerFileProtocol(scheme, handler[, completion])`
|
||||
### `protocol.registerFileProtocol(scheme, handler)`
|
||||
|
||||
* `scheme` String
|
||||
* `handler` Function
|
||||
* `request` Object
|
||||
* `url` String
|
||||
* `headers` Record<String, String>
|
||||
* `referrer` String
|
||||
* `method` String
|
||||
* `uploadData` [UploadData[]](structures/upload-data.md)
|
||||
* `request` ProtocolRequest
|
||||
* `callback` Function
|
||||
* `filePath` String | [FilePathWithHeaders](structures/file-path-with-headers.md) (optional)
|
||||
* `completion` Function (optional)
|
||||
* `error` Error
|
||||
* `response` (String | [ProtocolResponse](structures/protocol-response.md))
|
||||
|
||||
Registers a protocol of `scheme` that will send the file as a response. The
|
||||
`handler` will be called with `handler(request, callback)` when a `request` is
|
||||
going to be created with `scheme`. `completion` will be called with
|
||||
`completion(null)` when `scheme` is successfully registered or
|
||||
`completion(error)` when failed.
|
||||
Returns `Boolean` - Whether the protocol was successfully registered
|
||||
|
||||
Registers a protocol of `scheme` that will send a file as the response. The
|
||||
`handler` will be called with `request` and `callback` where `request` is
|
||||
an incoming request for the `scheme`.
|
||||
|
||||
To handle the `request`, the `callback` should be called with either the file's
|
||||
path or an object that has a `path` property, e.g. `callback(filePath)` or
|
||||
`callback({ path: filePath })`. The object may also have a `headers` property
|
||||
which gives a map of headers to values for the response headers, e.g.
|
||||
`callback({ path: filePath, headers: {"Content-Security-Policy": "default-src 'none'"]})`.
|
||||
|
||||
When `callback` is called with nothing, a number, or an object that has an
|
||||
`error` property, the `request` will fail with the `error` number you
|
||||
specified. For the available error numbers you can use, please see the
|
||||
[net error list][net-error].
|
||||
`callback({ path: filePath })`. The `filePath` must be an absolute path.
|
||||
|
||||
By default the `scheme` is treated like `http:`, which is parsed differently
|
||||
than protocols that follow the "generic URI syntax" like `file:`.
|
||||
from protocols that follow the "generic URI syntax" like `file:`.
|
||||
|
||||
### `protocol.registerBufferProtocol(scheme, handler[, completion])`
|
||||
### `protocol.registerBufferProtocol(scheme, handler)`
|
||||
|
||||
* `scheme` String
|
||||
* `handler` Function
|
||||
* `request` Object
|
||||
* `url` String
|
||||
* `headers` Record<String, String>
|
||||
* `referrer` String
|
||||
* `method` String
|
||||
* `uploadData` [UploadData[]](structures/upload-data.md)
|
||||
* `request` ProtocolRequest
|
||||
* `callback` Function
|
||||
* `buffer` (Buffer | [MimeTypedBuffer](structures/mime-typed-buffer.md)) (optional)
|
||||
* `completion` Function (optional)
|
||||
* `error` Error
|
||||
* `response` (Buffer | [ProtocolResponse](structures/protocol-response.md))
|
||||
|
||||
Returns `Boolean` - Whether the protocol was successfully registered
|
||||
|
||||
Registers a protocol of `scheme` that will send a `Buffer` as a response.
|
||||
|
||||
The usage is the same with `registerFileProtocol`, except that the `callback`
|
||||
should be called with either a `Buffer` object or an object that has the `data`,
|
||||
`mimeType`, and `charset` properties.
|
||||
should be called with either a `Buffer` object or an object that has the `data`
|
||||
property.
|
||||
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
const { protocol } = require('electron')
|
||||
|
||||
protocol.registerBufferProtocol('atom', (request, callback) => {
|
||||
callback({ mimeType: 'text/html', data: Buffer.from('<h5>Response</h5>') })
|
||||
}, (error) => {
|
||||
if (error) console.error('Failed to register protocol')
|
||||
})
|
||||
```
|
||||
|
||||
### `protocol.registerStringProtocol(scheme, handler[, completion])`
|
||||
### `protocol.registerStringProtocol(scheme, handler)`
|
||||
|
||||
* `scheme` String
|
||||
* `handler` Function
|
||||
* `request` Object
|
||||
* `url` String
|
||||
* `headers` Record<String, String>
|
||||
* `referrer` String
|
||||
* `method` String
|
||||
* `uploadData` [UploadData[]](structures/upload-data.md)
|
||||
* `request` ProtocolRequest
|
||||
* `callback` Function
|
||||
* `data` (String | [StringProtocolResponse](structures/string-protocol-response.md)) (optional)
|
||||
* `completion` Function (optional)
|
||||
* `error` Error
|
||||
* `response` (String | [ProtocolResponse](structures/protocol-response.md))
|
||||
|
||||
Returns `Boolean` - Whether the protocol was successfully registered
|
||||
|
||||
Registers a protocol of `scheme` that will send a `String` as a response.
|
||||
|
||||
The usage is the same with `registerFileProtocol`, except that the `callback`
|
||||
should be called with either a `String` or an object that has the `data`,
|
||||
`mimeType`, and `charset` properties.
|
||||
should be called with either a `String` or an object that has the `data`
|
||||
property.
|
||||
|
||||
### `protocol.registerHttpProtocol(scheme, handler[, completion])`
|
||||
### `protocol.registerHttpProtocol(scheme, handler)`
|
||||
|
||||
* `scheme` String
|
||||
* `handler` Function
|
||||
* `request` Object
|
||||
* `url` String
|
||||
* `headers` Record<String, String>
|
||||
* `referrer` String
|
||||
* `method` String
|
||||
* `uploadData` [UploadData[]](structures/upload-data.md)
|
||||
* `request` ProtocolRequest
|
||||
* `callback` Function
|
||||
* `redirectRequest` Object
|
||||
* `url` String
|
||||
* `method` String (optional)
|
||||
* `session` Session | null (optional)
|
||||
* `uploadData` [ProtocolResponseUploadData](structures/protocol-response-upload-data.md) (optional)
|
||||
* `completion` Function (optional)
|
||||
* `error` Error
|
||||
* `response` ProtocolResponse
|
||||
|
||||
Returns `Boolean` - Whether the protocol was successfully registered
|
||||
|
||||
Registers a protocol of `scheme` that will send an HTTP request as a response.
|
||||
|
||||
The usage is the same with `registerFileProtocol`, except that the `callback`
|
||||
should be called with a `redirectRequest` object that has the `url`, `method`,
|
||||
`referrer`, `uploadData` and `session` properties.
|
||||
should be called with an object that has the `url` property.
|
||||
|
||||
By default the HTTP request will reuse the current session. If you want the
|
||||
request to have a different session you should set `session` to `null`.
|
||||
|
||||
For POST requests the `uploadData` object must be provided.
|
||||
|
||||
### `protocol.registerStreamProtocol(scheme, handler[, completion])`
|
||||
### `protocol.registerStreamProtocol(scheme, handler)`
|
||||
|
||||
* `scheme` String
|
||||
* `handler` Function
|
||||
* `request` Object
|
||||
* `url` String
|
||||
* `headers` Record<String, String>
|
||||
* `referrer` String
|
||||
* `method` String
|
||||
* `uploadData` [UploadData[]](structures/upload-data.md)
|
||||
* `request` ProtocolRequest
|
||||
* `callback` Function
|
||||
* `stream` (ReadableStream | [StreamProtocolResponse](structures/stream-protocol-response.md)) (optional)
|
||||
* `completion` Function (optional)
|
||||
* `error` Error
|
||||
* `response` (ReadableStream | [ProtocolResponse](structures/protocol-response.md))
|
||||
|
||||
Registers a protocol of `scheme` that will send a `Readable` as a response.
|
||||
Returns `Boolean` - Whether the protocol was successfully registered
|
||||
|
||||
The usage is similar to the other `register{Any}Protocol`, except that the
|
||||
`callback` should be called with either a `Readable` object or an object that
|
||||
has the `data`, `statusCode`, and `headers` properties.
|
||||
Registers a protocol of `scheme` that will send a stream as a response.
|
||||
|
||||
The usage is the same with `registerFileProtocol`, except that the
|
||||
`callback` should be called with either a [`ReadableStream`](https://nodejs.org/api/stream.html#stream_class_stream_readable) object or an object that
|
||||
has the `data` property.
|
||||
|
||||
Example:
|
||||
|
||||
@@ -286,8 +221,6 @@ protocol.registerStreamProtocol('atom', (request, callback) => {
|
||||
},
|
||||
data: createStream('<h5>Response</h5>')
|
||||
})
|
||||
}, (error) => {
|
||||
if (error) console.error('Failed to register protocol')
|
||||
})
|
||||
```
|
||||
|
||||
@@ -295,132 +228,102 @@ It is possible to pass any object that implements the readable stream API (emits
|
||||
`data`/`end`/`error` events). For example, here's how a file could be returned:
|
||||
|
||||
```javascript
|
||||
const { protocol } = require('electron')
|
||||
const fs = require('fs')
|
||||
|
||||
protocol.registerStreamProtocol('atom', (request, callback) => {
|
||||
callback(fs.createReadStream('index.html'))
|
||||
}, (error) => {
|
||||
if (error) console.error('Failed to register protocol')
|
||||
})
|
||||
```
|
||||
|
||||
### `protocol.unregisterProtocol(scheme[, completion])`
|
||||
### `protocol.unregisterProtocol(scheme)`
|
||||
|
||||
* `scheme` String
|
||||
* `completion` Function (optional)
|
||||
* `error` Error
|
||||
|
||||
Returns `Boolean` - Whether the protocol was successfully unregistered
|
||||
|
||||
Unregisters the custom protocol of `scheme`.
|
||||
|
||||
### `protocol.isProtocolHandled(scheme)`
|
||||
### `protocol.isProtocolRegistered(scheme)`
|
||||
|
||||
* `scheme` String
|
||||
|
||||
Returns `Promise<Boolean>` - fulfilled with a boolean that indicates whether there is
|
||||
already a handler for `scheme`.
|
||||
Returns `Boolean` - Whether `scheme` is already registered.
|
||||
|
||||
### `protocol.interceptFileProtocol(scheme, handler[, completion])`
|
||||
### `protocol.interceptFileProtocol(scheme, handler)`
|
||||
|
||||
* `scheme` String
|
||||
* `handler` Function
|
||||
* `request` Object
|
||||
* `url` String
|
||||
* `headers` Record<String, String>
|
||||
* `referrer` String
|
||||
* `method` String
|
||||
* `uploadData` [UploadData[]](structures/upload-data.md)
|
||||
* `request` ProtocolRequest
|
||||
* `callback` Function
|
||||
* `filePath` String
|
||||
* `completion` Function (optional)
|
||||
* `error` Error
|
||||
* `response` (String | [ProtocolResponse](structures/protocol-response.md))
|
||||
|
||||
Returns `Boolean` - Whether the protocol was successfully intercepted
|
||||
|
||||
Intercepts `scheme` protocol and uses `handler` as the protocol's new handler
|
||||
which sends a file as a response.
|
||||
|
||||
### `protocol.interceptStringProtocol(scheme, handler[, completion])`
|
||||
### `protocol.interceptStringProtocol(scheme, handler)`
|
||||
|
||||
* `scheme` String
|
||||
* `handler` Function
|
||||
* `request` Object
|
||||
* `url` String
|
||||
* `headers` Record<String, String>
|
||||
* `referrer` String
|
||||
* `method` String
|
||||
* `uploadData` [UploadData[]](structures/upload-data.md)
|
||||
* `request` ProtocolRequest
|
||||
* `callback` Function
|
||||
* `data` (String | [StringProtocolResponse](structures/string-protocol-response.md)) (optional)
|
||||
* `completion` Function (optional)
|
||||
* `error` Error
|
||||
* `response` (String | [ProtocolResponse](structures/protocol-response.md))
|
||||
|
||||
Returns `Boolean` - Whether the protocol was successfully intercepted
|
||||
|
||||
Intercepts `scheme` protocol and uses `handler` as the protocol's new handler
|
||||
which sends a `String` as a response.
|
||||
|
||||
### `protocol.interceptBufferProtocol(scheme, handler[, completion])`
|
||||
### `protocol.interceptBufferProtocol(scheme, handler)`
|
||||
|
||||
* `scheme` String
|
||||
* `handler` Function
|
||||
* `request` Object
|
||||
* `url` String
|
||||
* `headers` Record<String, String>
|
||||
* `referrer` String
|
||||
* `method` String
|
||||
* `uploadData` [UploadData[]](structures/upload-data.md)
|
||||
* `request` ProtocolRequest
|
||||
* `callback` Function
|
||||
* `buffer` Buffer (optional)
|
||||
* `completion` Function (optional)
|
||||
* `error` Error
|
||||
* `response` (Buffer | [ProtocolResponse](structures/protocol-response.md))
|
||||
|
||||
Returns `Boolean` - Whether the protocol was successfully intercepted
|
||||
|
||||
Intercepts `scheme` protocol and uses `handler` as the protocol's new handler
|
||||
which sends a `Buffer` as a response.
|
||||
|
||||
### `protocol.interceptHttpProtocol(scheme, handler[, completion])`
|
||||
### `protocol.interceptHttpProtocol(scheme, handler)`
|
||||
|
||||
* `scheme` String
|
||||
* `handler` Function
|
||||
* `request` Object
|
||||
* `url` String
|
||||
* `headers` Record<String, String>
|
||||
* `referrer` String
|
||||
* `method` String
|
||||
* `uploadData` [UploadData[]](structures/upload-data.md)
|
||||
* `request` ProtocolRequest
|
||||
* `callback` Function
|
||||
* `redirectRequest` Object
|
||||
* `url` String
|
||||
* `method` String (optional)
|
||||
* `session` Session | null (optional)
|
||||
* `uploadData` [ProtocolResponseUploadData](structures/protocol-response-upload-data.md) (optional)
|
||||
* `completion` Function (optional)
|
||||
* `error` Error
|
||||
* `response` [ProtocolResponse](structures/protocol-response.md)
|
||||
|
||||
Returns `Boolean` - Whether the protocol was successfully intercepted
|
||||
|
||||
Intercepts `scheme` protocol and uses `handler` as the protocol's new handler
|
||||
which sends a new HTTP request as a response.
|
||||
|
||||
### `protocol.interceptStreamProtocol(scheme, handler[, completion])`
|
||||
### `protocol.interceptStreamProtocol(scheme, handler)`
|
||||
|
||||
* `scheme` String
|
||||
* `handler` Function
|
||||
* `request` Object
|
||||
* `url` String
|
||||
* `headers` Record<String, String>
|
||||
* `referrer` String
|
||||
* `method` String
|
||||
* `uploadData` [UploadData[]](structures/upload-data.md)
|
||||
* `request` ProtocolRequest
|
||||
* `callback` Function
|
||||
* `stream` (ReadableStream | [StreamProtocolResponse](structures/stream-protocol-response.md)) (optional)
|
||||
* `completion` Function (optional)
|
||||
* `error` Error
|
||||
* `response` (ReadableStream | [ProtocolResponse](structures/protocol-response.md))
|
||||
|
||||
Returns `Boolean` - Whether the protocol was successfully intercepted
|
||||
|
||||
Same as `protocol.registerStreamProtocol`, except that it replaces an existing
|
||||
protocol handler.
|
||||
|
||||
### `protocol.uninterceptProtocol(scheme[, completion])`
|
||||
### `protocol.uninterceptProtocol(scheme)`
|
||||
|
||||
* `scheme` String
|
||||
* `completion` Function (optional)
|
||||
* `error` Error
|
||||
|
||||
Returns `Boolean` - Whether the protocol was successfully unintercepted
|
||||
|
||||
Remove the interceptor installed for `scheme` and restore its original handler.
|
||||
|
||||
[net-error]: https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h
|
||||
### `protocol.isProtocolIntercepted(scheme)`
|
||||
|
||||
* `scheme` String
|
||||
|
||||
Returns `Boolean` - Whether `scheme` is already intercepted.
|
||||
|
||||
[file-system-api]: https://developer.mozilla.org/en-US/docs/Web/API/LocalFileSystem
|
||||
|
||||
@@ -17,7 +17,7 @@ renderer process:
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron').remote
|
||||
let win = new BrowserWindow({ width: 800, height: 600 })
|
||||
const win = new BrowserWindow({ width: 800, height: 600 })
|
||||
win.loadURL('https://github.com')
|
||||
```
|
||||
|
||||
|
||||
@@ -154,24 +154,43 @@ More may be added as needed to expose more Electron APIs in the sandbox, but any
|
||||
module in the main process can already be used through
|
||||
`electron.remote.require`.
|
||||
|
||||
## Status
|
||||
## Rendering untrusted content
|
||||
|
||||
Please use the `sandbox` option with care, as it is still an experimental
|
||||
feature. We are still not aware of the security implications of exposing some
|
||||
Electron renderer APIs to the preload script, but here are some things to
|
||||
consider before rendering untrusted content:
|
||||
Rendering untrusted content in Electron is still somewhat uncharted territory,
|
||||
though some apps are finding success (e.g. Beaker Browser). Our goal is to get
|
||||
as close to Chrome as we can in terms of the security of sandboxed content, but
|
||||
ultimately we will always be behind due to a few fundamental issues:
|
||||
|
||||
1. We do not have the dedicated resources or expertise that Chromium has to
|
||||
apply to the security of its product. We do our best to make use of what we
|
||||
have, to inherit everything we can from Chromium, and to respond quickly to
|
||||
security issues, but Electron cannot be as secure as Chromium without the
|
||||
resources that Chromium is able to dedicate.
|
||||
2. Some security features in Chrome (such as Safe Browsing and Certificate
|
||||
Transparency) require a centralized authority and dedicated servers, both of
|
||||
which run counter to the goals of the Electron project. As such, we disable
|
||||
those features in Electron, at the cost of the associated security they
|
||||
would otherwise bring.
|
||||
3. There is only one Chromium, whereas there are many thousands of apps built
|
||||
on Electron, all of which behave slightly differently. Accounting for those
|
||||
differences can yield a huge possibility space, and make it challenging to
|
||||
ensure the security of the platform in unusual use cases.
|
||||
4. We can't push security updates to users directly, so we rely on app vendors
|
||||
to upgrade the version of Electron underlying their app in order for
|
||||
security updates to reach users.
|
||||
|
||||
Here are some things to consider before rendering untrusted content:
|
||||
|
||||
- A preload script can accidentally leak privileged APIs to untrusted code,
|
||||
unless [`contextIsolation`](../tutorial/security.md#3-enable-context-isolation-for-remote-content)
|
||||
is also enabled.
|
||||
- Some bug in V8 engine may allow malicious code to access the renderer preload
|
||||
APIs, effectively granting full access to the system through the `remote`
|
||||
module. Therefore, it is highly recommended to
|
||||
[disable the `remote` module](../tutorial/security.md#15-disable-the-remote-module).
|
||||
If disabling is not feasible, you should selectively
|
||||
[filter the `remote` module](../tutorial/security.md#16-filter-the-remote-module).
|
||||
|
||||
Since rendering untrusted content in Electron is still uncharted territory,
|
||||
the APIs exposed to the sandbox preload script should be considered more
|
||||
unstable than the rest of Electron APIs, and may have breaking changes to fix
|
||||
security issues.
|
||||
- Some bug in the V8 engine may allow malicious code to access the renderer
|
||||
preload APIs, effectively granting full access to the system through the
|
||||
`remote` module. Therefore, it is highly recommended to [disable the `remote`
|
||||
module](../tutorial/security.md#15-disable-the-remote-module).
|
||||
If disabling is not feasible, you should selectively [filter the `remote`
|
||||
module](../tutorial/security.md#16-filter-the-remote-module).
|
||||
- While we make our best effort to backport Chromium security fixes to older
|
||||
versions of Electron, we do not make a guarantee that every fix will be
|
||||
backported. Your best chance at staying secure is to be on the latest stable
|
||||
version of Electron.
|
||||
|
||||
@@ -33,8 +33,8 @@ const { app, BrowserWindow, screen } = require('electron')
|
||||
let win
|
||||
|
||||
app.whenReady().then(() => {
|
||||
let displays = screen.getAllDisplays()
|
||||
let externalDisplay = displays.find((display) => {
|
||||
const displays = screen.getAllDisplays()
|
||||
const externalDisplay = displays.find((display) => {
|
||||
return display.bounds.x !== 0 || display.bounds.y !== 0
|
||||
})
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ Returns:
|
||||
* `message` String - The actual console message
|
||||
* `versionId` Number - The version ID of the service worker that sent the log message
|
||||
* `source` String - The type of source for this message. Can be `javascript`, `xml`, `network`, `console-api`, `storage`, `app-cache`, `rendering`, `security`, `deprecation`, `worker`, `violation`, `intervention`, `recommendation` or `other`.
|
||||
* `level` Number - The log level, from 0 to 3. In order it matches `verbose`, `info`, `warning` and `error`.
|
||||
* `level` Number - The log level, from 0 to 3. In order it matches `verbose`, `info`, `warning` and `error`.
|
||||
* `sourceUrl` String - The URL the message came from
|
||||
* `lineNumber` Number - The line number of the source that triggered this console message
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ property of [`WebContents`](web-contents.md), or from the `session` module.
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
|
||||
let win = new BrowserWindow({ width: 800, height: 600 })
|
||||
const win = new BrowserWindow({ width: 800, height: 600 })
|
||||
win.loadURL('http://github.com')
|
||||
|
||||
const ses = win.webContents.session
|
||||
@@ -332,7 +332,7 @@ verify proc.
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
let win = new BrowserWindow()
|
||||
const win = new BrowserWindow()
|
||||
|
||||
win.webContents.session.setCertificateVerifyProc((request, callback) => {
|
||||
const { hostname } = request
|
||||
@@ -348,8 +348,16 @@ win.webContents.session.setCertificateVerifyProc((request, callback) => {
|
||||
|
||||
* `handler` Function | null
|
||||
* `webContents` [WebContents](web-contents.md) - WebContents requesting the permission. Please note that if the request comes from a subframe you should use `requestingUrl` to check the request origin.
|
||||
* `permission` String - Enum of 'media', 'geolocation', 'notifications', 'midiSysex',
|
||||
'pointerLock', 'fullscreen', 'openExternal'.
|
||||
* `permission` String - The type of requested permission.
|
||||
* `media` - Request access to media devices such as camera, microphone and speakers.
|
||||
* `mediaKeySystem` - Request access to DRM protected content.
|
||||
* `geolocation` - Request access to user's current location.
|
||||
* `notifications` - Request notification creation and the ability to display them in the user's system tray.
|
||||
* `midi` - Request MIDI access in the `webmidi` API.
|
||||
* `midiSysex` - Request the use of system exclusive messages in the `webmidi` API.
|
||||
* `pointerLock` - Request to directly interpret mouse movements as an input method. Click [here](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API) to know more.
|
||||
* `fullscreen` - Request for the app to enter fullscreen mode.
|
||||
* `openExternal` - Request to open links in external applications.
|
||||
* `callback` Function
|
||||
* `permissionGranted` Boolean - Allow or deny the permission.
|
||||
* `details` Object - Some properties are only available on certain permission types.
|
||||
@@ -655,7 +663,7 @@ const path = require('path')
|
||||
app.whenReady().then(() => {
|
||||
const protocol = session.fromPartition('some-partition').protocol
|
||||
protocol.registerFileProtocol('atom', (request, callback) => {
|
||||
let url = request.url.substr(7)
|
||||
const url = request.url.substr(7)
|
||||
callback({ path: path.normalize(`${__dirname}/${url}`) })
|
||||
}, (error) => {
|
||||
if (error) console.error('Failed to register protocol')
|
||||
|
||||
@@ -8,3 +8,4 @@
|
||||
* `allowServiceWorkers` Boolean (optional) - Default false.
|
||||
* `supportFetchAPI` Boolean (optional) - Default false.
|
||||
* `corsEnabled` Boolean (optional) - Default false.
|
||||
* `stream` Boolean (optional) - Default false.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# KeyboardEvent Object extends `Event`
|
||||
# KeyboardEvent Object
|
||||
|
||||
* `ctrlKey` Boolean (optional) - whether the Control key was used in an accelerator to trigger the Event
|
||||
* `metaKey` Boolean (optional) - whether a meta key was used in an accelerator to trigger the Event
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
* `Pepper Plugin`
|
||||
* `Pepper Plugin Broker`
|
||||
* `Unknown`
|
||||
* `name` String (optional) - The name of the process. i.e. for plugins it might be Flash.
|
||||
Examples for utility: `Audio Service`, `Content Decryption Module Service`, `Network Service`, `Video Capture`, etc.
|
||||
* `cpu` [CPUUsage](cpu-usage.md) - CPU usage of the process.
|
||||
* `creationTime` Number - Creation time for this process.
|
||||
The time is represented as number of milliseconds since epoch.
|
||||
|
||||
@@ -4,3 +4,4 @@
|
||||
* `referrer` String
|
||||
* `method` String
|
||||
* `uploadData` [UploadData[]](upload-data.md) (optional)
|
||||
* `headers` Record<String, String>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* `trace_buffer_size_in_events` number (optional) - maximum size of the trace
|
||||
recording buffer in events.
|
||||
* `enable_argument_filter` boolean (optional) - if true, filter event data
|
||||
according to a whitelist of events that have been manually vetted to not
|
||||
according to a specific list of events that have been manually vetted to not
|
||||
include any PII. See [the implementation in
|
||||
Chromium][trace_event_args_whitelist.cc] for specifics.
|
||||
* `included_categories` String[] (optional) - a list of tracing categories to
|
||||
@@ -41,7 +41,7 @@ An example TraceConfig that roughly matches what Chrome DevTools records:
|
||||
'disabled-by-default-v8.cpu_profiler',
|
||||
'disabled-by-default-v8.cpu_profiler.hires'
|
||||
],
|
||||
excluded_categories: [ '*' ]
|
||||
excluded_categories: ['*']
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -209,7 +209,7 @@ not (transparent windows won't work correctly when DWM composition is disabled):
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow, systemPreferences } = require('electron')
|
||||
let browserOptions = { width: 1000, height: 800 }
|
||||
const browserOptions = { width: 1000, height: 800 }
|
||||
|
||||
// Make the window transparent only if the platform supports it.
|
||||
if (process.platform !== 'win32' || systemPreferences.isAeroGlassEnabled()) {
|
||||
@@ -218,7 +218,7 @@ if (process.platform !== 'win32' || systemPreferences.isAeroGlassEnabled()) {
|
||||
}
|
||||
|
||||
// Create the window.
|
||||
let win = new BrowserWindow(browserOptions)
|
||||
const win = new BrowserWindow(browserOptions)
|
||||
|
||||
// Navigate.
|
||||
if (browserOptions.transparent) {
|
||||
@@ -416,7 +416,7 @@ This API itself will not protect your user data; rather, it is a mechanism to al
|
||||
|
||||
Returns `Boolean` - `true` if the current process is a trusted accessibility client and `false` if it is not.
|
||||
|
||||
### `systemPreferences.getMediaAccessStatus(mediaType)` _macOS_
|
||||
### `systemPreferences.getMediaAccessStatus(mediaType)` _Windows_ _macOS_
|
||||
|
||||
* `mediaType` String - Can be `microphone`, `camera` or `screen`.
|
||||
|
||||
@@ -426,6 +426,9 @@ This user consent was not required on macOS 10.13 High Sierra or lower so this m
|
||||
macOS 10.14 Mojave or higher requires consent for `microphone` and `camera` access.
|
||||
macOS 10.15 Catalina or higher requires consent for `screen` access.
|
||||
|
||||
Windows 10 has a global setting controlling `microphone` and `camera` access for all win32 applications.
|
||||
It will always return `granted` for `screen` and for all media types on older versions of Windows.
|
||||
|
||||
### `systemPreferences.askForMediaAccess(mediaType)` _macOS_
|
||||
|
||||
* `mediaType` String - the type of media being requested; can be `microphone`, `camera`.
|
||||
|
||||
@@ -41,6 +41,10 @@ the button in the touch bar.
|
||||
A `NativeImage` representing the button's current icon. Changing this value immediately updates the button
|
||||
in the touch bar.
|
||||
|
||||
#### `touchBarButton.iconPosition`
|
||||
|
||||
A `String` - Can be `left`, `right` or `overlay`. Defaults to `overlay`.
|
||||
|
||||
#### `touchBarButton.enabled`
|
||||
|
||||
A `Boolean` representing whether the button is in an enabled state.
|
||||
|
||||
@@ -49,3 +49,7 @@ updates the control in the touch bar. Updating deep properties inside this array
|
||||
|
||||
An `Integer` representing the currently selected segment. Changing this value immediately updates the control
|
||||
in the touch bar. User interaction with the touch bar will update this value automatically.
|
||||
|
||||
#### `touchBarSegmentedControl.mode`
|
||||
|
||||
A `String` representing the current selection mode of the control. Can be `single`, `multiple` or `buttons`.
|
||||
|
||||
@@ -11,3 +11,11 @@ Process: [Main](../tutorial/application-architecture.md#main-and-renderer-proces
|
||||
* `small` - Small space between items. Maps to `NSTouchBarItemIdentifierFixedSpaceSmall`. This is the default.
|
||||
* `large` - Large space between items. Maps to `NSTouchBarItemIdentifierFixedSpaceLarge`.
|
||||
* `flexible` - Take up all available space. Maps to `NSTouchBarItemIdentifierFlexibleSpace`.
|
||||
|
||||
### Instance Properties
|
||||
|
||||
The following properties are available on instances of `TouchBarSpacer`:
|
||||
|
||||
#### `touchBarSpacer.size`
|
||||
|
||||
A `String` representing the size of the spacer. Can be `small`, `large` or `flexible`.
|
||||
|
||||
@@ -12,10 +12,10 @@ the [`BrowserWindow`](browser-window.md) object. An example of accessing the
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
|
||||
let win = new BrowserWindow({ width: 800, height: 1500 })
|
||||
const win = new BrowserWindow({ width: 800, height: 1500 })
|
||||
win.loadURL('http://github.com')
|
||||
|
||||
let contents = win.webContents
|
||||
const contents = win.webContents
|
||||
console.log(contents)
|
||||
```
|
||||
|
||||
@@ -402,6 +402,7 @@ Returns:
|
||||
* `key` String - Equivalent to [KeyboardEvent.key][keyboardevent].
|
||||
* `code` String - Equivalent to [KeyboardEvent.code][keyboardevent].
|
||||
* `isAutoRepeat` Boolean - Equivalent to [KeyboardEvent.repeat][keyboardevent].
|
||||
* `isComposing` Boolean - Equivalent to [KeyboardEvent.isComposing][keyboardevent].
|
||||
* `shift` Boolean - Equivalent to [KeyboardEvent.shiftKey][keyboardevent].
|
||||
* `control` Boolean - Equivalent to [KeyboardEvent.controlKey][keyboardevent].
|
||||
* `alt` Boolean - Equivalent to [KeyboardEvent.altKey][keyboardevent].
|
||||
@@ -417,7 +418,7 @@ To only prevent the menu shortcuts, use
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
|
||||
let win = new BrowserWindow({ width: 800, height: 600 })
|
||||
const win = new BrowserWindow({ width: 800, height: 600 })
|
||||
|
||||
win.webContents.on('before-input-event', (event, input) => {
|
||||
// For example, only enable application menu keyboard shortcuts when
|
||||
@@ -664,7 +665,7 @@ app.whenReady().then(() => {
|
||||
win = new BrowserWindow({ width: 800, height: 600 })
|
||||
win.webContents.on('select-bluetooth-device', (event, deviceList, callback) => {
|
||||
event.preventDefault()
|
||||
let result = deviceList.find((device) => {
|
||||
const result = deviceList.find((device) => {
|
||||
return device.deviceName === 'test'
|
||||
})
|
||||
if (!result) {
|
||||
@@ -690,7 +691,7 @@ buffer.
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
|
||||
let win = new BrowserWindow({ webPreferences: { offscreen: true } })
|
||||
const win = new BrowserWindow({ webPreferences: { offscreen: true } })
|
||||
win.webContents.on('paint', (event, dirty, image) => {
|
||||
// updateBitmap(dirty, image.getBitmap())
|
||||
})
|
||||
@@ -737,9 +738,9 @@ Emitted when a `<webview>` has been attached to this web contents.
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `level` Integer
|
||||
* `message` String
|
||||
* `line` Integer
|
||||
* `level` Integer - The log level, from 0 to 3. In order it matches `verbose`, `info`, `warning` and `error`.
|
||||
* `message` String - The actual console message
|
||||
* `line` Integer - The line number of the source that triggered this console message
|
||||
* `sourceId` String
|
||||
|
||||
Emitted when the associated window logs a console message.
|
||||
@@ -906,11 +907,11 @@ Returns `String` - The URL of the current web page.
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
let win = new BrowserWindow({ width: 800, height: 600 })
|
||||
win.loadURL('http://github.com')
|
||||
|
||||
let currentURL = win.webContents.getURL()
|
||||
console.log(currentURL)
|
||||
const win = new BrowserWindow({ width: 800, height: 600 })
|
||||
win.loadURL('http://github.com').then(() => {
|
||||
const currentURL = win.webContents.getURL()
|
||||
console.log(currentURL)
|
||||
})
|
||||
```
|
||||
|
||||
#### `contents.getTitle()`
|
||||
@@ -1310,6 +1311,8 @@ Returns [`PrinterInfo[]`](structures/printer-info.md)
|
||||
* `success` Boolean - Indicates success of the print call.
|
||||
* `failureReason` String - Error description called back if the print fails.
|
||||
|
||||
When a custom `pageSize` is passed, Chromium attempts to validate platform specific minumum values for `width_microns` and `height_microns`. Width and height must both be minimum 353 microns but may be higher on some operating systems.
|
||||
|
||||
Prints window's web page. When `silent` is set to `true`, Electron will pick
|
||||
the system's default printer if `deviceName` is empty and the default settings for printing.
|
||||
|
||||
@@ -1318,7 +1321,14 @@ Use `page-break-before: always;` CSS style to force to print to a new page.
|
||||
Example usage:
|
||||
|
||||
```js
|
||||
const options = { silent: true, deviceName: 'My-Printer' }
|
||||
const options = {
|
||||
silent: true,
|
||||
deviceName: 'My-Printer',
|
||||
pageRanges: {
|
||||
from: 0,
|
||||
to: 1
|
||||
}
|
||||
}
|
||||
win.webContents.print(options, (success, errorType) => {
|
||||
if (!success) console.log(errorType)
|
||||
})
|
||||
@@ -1333,13 +1343,12 @@ win.webContents.print(options, (success, errorType) => {
|
||||
* `landscape` Boolean (optional) - `true` for landscape, `false` for portrait.
|
||||
* `marginsType` Integer (optional) - Specifies the type of margins to use. Uses 0 for
|
||||
default margin, 1 for no margin, and 2 for minimum margin.
|
||||
and `width` in microns.
|
||||
* `scaleFactor` Number (optional) - The scale factor of the web page. Can range from 0 to 100.
|
||||
* `pageRanges` Record<string, number> (optional) - The page range to print.
|
||||
* `from` Number - the first page to print.
|
||||
* `to` Number - the last page to print (inclusive).
|
||||
* `from` Number - zero-based index of the first page to print.
|
||||
* `to` Number - zero-based index of the last page to print (inclusive).
|
||||
* `pageSize` String | Size (optional) - Specify page size of the generated PDF. Can be `A3`,
|
||||
`A4`, `A5`, `Legal`, `Letter`, `Tabloid` or an Object containing `height`
|
||||
`A4`, `A5`, `Legal`, `Letter`, `Tabloid` or an Object containing `height` and `width` in microns.
|
||||
* `printBackground` Boolean (optional) - Whether to print CSS backgrounds.
|
||||
* `printSelectionOnly` Boolean (optional) - Whether to print selection only.
|
||||
|
||||
@@ -1370,19 +1379,22 @@ An example of `webContents.printToPDF`:
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const os = require('os')
|
||||
|
||||
let win = new BrowserWindow({ width: 800, height: 600 })
|
||||
const win = new BrowserWindow({ width: 800, height: 600 })
|
||||
win.loadURL('http://github.com')
|
||||
|
||||
win.webContents.on('did-finish-load', () => {
|
||||
// Use default printing options
|
||||
win.webContents.printToPDF({}).then(data => {
|
||||
fs.writeFile('/tmp/print.pdf', data, (error) => {
|
||||
const pdfPath = path.join(os.homedir(), 'Desktop', 'temp.pdf')
|
||||
fs.writeFile(pdfPath, data, (error) => {
|
||||
if (error) throw error
|
||||
console.log('Write PDF successfully.')
|
||||
console.log(`Wrote PDF successfully to ${pdfPath}`)
|
||||
})
|
||||
}).catch(error => {
|
||||
console.log(error)
|
||||
console.log(`Failed to write PDF to ${pdfPath}: `, error)
|
||||
})
|
||||
})
|
||||
```
|
||||
@@ -1396,7 +1408,7 @@ creation:
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
let win = new BrowserWindow()
|
||||
const win = new BrowserWindow()
|
||||
win.webContents.on('devtools-opened', () => {
|
||||
win.webContents.addWorkSpace(__dirname)
|
||||
})
|
||||
@@ -1717,7 +1729,7 @@ Returns `Promise<void>` - resolves if the page is saved.
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
let win = new BrowserWindow()
|
||||
const win = new BrowserWindow()
|
||||
|
||||
win.loadURL('https://github.com')
|
||||
|
||||
|
||||
@@ -162,10 +162,14 @@ this limitation.
|
||||
* `error` Error
|
||||
|
||||
Returns `Promise<any>` - A promise that resolves with the result of the executed
|
||||
code or is rejected if execution throws or results in a rejected promise.
|
||||
code or is rejected if execution could not start.
|
||||
|
||||
Works like `executeJavaScript` but evaluates `scripts` in an isolated context.
|
||||
|
||||
Note that when the execution of script fails, the returned promise will not
|
||||
reject and the `result` would be `undefined`. This is because Chromium does not
|
||||
dispatch errors of isolated worlds to foreign worlds.
|
||||
|
||||
### `webFrame.setIsolatedWorldInfo(worldId, info)`
|
||||
* `worldId` Integer - The ID of the world to run the javascript in, `0` is the default world, `999` is the world used by Electrons `contextIsolation` feature. Chrome extensions reserve the range of IDs in `[1 << 20, 1 << 29)`. You can provide any integer here.
|
||||
* `info` Object
|
||||
|
||||
@@ -561,8 +561,8 @@ Stops any `findInPage` request for the `webview` with the provided `action`.
|
||||
* `collate` Boolean (optional) - Whether the web page should be collated.
|
||||
* `copies` Number (optional) - The number of copies of the web page to print.
|
||||
* `pageRanges` Record<string, number> (optional) - The page range to print.
|
||||
* `from` Number - the start page.
|
||||
* `to` Number - the end page.
|
||||
* `from` Number - zero-based index of the first page to print.
|
||||
* `to` Number - zero-based index of the last page to print (inclusive).
|
||||
* `duplexMode` String (optional) - Set the duplex mode of the printed web page. Can be `simplex`, `shortEdge`, or `longEdge`.
|
||||
* `dpi` Record<string, number> (optional)
|
||||
* `horizontal` Number (optional) - The horizontal dpi.
|
||||
@@ -755,9 +755,9 @@ Fired when page leaves fullscreen triggered by HTML API.
|
||||
|
||||
Returns:
|
||||
|
||||
* `level` Integer
|
||||
* `message` String
|
||||
* `line` Integer
|
||||
* `level` Integer - The log level, from 0 to 3. In order it matches `verbose`, `info`, `warning` and `error`.
|
||||
* `message` String - The actual console message
|
||||
* `line` Integer - The line number of the source that triggered this console message
|
||||
* `sourceId` String
|
||||
|
||||
Fired when the guest window logs a console message.
|
||||
@@ -816,7 +816,7 @@ const { shell } = require('electron')
|
||||
const webview = document.querySelector('webview')
|
||||
|
||||
webview.addEventListener('new-window', async (e) => {
|
||||
const protocol = require('url').parse(e.url).protocol
|
||||
const protocol = (new URL(e.url)).protocol
|
||||
if (protocol === 'http:' || protocol === 'https:') {
|
||||
await shell.openExternal(e.url)
|
||||
}
|
||||
|
||||
@@ -94,6 +94,6 @@ mainWindow.webContents.on('new-window', (event, url, frameName, disposition, opt
|
||||
|
||||
```javascript
|
||||
// renderer process (mainWindow)
|
||||
let modal = window.open('', 'modal')
|
||||
const modal = window.open('', 'modal')
|
||||
modal.document.write('<h1>Hello</h1>')
|
||||
```
|
||||
|
||||
@@ -14,6 +14,15 @@ This document uses the following convention to categorize breaking changes:
|
||||
|
||||
## Planned Breaking API Changes (12.0)
|
||||
|
||||
### Default Changed: `contextIsolation` defaults to `true`
|
||||
|
||||
In Electron 12, `contextIsolation` will be enabled by default. To restore
|
||||
the previous behavior, `contextIsolation: false` must be specified in WebPreferences.
|
||||
|
||||
We [recommend having contextIsolation enabled](https://github.com/electron/electron/blob/master/docs/tutorial/security.md#3-enable-context-isolation-for-remote-content) for the security of your application.
|
||||
|
||||
For more details see: https://github.com/electron/electron/issues/23506
|
||||
|
||||
### Removed: `crashReporter` methods in the renderer process
|
||||
|
||||
The following `crashReporter` methods are no longer available in the renderer
|
||||
@@ -30,8 +39,21 @@ They should be called only from the main process.
|
||||
|
||||
See [#23265](https://github.com/electron/electron/pull/23265) for more details.
|
||||
|
||||
### Default Changed: `crashReporter.start({ compress: true })`
|
||||
|
||||
The default value of the `compress` option to `crashReporter.start` has changed
|
||||
from `false` to `true`. This means that crash dumps will be uploaded to the
|
||||
crash ingestion server with the `Content-Encoding: gzip` header, and the body
|
||||
will be compressed.
|
||||
|
||||
If your crash ingestion server does not support compressed payloads, you can
|
||||
turn off compression by specifying `{ compress: false }` in the crash reporter
|
||||
options.
|
||||
|
||||
## Planned Breaking API Changes (11.0)
|
||||
|
||||
There are no breaking changes planned for 11.0.
|
||||
|
||||
## Planned Breaking API Changes (10.0)
|
||||
|
||||
### Deprecated: `companyName` argument to `crashReporter.start()`
|
||||
@@ -79,6 +101,12 @@ All above methods remain non-deprecated when called from the main process.
|
||||
|
||||
See [#23265](https://github.com/electron/electron/pull/23265) for more details.
|
||||
|
||||
### Deprecated: `crashReporter.start({ compress: false })`
|
||||
|
||||
Setting `{ compress: false }` in `crashReporter.start` is deprecated. Nearly
|
||||
all crash ingestion servers support gzip compression. This option will be
|
||||
removed in a future version of Electron.
|
||||
|
||||
### Removed: Browser Window Affinity
|
||||
|
||||
The `affinity` option when constructing a new `BrowserWindow` will be removed
|
||||
@@ -238,7 +266,7 @@ const getGuestForWebContents = (webContentsId, contents) => {
|
||||
throw new Error(`Invalid webContentsId: ${webContentsId}`)
|
||||
}
|
||||
if (guest.hostWebContents !== contents) {
|
||||
throw new Error(`Access denied to webContents`)
|
||||
throw new Error('Access denied to webContents')
|
||||
}
|
||||
return guest
|
||||
}
|
||||
@@ -294,7 +322,7 @@ powerMonitor.querySystemIdleState(threshold, callback)
|
||||
const idleState = powerMonitor.getSystemIdleState(threshold)
|
||||
```
|
||||
|
||||
### API Changed: `powerMonitor.querySystemIdleTime` is now `powerMonitor.getSystemIdleState`
|
||||
### API Changed: `powerMonitor.querySystemIdleTime` is now `powerMonitor.getSystemIdleTime`
|
||||
|
||||
```js
|
||||
// Removed in Electron 7.0
|
||||
@@ -582,11 +610,11 @@ const { memory } = metrics[0] // Deprecated property
|
||||
|
||||
```js
|
||||
// Deprecated
|
||||
let optionsA = { webPreferences: { blinkFeatures: '' } }
|
||||
let windowA = new BrowserWindow(optionsA)
|
||||
const optionsA = { webPreferences: { blinkFeatures: '' } }
|
||||
const windowA = new BrowserWindow(optionsA)
|
||||
// Replace with
|
||||
let optionsB = { webPreferences: { enableBlinkFeatures: '' } }
|
||||
let windowB = new BrowserWindow(optionsB)
|
||||
const optionsB = { webPreferences: { enableBlinkFeatures: '' } }
|
||||
const windowB = new BrowserWindow(optionsB)
|
||||
|
||||
// Deprecated
|
||||
window.on('app-command', (e, cmd) => {
|
||||
@@ -757,11 +785,11 @@ The following list includes the breaking API changes made in Electron 2.0.
|
||||
|
||||
```js
|
||||
// Deprecated
|
||||
let optionsA = { titleBarStyle: 'hidden-inset' }
|
||||
let windowA = new BrowserWindow(optionsA)
|
||||
const optionsA = { titleBarStyle: 'hidden-inset' }
|
||||
const windowA = new BrowserWindow(optionsA)
|
||||
// Replace with
|
||||
let optionsB = { titleBarStyle: 'hiddenInset' }
|
||||
let windowB = new BrowserWindow(optionsB)
|
||||
const optionsB = { titleBarStyle: 'hiddenInset' }
|
||||
const windowB = new BrowserWindow(optionsB)
|
||||
```
|
||||
|
||||
### `menu`
|
||||
|
||||
@@ -23,4 +23,3 @@ For guides on Electron app development, see
|
||||
* [Debugging on macOS](debugging-instructions-macos.md)
|
||||
* [Setting Up Symbol Server in Debugger](setting-up-symbol-server.md)
|
||||
* [Patches](patches.md)
|
||||
* [Upgrading Node](upgrading-node.md)
|
||||
|
||||
@@ -10,6 +10,10 @@ Check the build prerequisites for your platform before proceeding
|
||||
* [Linux](build-instructions-linux.md#prerequisites)
|
||||
* [Windows](build-instructions-windows.md#prerequisites)
|
||||
|
||||
## Build Tools
|
||||
|
||||
[Electron's Build Tools](https://github.com/electron/build-tools) automate much of the setup for compiling Electron from source with different configurations and build targets. If you wish to set up the environment manually, the instructions are listed below.
|
||||
|
||||
## GN prerequisites
|
||||
|
||||
You'll need to install [`depot_tools`][depot-tools], the toolset
|
||||
|
||||
@@ -15,7 +15,7 @@ calls, and other compiler optimizations. The only workaround is to build an
|
||||
unoptimized local build.
|
||||
|
||||
The official symbol server URL for Electron is
|
||||
https://electron-symbols.githubapp.com.
|
||||
https://symbols.electronjs.org.
|
||||
You cannot visit this URL directly, you must add it to the symbol path of your
|
||||
debugging tool. In the examples below, a local cache directory is used to avoid
|
||||
repeatedly fetching the PDB from the server. Replace `c:\code\symbols` with an
|
||||
@@ -30,7 +30,7 @@ directory on your computer, if you'd prefer a different location for downloaded
|
||||
symbols):
|
||||
|
||||
```powershell
|
||||
SRV*c:\code\symbols\*https://electron-symbols.githubapp.com
|
||||
SRV*c:\code\symbols\*https://symbols.electronjs.org
|
||||
```
|
||||
|
||||
Set this string as `_NT_SYMBOL_PATH` in the environment, using the Windbg menus,
|
||||
@@ -38,7 +38,7 @@ or by typing the `.sympath` command. If you would like to get symbols from
|
||||
Microsoft's symbol server as well, you should list that first:
|
||||
|
||||
```powershell
|
||||
SRV*c:\code\symbols\*https://msdl.microsoft.com/download/symbols;SRV*c:\code\symbols\*https://electron-symbols.githubapp.com
|
||||
SRV*c:\code\symbols\*https://msdl.microsoft.com/download/symbols;SRV*c:\code\symbols\*https://symbols.electronjs.org
|
||||
```
|
||||
|
||||
## Using the symbol server in Visual Studio
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
# Upgrading Node
|
||||
|
||||
## Discussion
|
||||
|
||||
Chromium and Node.js both depend on V8, and Electron contains
|
||||
only a single copy of V8, so it's important to ensure that the
|
||||
version of V8 chosen is compatible with the build's version of
|
||||
Node.js and Chromium.
|
||||
|
||||
Upgrading Node is much easier than upgrading Chromium, so fewer
|
||||
conflicts arise if one upgrades Chromium first, then chooses the
|
||||
upstream Node release whose version of V8 is closest to the one
|
||||
Chromium contains.
|
||||
|
||||
Electron has its own [Node fork](https://github.com/electron/node)
|
||||
with modifications for the V8 build details mentioned above
|
||||
and for exposing API needed by Electron. Once an upstream Node
|
||||
release is chosen, it's placed in a branch in Electron's Node fork
|
||||
and any Electron Node patches are applied there.
|
||||
|
||||
Another factor is that the Node project patches its version of V8.
|
||||
As mentioned above, Electron builds everything with a single copy
|
||||
of V8, so Node's V8 patches must be ported to that copy.
|
||||
|
||||
Once all of Electron's dependencies are building and using the same
|
||||
copy of V8, the next step is to fix any Electron code issues caused
|
||||
by the Node upgrade.
|
||||
|
||||
[FIXME] something about a Node debugger in Atom that we (e.g. deepak)
|
||||
use and need to confirm doesn't break with the Node upgrade?
|
||||
|
||||
So in short, the primary steps are:
|
||||
|
||||
1. Update Electron's Node fork to the desired version
|
||||
2. Backport Node's V8 patches to our copy of V8
|
||||
3. Update the GN build files, porting changes from node's GYP files
|
||||
4. Update Electron's DEPS to use new version of Node
|
||||
|
||||
## Updating Electron's Node [fork](https://github.com/electron/node)
|
||||
|
||||
1. Ensure that `master` on `electron/node` has updated release tags from `nodejs/node`
|
||||
2. Create a branch in https://github.com/electron/node: `electron-node-vX.X.X` where the base that you're branching from is the tag for the desired update
|
||||
- `vX.X.X` Must use a version of Node compatible with our current version of Chromium
|
||||
3. Re-apply our commits from the previous version of Node we were using (`vY.Y.Y`) to `v.X.X.X`
|
||||
- Check release tag and select the range of commits we need to re-apply
|
||||
- Cherry-pick commit range:
|
||||
1. Checkout both `vY.Y.Y` & `v.X.X.X`
|
||||
2. `git cherry-pick FIRST_COMMIT_HASH..LAST_COMMIT_HASH`
|
||||
- Resolve merge conflicts in each file encountered, then:
|
||||
1. `git add <conflict-file>`
|
||||
2. `git cherry-pick --continue`
|
||||
3. Repeat until finished
|
||||
|
||||
|
||||
## Updating [V8](https://github.com/electron/node/src/V8) Patches
|
||||
|
||||
We need to generate a patch file from each patch that Node
|
||||
applies to V8.
|
||||
|
||||
```sh
|
||||
$ cd third_party/electron_node
|
||||
$ CURRENT_NODE_VERSION=vX.Y.Z
|
||||
# Find the last commit with the message "deps: update V8 to <some version>"
|
||||
# This commit corresponds to Node resetting V8 to its pristine upstream
|
||||
# state at the stated version.
|
||||
$ LAST_V8_UPDATE="$(git log --grep='^deps: update V8' --format='%H' -1 deps/v8)"
|
||||
# This creates a patch file containing all changes in deps/v8 from
|
||||
# $LAST_V8_UPDATE up to the current Node version, formatted in a way that
|
||||
# it will apply cleanly to the V8 repository (i.e. with `deps/v8`
|
||||
# stripped off the path and excluding the v8/gypfiles directory, which
|
||||
# isn't present in V8.
|
||||
$ git format-patch \
|
||||
--relative=deps/v8 \
|
||||
$LAST_V8_UPDATE..$CURRENT_NODE_VERSION \
|
||||
deps/v8 \
|
||||
':(exclude)deps/v8/gypfiles' \
|
||||
--stdout \
|
||||
> ../../electron/common/patches/v8/node_v8_patches.patch
|
||||
```
|
||||
|
||||
This list of patches will probably include one that claims to
|
||||
make the V8 API backwards-compatible with a previous version of
|
||||
V8. Unfortunately, those patches almost always change the V8 API
|
||||
in a way that is incompatible with Chromium.
|
||||
|
||||
It's usually easier to update Node to work without the
|
||||
compatibility patch than to update Chromium to work with the
|
||||
compatibility patch, so it's recommended to revert the
|
||||
compatibility patch and fix any errors that arise when compiling
|
||||
Node.
|
||||
|
||||
## Update Electron's `DEPS` file
|
||||
|
||||
Update the `DEPS` file in the root of
|
||||
[electron/electron](https://github.com/electron/electron) to
|
||||
point to the git hash of the updated Node.
|
||||
|
||||
## Notes
|
||||
|
||||
- Node maintains its own fork of V8
|
||||
- They backport a small amount of things as needed
|
||||
- Documentation in Node about how [they work with V8](https://nodejs.org/api/v8.html)
|
||||
- We update code such that we only use one copy of V8 across all of Electron
|
||||
- E.g Electron, Chromium, and Node.js
|
||||
- We don’t track upstream closely due to logistics:
|
||||
- Upstream uses multiple repos and so merging into a single repo
|
||||
would result in lost history. So we only update when we’re planning
|
||||
a Node version bump in Electron.
|
||||
- Chromium is large and time-consuming to update, so we typically
|
||||
choose the Node version based on which of its releases has a version
|
||||
of V8 that’s closest to the version in Chromium that we’re using.
|
||||
- We sometimes have to wait for the next periodic Node release
|
||||
because it will sync more closely with the version of V8 in the new Chromium
|
||||
- Electron keeps all its patches in the repo because it’s simpler than
|
||||
maintaining different repos for patches for each upstream project.
|
||||
- Crashpad, Node.js, Chromium, Skia etc. patches are all kept in the same place
|
||||
- Building Node:
|
||||
- We maintain our own GN build files for Node.js to make it easier to ensure
|
||||
that eevrything is built with the same compiler flags.
|
||||
This means that every time we upgrade Node.js we have to do a modest amount of
|
||||
work to synchronize the GN files with the upstream GYP files.
|
||||
33
docs/faq.md
33
docs/faq.md
@@ -43,26 +43,14 @@ use HTML5 APIs which are already available in browsers. Good candidates are
|
||||
[Storage API][storage], [`localStorage`][local-storage],
|
||||
[`sessionStorage`][session-storage], and [IndexedDB][indexed-db].
|
||||
|
||||
Or you can use the IPC system, which is specific to Electron, to store objects
|
||||
in the main process as a global variable, and then to access them from the
|
||||
renderers through the `remote` property of `electron` module:
|
||||
|
||||
```javascript
|
||||
// In the main process.
|
||||
global.sharedObject = {
|
||||
someProperty: 'default value'
|
||||
}
|
||||
```
|
||||
|
||||
```javascript
|
||||
// In page 1.
|
||||
require('electron').remote.getGlobal('sharedObject').someProperty = 'new value'
|
||||
```
|
||||
|
||||
```javascript
|
||||
// In page 2.
|
||||
console.log(require('electron').remote.getGlobal('sharedObject').someProperty)
|
||||
```
|
||||
Alternatively, you can use the IPC primitives that are provided by Electron. To
|
||||
share data between the main and renderer processes, you can use the
|
||||
[`ipcMain`](api/ipc-main.md) and [`ipcRenderer`](api/ipc-renderer.md) modules.
|
||||
To communicate directly between web pages, you can send a
|
||||
[`MessagePort`][message-port] from one to the other, possibly via the main process
|
||||
using [`ipcRenderer.postMessage()`](api/ipc-renderer.md#ipcrendererpostmessagechannel-message-transfer).
|
||||
Subsequent communication over message ports is direct and does not detour through
|
||||
the main process.
|
||||
|
||||
## My app's tray disappeared after a few minutes.
|
||||
|
||||
@@ -107,7 +95,7 @@ To solve this, you can turn off node integration in Electron:
|
||||
```javascript
|
||||
// In the main process.
|
||||
const { BrowserWindow } = require('electron')
|
||||
let win = new BrowserWindow({
|
||||
const win = new BrowserWindow({
|
||||
webPreferences: {
|
||||
nodeIntegration: false
|
||||
}
|
||||
@@ -155,7 +143,7 @@ To achieve this goal, set the background in the constructor for [BrowserWindow][
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
let win = new BrowserWindow({
|
||||
const win = new BrowserWindow({
|
||||
backgroundColor: '#fff'
|
||||
})
|
||||
```
|
||||
@@ -171,5 +159,6 @@ Notice that just setting the background in the CSS does not have the desired eff
|
||||
[local-storage]: https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage
|
||||
[session-storage]: https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage
|
||||
[indexed-db]: https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API
|
||||
[message-port]: https://developer.mozilla.org/en-US/docs/Web/API/MessagePort
|
||||
[browser-window]: api/browser-window.md
|
||||
[subpixel rendering example]: images/subpixel-rendering-screenshot.gif
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
# Electron App Feedback Program
|
||||
|
||||
Electron is working on building a streamlined release process and having faster releases. To help with that, we have the App Feedback Program for large-scale Electron apps to test our beta releases and report app-specific issues to the Electron team. We use this program to help us prioritize work and get applications upgraded to the next stable release as soon as possible. There are a few requirements we expect from participants, such as attending short, online weekly check-ins. Please visit the [blog post](https://electronjs.org/blog/app-feedback-program) for details and sign-up.
|
||||
@@ -38,11 +38,11 @@ process of the web page must communicate with the main process to request that
|
||||
the main process perform those operations.
|
||||
|
||||
> #### Aside: Communication Between Processes
|
||||
> In Electron, we have several ways to communicate between the main process
|
||||
and renderer processes, such as [`ipcRenderer`](../api/ipc-renderer.md) and
|
||||
[`ipcMain`](../api/ipc-main.md) modules for sending messages, and the
|
||||
[remote](../api/remote.md) module for RPC style communication. There is also
|
||||
an FAQ entry on [how to share data between web pages][share-data].
|
||||
> In Electron, communicating between the main process and renderer processes,
|
||||
> is done through the [`ipcRenderer`](../api/ipc-renderer.md) and
|
||||
> [`ipcMain`](../api/ipc-main.md) modules. There is also an FAQ entry on [how
|
||||
> to share data between web pages][share-data].
|
||||
|
||||
|
||||
## Using Electron APIs
|
||||
|
||||
@@ -71,20 +71,26 @@ const win = new BrowserWindow()
|
||||
```
|
||||
|
||||
Since communication between the processes is possible, a renderer process
|
||||
can call upon the main process to perform tasks. Electron comes with a
|
||||
module called `remote` that exposes APIs usually only available on the
|
||||
main process. In order to create a `BrowserWindow` from a renderer process,
|
||||
we'd use the remote as a middle-man:
|
||||
can call upon the main process to perform tasks through IPC.
|
||||
|
||||
```javascript
|
||||
// This will work in a renderer process, but be `undefined` in the
|
||||
// main process:
|
||||
const { remote } = require('electron')
|
||||
const { BrowserWindow } = remote
|
||||
// In the main process:
|
||||
const { ipcMain } = require('electron')
|
||||
|
||||
const win = new BrowserWindow()
|
||||
ipcMain.handle('perform-action', (event, ...args) => {
|
||||
// ... do something on behalf of the renderer ...
|
||||
})
|
||||
|
||||
// In the renderer process:
|
||||
const { ipcRenderer } = require('electron')
|
||||
|
||||
ipcRenderer.invoke('perform-action', ...args)
|
||||
```
|
||||
|
||||
Note that code in the renderer may not be trustworthy, so it's important
|
||||
to carefully validate in the main process requests that come from renderers,
|
||||
especially if they host third-party content.
|
||||
|
||||
## Using Node.js APIs
|
||||
|
||||
Electron exposes full access to Node.js both in the main and the renderer
|
||||
|
||||
@@ -15,7 +15,7 @@ can open them programmatically by calling the `openDevTools()` API on the
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
|
||||
let win = new BrowserWindow()
|
||||
const win = new BrowserWindow()
|
||||
win.webContents.openDevTools()
|
||||
```
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ fs.readdirSync('/path/to/example.asar')
|
||||
Use a module from the archive:
|
||||
|
||||
```javascript
|
||||
require('/path/to/example.asar/dir/module.js')
|
||||
require('./path/to/example.asar/dir/module.js')
|
||||
```
|
||||
|
||||
You can also display a web page in an `asar` archive with `BrowserWindow`:
|
||||
|
||||
@@ -9,9 +9,9 @@ const childProcess = require('child_process')
|
||||
const electronPath = require('electron')
|
||||
|
||||
// spawn the process
|
||||
let env = { /* ... */ }
|
||||
let stdio = ['inherit', 'inherit', 'inherit', 'ipc']
|
||||
let appProcess = childProcess.spawn(electronPath, ['./app'], { stdio, env })
|
||||
const env = { /* ... */ }
|
||||
const stdio = ['inherit', 'inherit', 'inherit', 'ipc']
|
||||
const appProcess = childProcess.spawn(electronPath, ['./app'], { stdio, env })
|
||||
|
||||
// listen for IPC messages from the app
|
||||
appProcess.on('message', (msg) => {
|
||||
@@ -50,7 +50,7 @@ class TestDriver {
|
||||
// handle rpc responses
|
||||
this.process.on('message', (message) => {
|
||||
// pop the handler
|
||||
let rpcCall = this.rpcCalls[message.msgId]
|
||||
const rpcCall = this.rpcCalls[message.msgId]
|
||||
if (!rpcCall) return
|
||||
this.rpcCalls[message.msgId] = null
|
||||
// reject/resolve
|
||||
@@ -70,7 +70,7 @@ class TestDriver {
|
||||
// to use: driver.rpc('method', 1, 2, 3).then(...)
|
||||
async rpc (cmd, ...args) {
|
||||
// send rpc request
|
||||
let msgId = this.rpcCalls.length
|
||||
const msgId = this.rpcCalls.length
|
||||
this.process.send({ msgId, cmd, args })
|
||||
return new Promise((resolve, reject) => this.rpcCalls.push({ resolve, reject }))
|
||||
}
|
||||
@@ -92,10 +92,10 @@ async function onMessage ({ msgId, cmd, args }) {
|
||||
let method = METHODS[cmd]
|
||||
if (!method) method = () => new Error('Invalid method: ' + cmd)
|
||||
try {
|
||||
let resolve = await method(...args)
|
||||
const resolve = await method(...args)
|
||||
process.send({ msgId, resolve })
|
||||
} catch (err) {
|
||||
let reject = {
|
||||
const reject = {
|
||||
message: err.message,
|
||||
stack: err.stack,
|
||||
name: err.name
|
||||
@@ -119,7 +119,7 @@ Then, in your test suite, you can use your test-driver as follows:
|
||||
const test = require('ava')
|
||||
const electronPath = require('electron')
|
||||
|
||||
let app = new TestDriver({
|
||||
const app = new TestDriver({
|
||||
path: electronPath,
|
||||
args: ['./app'],
|
||||
env: {
|
||||
|
||||
@@ -100,6 +100,25 @@ To see all of this in action, check out Electron Fiddle's source code,
|
||||
[especially its `electron-forge` configuration
|
||||
file](https://github.com/electron/fiddle/blob/master/forge.config.js).
|
||||
|
||||
If you plan to access the microphone or camera within your app using Electron's APIs, you'll also
|
||||
need to add the following entitlements:
|
||||
|
||||
```xml
|
||||
<key>com.apple.security.device.audio-input</key>
|
||||
<true/>
|
||||
<key>com.apple.security.device.camera</key>
|
||||
<true/>
|
||||
```
|
||||
|
||||
If these are not present in your app's entitlements when you invoke, for example:
|
||||
|
||||
```js
|
||||
const { systemPreferences } = require('electron')
|
||||
|
||||
const microphone = systemPreferences.askForMediaAccess('microphone')
|
||||
```
|
||||
|
||||
Your app may crash. See the Resource Access section in [Hardened Runtime](https://developer.apple.com/documentation/security/hardened_runtime) for more information and entitlements you may need.
|
||||
|
||||
## `electron-builder`
|
||||
|
||||
|
||||
@@ -4,15 +4,17 @@
|
||||
* We strive for weekly beta releases, however we often release more betas than scheduled.
|
||||
* All dates are our goals but there may be reasons for adjusting the stable deadline, such as security bugs.
|
||||
* Take a look at the [5.0.0 Timeline blog post](https://electronjs.org/blog/electron-5-0-timeline) for info about publicizing our release dates.
|
||||
* Since Electron 6.0, we've been targetting every other Chromium version and releasing our stable on the same day as Chrome stable. You can reference Chromium's release schedule [here](https://chromiumdash.appspot.com/schedule). See [Electron's new release cadence blog post](https://www.electronjs.org/blog/12-week-cadence) for more details on our release schedule.
|
||||
|
||||
| Version | -beta.1 | Stable | Chrome | Node |
|
||||
| ------- | ------- | ------ | ------ | ---- |
|
||||
| 2.0.0 | 2018-02-21 | 2018-05-01 | M61 | v8 |
|
||||
| 3.0.0 | 2018-06-21 | 2018-09-18 | M66 | v10 |
|
||||
| 4.0.0 | 2018-10-11 | 2018-12-20 | M69 | v10 |
|
||||
| 5.0.0 | 2019-01-22 | 2019-04-24 | M73 | v12 |
|
||||
| 6.0.0 | 2019-05-01 | 2019-07-30 | M76 | v12 |
|
||||
| 7.0.0 | 2019-08-01 | 2019-10-22 | M78 | v12 |
|
||||
| 8.0.0 | 2019-10-24 | 2020-02-04 | M80 | v12 |
|
||||
| 9.0.0 | 2020-02-06 | 2020-05-19 | M83 | v12 |
|
||||
| 10.0.0 | TBD | TBD | TBD | TBD |
|
||||
| 2.0.0 | 2018-02-21 | 2018-05-01 | M61 | v8.9 |
|
||||
| 3.0.0 | 2018-06-21 | 2018-09-18 | M66 | v10.2 |
|
||||
| 4.0.0 | 2018-10-11 | 2018-12-20 | M69 | v10.11 |
|
||||
| 5.0.0 | 2019-01-22 | 2019-04-24 | M73 | v12.0 |
|
||||
| 6.0.0 | 2019-05-01 | 2019-07-30 | M76 | v12.4 |
|
||||
| 7.0.0 | 2019-08-01 | 2019-10-22 | M78 | v12.8 |
|
||||
| 8.0.0 | 2019-10-24 | 2020-02-04 | M80 | v12.13 |
|
||||
| 9.0.0 | 2020-02-06 | 2020-05-19 | M83 | v12.14 |
|
||||
| 10.0.0 | 2020-05-21 | 2020-08-25 | M85 | v12.x |
|
||||
| 11.0.0 | TBD | TBD | TBD| TBD |
|
||||
|
||||
@@ -87,7 +87,7 @@ e.g. `2.0.1`.
|
||||
|
||||
Specifically, the above means:
|
||||
|
||||
1. Admitting non-breaking-API changes before Week 3 in the beta cycle is okay, even if those changes have the potential to cause moderate side-affects
|
||||
1. Admitting non-breaking-API changes before Week 3 in the beta cycle is okay, even if those changes have the potential to cause moderate side-effects
|
||||
2. Admitting feature-flagged changes, that do not otherwise alter existing code paths, at most points in the beta cycle is okay. Users can explicitly enable those flags in their apps.
|
||||
3. Admitting features of any sort after Week 3 in the beta cycle is 👎 without a very good reason.
|
||||
|
||||
@@ -139,7 +139,7 @@ We seek to increase clarity at all levels of the update and releases process. St
|
||||
* Commits that would result in a semver **minor** bump must start with `feat:`.
|
||||
* Commits that would result in a semver **patch** bump must start with `fix:`.
|
||||
|
||||
* We allow squashing of commits, provided that the squashed message adheres the the above message format.
|
||||
* We allow squashing of commits, provided that the squashed message adheres to the above message format.
|
||||
* It is acceptable for some commits in a pull request to not include a semantic prefix, as long as the pull request title contains a meaningful encompassing semantic message.
|
||||
|
||||
# Versioned `master`
|
||||
|
||||
@@ -44,23 +44,10 @@ run the main process. An example of your `package.json` might look like this:
|
||||
```
|
||||
|
||||
__Note__: If the `main` field is not present in `package.json`, Electron will
|
||||
attempt to load an `index.js` (as Node.js does). If this was actually
|
||||
a simple Node application, you would add a `start` script that instructs `node`
|
||||
to execute the current package:
|
||||
attempt to load an `index.js` (as Node.js does).
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "your-app",
|
||||
"version": "0.1.0",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"start": "node ."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Turning this Node application into an Electron application is quite simple - we
|
||||
merely replace the `node` runtime with the `electron` runtime.
|
||||
By default, `npm start` would run the main script with Node.js. in order to make
|
||||
it run with Electron, you can add a `start` script:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -109,7 +96,7 @@ const { app, BrowserWindow } = require('electron')
|
||||
|
||||
function createWindow () {
|
||||
// Create the browser window.
|
||||
let win = new BrowserWindow({
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
@@ -154,10 +141,10 @@ function createWindow () {
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
// Quit when all windows are closed, except on macOS. There, it's common
|
||||
// for applications and their menu bar to stay active until the user quits
|
||||
// explicitly with Cmd + Q.
|
||||
app.on('window-all-closed', () => {
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
|
||||
@@ -37,18 +37,18 @@ inAppPurchase.on('transactions-updated', (event, transactions) => {
|
||||
|
||||
// Check each transaction.
|
||||
transactions.forEach(function (transaction) {
|
||||
let payment = transaction.payment
|
||||
const payment = transaction.payment
|
||||
|
||||
switch (transaction.transactionState) {
|
||||
case 'purchasing':
|
||||
console.log(`Purchasing ${payment.productIdentifier}...`)
|
||||
break
|
||||
case 'purchased':
|
||||
|
||||
case 'purchased': {
|
||||
console.log(`${payment.productIdentifier} purchased.`)
|
||||
|
||||
// Get the receipt url.
|
||||
let receiptURL = inAppPurchase.getReceiptURL()
|
||||
const receiptURL = inAppPurchase.getReceiptURL()
|
||||
|
||||
console.log(`Receipt URL: ${receiptURL}`)
|
||||
|
||||
@@ -62,6 +62,8 @@ inAppPurchase.on('transactions-updated', (event, transactions) => {
|
||||
inAppPurchase.finishTransactionByDate(transaction.transactionDate)
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
case 'failed':
|
||||
|
||||
console.log(`Failed to purchase ${payment.productIdentifier}.`)
|
||||
@@ -105,8 +107,8 @@ inAppPurchase.getProducts(PRODUCT_IDS).then(products => {
|
||||
})
|
||||
|
||||
// Ask the user which product he/she wants to purchase.
|
||||
let selectedProduct = products[0]
|
||||
let selectedQuantity = 1
|
||||
const selectedProduct = products[0]
|
||||
const selectedQuantity = 1
|
||||
|
||||
// Purchase the selected product.
|
||||
inAppPurchase.purchaseProduct(selectedProduct.productIdentifier, selectedQuantity).then(isProductValid => {
|
||||
|
||||
@@ -10,7 +10,7 @@ so the `nodeIntegrationInWorker` option should be set to `true` in
|
||||
`webPreferences`.
|
||||
|
||||
```javascript
|
||||
let win = new BrowserWindow({
|
||||
const win = new BrowserWindow({
|
||||
webPreferences: {
|
||||
nodeIntegrationInWorker: true
|
||||
}
|
||||
@@ -44,7 +44,7 @@ loads no native modules after the Web Workers get started.
|
||||
process.dlopen = () => {
|
||||
throw new Error('Load native module is not safe')
|
||||
}
|
||||
let worker = new Worker('script.js')
|
||||
const worker = new Worker('script.js')
|
||||
```
|
||||
|
||||
[web-workers]: https://developer.mozilla.org/en/docs/Web/API/Web_Workers_API/Using_web_workers
|
||||
|
||||
@@ -10,7 +10,7 @@ you want to show Notifications in the main process please check out the
|
||||
[Notification](../api/notification.md) module.
|
||||
|
||||
```javascript
|
||||
let myNotification = new Notification('Title', {
|
||||
const myNotification = new Notification('Title', {
|
||||
body: 'Lorem Ipsum Dolor Sit Amet'
|
||||
})
|
||||
|
||||
|
||||
@@ -39,6 +39,29 @@ will be started with the path of the file added as a command line argument.
|
||||
|
||||
## macOS Notes
|
||||
|
||||
### Adding the Recent Documents list to the application menu:
|
||||
|
||||
![macOS Recent Documents menu item][menu-item-image]
|
||||
|
||||
You can add menu items to access and clear recent documents by adding the following code snippet to your menu's template.
|
||||
|
||||
```json
|
||||
{
|
||||
"submenu":[
|
||||
{
|
||||
"label":"Open Recent",
|
||||
"role":"recentdocuments",
|
||||
"submenu":[
|
||||
{
|
||||
"label":"Clear Recent",
|
||||
"role":"clearrecentdocuments"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
When a file is requested from the recent documents menu, the `open-file` event
|
||||
of `app` module will be emitted for it.
|
||||
|
||||
@@ -47,3 +70,4 @@ of `app` module will be emitted for it.
|
||||
[addrecentdocument]: ../api/app.md#appaddrecentdocumentpath-macos-windows
|
||||
[clearrecentdocuments]: ../api/app.md#appclearrecentdocuments-macos-windows
|
||||
[app-registration]: https://msdn.microsoft.com/en-us/library/cc144104(VS.85).aspx
|
||||
[menu-item-image]: https://user-images.githubusercontent.com/3168941/33003655-ea601c3a-cd70-11e7-97fa-7c062149cfb1.png
|
||||
|
||||
@@ -58,9 +58,9 @@ threshold, we will attempt to support backwards compatibility beyond two version
|
||||
until the maintainers feel the maintenance burden is too high to continue doing so.
|
||||
|
||||
### Currently supported versions
|
||||
- 8.1.x
|
||||
- 7.1.x
|
||||
- 6.1.x
|
||||
- 9.x.y
|
||||
- 8.x.y
|
||||
- 7.x.y
|
||||
|
||||
### End-of-life
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ app.commandLine.appendSwitch('ppapi-flash-path', path.join(__dirname, pluginName
|
||||
app.commandLine.appendSwitch('ppapi-flash-version', '17.0.0.169')
|
||||
|
||||
app.whenReady().then(() => {
|
||||
let win = new BrowserWindow({
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
|
||||
@@ -146,7 +146,7 @@ const options = {
|
||||
}
|
||||
}
|
||||
|
||||
let client = webdriverio.remote(options)
|
||||
const client = webdriverio.remote(options)
|
||||
|
||||
client
|
||||
.init()
|
||||
|
||||
@@ -149,7 +149,7 @@ To set the overlay icon for a window, you can use the
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
let win = new BrowserWindow()
|
||||
const win = new BrowserWindow()
|
||||
win.setOverlayIcon('path/to/overlay.png', 'Description for overlay')
|
||||
```
|
||||
|
||||
@@ -168,7 +168,7 @@ To flash the BrowserWindow taskbar button, you can use the
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
let win = new BrowserWindow()
|
||||
const win = new BrowserWindow()
|
||||
win.once('focus', () => win.flashFrame(false))
|
||||
win.flashFrame(true)
|
||||
```
|
||||
|
||||
@@ -54,8 +54,11 @@ template("electron_extra_paks") {
|
||||
])
|
||||
output = "${invoker.output_dir}/resources.pak"
|
||||
sources = [
|
||||
"$root_gen_dir/chrome/dev_ui_browser_resources.pak",
|
||||
"$root_gen_dir/components/components_resources.pak",
|
||||
"$root_gen_dir/content/browser/resources/media/media_internals_resources.pak",
|
||||
"$root_gen_dir/content/browser/tracing/tracing_resources.pak",
|
||||
"$root_gen_dir/content/browser/webrtc/resources/webrtc_internals_resources.pak",
|
||||
"$root_gen_dir/content/content_resources.pak",
|
||||
"$root_gen_dir/content/dev_ui_content_resources.pak",
|
||||
"$root_gen_dir/mojo/public/js/mojo_bindings_resources.pak",
|
||||
@@ -65,10 +68,13 @@ template("electron_extra_paks") {
|
||||
"$target_gen_dir/electron_resources.pak",
|
||||
]
|
||||
deps = [
|
||||
"//chrome/browser:dev_ui_browser_resources",
|
||||
"//components/resources",
|
||||
"//content:content_resources",
|
||||
"//content:dev_ui_content_resources",
|
||||
"//content/browser/resources/media:media_internals_resources",
|
||||
"//content/browser/tracing:resources",
|
||||
"//content/browser/webrtc/resources",
|
||||
"//electron:resources",
|
||||
"//mojo/public/js:resources",
|
||||
"//net:net_resources",
|
||||
|
||||
@@ -75,4 +75,9 @@
|
||||
<message name="IDS_ACCEPT_LANGUAGES" use_name_for_id="true">
|
||||
en-US,en
|
||||
</message>
|
||||
<if expr="is_win">
|
||||
<message name="IDS_UTILITY_PROCESS_UTILITY_WIN_NAME" desc="The name of the utility process used to handle Windows utility operations.">
|
||||
Windows Utilities
|
||||
</message>
|
||||
</if>
|
||||
</grit-part>
|
||||
|
||||
@@ -43,7 +43,6 @@ auto_filenames = {
|
||||
"docs/api/power-monitor.md",
|
||||
"docs/api/power-save-blocker.md",
|
||||
"docs/api/process.md",
|
||||
"docs/api/protocol-ns.md",
|
||||
"docs/api/protocol.md",
|
||||
"docs/api/remote.md",
|
||||
"docs/api/sandbox-option.md",
|
||||
@@ -136,13 +135,12 @@ auto_filenames = {
|
||||
|
||||
sandbox_bundle_deps = [
|
||||
"lib/browser/api/module-names.ts",
|
||||
"lib/common/api/clipboard.js",
|
||||
"lib/common/api/clipboard.ts",
|
||||
"lib/common/api/deprecate.ts",
|
||||
"lib/common/api/module-list.ts",
|
||||
"lib/common/api/native-image.js",
|
||||
"lib/common/api/shell.js",
|
||||
"lib/common/api/native-image.ts",
|
||||
"lib/common/api/shell.ts",
|
||||
"lib/common/define-properties.ts",
|
||||
"lib/common/electron-binding-setup.ts",
|
||||
"lib/common/type-utils.ts",
|
||||
"lib/common/web-view-methods.ts",
|
||||
"lib/common/webpack-globals-provider.ts",
|
||||
@@ -150,7 +148,7 @@ auto_filenames = {
|
||||
"lib/renderer/api/crash-reporter.ts",
|
||||
"lib/renderer/api/desktop-capturer.ts",
|
||||
"lib/renderer/api/ipc-renderer.ts",
|
||||
"lib/renderer/api/remote.js",
|
||||
"lib/renderer/api/remote.ts",
|
||||
"lib/renderer/api/web-frame.ts",
|
||||
"lib/renderer/inspector.ts",
|
||||
"lib/renderer/ipc-renderer-internal-utils.ts",
|
||||
@@ -167,61 +165,65 @@ auto_filenames = {
|
||||
"lib/renderer/window-setup.ts",
|
||||
"lib/sandboxed_renderer/api/exports/electron.ts",
|
||||
"lib/sandboxed_renderer/api/module-list.ts",
|
||||
"lib/sandboxed_renderer/init.js",
|
||||
"lib/sandboxed_renderer/init.ts",
|
||||
"package.json",
|
||||
"tsconfig.electron.json",
|
||||
"tsconfig.json",
|
||||
"typings/internal-ambient.d.ts",
|
||||
"typings/internal-electron.d.ts",
|
||||
]
|
||||
|
||||
isolated_bundle_deps = [
|
||||
"lib/common/electron-binding-setup.ts",
|
||||
"lib/isolated_renderer/init.js",
|
||||
"lib/isolated_renderer/init.ts",
|
||||
"lib/renderer/web-view/web-view-constants.ts",
|
||||
"lib/renderer/web-view/web-view-element.ts",
|
||||
"package.json",
|
||||
"tsconfig.electron.json",
|
||||
"tsconfig.json",
|
||||
"typings/internal-ambient.d.ts",
|
||||
"typings/internal-electron.d.ts",
|
||||
]
|
||||
|
||||
browser_bundle_deps = [
|
||||
"lib/browser/api/app.ts",
|
||||
"lib/browser/api/auto-updater.js",
|
||||
"lib/browser/api/auto-updater/auto-updater-native.js",
|
||||
"lib/browser/api/auto-updater/auto-updater-win.js",
|
||||
"lib/browser/api/auto-updater/squirrel-update-win.js",
|
||||
"lib/browser/api/browser-view.js",
|
||||
"lib/browser/api/browser-window.js",
|
||||
"lib/browser/api/content-tracing.js",
|
||||
"lib/browser/api/auto-updater.ts",
|
||||
"lib/browser/api/auto-updater/auto-updater-native.ts",
|
||||
"lib/browser/api/auto-updater/auto-updater-win.ts",
|
||||
"lib/browser/api/auto-updater/squirrel-update-win.ts",
|
||||
"lib/browser/api/base-window.ts",
|
||||
"lib/browser/api/browser-view.ts",
|
||||
"lib/browser/api/browser-window.ts",
|
||||
"lib/browser/api/content-tracing.ts",
|
||||
"lib/browser/api/crash-reporter.ts",
|
||||
"lib/browser/api/dialog.js",
|
||||
"lib/browser/api/desktop-capturer.ts",
|
||||
"lib/browser/api/dialog.ts",
|
||||
"lib/browser/api/exports/electron.ts",
|
||||
"lib/browser/api/global-shortcut.js",
|
||||
"lib/browser/api/in-app-purchase.js",
|
||||
"lib/browser/api/global-shortcut.ts",
|
||||
"lib/browser/api/in-app-purchase.ts",
|
||||
"lib/browser/api/ipc-main.ts",
|
||||
"lib/browser/api/menu-item-roles.js",
|
||||
"lib/browser/api/menu-item.js",
|
||||
"lib/browser/api/menu-utils.js",
|
||||
"lib/browser/api/menu.js",
|
||||
"lib/browser/api/menu-item-roles.ts",
|
||||
"lib/browser/api/menu-item.ts",
|
||||
"lib/browser/api/menu-utils.ts",
|
||||
"lib/browser/api/menu.ts",
|
||||
"lib/browser/api/message-channel.ts",
|
||||
"lib/browser/api/module-list.ts",
|
||||
"lib/browser/api/native-theme.ts",
|
||||
"lib/browser/api/net-log.js",
|
||||
"lib/browser/api/net.js",
|
||||
"lib/browser/api/notification.js",
|
||||
"lib/browser/api/net-log.ts",
|
||||
"lib/browser/api/net.ts",
|
||||
"lib/browser/api/notification.ts",
|
||||
"lib/browser/api/power-monitor.ts",
|
||||
"lib/browser/api/power-save-blocker.js",
|
||||
"lib/browser/api/power-save-blocker.ts",
|
||||
"lib/browser/api/protocol.ts",
|
||||
"lib/browser/api/screen.ts",
|
||||
"lib/browser/api/session.js",
|
||||
"lib/browser/api/session.ts",
|
||||
"lib/browser/api/system-preferences.ts",
|
||||
"lib/browser/api/top-level-window.js",
|
||||
"lib/browser/api/touch-bar.js",
|
||||
"lib/browser/api/tray.js",
|
||||
"lib/browser/api/view.js",
|
||||
"lib/browser/api/views/image-view.js",
|
||||
"lib/browser/api/web-contents-view.js",
|
||||
"lib/browser/api/web-contents.js",
|
||||
"lib/browser/chrome-extension-shim.js",
|
||||
"lib/browser/api/touch-bar.ts",
|
||||
"lib/browser/api/tray.ts",
|
||||
"lib/browser/api/view.ts",
|
||||
"lib/browser/api/views/image-view.ts",
|
||||
"lib/browser/api/web-contents-view.ts",
|
||||
"lib/browser/api/web-contents.ts",
|
||||
"lib/browser/chrome-extension-shim.ts",
|
||||
"lib/browser/default-menu.ts",
|
||||
"lib/browser/desktop-capturer.ts",
|
||||
"lib/browser/devtools.ts",
|
||||
@@ -232,18 +234,16 @@ auto_filenames = {
|
||||
"lib/browser/ipc-main-internal-utils.ts",
|
||||
"lib/browser/ipc-main-internal.ts",
|
||||
"lib/browser/message-port-main.ts",
|
||||
"lib/browser/navigation-controller.js",
|
||||
"lib/browser/navigation-controller.ts",
|
||||
"lib/browser/remote/objects-registry.ts",
|
||||
"lib/browser/remote/server.ts",
|
||||
"lib/browser/rpc-server.js",
|
||||
"lib/browser/utils.ts",
|
||||
"lib/common/api/clipboard.js",
|
||||
"lib/browser/rpc-server.ts",
|
||||
"lib/common/api/clipboard.ts",
|
||||
"lib/common/api/deprecate.ts",
|
||||
"lib/common/api/module-list.ts",
|
||||
"lib/common/api/native-image.js",
|
||||
"lib/common/api/shell.js",
|
||||
"lib/common/api/native-image.ts",
|
||||
"lib/common/api/shell.ts",
|
||||
"lib/common/define-properties.ts",
|
||||
"lib/common/electron-binding-setup.ts",
|
||||
"lib/common/init.ts",
|
||||
"lib/common/parse-features-string.ts",
|
||||
"lib/common/reset-search-paths.ts",
|
||||
@@ -255,29 +255,31 @@ auto_filenames = {
|
||||
"package.json",
|
||||
"tsconfig.electron.json",
|
||||
"tsconfig.json",
|
||||
"typings/internal-ambient.d.ts",
|
||||
"typings/internal-electron.d.ts",
|
||||
]
|
||||
|
||||
renderer_bundle_deps = [
|
||||
"lib/browser/api/module-names.ts",
|
||||
"lib/common/api/clipboard.js",
|
||||
"lib/common/api/clipboard.ts",
|
||||
"lib/common/api/deprecate.ts",
|
||||
"lib/common/api/module-list.ts",
|
||||
"lib/common/api/native-image.js",
|
||||
"lib/common/api/shell.js",
|
||||
"lib/common/api/native-image.ts",
|
||||
"lib/common/api/shell.ts",
|
||||
"lib/common/define-properties.ts",
|
||||
"lib/common/electron-binding-setup.ts",
|
||||
"lib/common/init.ts",
|
||||
"lib/common/reset-search-paths.ts",
|
||||
"lib/common/type-utils.ts",
|
||||
"lib/common/web-view-methods.ts",
|
||||
"lib/common/webpack-globals-provider.ts",
|
||||
"lib/common/webpack-provider.ts",
|
||||
"lib/renderer/api/context-bridge.ts",
|
||||
"lib/renderer/api/crash-reporter.ts",
|
||||
"lib/renderer/api/desktop-capturer.ts",
|
||||
"lib/renderer/api/exports/electron.ts",
|
||||
"lib/renderer/api/ipc-renderer.ts",
|
||||
"lib/renderer/api/module-list.ts",
|
||||
"lib/renderer/api/remote.js",
|
||||
"lib/renderer/api/remote.ts",
|
||||
"lib/renderer/api/web-frame.ts",
|
||||
"lib/renderer/init.ts",
|
||||
"lib/renderer/inspector.ts",
|
||||
@@ -292,41 +294,54 @@ auto_filenames = {
|
||||
"lib/renderer/web-view/web-view-element.ts",
|
||||
"lib/renderer/web-view/web-view-impl.ts",
|
||||
"lib/renderer/web-view/web-view-init.ts",
|
||||
"lib/renderer/webpack-provider.ts",
|
||||
"lib/renderer/window-setup.ts",
|
||||
"package.json",
|
||||
"tsconfig.electron.json",
|
||||
"tsconfig.json",
|
||||
"typings/internal-ambient.d.ts",
|
||||
"typings/internal-electron.d.ts",
|
||||
]
|
||||
|
||||
worker_bundle_deps = [
|
||||
"lib/browser/api/module-names.ts",
|
||||
"lib/common/api/clipboard.js",
|
||||
"lib/common/api/clipboard.ts",
|
||||
"lib/common/api/deprecate.ts",
|
||||
"lib/common/api/module-list.ts",
|
||||
"lib/common/api/native-image.js",
|
||||
"lib/common/api/shell.js",
|
||||
"lib/common/api/native-image.ts",
|
||||
"lib/common/api/shell.ts",
|
||||
"lib/common/define-properties.ts",
|
||||
"lib/common/electron-binding-setup.ts",
|
||||
"lib/common/init.ts",
|
||||
"lib/common/reset-search-paths.ts",
|
||||
"lib/common/type-utils.ts",
|
||||
"lib/common/webpack-globals-provider.ts",
|
||||
"lib/common/webpack-provider.ts",
|
||||
"lib/renderer/api/context-bridge.ts",
|
||||
"lib/renderer/api/crash-reporter.ts",
|
||||
"lib/renderer/api/desktop-capturer.ts",
|
||||
"lib/renderer/api/exports/electron.ts",
|
||||
"lib/renderer/api/ipc-renderer.ts",
|
||||
"lib/renderer/api/module-list.ts",
|
||||
"lib/renderer/api/remote.js",
|
||||
"lib/renderer/api/remote.ts",
|
||||
"lib/renderer/api/web-frame.ts",
|
||||
"lib/renderer/ipc-renderer-internal-utils.ts",
|
||||
"lib/renderer/ipc-renderer-internal.ts",
|
||||
"lib/renderer/remote/callbacks-registry.ts",
|
||||
"lib/renderer/webpack-provider.ts",
|
||||
"lib/worker/init.js",
|
||||
"lib/worker/init.ts",
|
||||
"package.json",
|
||||
"tsconfig.electron.json",
|
||||
"tsconfig.json",
|
||||
"typings/internal-ambient.d.ts",
|
||||
"typings/internal-electron.d.ts",
|
||||
]
|
||||
|
||||
asar_bundle_deps = [
|
||||
"lib/asar/fs-wrapper.ts",
|
||||
"lib/asar/init.ts",
|
||||
"lib/common/webpack-provider.ts",
|
||||
"package.json",
|
||||
"tsconfig.electron.json",
|
||||
"tsconfig.json",
|
||||
"typings/internal-ambient.d.ts",
|
||||
"typings/internal-electron.d.ts",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -14,11 +14,11 @@ filenames = {
|
||||
|
||||
default_app_octicon_sources = [
|
||||
"node_modules/@primer/octicons/build/build.css",
|
||||
"node_modules/@primer/octicons/build/svg/gear.svg",
|
||||
"node_modules/@primer/octicons/build/svg/gift.svg",
|
||||
"node_modules/@primer/octicons/build/svg/gist.svg",
|
||||
"node_modules/@primer/octicons/build/svg/mark-github.svg",
|
||||
"node_modules/@primer/octicons/build/svg/star.svg",
|
||||
"node_modules/@primer/octicons/build/svg/book-24.svg",
|
||||
"node_modules/@primer/octicons/build/svg/code-square-24.svg",
|
||||
"node_modules/@primer/octicons/build/svg/gift-24.svg",
|
||||
"node_modules/@primer/octicons/build/svg/mark-github-16.svg",
|
||||
"node_modules/@primer/octicons/build/svg/star-fill-24.svg",
|
||||
]
|
||||
|
||||
lib_sources = [
|
||||
@@ -44,6 +44,8 @@ filenames = {
|
||||
"shell/browser/api/electron_api_app_mac.mm",
|
||||
"shell/browser/api/electron_api_auto_updater.cc",
|
||||
"shell/browser/api/electron_api_auto_updater.h",
|
||||
"shell/browser/api/electron_api_base_window.cc",
|
||||
"shell/browser/api/electron_api_base_window.h",
|
||||
"shell/browser/api/electron_api_browser_view.cc",
|
||||
"shell/browser/api/electron_api_browser_view.h",
|
||||
"shell/browser/api/electron_api_browser_window.cc",
|
||||
@@ -79,7 +81,6 @@ filenames = {
|
||||
"shell/browser/api/electron_api_native_theme.h",
|
||||
"shell/browser/api/electron_api_native_theme_mac.mm",
|
||||
"shell/browser/api/electron_api_net.cc",
|
||||
"shell/browser/api/electron_api_net.h",
|
||||
"shell/browser/api/electron_api_net_log.cc",
|
||||
"shell/browser/api/electron_api_net_log.h",
|
||||
"shell/browser/api/electron_api_notification.cc",
|
||||
@@ -102,8 +103,6 @@ filenames = {
|
||||
"shell/browser/api/electron_api_system_preferences.h",
|
||||
"shell/browser/api/electron_api_system_preferences_mac.mm",
|
||||
"shell/browser/api/electron_api_system_preferences_win.cc",
|
||||
"shell/browser/api/electron_api_top_level_window.cc",
|
||||
"shell/browser/api/electron_api_top_level_window.h",
|
||||
"shell/browser/api/electron_api_tray.cc",
|
||||
"shell/browser/api/electron_api_tray.h",
|
||||
"shell/browser/api/electron_api_url_loader.cc",
|
||||
@@ -357,8 +356,6 @@ filenames = {
|
||||
"shell/browser/ui/inspectable_web_contents.cc",
|
||||
"shell/browser/ui/inspectable_web_contents.h",
|
||||
"shell/browser/ui/inspectable_web_contents_delegate.h",
|
||||
"shell/browser/ui/inspectable_web_contents_impl.cc",
|
||||
"shell/browser/ui/inspectable_web_contents_impl.h",
|
||||
"shell/browser/ui/inspectable_web_contents_view.h",
|
||||
"shell/browser/ui/inspectable_web_contents_view_delegate.cc",
|
||||
"shell/browser/ui/inspectable_web_contents_view_delegate.h",
|
||||
@@ -401,6 +398,8 @@ filenames = {
|
||||
"shell/browser/ui/views/submenu_button.h",
|
||||
"shell/browser/ui/views/win_frame_view.cc",
|
||||
"shell/browser/ui/views/win_frame_view.h",
|
||||
"shell/browser/ui/webui/accessibility_ui.cc",
|
||||
"shell/browser/ui/webui/accessibility_ui.h",
|
||||
"shell/browser/ui/win/dialog_thread.cc",
|
||||
"shell/browser/ui/win/dialog_thread.h",
|
||||
"shell/browser/ui/win/electron_desktop_native_widget_aura.cc",
|
||||
@@ -525,6 +524,8 @@ filenames = {
|
||||
"shell/common/gin_helper/function_template_extensions.h",
|
||||
"shell/common/gin_helper/locker.cc",
|
||||
"shell/common/gin_helper/locker.h",
|
||||
"shell/common/gin_helper/microtasks_scope.cc",
|
||||
"shell/common/gin_helper/microtasks_scope.h",
|
||||
"shell/common/gin_helper/object_template_builder.cc",
|
||||
"shell/common/gin_helper/object_template_builder.h",
|
||||
"shell/common/gin_helper/persistent_dictionary.cc",
|
||||
@@ -578,8 +579,6 @@ filenames = {
|
||||
"shell/common/world_ids.h",
|
||||
"shell/renderer/api/context_bridge/object_cache.cc",
|
||||
"shell/renderer/api/context_bridge/object_cache.h",
|
||||
"shell/renderer/api/context_bridge/render_frame_function_store.cc",
|
||||
"shell/renderer/api/context_bridge/render_frame_function_store.h",
|
||||
"shell/renderer/api/electron_api_context_bridge.cc",
|
||||
"shell/renderer/api/electron_api_context_bridge.h",
|
||||
"shell/renderer/api/electron_api_crash_reporter_renderer.cc",
|
||||
|
||||
@@ -10,6 +10,7 @@ hunspell_dictionaries = [
|
||||
"//third_party/hunspell_dictionaries/en-AU-9-0.bdic",
|
||||
"//third_party/hunspell_dictionaries/en-CA-9-0.bdic",
|
||||
"//third_party/hunspell_dictionaries/en-GB-9-0.bdic",
|
||||
"//third_party/hunspell_dictionaries/en-GB-oxendict-9-0.bdic",
|
||||
"//third_party/hunspell_dictionaries/en-US-9-0.bdic",
|
||||
"//third_party/hunspell_dictionaries/es-ES-3-0.bdic",
|
||||
"//third_party/hunspell_dictionaries/et-EE-3-0.bdic",
|
||||
|
||||
814
lib/asar/fs-wrapper.ts
Normal file
814
lib/asar/fs-wrapper.ts
Normal file
@@ -0,0 +1,814 @@
|
||||
import { Buffer } from 'buffer';
|
||||
import * as path from 'path';
|
||||
import * as util from 'util';
|
||||
|
||||
const asar = process._linkedBinding('electron_common_asar');
|
||||
const v8Util = process._linkedBinding('electron_common_v8_util');
|
||||
|
||||
const Module = require('module');
|
||||
|
||||
const Promise: PromiseConstructor = global.Promise as any;
|
||||
|
||||
const envNoAsar = process.env.ELECTRON_NO_ASAR &&
|
||||
process.type !== 'browser' &&
|
||||
process.type !== 'renderer';
|
||||
const isAsarDisabled = () => process.noAsar || envNoAsar;
|
||||
|
||||
const internalBinding = (process as any).internalBinding;
|
||||
delete (process as any).internalBinding;
|
||||
|
||||
const nextTick = (functionToCall: Function, args: any[] = []) => {
|
||||
process.nextTick(() => functionToCall(...args));
|
||||
};
|
||||
|
||||
// Cache asar archive objects.
|
||||
const cachedArchives = new Map<string, NodeJS.AsarArchive>();
|
||||
|
||||
const getOrCreateArchive = (archivePath: string) => {
|
||||
const isCached = cachedArchives.has(archivePath);
|
||||
if (isCached) {
|
||||
return cachedArchives.get(archivePath);
|
||||
}
|
||||
|
||||
const newArchive = asar.createArchive(archivePath);
|
||||
if (!newArchive) return null;
|
||||
|
||||
cachedArchives.set(archivePath, newArchive);
|
||||
return newArchive;
|
||||
};
|
||||
|
||||
// Separate asar package's path from full path.
|
||||
const splitPath = (archivePathOrBuffer: string | Buffer) => {
|
||||
// Shortcut for disabled asar.
|
||||
if (isAsarDisabled()) return { isAsar: <const>false };
|
||||
|
||||
// Check for a bad argument type.
|
||||
let archivePath = archivePathOrBuffer;
|
||||
if (Buffer.isBuffer(archivePathOrBuffer)) {
|
||||
archivePath = archivePathOrBuffer.toString();
|
||||
}
|
||||
if (typeof archivePath !== 'string') return { isAsar: <const>false };
|
||||
|
||||
return asar.splitPath(path.normalize(archivePath));
|
||||
};
|
||||
|
||||
// Convert asar archive's Stats object to fs's Stats object.
|
||||
let nextInode = 0;
|
||||
|
||||
const uid = process.getuid != null ? process.getuid() : 0;
|
||||
const gid = process.getgid != null ? process.getgid() : 0;
|
||||
|
||||
const fakeTime = new Date();
|
||||
|
||||
const asarStatsToFsStats = function (stats: NodeJS.AsarFileStat) {
|
||||
const { Stats, constants } = require('fs');
|
||||
|
||||
let mode = constants.S_IROTH ^ constants.S_IRGRP ^ constants.S_IRUSR ^ constants.S_IWUSR;
|
||||
|
||||
if (stats.isFile) {
|
||||
mode ^= constants.S_IFREG;
|
||||
} else if (stats.isDirectory) {
|
||||
mode ^= constants.S_IFDIR;
|
||||
} else if (stats.isLink) {
|
||||
mode ^= constants.S_IFLNK;
|
||||
}
|
||||
|
||||
return new Stats(
|
||||
1, // dev
|
||||
mode, // mode
|
||||
1, // nlink
|
||||
uid,
|
||||
gid,
|
||||
0, // rdev
|
||||
undefined, // blksize
|
||||
++nextInode, // ino
|
||||
stats.size,
|
||||
undefined, // blocks,
|
||||
fakeTime.getTime(), // atim_msec
|
||||
fakeTime.getTime(), // mtim_msec
|
||||
fakeTime.getTime(), // ctim_msec
|
||||
fakeTime.getTime() // birthtim_msec
|
||||
);
|
||||
};
|
||||
|
||||
const enum AsarError {
|
||||
NOT_FOUND = 'NOT_FOUND',
|
||||
NOT_DIR = 'NOT_DIR',
|
||||
NO_ACCESS = 'NO_ACCESS',
|
||||
INVALID_ARCHIVE = 'INVALID_ARCHIVE'
|
||||
}
|
||||
|
||||
type AsarErrorObject = Error & { code?: string, errno?: number };
|
||||
|
||||
const createError = (errorType: AsarError, { asarPath, filePath }: { asarPath?: string, filePath?: string } = {}) => {
|
||||
let error: AsarErrorObject;
|
||||
switch (errorType) {
|
||||
case AsarError.NOT_FOUND:
|
||||
error = new Error(`ENOENT, ${filePath} not found in ${asarPath}`);
|
||||
error.code = 'ENOENT';
|
||||
error.errno = -2;
|
||||
break;
|
||||
case AsarError.NOT_DIR:
|
||||
error = new Error('ENOTDIR, not a directory');
|
||||
error.code = 'ENOTDIR';
|
||||
error.errno = -20;
|
||||
break;
|
||||
case AsarError.NO_ACCESS:
|
||||
error = new Error(`EACCES: permission denied, access '${filePath}'`);
|
||||
error.code = 'EACCES';
|
||||
error.errno = -13;
|
||||
break;
|
||||
case AsarError.INVALID_ARCHIVE:
|
||||
error = new Error(`Invalid package ${asarPath}`);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Invalid error type "${errorType}" passed to createError.`);
|
||||
}
|
||||
return error;
|
||||
};
|
||||
|
||||
const overrideAPISync = function (module: Record<string, any>, name: string, pathArgumentIndex?: number | null, fromAsync: boolean = false) {
|
||||
if (pathArgumentIndex == null) pathArgumentIndex = 0;
|
||||
const old = module[name];
|
||||
const func = function (this: any, ...args: any[]) {
|
||||
const pathArgument = args[pathArgumentIndex!];
|
||||
const pathInfo = splitPath(pathArgument);
|
||||
if (!pathInfo.isAsar) return old.apply(this, args);
|
||||
const { asarPath, filePath } = pathInfo;
|
||||
|
||||
const archive = getOrCreateArchive(asarPath);
|
||||
if (!archive) throw createError(AsarError.INVALID_ARCHIVE, { asarPath });
|
||||
|
||||
const newPath = archive.copyFileOut(filePath);
|
||||
if (!newPath) throw createError(AsarError.NOT_FOUND, { asarPath, filePath });
|
||||
|
||||
args[pathArgumentIndex!] = newPath;
|
||||
return old.apply(this, args);
|
||||
};
|
||||
if (fromAsync) {
|
||||
return func;
|
||||
}
|
||||
module[name] = func;
|
||||
};
|
||||
|
||||
const overrideAPI = function (module: Record<string, any>, name: string, pathArgumentIndex?: number | null) {
|
||||
if (pathArgumentIndex == null) pathArgumentIndex = 0;
|
||||
const old = module[name];
|
||||
module[name] = function (this: any, ...args: any[]) {
|
||||
const pathArgument = args[pathArgumentIndex!];
|
||||
const pathInfo = splitPath(pathArgument);
|
||||
if (!pathInfo.isAsar) return old.apply(this, args);
|
||||
const { asarPath, filePath } = pathInfo;
|
||||
|
||||
const callback = args[args.length - 1];
|
||||
if (typeof callback !== 'function') {
|
||||
return overrideAPISync(module, name, pathArgumentIndex!, true)!.apply(this, args);
|
||||
}
|
||||
|
||||
const archive = getOrCreateArchive(asarPath);
|
||||
if (!archive) {
|
||||
const error = createError(AsarError.INVALID_ARCHIVE, { asarPath });
|
||||
nextTick(callback, [error]);
|
||||
return;
|
||||
}
|
||||
|
||||
const newPath = archive.copyFileOut(filePath);
|
||||
if (!newPath) {
|
||||
const error = createError(AsarError.NOT_FOUND, { asarPath, filePath });
|
||||
nextTick(callback, [error]);
|
||||
return;
|
||||
}
|
||||
|
||||
args[pathArgumentIndex!] = newPath;
|
||||
return old.apply(this, args);
|
||||
};
|
||||
|
||||
if (old[util.promisify.custom]) {
|
||||
module[name][util.promisify.custom] = makePromiseFunction(old[util.promisify.custom], pathArgumentIndex);
|
||||
}
|
||||
|
||||
if (module.promises && module.promises[name]) {
|
||||
module.promises[name] = makePromiseFunction(module.promises[name], pathArgumentIndex);
|
||||
}
|
||||
};
|
||||
|
||||
const makePromiseFunction = function (orig: Function, pathArgumentIndex: number) {
|
||||
return function (this: any, ...args: any[]) {
|
||||
const pathArgument = args[pathArgumentIndex];
|
||||
const pathInfo = splitPath(pathArgument);
|
||||
if (!pathInfo.isAsar) return orig.apply(this, args);
|
||||
const { asarPath, filePath } = pathInfo;
|
||||
|
||||
const archive = getOrCreateArchive(asarPath);
|
||||
if (!archive) {
|
||||
return Promise.reject(createError(AsarError.INVALID_ARCHIVE, { asarPath }));
|
||||
}
|
||||
|
||||
const newPath = archive.copyFileOut(filePath);
|
||||
if (!newPath) {
|
||||
return Promise.reject(createError(AsarError.NOT_FOUND, { asarPath, filePath }));
|
||||
}
|
||||
|
||||
args[pathArgumentIndex] = newPath;
|
||||
return orig.apply(this, args);
|
||||
};
|
||||
};
|
||||
|
||||
// Override fs APIs.
|
||||
export const wrapFsWithAsar = (fs: Record<string, any>) => {
|
||||
const logFDs: Record<string, number> = {};
|
||||
const logASARAccess = (asarPath: string, filePath: string, offset: number) => {
|
||||
if (!process.env.ELECTRON_LOG_ASAR_READS) return;
|
||||
if (!logFDs[asarPath]) {
|
||||
const path = require('path');
|
||||
const logFilename = `${path.basename(asarPath, '.asar')}-access-log.txt`;
|
||||
const logPath = path.join(require('os').tmpdir(), logFilename);
|
||||
logFDs[asarPath] = fs.openSync(logPath, 'a');
|
||||
}
|
||||
fs.writeSync(logFDs[asarPath], `${offset}: ${filePath}\n`);
|
||||
};
|
||||
|
||||
const { lstatSync } = fs;
|
||||
fs.lstatSync = (pathArgument: string, options: any) => {
|
||||
const pathInfo = splitPath(pathArgument);
|
||||
if (!pathInfo.isAsar) return lstatSync(pathArgument, options);
|
||||
const { asarPath, filePath } = pathInfo;
|
||||
|
||||
const archive = getOrCreateArchive(asarPath);
|
||||
if (!archive) throw createError(AsarError.INVALID_ARCHIVE, { asarPath });
|
||||
|
||||
const stats = archive.stat(filePath);
|
||||
if (!stats) throw createError(AsarError.NOT_FOUND, { asarPath, filePath });
|
||||
|
||||
return asarStatsToFsStats(stats);
|
||||
};
|
||||
|
||||
const { lstat } = fs;
|
||||
fs.lstat = function (pathArgument: string, options: any, callback: any) {
|
||||
const pathInfo = splitPath(pathArgument);
|
||||
if (typeof options === 'function') {
|
||||
callback = options;
|
||||
options = {};
|
||||
}
|
||||
if (!pathInfo.isAsar) return lstat(pathArgument, options, callback);
|
||||
const { asarPath, filePath } = pathInfo;
|
||||
|
||||
const archive = getOrCreateArchive(asarPath);
|
||||
if (!archive) {
|
||||
const error = createError(AsarError.INVALID_ARCHIVE, { asarPath });
|
||||
nextTick(callback, [error]);
|
||||
return;
|
||||
}
|
||||
|
||||
const stats = archive.stat(filePath);
|
||||
if (!stats) {
|
||||
const error = createError(AsarError.NOT_FOUND, { asarPath, filePath });
|
||||
nextTick(callback, [error]);
|
||||
return;
|
||||
}
|
||||
|
||||
const fsStats = asarStatsToFsStats(stats);
|
||||
nextTick(callback, [null, fsStats]);
|
||||
};
|
||||
|
||||
fs.promises.lstat = util.promisify(fs.lstat);
|
||||
|
||||
const { statSync } = fs;
|
||||
fs.statSync = (pathArgument: string, options: any) => {
|
||||
const { isAsar } = splitPath(pathArgument);
|
||||
if (!isAsar) return statSync(pathArgument, options);
|
||||
|
||||
// Do not distinguish links for now.
|
||||
return fs.lstatSync(pathArgument, options);
|
||||
};
|
||||
|
||||
const { stat } = fs;
|
||||
fs.stat = (pathArgument: string, options: any, callback: any) => {
|
||||
const { isAsar } = splitPath(pathArgument);
|
||||
if (typeof options === 'function') {
|
||||
callback = options;
|
||||
options = {};
|
||||
}
|
||||
if (!isAsar) return stat(pathArgument, options, callback);
|
||||
|
||||
// Do not distinguish links for now.
|
||||
process.nextTick(() => fs.lstat(pathArgument, options, callback));
|
||||
};
|
||||
|
||||
fs.promises.stat = util.promisify(fs.stat);
|
||||
|
||||
const wrapRealpathSync = function (realpathSync: Function) {
|
||||
return function (this: any, pathArgument: string, options: any) {
|
||||
const pathInfo = splitPath(pathArgument);
|
||||
if (!pathInfo.isAsar) return realpathSync.apply(this, arguments);
|
||||
const { asarPath, filePath } = pathInfo;
|
||||
|
||||
const archive = getOrCreateArchive(asarPath);
|
||||
if (!archive) {
|
||||
throw createError(AsarError.INVALID_ARCHIVE, { asarPath });
|
||||
}
|
||||
|
||||
const fileRealPath = archive.realpath(filePath);
|
||||
if (fileRealPath === false) {
|
||||
throw createError(AsarError.NOT_FOUND, { asarPath, filePath });
|
||||
}
|
||||
|
||||
return path.join(realpathSync(asarPath, options), fileRealPath);
|
||||
};
|
||||
};
|
||||
|
||||
const { realpathSync } = fs;
|
||||
fs.realpathSync = wrapRealpathSync(realpathSync);
|
||||
fs.realpathSync.native = wrapRealpathSync(realpathSync.native);
|
||||
|
||||
const wrapRealpath = function (realpath: Function) {
|
||||
return function (this: any, pathArgument: string, options: any, callback: any) {
|
||||
const pathInfo = splitPath(pathArgument);
|
||||
if (!pathInfo.isAsar) return realpath.apply(this, arguments);
|
||||
const { asarPath, filePath } = pathInfo;
|
||||
|
||||
if (arguments.length < 3) {
|
||||
callback = options;
|
||||
options = {};
|
||||
}
|
||||
|
||||
const archive = getOrCreateArchive(asarPath);
|
||||
if (!archive) {
|
||||
const error = createError(AsarError.INVALID_ARCHIVE, { asarPath });
|
||||
nextTick(callback, [error]);
|
||||
return;
|
||||
}
|
||||
|
||||
const fileRealPath = archive.realpath(filePath);
|
||||
if (fileRealPath === false) {
|
||||
const error = createError(AsarError.NOT_FOUND, { asarPath, filePath });
|
||||
nextTick(callback, [error]);
|
||||
return;
|
||||
}
|
||||
|
||||
realpath(asarPath, options, (error: Error | null, archiveRealPath: string) => {
|
||||
if (error === null) {
|
||||
const fullPath = path.join(archiveRealPath, fileRealPath);
|
||||
callback(null, fullPath);
|
||||
} else {
|
||||
callback(error);
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
const { realpath } = fs;
|
||||
fs.realpath = wrapRealpath(realpath);
|
||||
fs.realpath.native = wrapRealpath(realpath.native);
|
||||
|
||||
fs.promises.realpath = util.promisify(fs.realpath.native);
|
||||
|
||||
const { exists } = fs;
|
||||
fs.exists = (pathArgument: string, callback: any) => {
|
||||
const pathInfo = splitPath(pathArgument);
|
||||
if (!pathInfo.isAsar) return exists(pathArgument, callback);
|
||||
const { asarPath, filePath } = pathInfo;
|
||||
|
||||
const archive = getOrCreateArchive(asarPath);
|
||||
if (!archive) {
|
||||
const error = createError(AsarError.INVALID_ARCHIVE, { asarPath });
|
||||
nextTick(callback, [error]);
|
||||
return;
|
||||
}
|
||||
|
||||
const pathExists = (archive.stat(filePath) !== false);
|
||||
nextTick(callback, [pathExists]);
|
||||
};
|
||||
|
||||
fs.exists[util.promisify.custom] = (pathArgument: string) => {
|
||||
const pathInfo = splitPath(pathArgument);
|
||||
if (!pathInfo.isAsar) return exists[util.promisify.custom](pathArgument);
|
||||
const { asarPath, filePath } = pathInfo;
|
||||
|
||||
const archive = getOrCreateArchive(asarPath);
|
||||
if (!archive) {
|
||||
const error = createError(AsarError.INVALID_ARCHIVE, { asarPath });
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
return Promise.resolve(archive.stat(filePath) !== false);
|
||||
};
|
||||
|
||||
const { existsSync } = fs;
|
||||
fs.existsSync = (pathArgument: string) => {
|
||||
const pathInfo = splitPath(pathArgument);
|
||||
if (!pathInfo.isAsar) return existsSync(pathArgument);
|
||||
const { asarPath, filePath } = pathInfo;
|
||||
|
||||
const archive = getOrCreateArchive(asarPath);
|
||||
if (!archive) return false;
|
||||
|
||||
return archive.stat(filePath) !== false;
|
||||
};
|
||||
|
||||
const { access } = fs;
|
||||
fs.access = function (pathArgument: string, mode: any, callback: any) {
|
||||
const pathInfo = splitPath(pathArgument);
|
||||
if (!pathInfo.isAsar) return access.apply(this, arguments);
|
||||
const { asarPath, filePath } = pathInfo;
|
||||
|
||||
if (typeof mode === 'function') {
|
||||
callback = mode;
|
||||
mode = fs.constants.F_OK;
|
||||
}
|
||||
|
||||
const archive = getOrCreateArchive(asarPath);
|
||||
if (!archive) {
|
||||
const error = createError(AsarError.INVALID_ARCHIVE, { asarPath });
|
||||
nextTick(callback, [error]);
|
||||
return;
|
||||
}
|
||||
|
||||
const info = archive.getFileInfo(filePath);
|
||||
if (!info) {
|
||||
const error = createError(AsarError.NOT_FOUND, { asarPath, filePath });
|
||||
nextTick(callback, [error]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (info.unpacked) {
|
||||
const realPath = archive.copyFileOut(filePath);
|
||||
return fs.access(realPath, mode, callback);
|
||||
}
|
||||
|
||||
const stats = archive.stat(filePath);
|
||||
if (!stats) {
|
||||
const error = createError(AsarError.NOT_FOUND, { asarPath, filePath });
|
||||
nextTick(callback, [error]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode & fs.constants.W_OK) {
|
||||
const error = createError(AsarError.NO_ACCESS, { asarPath, filePath });
|
||||
nextTick(callback, [error]);
|
||||
return;
|
||||
}
|
||||
|
||||
nextTick(callback);
|
||||
};
|
||||
|
||||
fs.promises.access = util.promisify(fs.access);
|
||||
|
||||
const { accessSync } = fs;
|
||||
fs.accessSync = function (pathArgument: string, mode: any) {
|
||||
const pathInfo = splitPath(pathArgument);
|
||||
if (!pathInfo.isAsar) return accessSync.apply(this, arguments);
|
||||
const { asarPath, filePath } = pathInfo;
|
||||
|
||||
if (mode == null) mode = fs.constants.F_OK;
|
||||
|
||||
const archive = getOrCreateArchive(asarPath);
|
||||
if (!archive) {
|
||||
throw createError(AsarError.INVALID_ARCHIVE, { asarPath });
|
||||
}
|
||||
|
||||
const info = archive.getFileInfo(filePath);
|
||||
if (!info) {
|
||||
throw createError(AsarError.NOT_FOUND, { asarPath, filePath });
|
||||
}
|
||||
|
||||
if (info.unpacked) {
|
||||
const realPath = archive.copyFileOut(filePath);
|
||||
return fs.accessSync(realPath, mode);
|
||||
}
|
||||
|
||||
const stats = archive.stat(filePath);
|
||||
if (!stats) {
|
||||
throw createError(AsarError.NOT_FOUND, { asarPath, filePath });
|
||||
}
|
||||
|
||||
if (mode & fs.constants.W_OK) {
|
||||
throw createError(AsarError.NO_ACCESS, { asarPath, filePath });
|
||||
}
|
||||
};
|
||||
|
||||
const { readFile } = fs;
|
||||
fs.readFile = function (pathArgument: string, options: any, callback: any) {
|
||||
const pathInfo = splitPath(pathArgument);
|
||||
if (!pathInfo.isAsar) return readFile.apply(this, arguments);
|
||||
const { asarPath, filePath } = pathInfo;
|
||||
|
||||
if (typeof options === 'function') {
|
||||
callback = options;
|
||||
options = { encoding: null };
|
||||
} else if (typeof options === 'string') {
|
||||
options = { encoding: options };
|
||||
} else if (options === null || options === undefined) {
|
||||
options = { encoding: null };
|
||||
} else if (typeof options !== 'object') {
|
||||
throw new TypeError('Bad arguments');
|
||||
}
|
||||
|
||||
const { encoding } = options;
|
||||
const archive = getOrCreateArchive(asarPath);
|
||||
if (!archive) {
|
||||
const error = createError(AsarError.INVALID_ARCHIVE, { asarPath });
|
||||
nextTick(callback, [error]);
|
||||
return;
|
||||
}
|
||||
|
||||
const info = archive.getFileInfo(filePath);
|
||||
if (!info) {
|
||||
const error = createError(AsarError.NOT_FOUND, { asarPath, filePath });
|
||||
nextTick(callback, [error]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (info.size === 0) {
|
||||
nextTick(callback, [null, encoding ? '' : Buffer.alloc(0)]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (info.unpacked) {
|
||||
const realPath = archive.copyFileOut(filePath);
|
||||
return fs.readFile(realPath, options, callback);
|
||||
}
|
||||
|
||||
logASARAccess(asarPath, filePath, info.offset);
|
||||
archive.read(info.offset, info.size).then((buf) => {
|
||||
const buffer = Buffer.from(buf);
|
||||
callback(null, encoding ? buffer.toString(encoding) : buffer);
|
||||
}, (err) => {
|
||||
const error: AsarErrorObject = new Error(`EINVAL, ${err.message} while reading ${filePath} in ${asarPath}`);
|
||||
error.code = 'EINVAL';
|
||||
error.errno = -22;
|
||||
callback(error);
|
||||
});
|
||||
};
|
||||
|
||||
fs.promises.readFile = util.promisify(fs.readFile);
|
||||
|
||||
const { readFileSync } = fs;
|
||||
fs.readFileSync = function (pathArgument: string, options: any) {
|
||||
const pathInfo = splitPath(pathArgument);
|
||||
if (!pathInfo.isAsar) return readFileSync.apply(this, arguments);
|
||||
const { asarPath, filePath } = pathInfo;
|
||||
|
||||
const archive = getOrCreateArchive(asarPath);
|
||||
if (!archive) throw createError(AsarError.INVALID_ARCHIVE, { asarPath });
|
||||
|
||||
const info = archive.getFileInfo(filePath);
|
||||
if (!info) throw createError(AsarError.NOT_FOUND, { asarPath, filePath });
|
||||
|
||||
if (info.size === 0) return (options) ? '' : Buffer.alloc(0);
|
||||
if (info.unpacked) {
|
||||
const realPath = archive.copyFileOut(filePath);
|
||||
return fs.readFileSync(realPath, options);
|
||||
}
|
||||
|
||||
if (!options) {
|
||||
options = { encoding: null };
|
||||
} else if (typeof options === 'string') {
|
||||
options = { encoding: options };
|
||||
} else if (typeof options !== 'object') {
|
||||
throw new TypeError('Bad arguments');
|
||||
}
|
||||
|
||||
const { encoding } = options;
|
||||
|
||||
logASARAccess(asarPath, filePath, info.offset);
|
||||
let arrayBuffer: ArrayBuffer;
|
||||
try {
|
||||
arrayBuffer = archive.readSync(info.offset, info.size);
|
||||
} catch (err) {
|
||||
const error: AsarErrorObject = new Error(`EINVAL, ${err.message} while reading ${filePath} in ${asarPath}`);
|
||||
error.code = 'EINVAL';
|
||||
error.errno = -22;
|
||||
throw error;
|
||||
}
|
||||
const buffer = Buffer.from(arrayBuffer);
|
||||
return encoding ? buffer.toString(encoding) : buffer;
|
||||
};
|
||||
|
||||
const { readdir } = fs;
|
||||
fs.readdir = function (pathArgument: string, options: { encoding?: string | null; withFileTypes?: boolean } = {}, callback?: Function) {
|
||||
const pathInfo = splitPath(pathArgument);
|
||||
if (typeof options === 'function') {
|
||||
callback = options;
|
||||
options = {};
|
||||
}
|
||||
if (!pathInfo.isAsar) return readdir.apply(this, arguments);
|
||||
const { asarPath, filePath } = pathInfo;
|
||||
|
||||
const archive = getOrCreateArchive(asarPath);
|
||||
if (!archive) {
|
||||
const error = createError(AsarError.INVALID_ARCHIVE, { asarPath });
|
||||
nextTick(callback!, [error]);
|
||||
return;
|
||||
}
|
||||
|
||||
const files = archive.readdir(filePath);
|
||||
if (!files) {
|
||||
const error = createError(AsarError.NOT_FOUND, { asarPath, filePath });
|
||||
nextTick(callback!, [error]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (options.withFileTypes) {
|
||||
const dirents = [];
|
||||
for (const file of files) {
|
||||
const stats = archive.stat(file);
|
||||
if (!stats) {
|
||||
const error = createError(AsarError.NOT_FOUND, { asarPath, filePath: file });
|
||||
nextTick(callback!, [error]);
|
||||
return;
|
||||
}
|
||||
if (stats.isFile) {
|
||||
dirents.push(new fs.Dirent(file, fs.constants.UV_DIRENT_FILE));
|
||||
} else if (stats.isDirectory) {
|
||||
dirents.push(new fs.Dirent(file, fs.constants.UV_DIRENT_DIR));
|
||||
} else if (stats.isLink) {
|
||||
dirents.push(new fs.Dirent(file, fs.constants.UV_DIRENT_LINK));
|
||||
}
|
||||
}
|
||||
nextTick(callback!, [null, dirents]);
|
||||
return;
|
||||
}
|
||||
|
||||
nextTick(callback!, [null, files]);
|
||||
};
|
||||
|
||||
fs.promises.readdir = util.promisify(fs.readdir);
|
||||
|
||||
const { readdirSync } = fs;
|
||||
fs.readdirSync = function (pathArgument: string, options: { encoding: BufferEncoding | null; withFileTypes?: false } | BufferEncoding | null) {
|
||||
const pathInfo = splitPath(pathArgument);
|
||||
if (!pathInfo.isAsar) return readdirSync.apply(this, arguments);
|
||||
const { asarPath, filePath } = pathInfo;
|
||||
|
||||
const archive = getOrCreateArchive(asarPath);
|
||||
if (!archive) {
|
||||
throw createError(AsarError.INVALID_ARCHIVE, { asarPath });
|
||||
}
|
||||
|
||||
const files = archive.readdir(filePath);
|
||||
if (!files) {
|
||||
throw createError(AsarError.NOT_FOUND, { asarPath, filePath });
|
||||
}
|
||||
|
||||
if (options && (options as any).withFileTypes) {
|
||||
const dirents = [];
|
||||
for (const file of files) {
|
||||
const stats = archive.stat(file);
|
||||
if (!stats) {
|
||||
throw createError(AsarError.NOT_FOUND, { asarPath, filePath: file });
|
||||
}
|
||||
if (stats.isFile) {
|
||||
dirents.push(new fs.Dirent(file, fs.constants.UV_DIRENT_FILE));
|
||||
} else if (stats.isDirectory) {
|
||||
dirents.push(new fs.Dirent(file, fs.constants.UV_DIRENT_DIR));
|
||||
} else if (stats.isLink) {
|
||||
dirents.push(new fs.Dirent(file, fs.constants.UV_DIRENT_LINK));
|
||||
}
|
||||
}
|
||||
return dirents;
|
||||
}
|
||||
|
||||
return files;
|
||||
};
|
||||
|
||||
const { internalModuleReadJSON } = internalBinding('fs');
|
||||
internalBinding('fs').internalModuleReadJSON = (pathArgument: string) => {
|
||||
const pathInfo = splitPath(pathArgument);
|
||||
if (!pathInfo.isAsar) return internalModuleReadJSON(pathArgument);
|
||||
const { asarPath, filePath } = pathInfo;
|
||||
|
||||
const archive = getOrCreateArchive(asarPath);
|
||||
if (!archive) return [];
|
||||
|
||||
const info = archive.getFileInfo(filePath);
|
||||
if (!info) return [];
|
||||
if (info.size === 0) return ['', false];
|
||||
if (info.unpacked) {
|
||||
const realPath = archive.copyFileOut(filePath);
|
||||
return fs.readFileSync(realPath, { encoding: 'utf8' });
|
||||
}
|
||||
|
||||
logASARAccess(asarPath, filePath, info.offset);
|
||||
let arrayBuffer: ArrayBuffer;
|
||||
try {
|
||||
arrayBuffer = archive.readSync(info.offset, info.size);
|
||||
} catch (err) {
|
||||
const error: AsarErrorObject = new Error(`EINVAL, ${err.message} while reading ${filePath} in ${asarPath}`);
|
||||
error.code = 'EINVAL';
|
||||
error.errno = -22;
|
||||
throw error;
|
||||
}
|
||||
const buffer = Buffer.from(arrayBuffer);
|
||||
const str = buffer.toString('utf8');
|
||||
return [str, str.length > 0];
|
||||
};
|
||||
|
||||
const { internalModuleStat } = internalBinding('fs');
|
||||
internalBinding('fs').internalModuleStat = (pathArgument: string) => {
|
||||
const pathInfo = splitPath(pathArgument);
|
||||
if (!pathInfo.isAsar) return internalModuleStat(pathArgument);
|
||||
const { asarPath, filePath } = pathInfo;
|
||||
|
||||
// -ENOENT
|
||||
const archive = getOrCreateArchive(asarPath);
|
||||
if (!archive) return -34;
|
||||
|
||||
// -ENOENT
|
||||
const stats = archive.stat(filePath);
|
||||
if (!stats) return -34;
|
||||
|
||||
return (stats.isDirectory) ? 1 : 0;
|
||||
};
|
||||
|
||||
// Calling mkdir for directory inside asar archive should throw ENOTDIR
|
||||
// error, but on Windows it throws ENOENT.
|
||||
if (process.platform === 'win32') {
|
||||
const { mkdir } = fs;
|
||||
fs.mkdir = (pathArgument: string, options: any, callback: any) => {
|
||||
if (typeof options === 'function') {
|
||||
callback = options;
|
||||
options = {};
|
||||
}
|
||||
|
||||
const pathInfo = splitPath(pathArgument);
|
||||
if (pathInfo.isAsar && pathInfo.filePath.length > 0) {
|
||||
const error = createError(AsarError.NOT_DIR);
|
||||
nextTick(callback, [error]);
|
||||
return;
|
||||
}
|
||||
|
||||
mkdir(pathArgument, options, callback);
|
||||
};
|
||||
|
||||
fs.promises.mkdir = util.promisify(fs.mkdir);
|
||||
|
||||
const { mkdirSync } = fs;
|
||||
fs.mkdirSync = function (pathArgument: string, options: any) {
|
||||
const pathInfo = splitPath(pathArgument);
|
||||
if (pathInfo.isAsar && pathInfo.filePath.length) throw createError(AsarError.NOT_DIR);
|
||||
return mkdirSync(pathArgument, options);
|
||||
};
|
||||
}
|
||||
|
||||
function invokeWithNoAsar (func: Function) {
|
||||
return function (this: any) {
|
||||
const processNoAsarOriginalValue = process.noAsar;
|
||||
process.noAsar = true;
|
||||
try {
|
||||
return func.apply(this, arguments);
|
||||
} finally {
|
||||
process.noAsar = processNoAsarOriginalValue;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Strictly implementing the flags of fs.copyFile is hard, just do a simple
|
||||
// implementation for now. Doing 2 copies won't spend much time more as OS
|
||||
// has filesystem caching.
|
||||
overrideAPI(fs, 'copyFile');
|
||||
overrideAPISync(fs, 'copyFileSync');
|
||||
|
||||
overrideAPI(fs, 'open');
|
||||
overrideAPISync(process, 'dlopen', 1);
|
||||
overrideAPISync(Module._extensions, '.node', 1);
|
||||
overrideAPISync(fs, 'openSync');
|
||||
|
||||
const overrideChildProcess = (childProcess: Record<string, any>) => {
|
||||
// Executing a command string containing a path to an asar archive
|
||||
// confuses `childProcess.execFile`, which is internally called by
|
||||
// `childProcess.{exec,execSync}`, causing Electron to consider the full
|
||||
// command as a single path to an archive.
|
||||
const { exec, execSync } = childProcess;
|
||||
childProcess.exec = invokeWithNoAsar(exec);
|
||||
childProcess.exec[util.promisify.custom] = invokeWithNoAsar(exec[util.promisify.custom]);
|
||||
childProcess.execSync = invokeWithNoAsar(execSync);
|
||||
|
||||
overrideAPI(childProcess, 'execFile');
|
||||
overrideAPISync(childProcess, 'execFileSync');
|
||||
};
|
||||
|
||||
// Lazily override the child_process APIs only when child_process is
|
||||
// fetched the first time. We will eagerly override the child_process APIs
|
||||
// when this env var is set so that stack traces generated inside node unit
|
||||
// tests will match. This env var will only slow things down in users apps
|
||||
// and should not be used.
|
||||
if (process.env.ELECTRON_EAGER_ASAR_HOOK_FOR_TESTING) {
|
||||
overrideChildProcess(require('child_process'));
|
||||
} else {
|
||||
const originalModuleLoad = Module._load;
|
||||
Module._load = (request: string, ...args: any[]) => {
|
||||
const loadResult = originalModuleLoad(request, ...args);
|
||||
if (request === 'child_process') {
|
||||
if (!v8Util.getHiddenValue(loadResult, 'asar-ready')) {
|
||||
v8Util.setHiddenValue(loadResult, 'asar-ready', true);
|
||||
// Just to make it obvious what we are dealing with here
|
||||
const childProcess = loadResult;
|
||||
|
||||
overrideChildProcess(childProcess);
|
||||
}
|
||||
}
|
||||
return loadResult;
|
||||
};
|
||||
}
|
||||
};
|
||||
3
lib/asar/init.ts
Normal file
3
lib/asar/init.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { wrapFsWithAsar } from './fs-wrapper';
|
||||
|
||||
wrapFsWithAsar(require('fs'));
|
||||
21
lib/browser/.eslintrc.json
Normal file
21
lib/browser/.eslintrc.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"rules": {
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
"paths": [
|
||||
"electron",
|
||||
"electron/renderer"
|
||||
],
|
||||
"patterns": [
|
||||
"./*",
|
||||
"../*",
|
||||
"@electron/internal/isolated_renderer/*",
|
||||
"@electron/internal/renderer/*",
|
||||
"@electron/internal/sandboxed_worker/*",
|
||||
"@electron/internal/worker/*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,41 +1,36 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
import { deprecate, Menu } from 'electron';
|
||||
import { EventEmitter } from 'events';
|
||||
import { deprecate, Menu } from 'electron/main';
|
||||
|
||||
const bindings = process.electronBinding('app');
|
||||
const commandLine = process.electronBinding('command_line');
|
||||
const { app, App } = bindings;
|
||||
const bindings = process._linkedBinding('electron_browser_app');
|
||||
const commandLine = process._linkedBinding('electron_common_command_line');
|
||||
const { app } = bindings;
|
||||
|
||||
// Only one app object permitted.
|
||||
export default app;
|
||||
|
||||
let dockMenu: Electron.Menu | null = null;
|
||||
|
||||
// App is an EventEmitter.
|
||||
Object.setPrototypeOf(App.prototype, EventEmitter.prototype);
|
||||
EventEmitter.call(app as any);
|
||||
|
||||
// Properties.
|
||||
|
||||
const nativeASGetter = app.isAccessibilitySupportEnabled;
|
||||
const nativeASSetter = app.setAccessibilitySupportEnabled;
|
||||
Object.defineProperty(App.prototype, 'accessibilitySupportEnabled', {
|
||||
Object.defineProperty(app, 'accessibilitySupportEnabled', {
|
||||
get: () => nativeASGetter.call(app),
|
||||
set: (enabled) => nativeASSetter.call(app, enabled)
|
||||
});
|
||||
|
||||
const nativeBCGetter = app.getBadgeCount;
|
||||
const nativeBCSetter = app.setBadgeCount;
|
||||
Object.defineProperty(App.prototype, 'badgeCount', {
|
||||
Object.defineProperty(app, 'badgeCount', {
|
||||
get: () => nativeBCGetter.call(app),
|
||||
set: (count) => nativeBCSetter.call(app, count)
|
||||
});
|
||||
|
||||
const nativeNGetter = app.getName;
|
||||
const nativeNSetter = app.setName;
|
||||
Object.defineProperty(App.prototype, 'name', {
|
||||
Object.defineProperty(app, 'name', {
|
||||
get: () => nativeNGetter.call(app),
|
||||
set: (name) => nativeNSetter.call(app, name)
|
||||
});
|
||||
@@ -60,7 +55,7 @@ Object.defineProperty(app, 'applicationMenu', {
|
||||
}
|
||||
});
|
||||
|
||||
App.prototype.isPackaged = (() => {
|
||||
(app as any).isPackaged = (() => {
|
||||
const execFile = path.basename(process.execPath).toLowerCase();
|
||||
if (process.platform === 'win32') {
|
||||
return execFile !== 'electron.exe';
|
||||
@@ -137,4 +132,4 @@ for (const name of events) {
|
||||
|
||||
// Deprecate allowRendererProcessReuse but only if they set it to false, no need to log if
|
||||
// they are setting it to true
|
||||
deprecate.removeProperty(app, 'allowRendererProcessReuse', [false]);
|
||||
deprecate.removeProperty({ __proto__: app } as any, 'allowRendererProcessReuse', [false]);
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
module.exports = require('@electron/internal/browser/api/auto-updater/auto-updater-win');
|
||||
} else {
|
||||
module.exports = require('@electron/internal/browser/api/auto-updater/auto-updater-native');
|
||||
}
|
||||
5
lib/browser/api/auto-updater.ts
Normal file
5
lib/browser/api/auto-updater.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
if (process.platform === 'win32') {
|
||||
module.exports = require('./auto-updater/auto-updater-win');
|
||||
} else {
|
||||
module.exports = require('./auto-updater/auto-updater-native');
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const EventEmitter = require('events').EventEmitter;
|
||||
const { autoUpdater, AutoUpdater } = process.electronBinding('auto_updater');
|
||||
|
||||
// AutoUpdater is an EventEmitter.
|
||||
Object.setPrototypeOf(AutoUpdater.prototype, EventEmitter.prototype);
|
||||
EventEmitter.call(autoUpdater);
|
||||
|
||||
module.exports = autoUpdater;
|
||||
3
lib/browser/api/auto-updater/auto-updater-native.ts
Normal file
3
lib/browser/api/auto-updater/auto-updater-native.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
const { autoUpdater } = process._linkedBinding('electron_browser_auto_updater');
|
||||
|
||||
export default autoUpdater;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user