mirror of
https://github.com/electron/electron.git
synced 2026-04-10 03:01:51 -04:00
Compare commits
346 Commits
v13.0.0-be
...
v14.0.0-ni
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1fc230158b | ||
|
|
8f8708680f | ||
|
|
a264fc891d | ||
|
|
28143774c1 | ||
|
|
2c65060ec8 | ||
|
|
8d0e7aed9f | ||
|
|
9d9921b533 | ||
|
|
2086e1903c | ||
|
|
476e908269 | ||
|
|
16236a195b | ||
|
|
9b144a6a97 | ||
|
|
e379b455c9 | ||
|
|
71c248176b | ||
|
|
014f2e622e | ||
|
|
9fb3a49c7c | ||
|
|
42e5421276 | ||
|
|
961b74b2ac | ||
|
|
a699dfdf83 | ||
|
|
1dae3da901 | ||
|
|
e5e8ab4eea | ||
|
|
38c877e9d3 | ||
|
|
a0589ca5d7 | ||
|
|
3d6343ed51 | ||
|
|
41bb3f1321 | ||
|
|
005101424a | ||
|
|
99909baeac | ||
|
|
dd80952877 | ||
|
|
0f898b2260 | ||
|
|
b0167b269a | ||
|
|
c17f5a783c | ||
|
|
dc0c52eaa7 | ||
|
|
9601dc59fc | ||
|
|
e0fa327daf | ||
|
|
bfed86126c | ||
|
|
ee8b69d067 | ||
|
|
37f7e66873 | ||
|
|
77444867b7 | ||
|
|
18a76c6b9d | ||
|
|
a1a90ed03b | ||
|
|
791eddd541 | ||
|
|
c37c9adbe2 | ||
|
|
5a9a298a74 | ||
|
|
0b42316803 | ||
|
|
3dcba234b5 | ||
|
|
c200840006 | ||
|
|
733f81449d | ||
|
|
56c3103e73 | ||
|
|
e373df3bc3 | ||
|
|
3879e9e065 | ||
|
|
ea6d3fae98 | ||
|
|
5ec3e02d13 | ||
|
|
0a1b26b1d5 | ||
|
|
aedec5206c | ||
|
|
cdf04f3ae7 | ||
|
|
fa61e3b119 | ||
|
|
b97b973306 | ||
|
|
72092c2312 | ||
|
|
7c398062dd | ||
|
|
7584ca16c1 | ||
|
|
2ceae36766 | ||
|
|
7cf1f8d11c | ||
|
|
9afae17380 | ||
|
|
7884f52976 | ||
|
|
79f67417f0 | ||
|
|
82b0d67d70 | ||
|
|
5d15cec0fd | ||
|
|
a76b53348c | ||
|
|
cce73c3b8d | ||
|
|
08c4b0ab61 | ||
|
|
a1386dc19b | ||
|
|
ae0de8ef9f | ||
|
|
7c32deb70f | ||
|
|
dc7fa1d9f1 | ||
|
|
1c57e078aa | ||
|
|
33bbdcf1de | ||
|
|
be3c2fd0af | ||
|
|
d2654c652a | ||
|
|
583660a85a | ||
|
|
28904714ae | ||
|
|
43d27cc4d1 | ||
|
|
93311c8686 | ||
|
|
362e8421d6 | ||
|
|
13f36d54cf | ||
|
|
79077f6df9 | ||
|
|
4ca518468d | ||
|
|
c4931ff70e | ||
|
|
503d24a473 | ||
|
|
7063b5ef2c | ||
|
|
11199d8824 | ||
|
|
69f3e330e7 | ||
|
|
6ee819aa65 | ||
|
|
4f3664e6d9 | ||
|
|
e12a3cb59c | ||
|
|
8164322195 | ||
|
|
400d7c4bce | ||
|
|
ac9ec1a6ea | ||
|
|
6327a5a4a2 | ||
|
|
99fc054ce9 | ||
|
|
0d7fd7a74f | ||
|
|
b8c2481edb | ||
|
|
484931bba2 | ||
|
|
a354c95d4c | ||
|
|
e12128b65b | ||
|
|
22a70eb803 | ||
|
|
9236e56ddc | ||
|
|
5ee906fd04 | ||
|
|
20801573aa | ||
|
|
e37533b73a | ||
|
|
f8bdef5349 | ||
|
|
dba4df9326 | ||
|
|
b6315612dd | ||
|
|
f78f8d15a9 | ||
|
|
6df2680cb6 | ||
|
|
e775467e9c | ||
|
|
2e9ed50bb0 | ||
|
|
6bd13cc98f | ||
|
|
ef4954fa1f | ||
|
|
f755c521eb | ||
|
|
95e26e2fd4 | ||
|
|
6772e7773e | ||
|
|
17f527f757 | ||
|
|
f73d09374e | ||
|
|
da8c35e3b2 | ||
|
|
c428ec5cd5 | ||
|
|
16b0d1fbdd | ||
|
|
3a569c176a | ||
|
|
14834f35df | ||
|
|
968b30c9b4 | ||
|
|
17a44895dd | ||
|
|
00fa60ef76 | ||
|
|
2865d161b7 | ||
|
|
7d04f729d8 | ||
|
|
e454bded3c | ||
|
|
fe0da255b6 | ||
|
|
63317627b5 | ||
|
|
77dcf1020a | ||
|
|
641e9337f3 | ||
|
|
0c2150a6fa | ||
|
|
62b38812b6 | ||
|
|
3ed8da0931 | ||
|
|
e2f49edf83 | ||
|
|
1fcd6e2740 | ||
|
|
19d7a6b761 | ||
|
|
82ea8ea68c | ||
|
|
c280d770dc | ||
|
|
29603bcc27 | ||
|
|
55c66e3e92 | ||
|
|
9904438118 | ||
|
|
e6aefed0ee | ||
|
|
fa65faa4b0 | ||
|
|
e323bfe661 | ||
|
|
976222b509 | ||
|
|
2a55ae4b85 | ||
|
|
05d164e660 | ||
|
|
ba3b2189ad | ||
|
|
bdeeabdc3c | ||
|
|
f55aa78883 | ||
|
|
52262a9db0 | ||
|
|
5fe07e1e23 | ||
|
|
b9ea4a6ba4 | ||
|
|
a006cf681b | ||
|
|
9684d85101 | ||
|
|
1594c54933 | ||
|
|
9127cff58b | ||
|
|
0f3620099a | ||
|
|
6016e244fa | ||
|
|
54e72fa8e3 | ||
|
|
5d13820441 | ||
|
|
c9217f07e6 | ||
|
|
9fecf8369f | ||
|
|
9a7cfc42aa | ||
|
|
1f575ca3af | ||
|
|
b6254bfd36 | ||
|
|
ae2059eaa1 | ||
|
|
ff96fabe5e | ||
|
|
3122820e58 | ||
|
|
01ca00ec82 | ||
|
|
606fd87d1e | ||
|
|
5be2183dd7 | ||
|
|
2632564ccf | ||
|
|
521146f71e | ||
|
|
dd975328a0 | ||
|
|
fb4e99e729 | ||
|
|
77365e701f | ||
|
|
1453a8e743 | ||
|
|
b9b734c9c4 | ||
|
|
6fbd84fc80 | ||
|
|
7918ddb026 | ||
|
|
89df6b98da | ||
|
|
640a145112 | ||
|
|
aaf03765ed | ||
|
|
7f7b1f6c8a | ||
|
|
d874a59056 | ||
|
|
4f97b9303c | ||
|
|
83d93bcbdc | ||
|
|
d93690ccdc | ||
|
|
3d2b740d9e | ||
|
|
39e3576c48 | ||
|
|
61cf1abd4d | ||
|
|
1e9e2f8cf6 | ||
|
|
7c36463085 | ||
|
|
6a0b03ba6a | ||
|
|
94af0e8bb0 | ||
|
|
5b598037bb | ||
|
|
ea62ecd188 | ||
|
|
665ac6f9c8 | ||
|
|
74318705c2 | ||
|
|
205f572181 | ||
|
|
451e0931bf | ||
|
|
deeb2de14b | ||
|
|
d10398610b | ||
|
|
e99893df22 | ||
|
|
fa320eeb90 | ||
|
|
96ce59609d | ||
|
|
703f8707db | ||
|
|
8c3165434a | ||
|
|
c8d18a0a1c | ||
|
|
db7059eb0a | ||
|
|
a79ef2d525 | ||
|
|
79bcb882ac | ||
|
|
a68d43ce8b | ||
|
|
502d4c19ce | ||
|
|
f35fc93080 | ||
|
|
4057e6b56e | ||
|
|
b52ccc9726 | ||
|
|
8476bed36e | ||
|
|
2d3c65beca | ||
|
|
3b183854ff | ||
|
|
baadcd48df | ||
|
|
14acf00ba9 | ||
|
|
fc7f2042ec | ||
|
|
485fa5bea9 | ||
|
|
08330cb079 | ||
|
|
54bc21929a | ||
|
|
bccafa0289 | ||
|
|
b6ff12ef7f | ||
|
|
80f89a3472 | ||
|
|
c49bc282d5 | ||
|
|
7e961d8a37 | ||
|
|
b6d2ae0455 | ||
|
|
97b6868e9c | ||
|
|
29dfabadfd | ||
|
|
d0989802bd | ||
|
|
ec893f8322 | ||
|
|
22d8f22cfb | ||
|
|
86d23cee40 | ||
|
|
29dc5a2f83 | ||
|
|
3160e608e2 | ||
|
|
f1bb6be4b9 | ||
|
|
2cd53eb46a | ||
|
|
5fc298ee5f | ||
|
|
d54bee03d0 | ||
|
|
4a6bc7a42f | ||
|
|
3010dd93e3 | ||
|
|
88bbe2a352 | ||
|
|
185c343b22 | ||
|
|
b15b820bca | ||
|
|
9f5e3f6685 | ||
|
|
003dd6c16c | ||
|
|
fdc2e2bc57 | ||
|
|
b045d42b0e | ||
|
|
76538d2d38 | ||
|
|
676f74f3dc | ||
|
|
08036802cb | ||
|
|
9e336f5d0c | ||
|
|
d4bec23bde | ||
|
|
d0e88c2476 | ||
|
|
fae4d87a5a | ||
|
|
57a8781c01 | ||
|
|
8f4e362d8f | ||
|
|
d27ad0d182 | ||
|
|
1e16606524 | ||
|
|
b023b33c05 | ||
|
|
45c4dd529f | ||
|
|
41fdf450b2 | ||
|
|
8dfe4abd14 | ||
|
|
f933c249fe | ||
|
|
5e7ae59d29 | ||
|
|
f73256651b | ||
|
|
a442f11574 | ||
|
|
b8926cb4e8 | ||
|
|
b7eb521cec | ||
|
|
ab74cf4e1a | ||
|
|
8d38e9dd54 | ||
|
|
4d1d6c8a3a | ||
|
|
40d779a7f3 | ||
|
|
6bce814736 | ||
|
|
5b710519cf | ||
|
|
6c90411e21 | ||
|
|
74e7f98572 | ||
|
|
8badc6583f | ||
|
|
35cafdd1d8 | ||
|
|
089ac8180f | ||
|
|
102a3740ea | ||
|
|
32ec7e1e21 | ||
|
|
73d0a16ae2 | ||
|
|
5df13e7c8a | ||
|
|
8c6027c519 | ||
|
|
5b205731f6 | ||
|
|
d274df7e3a | ||
|
|
aadf2f4a7c | ||
|
|
d9997c303f | ||
|
|
ab943d78b2 | ||
|
|
f6949dd197 | ||
|
|
e27b7ed248 | ||
|
|
41b5cd1a84 | ||
|
|
7e22523ed2 | ||
|
|
3270613bf7 | ||
|
|
0505beb43d | ||
|
|
8949b8a462 | ||
|
|
5b50c88508 | ||
|
|
9ccb8f5910 | ||
|
|
46cfb347d7 | ||
|
|
ee0ab6f392 | ||
|
|
f4e1a343b9 | ||
|
|
b3a0743121 | ||
|
|
b36292780f | ||
|
|
e99e6a5a8a | ||
|
|
54cc68dd7a | ||
|
|
59432fe30a | ||
|
|
f51f427646 | ||
|
|
4e02d9407a | ||
|
|
77ad17b383 | ||
|
|
be627568b2 | ||
|
|
59669e99cb | ||
|
|
dc36e8e6fc | ||
|
|
1a296e59c2 | ||
|
|
0d94e0d1d9 | ||
|
|
2fed02556d | ||
|
|
eccfa516c5 | ||
|
|
f114dcfd6e | ||
|
|
54bc71da34 | ||
|
|
afb7d9f550 | ||
|
|
d92bab0e29 | ||
|
|
e900271bea | ||
|
|
87df2766ba | ||
|
|
c8148febfa | ||
|
|
e715b9c921 | ||
|
|
55e50a0879 | ||
|
|
b820b4078d | ||
|
|
5defd96ecd | ||
|
|
ca75bca667 | ||
|
|
0b042d3b1c | ||
|
|
9b93750e5e | ||
|
|
6e121d2250 | ||
|
|
2e091d401e |
@@ -85,17 +85,12 @@ machine-linux-2xlarge: &machine-linux-2xlarge
|
||||
|
||||
machine-mac: &machine-mac
|
||||
macos:
|
||||
xcode: "12.2.0"
|
||||
xcode: "12.4.0"
|
||||
|
||||
machine-mac-large: &machine-mac-large
|
||||
resource_class: large
|
||||
macos:
|
||||
xcode: "12.2.0"
|
||||
|
||||
machine-mac-large-arm: &machine-mac-large-arm
|
||||
resource_class: large
|
||||
macos:
|
||||
xcode: "12.2.0"
|
||||
xcode: "12.4.0"
|
||||
|
||||
machine-mac-arm64: &machine-mac-arm64
|
||||
resource_class: electronjs/macos-arm64
|
||||
@@ -230,6 +225,18 @@ step-maybe-notify-slack-success: &step-maybe-notify-slack-success
|
||||
fi
|
||||
when: on_success
|
||||
|
||||
step-maybe-cleanup-arm64-mac: &step-maybe-cleanup-arm64-mac
|
||||
run:
|
||||
name: Cleanup after testing
|
||||
command: |
|
||||
if [ "$TARGET_ARCH" == "arm64" ] &&[ "`uname`" == "Darwin" ]; then
|
||||
killall Electron || echo "No Electron processes left running"
|
||||
killall Safari || echo "No Safari processes left running"
|
||||
rm -rf ~/Library/Application\ Support/Electron*
|
||||
rm -rf ~/Library/Application\ Support/electron*
|
||||
fi
|
||||
when: always
|
||||
|
||||
step-checkout-electron: &step-checkout-electron
|
||||
checkout:
|
||||
path: src/electron
|
||||
@@ -313,9 +320,10 @@ step-setup-goma-for-build: &step-setup-goma-for-build
|
||||
npm install
|
||||
mkdir third_party
|
||||
node -e "require('./src/utils/goma.js').downloadAndPrepare({ gomaOneForAll: true })"
|
||||
node -e "require('./src/utils/goma.js').ensure()"
|
||||
third_party/goma/goma_ctl.py ensure_start
|
||||
echo 'export GN_GOMA_FILE='`node -e "console.log(require('./src/utils/goma.js').gnFilePath)"` >> $BASH_ENV
|
||||
echo 'export LOCAL_GOMA_DIR='`node -e "console.log(require('./src/utils/goma.js').dir)"` >> $BASH_ENV
|
||||
echo 'export GOMA_FALLBACK_ON_AUTH_FAILURE=true' >> $BASH_ENV
|
||||
cd ..
|
||||
|
||||
step-restore-brew-cache: &step-restore-brew-cache
|
||||
@@ -517,7 +525,9 @@ step-electron-build: &step-electron-build
|
||||
ninja -C out/Default electron:electron_mksnapshot_zip -j $NUMBER_OF_NINJA_PROCESSES
|
||||
ninja -C out/Default tools/v8_context_snapshot -j $NUMBER_OF_NINJA_PROCESSES
|
||||
gn desc out/Default v8:run_mksnapshot_default args > out/Default/mksnapshot_args
|
||||
rm -rf out/Default/clang_x64_v8_arm64/gen
|
||||
rm -rf out/Default/clang_x64_v8_arm64/obj
|
||||
rm -rf out/Default/clang_x64/obj
|
||||
|
||||
# Regenerate because we just deleted some ninja files
|
||||
gn gen out/Default --args="import(\"$GN_CONFIG\") import(\"$GN_GOMA_FILE\") $GN_EXTRA_ARGS $GN_BUILDFLAG_ARGS"
|
||||
@@ -840,7 +850,7 @@ step-maybe-zip-symbols: &step-maybe-zip-symbols
|
||||
export BUILD_PATH="$PWD/out/Default"
|
||||
ninja -C out/Default electron:licenses
|
||||
ninja -C out/Default electron:electron_version
|
||||
electron/script/zip-symbols.py -b $BUILD_PATH
|
||||
DELETE_DSYMS_AFTER_ZIP=1 electron/script/zip-symbols.py -b $BUILD_PATH
|
||||
|
||||
step-symbols-store: &step-symbols-store
|
||||
store_artifacts:
|
||||
@@ -920,7 +930,7 @@ step-ninja-summary: &step-ninja-summary
|
||||
command: |
|
||||
set +e
|
||||
set +o pipefail
|
||||
python depot_tools/post_build_ninja_summary.py -C src/out/Default
|
||||
python depot_tools/post_build_ninja_summary.py -C src/out/Default || echo Ninja Summary Failed
|
||||
|
||||
step-ninja-report: &step-ninja-report
|
||||
store_artifacts:
|
||||
@@ -1018,7 +1028,7 @@ step-minimize-workspace-size-from-checkout: &step-minimize-workspace-size-from-c
|
||||
name: Remove some unused data to avoid storing it in the workspace/cache
|
||||
command: |
|
||||
rm -rf src/android_webview
|
||||
rm -rf src/ios
|
||||
rm -rf src/ios/chrome
|
||||
rm -rf src/third_party/blink/web_tests
|
||||
rm -rf src/third_party/blink/perf_tests
|
||||
rm -rf src/third_party/WebKit/LayoutTests
|
||||
@@ -1340,6 +1350,8 @@ steps-tests: &steps-tests
|
||||
|
||||
- *step-maybe-notify-slack-failure
|
||||
|
||||
- *step-maybe-cleanup-arm64-mac
|
||||
|
||||
steps-test-nan: &steps-test-nan
|
||||
steps:
|
||||
- attach_workspace:
|
||||
@@ -1372,9 +1384,6 @@ steps-test-node: &steps-test-node
|
||||
- store_test_results:
|
||||
path: src/junit
|
||||
|
||||
chromium-upgrade-branches: &chromium-upgrade-branches
|
||||
/chromium\-upgrade\/[0-9]+/
|
||||
|
||||
# Command Aliases
|
||||
commands:
|
||||
maybe-restore-portaled-src-cache:
|
||||
@@ -2077,20 +2086,6 @@ jobs:
|
||||
<<: *env-testing-build
|
||||
<<: *steps-electron-gn-check
|
||||
|
||||
osx-release-x64:
|
||||
<<: *machine-mac-large
|
||||
environment:
|
||||
<<: *env-mac-large
|
||||
<<: *env-release-build
|
||||
<<: *env-ninja-status
|
||||
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
|
||||
|
||||
osx-publish-x64:
|
||||
<<: *machine-mac-large
|
||||
environment:
|
||||
@@ -2104,7 +2099,7 @@ jobs:
|
||||
checkout: true
|
||||
|
||||
osx-publish-arm64:
|
||||
<<: *machine-mac-large-arm
|
||||
<<: *machine-mac-large
|
||||
environment:
|
||||
<<: *env-mac-large-release
|
||||
<<: *env-release-build
|
||||
@@ -2129,7 +2124,7 @@ jobs:
|
||||
checkout: false
|
||||
|
||||
osx-publish-arm64-skip-checkout:
|
||||
<<: *machine-mac-large-arm
|
||||
<<: *machine-mac-large
|
||||
environment:
|
||||
<<: *env-mac-large-release
|
||||
<<: *env-release-build
|
||||
@@ -2142,7 +2137,7 @@ jobs:
|
||||
checkout: false
|
||||
|
||||
osx-testing-arm64:
|
||||
<<: *machine-mac-large-arm
|
||||
<<: *machine-mac-large
|
||||
environment:
|
||||
<<: *env-mac-large
|
||||
<<: *env-testing-build
|
||||
@@ -2181,21 +2176,6 @@ jobs:
|
||||
<<: *env-mas
|
||||
<<: *env-testing-build
|
||||
<<: *steps-electron-gn-check
|
||||
|
||||
mas-release:
|
||||
<<: *machine-mac-large
|
||||
environment:
|
||||
<<: *env-mac-large
|
||||
<<: *env-mas
|
||||
<<: *env-release-build
|
||||
<<: *env-ninja-status
|
||||
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-publish:
|
||||
<<: *machine-mac-large
|
||||
@@ -2211,7 +2191,7 @@ jobs:
|
||||
checkout: true
|
||||
|
||||
mas-publish-arm64:
|
||||
<<: *machine-mac-large-arm
|
||||
<<: *machine-mac-large
|
||||
environment:
|
||||
<<: *env-mac-large-release
|
||||
<<: *env-mas-apple-silicon
|
||||
@@ -2236,7 +2216,7 @@ jobs:
|
||||
checkout: false
|
||||
|
||||
mas-publish-arm64-skip-checkout:
|
||||
<<: *machine-mac-large-arm
|
||||
<<: *machine-mac-large
|
||||
environment:
|
||||
<<: *env-mac-large-release
|
||||
<<: *env-mas-apple-silicon
|
||||
@@ -2249,7 +2229,7 @@ jobs:
|
||||
checkout: false
|
||||
|
||||
mas-testing-arm64:
|
||||
<<: *machine-mac-large-arm
|
||||
<<: *machine-mac-large
|
||||
environment:
|
||||
<<: *env-mac-large
|
||||
<<: *env-testing-build
|
||||
@@ -2311,7 +2291,7 @@ jobs:
|
||||
<<: *steps-tests
|
||||
|
||||
linux-x64-testing-asan-tests:
|
||||
<<: *machine-linux-medium
|
||||
<<: *machine-linux-xlarge
|
||||
environment:
|
||||
<<: *env-linux-medium
|
||||
<<: *env-headless-testing
|
||||
@@ -2407,21 +2387,6 @@ jobs:
|
||||
parallelism: 2
|
||||
<<: *steps-tests
|
||||
|
||||
osx-release-x64-tests:
|
||||
<<: *machine-mac-large
|
||||
environment:
|
||||
<<: *env-mac-large
|
||||
<<: *env-stack-dumping
|
||||
<<: *env-send-slack-notifications
|
||||
<<: *steps-tests
|
||||
|
||||
osx-verify-ffmpeg:
|
||||
<<: *machine-mac
|
||||
environment:
|
||||
<<: *env-machine-mac
|
||||
<<: *env-send-slack-notifications
|
||||
<<: *steps-verify-ffmpeg
|
||||
|
||||
osx-testing-arm64-tests:
|
||||
<<: *machine-mac-arm64
|
||||
environment:
|
||||
@@ -2438,21 +2403,6 @@ jobs:
|
||||
parallelism: 2
|
||||
<<: *steps-tests
|
||||
|
||||
mas-release-tests:
|
||||
<<: *machine-mac-large
|
||||
environment:
|
||||
<<: *env-mac-large
|
||||
<<: *env-stack-dumping
|
||||
<<: *env-send-slack-notifications
|
||||
<<: *steps-tests
|
||||
|
||||
mas-verify-ffmpeg:
|
||||
<<: *machine-mac
|
||||
environment:
|
||||
<<: *env-machine-mac
|
||||
<<: *env-send-slack-notifications
|
||||
<<: *steps-verify-ffmpeg
|
||||
|
||||
mas-testing-arm64-tests:
|
||||
<<: *machine-mac-arm64
|
||||
environment:
|
||||
@@ -2494,22 +2444,6 @@ jobs:
|
||||
steps:
|
||||
- *step-maybe-notify-slack-success
|
||||
|
||||
mas-release-summary:
|
||||
<<: *machine-mac
|
||||
environment:
|
||||
<<: *env-machine-mac
|
||||
<<: *env-send-slack-notifications
|
||||
steps:
|
||||
- *step-maybe-notify-slack-success
|
||||
|
||||
osx-release-x64-summary:
|
||||
<<: *machine-mac
|
||||
environment:
|
||||
<<: *env-machine-mac
|
||||
<<: *env-send-slack-notifications
|
||||
steps:
|
||||
- *step-maybe-notify-slack-success
|
||||
|
||||
workflows:
|
||||
version: 2.1
|
||||
|
||||
@@ -2586,7 +2520,7 @@ workflows:
|
||||
when: << pipeline.parameters.run-mas-publish-arm64 >>
|
||||
jobs:
|
||||
- mas-publish-arm64:
|
||||
context: release-env
|
||||
context: release-env
|
||||
|
||||
publish-macos:
|
||||
when: << pipeline.parameters.run-macos-publish >>
|
||||
@@ -2595,15 +2529,19 @@ workflows:
|
||||
- osx-publish-x64-skip-checkout:
|
||||
requires:
|
||||
- mac-checkout
|
||||
context: release-env
|
||||
- mas-publish-x64-skip-checkout:
|
||||
requires:
|
||||
- mac-checkout
|
||||
context: release-env
|
||||
- osx-publish-arm64-skip-checkout:
|
||||
requires:
|
||||
- mac-checkout
|
||||
context: release-env
|
||||
- mas-publish-arm64-skip-checkout:
|
||||
requires:
|
||||
- mac-checkout
|
||||
context: release-env
|
||||
|
||||
lint:
|
||||
when: << pipeline.parameters.run-lint >>
|
||||
@@ -2716,7 +2654,6 @@ workflows:
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- *chromium-upgrade-branches
|
||||
jobs:
|
||||
- linux-checkout-fast
|
||||
- linux-checkout-and-save-cache
|
||||
@@ -2757,49 +2694,6 @@ workflows:
|
||||
requires:
|
||||
- linux-arm64-release
|
||||
|
||||
nightly-mac-release-test:
|
||||
triggers:
|
||||
- schedule:
|
||||
cron: "0 0 * * *"
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- *chromium-upgrade-branches
|
||||
jobs:
|
||||
- mac-checkout-fast
|
||||
- mac-checkout-and-save-cache
|
||||
|
||||
- osx-release-x64:
|
||||
requires:
|
||||
- mac-checkout-and-save-cache
|
||||
- osx-release-x64-tests:
|
||||
requires:
|
||||
- osx-release-x64
|
||||
- osx-verify-ffmpeg:
|
||||
requires:
|
||||
- osx-release-x64
|
||||
- osx-release-x64-summary:
|
||||
requires:
|
||||
- osx-release-x64
|
||||
- osx-release-x64-tests
|
||||
- osx-verify-ffmpeg
|
||||
|
||||
- mas-release:
|
||||
requires:
|
||||
- mac-checkout-and-save-cache
|
||||
- mas-release-tests:
|
||||
requires:
|
||||
- mas-release
|
||||
- mas-verify-ffmpeg:
|
||||
requires:
|
||||
- mas-release
|
||||
- mas-release-summary:
|
||||
requires:
|
||||
- mas-release
|
||||
- mas-release-tests
|
||||
- mas-verify-ffmpeg
|
||||
|
||||
# Various slow and non-essential checks we run only nightly.
|
||||
# Sanitizer jobs should be added here.
|
||||
linux-checks-nightly:
|
||||
@@ -2810,7 +2704,6 @@ workflows:
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- *chromium-upgrade-branches
|
||||
jobs:
|
||||
- linux-checkout-for-native-tests
|
||||
|
||||
|
||||
@@ -4,4 +4,3 @@
|
||||
APPVEYOR_CLOUD_TOKEN=
|
||||
CIRCLE_TOKEN=
|
||||
ELECTRON_GITHUB_TOKEN=
|
||||
VSTS_TOKEN=
|
||||
6
.github/CODEOWNERS
vendored
6
.github/CODEOWNERS
vendored
@@ -13,9 +13,3 @@ DEPS @electron/wg-upgrades
|
||||
|
||||
# Security WG
|
||||
/lib/browser/rpc-server.ts @electron/wg-security
|
||||
|
||||
# Remote Change Disliker
|
||||
/lib/browser/remote/ @nornagon
|
||||
/lib/renderer/remote/ @nornagon
|
||||
/lib/renderer/api/remote.ts @nornagon
|
||||
/docs/api/remote.md @nornagon
|
||||
|
||||
58
.github/ISSUE_TEMPLATE/Bug_report.md
vendored
58
.github/ISSUE_TEMPLATE/Bug_report.md
vendored
@@ -1,58 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve Electron
|
||||
|
||||
---
|
||||
|
||||
<!-- As an open source project with a dedicated but small maintainer team, it can sometimes take a long time for issues to be addressed so please be patient and we will get back to you as soon as we can.
|
||||
-->
|
||||
|
||||
### Preflight Checklist
|
||||
<!-- Please ensure you've completed the following steps by replacing [ ] with [x]-->
|
||||
|
||||
* [ ] I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/master/CONTRIBUTING.md) for this project.
|
||||
* [ ] I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/master/CODE_OF_CONDUCT.md) that this project adheres to.
|
||||
* [ ] I have searched the issue tracker for an issue that matches the one I want to file, without success.
|
||||
|
||||
### Issue Details
|
||||
|
||||
* **Electron Version:**
|
||||
* <!-- (output of `node_modules/.bin/electron --version`) e.g. 4.0.3 -->
|
||||
* **Operating System:**
|
||||
* <!-- (Platform and Version) e.g. macOS 10.13.6 / Windows 10 (1803) / Ubuntu 18.04 x64 -->
|
||||
* **Last Known Working Electron version:**
|
||||
* <!-- (if applicable) e.g. 3.1.0 -->
|
||||
|
||||
### Expected Behavior
|
||||
<!-- A clear and concise description of what you expected to happen. -->
|
||||
|
||||
### Actual Behavior
|
||||
<!-- A clear and concise description of what actually happened. -->
|
||||
|
||||
### To Reproduce
|
||||
<!--
|
||||
Your best chance of getting this bug looked at quickly is to provide an example.
|
||||
-->
|
||||
|
||||
<!--
|
||||
For bugs that can be encapsulated in a small experiment, you can use Electron Fiddle (https://github.com/electron/fiddle) to publish your example to a GitHub Gist and link it your bug report.
|
||||
-->
|
||||
|
||||
<!--
|
||||
If Fiddle is insufficient to produce an example, please provide an example REPOSITORY that can be cloned and run. You can fork electron-quick-start (https://github.com/electron/electron-quick-start) and include a link to the branch with your changes.
|
||||
-->
|
||||
|
||||
<!--
|
||||
If you provide a URL, please list the commands required to clone/setup/run your repo e.g.
|
||||
```sh
|
||||
$ git clone $YOUR_URL -b $BRANCH
|
||||
$ npm install
|
||||
$ npm start || electron .
|
||||
```
|
||||
-->
|
||||
|
||||
### Screenshots
|
||||
<!-- If applicable, add screenshots to help explain your problem. -->
|
||||
|
||||
### Additional Information
|
||||
<!-- Add any other context about the problem here. -->
|
||||
77
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
77
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
name: Bug Report
|
||||
description: Report an Electron bug
|
||||
title: "[Bug]: "
|
||||
labels: "bug :beetle:"
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Preflight Checklist
|
||||
description: Please ensure you've completed all of the following.
|
||||
options:
|
||||
- label: I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/master/CONTRIBUTING.md) for this project.
|
||||
required: true
|
||||
- label: I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/master/CODE_OF_CONDUCT.md) that this project adheres to.
|
||||
required: true
|
||||
- label: I have searched the [issue tracker](https://www.github.com/electron/electron/issues) for a feature request that matches the one I want to file, without success.
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: Electron Version
|
||||
description: What version of Electron are you using?
|
||||
placeholder: 12.0.0
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: What operating system are you using?
|
||||
options:
|
||||
- Windows
|
||||
- macOS
|
||||
- Ubuntu
|
||||
- Other Linux
|
||||
- Other (specify below)
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: Operating System Version
|
||||
description: What operating system version are you using? On Windows, click Start button > Settings > System > About. On macOS, click the Apple Menu > About This Mac. On Linux, use lsb_release or uname -a.
|
||||
placeholder: "e.g. Windows 10 version 1909, macOS Catalina 10.15.7, or Ubuntu 20.04"
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: What arch are you using?
|
||||
options:
|
||||
- x64
|
||||
- ia32
|
||||
- arm64 (including Apple Silicon)
|
||||
- Other (specify below)
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: Last Known Working Electron version
|
||||
description: What is the last version of Electron this worked in, if applicable?
|
||||
placeholder: 11.0.0
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Expected Behavior
|
||||
description: A clear and concise description of what you expected to happen.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Actual Behavior
|
||||
description: A clear description of what actually happens.
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: Testcase Gist URL
|
||||
description: If you can reproduce the issue in a standalone test case, please use [Electron Fiddle](https://github.com/electron/fiddle) to create one and to publish it as a [GitHub gist](https://gist.github.com) and put the gist URL here. This is **the best way** to ensure this issue is triaged quickly.
|
||||
placeholder: https://gist.github.com/...
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional Information
|
||||
description: If your problem needs further explanation, or if the issue you're seeing cannot be reproduced in a gist, please add more information here.
|
||||
21
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
21
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@@ -1,18 +1,19 @@
|
||||
name: Feature Request
|
||||
about: Suggest an idea for Electron
|
||||
description: Suggest an idea for Electron
|
||||
title: "[Feature Request]: "
|
||||
labels: "enhancement ✨"
|
||||
labels: "enhancement :sparkles:"
|
||||
body:
|
||||
- type: textarea
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Preflight Checklist
|
||||
description: Please ensure you've completed the following steps by replacing [ ] with [x]
|
||||
value: |
|
||||
* [ ] I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/master/CONTRIBUTING.md) for this project.
|
||||
* [ ] I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/master/CODE_OF_CONDUCT.md) that this project adheres to.
|
||||
* [ ] I have searched the issue tracker for a feature request that matches the one I want to file, without success.
|
||||
validations:
|
||||
required: true
|
||||
description: Please ensure you've completed all of the following.
|
||||
options:
|
||||
- label: I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/master/CONTRIBUTING.md) for this project.
|
||||
required: true
|
||||
- label: I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/master/CODE_OF_CONDUCT.md) that this project adheres to.
|
||||
required: true
|
||||
- label: I have searched the [issue tracker](https://www.github.com/electron/electron/issues) for a feature request that matches the one I want to file, without success.
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Problem Description
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
---
|
||||
name: Mac App Store Private API Rejection
|
||||
about: Your app was rejected from the Mac App Store for using private API's
|
||||
|
||||
---
|
||||
|
||||
<!-- As an open source project with a dedicated but small maintainer team, it can sometimes take a long time for issues to be addressed so please be patient and we will get back to you as soon as we can.
|
||||
-->
|
||||
|
||||
### Preflight Checklist
|
||||
<!-- Please ensure you've completed the following steps by replacing [ ] with [x]-->
|
||||
|
||||
* [ ] I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/master/CONTRIBUTING.md) for this project.
|
||||
* [ ] I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/master/CODE_OF_CONDUCT.md) that this project adheres to.
|
||||
|
||||
### Issue Details
|
||||
|
||||
* **Electron Version:**
|
||||
* <!-- (output of `node_modules/.bin/electron --version`) e.g. 4.0.3 -->
|
||||
|
||||
### Rejection Email
|
||||
<!-- Paste the contents of your rejection email here, censoring any private information such as app names.-->
|
||||
|
||||
### Additional Information
|
||||
<!-- Add any other context about the problem here. -->
|
||||
30
.github/ISSUE_TEMPLATE/mac_app_store_private_api_rejection.yml
vendored
Normal file
30
.github/ISSUE_TEMPLATE/mac_app_store_private_api_rejection.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
name: Report Mac App Store Private API Rejection
|
||||
description: Your app was rejected from the Mac App Store for using private API's
|
||||
title: "[MAS Rejection]: "
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Preflight Checklist
|
||||
description: Please ensure you've completed all of the following.
|
||||
options:
|
||||
- label: I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/master/CONTRIBUTING.md) for this project.
|
||||
required: true
|
||||
- label: I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/master/CODE_OF_CONDUCT.md) that this project adheres to.
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: Electron Version
|
||||
description: What version of Electron are you using?
|
||||
placeholder: 12.0.0
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Rejection Email
|
||||
description: Paste the contents of your rejection email here, censoring any private information such as app names.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional Information
|
||||
description: Add any other context about the problem here.
|
||||
22
.gitignore
vendored
22
.gitignore
vendored
@@ -17,24 +17,6 @@
|
||||
*.xcodeproj
|
||||
/.idea/
|
||||
/dist/
|
||||
/external_binaries/
|
||||
/out/
|
||||
/vendor/.gclient
|
||||
/vendor/debian_jessie_mips64-sysroot/
|
||||
/vendor/debian_stretch_amd64-sysroot/
|
||||
/vendor/debian_stretch_arm-sysroot/
|
||||
/vendor/debian_stretch_arm64-sysroot/
|
||||
/vendor/debian_stretch_i386-sysroot/
|
||||
/vendor/gcc-4.8.3-d197-n64-loongson/
|
||||
/vendor/readme-gcc483-loongson.txt
|
||||
/vendor/download/
|
||||
/vendor/llvm-build/
|
||||
/vendor/llvm/
|
||||
/vendor/npm/
|
||||
/vendor/python_26/
|
||||
/vendor/native_mksnapshot
|
||||
/vendor/LICENSES.chromium.html
|
||||
/vendor/pyyaml
|
||||
node_modules/
|
||||
SHASUMS256.txt
|
||||
**/package-lock.json
|
||||
@@ -68,4 +50,6 @@ ts-gen
|
||||
.depshash-target
|
||||
|
||||
# Used to accelerate builds after sync
|
||||
patches/mtime-cache.json
|
||||
patches/mtime-cache.json
|
||||
|
||||
spec/fixtures/logo.png
|
||||
1
.husky/.gitignore
vendored
Normal file
1
.husky/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
_
|
||||
4
.husky/pre-commit
Executable file
4
.husky/pre-commit
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
npm run precommit
|
||||
4
.husky/pre-push
Executable file
4
.husky/pre-push
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
npm run prepack
|
||||
28
BUILD.gn
28
BUILD.gn
@@ -32,6 +32,10 @@ if (is_mac) {
|
||||
import("//ui/gl/features.gni")
|
||||
import("//v8/gni/v8.gni")
|
||||
import("build/rules.gni")
|
||||
|
||||
assert(
|
||||
mac_deployment_target == "10.11.0",
|
||||
"Chromium has updated the mac_deployment_target, please update this assert, update the supported versions documentation (docs/tutorial/support.md) and flag this as a breaking change")
|
||||
}
|
||||
|
||||
if (is_linux) {
|
||||
@@ -402,7 +406,10 @@ source_set("electron_lib") {
|
||||
}
|
||||
|
||||
if (!is_mas_build) {
|
||||
deps += [ "//components/crash/core/app" ]
|
||||
deps += [
|
||||
"//components/crash/core/app",
|
||||
"//components/crash/core/browser",
|
||||
]
|
||||
}
|
||||
|
||||
sources = filenames.lib_sources
|
||||
@@ -434,12 +441,16 @@ source_set("electron_lib") {
|
||||
}
|
||||
|
||||
if (is_linux) {
|
||||
deps += [ "//components/crash/content/browser" ]
|
||||
deps += [
|
||||
"//build/config/linux/gtk:gtkprint",
|
||||
"//components/crash/content/browser",
|
||||
]
|
||||
}
|
||||
|
||||
if (is_mac) {
|
||||
deps += [
|
||||
"//components/remote_cocoa/app_shim",
|
||||
"//components/remote_cocoa/browser",
|
||||
"//content/common:mac_helpers",
|
||||
"//ui/accelerated_widget_mac",
|
||||
]
|
||||
@@ -505,10 +516,6 @@ source_set("electron_lib") {
|
||||
]
|
||||
if (use_x11) {
|
||||
sources += filenames.lib_sources_linux_x11
|
||||
deps += [
|
||||
"//ui/gfx/x",
|
||||
"//ui/gtk/x",
|
||||
]
|
||||
}
|
||||
configs += [ ":gio_unix" ]
|
||||
defines += [
|
||||
@@ -619,6 +626,9 @@ source_set("electron_lib") {
|
||||
"//chrome/services/printing/public/mojom",
|
||||
"//components/printing/common:mojo_interfaces",
|
||||
]
|
||||
if (is_mac) {
|
||||
deps += [ "//chrome/services/mac_notifications/public/mojom" ]
|
||||
}
|
||||
}
|
||||
|
||||
if (enable_electron_extensions) {
|
||||
@@ -632,6 +642,7 @@ source_set("electron_lib") {
|
||||
"//components/zoom",
|
||||
"//extensions/browser",
|
||||
"//extensions/browser:core_api_provider",
|
||||
"//extensions/browser/updater",
|
||||
"//extensions/common",
|
||||
"//extensions/common:core_api_provider",
|
||||
"//extensions/renderer",
|
||||
@@ -1153,11 +1164,6 @@ if (is_mac) {
|
||||
"//build/config/win:delayloads",
|
||||
]
|
||||
|
||||
if (target_cpu == "arm64") {
|
||||
configs -= [ "//build/config/win:cfi_linker" ]
|
||||
ldflags += [ "/guard:cf,nolongjmp" ]
|
||||
}
|
||||
|
||||
if (current_cpu == "x86") {
|
||||
# Set the initial stack size to 0.5MiB, instead of the 1.5MiB needed by
|
||||
# Chrome's main thread. This saves significant memory on threads (like
|
||||
|
||||
10
DEPS
10
DEPS
@@ -14,11 +14,11 @@ gclient_gn_args = [
|
||||
|
||||
vars = {
|
||||
'chromium_version':
|
||||
'1f252b391a40e2681b0d9aff6497b7401863d1fc',
|
||||
'92.0.4498.0',
|
||||
'node_version':
|
||||
'v14.16.0',
|
||||
'v14.16.1',
|
||||
'nan_version':
|
||||
'2c4ee8a32a299eada3cd6e468bbd0a473bfea96d',
|
||||
'v2.14.2',
|
||||
'squirrel.mac_version':
|
||||
'cdc0729c8bf8576bfef18629186e1e9ecf1b0d9f',
|
||||
|
||||
@@ -48,6 +48,8 @@ vars = {
|
||||
# It's only needed to parse the native tests configurations.
|
||||
'checkout_pyyaml': False,
|
||||
|
||||
'use_rts': False,
|
||||
|
||||
'mac_xcode_version': 'default',
|
||||
|
||||
# To allow running hooks without parsing the DEPS tree
|
||||
@@ -86,7 +88,7 @@ deps = {
|
||||
'url': (Var("nodejs_git")) + '/node.git@' + (Var("node_version")),
|
||||
'condition': 'checkout_node and process_deps',
|
||||
},
|
||||
'src/electron/vendor/pyyaml': {
|
||||
'src/third_party/pyyaml': {
|
||||
'url': (Var("yaml_git")) + '/pyyaml.git@' + (Var("pyyaml_version")),
|
||||
'condition': 'checkout_pyyaml and process_deps',
|
||||
},
|
||||
|
||||
@@ -1 +1 @@
|
||||
13.0.0-nightly.20210303
|
||||
14.0.0-nightly.20210506
|
||||
@@ -36,6 +36,7 @@ environment:
|
||||
ELECTRON_ENABLE_STACK_DUMPING: 1
|
||||
MOCHA_REPORTER: mocha-multi-reporters
|
||||
MOCHA_MULTI_REPORTERS: mocha-appveyor-reporter, tap
|
||||
GOMA_FALLBACK_ON_AUTH_FAILURE: true
|
||||
notifications:
|
||||
- provider: Webhook
|
||||
url: https://electron-mission-control.herokuapp.com/rest/appveyor-hook
|
||||
|
||||
@@ -19,4 +19,12 @@ enable_basic_printing = true
|
||||
angle_enable_vulkan_validation_layers = false
|
||||
dawn_enable_vulkan_validation_layers = false
|
||||
|
||||
# This breaks native node modules
|
||||
libcxx_abi_unstable = false
|
||||
|
||||
# These are disabled because they cause the zip manifest to differ between
|
||||
# testing and release builds.
|
||||
# See https://chromium-review.googlesource.com/c/chromium/src/+/2774898.
|
||||
enable_pseudolocales = false
|
||||
|
||||
is_cfi = false
|
||||
|
||||
@@ -39,7 +39,7 @@ def main(dump_syms, binary, out_dir, stamp_file, dsym_file=None):
|
||||
args += ["-g", dsym_file]
|
||||
args += [binary]
|
||||
|
||||
symbol_data = subprocess.check_output(args)
|
||||
symbol_data = subprocess.check_output(args).decode(sys.stdout.encoding)
|
||||
symbol_path = os.path.join(out_dir, get_symbol_path(symbol_data))
|
||||
mkdir_p(os.path.dirname(symbol_path))
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
# require any direct Cocoa locale support.
|
||||
|
||||
import os
|
||||
import errno
|
||||
import sys
|
||||
|
||||
|
||||
@@ -16,7 +17,7 @@ def main(args):
|
||||
try:
|
||||
os.makedirs(dirname)
|
||||
except OSError as e:
|
||||
if e.errno == os.errno.EEXIST:
|
||||
if e.errno == errno.EEXIST:
|
||||
# It's OK if it already exists
|
||||
pass
|
||||
else:
|
||||
|
||||
@@ -15,12 +15,6 @@ args = [cmd, "run",
|
||||
try:
|
||||
subprocess.check_output(args, stderr=subprocess.STDOUT)
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(
|
||||
"NPM script '"
|
||||
+ sys.argv[2]
|
||||
+ "' failed with code '"
|
||||
+ str(e.returncode)
|
||||
+ "':\n"
|
||||
+ e.output
|
||||
)
|
||||
error_msg = "NPM script '{}' failed with code '{}':\n".format(sys.argv[2], e.returncode)
|
||||
print(error_msg + e.output.decode('ascii'))
|
||||
sys.exit(e.returncode)
|
||||
|
||||
@@ -61,13 +61,6 @@ module.exports = ({
|
||||
);
|
||||
}
|
||||
|
||||
if (defines.ENABLE_REMOTE_MODULE === 'false') {
|
||||
ignoredModules.push(
|
||||
'@electron/internal/browser/remote/server',
|
||||
'@electron/internal/renderer/api/remote'
|
||||
);
|
||||
}
|
||||
|
||||
if (defines.ENABLE_VIEWS_API === 'false') {
|
||||
ignoredModules.push(
|
||||
'@electron/internal/browser/api/views/image-view.js'
|
||||
@@ -163,7 +156,7 @@ if ((globalThis.process || binding.process).argv.includes("--profile-electron-in
|
||||
setImmediate: false
|
||||
},
|
||||
optimization: {
|
||||
minimize: true,
|
||||
minimize: env.mode === 'production',
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
terserOptions: {
|
||||
|
||||
@@ -22,6 +22,11 @@ template("webpack_build") {
|
||||
"//electron/typings/internal-electron.d.ts",
|
||||
] + invoker.inputs
|
||||
|
||||
mode = "development"
|
||||
if (is_official_build) {
|
||||
mode = "production"
|
||||
}
|
||||
|
||||
args = [
|
||||
"--config",
|
||||
rebase_path(invoker.config_file),
|
||||
@@ -29,6 +34,7 @@ template("webpack_build") {
|
||||
"--output-path=" + rebase_path(get_path_info(invoker.out_file, "dir")),
|
||||
"--env.buildflags=" +
|
||||
rebase_path("$target_gen_dir/buildflags/buildflags.h"),
|
||||
"--env.mode=" + mode,
|
||||
]
|
||||
deps += [ "buildflags" ]
|
||||
|
||||
|
||||
@@ -39,6 +39,8 @@ PATHS_TO_SKIP = [
|
||||
'./crashpad_handler',
|
||||
# Skip because these are outputs that we don't need.
|
||||
'resources/inspector',
|
||||
'gen/third_party/devtools-frontend/src',
|
||||
'gen/ui/webui'
|
||||
]
|
||||
|
||||
def skip_path(dep, dist_zip, target_cpu):
|
||||
|
||||
@@ -12,7 +12,6 @@ buildflag_header("buildflags") {
|
||||
"ENABLE_DESKTOP_CAPTURER=$enable_desktop_capturer",
|
||||
"ENABLE_RUN_AS_NODE=$enable_run_as_node",
|
||||
"ENABLE_OSR=$enable_osr",
|
||||
"ENABLE_REMOTE_MODULE=$enable_remote_module",
|
||||
"ENABLE_VIEWS_API=$enable_views_api",
|
||||
"ENABLE_PDF_VIEWER=$enable_pdf_viewer",
|
||||
"ENABLE_TTS=$enable_tts",
|
||||
|
||||
@@ -10,8 +10,6 @@ declare_args() {
|
||||
|
||||
enable_osr = true
|
||||
|
||||
enable_remote_module = true
|
||||
|
||||
enable_views_api = true
|
||||
|
||||
enable_pdf_viewer = true
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# Use of this source code is governed by the MIT license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
import("//build/config/ozone.gni")
|
||||
import("//build/config/ui.gni")
|
||||
import("//components/spellcheck/spellcheck_build_features.gni")
|
||||
import("//electron/buildflags/buildflags.gni")
|
||||
@@ -16,8 +17,6 @@ static_library("chrome") {
|
||||
"//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",
|
||||
"//chrome/browser/crash_upload_list/crash_upload_list_crashpad.h",
|
||||
"//chrome/browser/devtools/devtools_contents_resizing_strategy.cc",
|
||||
"//chrome/browser/devtools/devtools_contents_resizing_strategy.h",
|
||||
"//chrome/browser/devtools/devtools_embedder_message_dispatcher.cc",
|
||||
@@ -46,7 +45,6 @@ static_library("chrome") {
|
||||
"//chrome/browser/predictors/resolve_host_client_impl.h",
|
||||
"//chrome/browser/ssl/security_state_tab_helper.cc",
|
||||
"//chrome/browser/ssl/security_state_tab_helper.h",
|
||||
"//chrome/browser/ssl/tls_deprecation_config.cc",
|
||||
"//chrome/browser/ui/views/autofill/autofill_popup_view_utils.cc",
|
||||
"//chrome/browser/ui/views/autofill/autofill_popup_view_utils.h",
|
||||
"//extensions/browser/app_window/size_constraints.cc",
|
||||
@@ -95,12 +93,18 @@ static_library("chrome") {
|
||||
|
||||
if (is_linux) {
|
||||
sources += [ "//chrome/browser/icon_loader_auralinux.cc" ]
|
||||
if (use_x11 || use_ozone) {
|
||||
sources +=
|
||||
[ "//chrome/browser/extensions/global_shortcut_listener_linux.cc" ]
|
||||
}
|
||||
if (use_x11) {
|
||||
sources += [
|
||||
"//chrome/browser/extensions/global_shortcut_listener_x11.cc",
|
||||
"//chrome/browser/extensions/global_shortcut_listener_x11.h",
|
||||
]
|
||||
} else if (use_ozone) {
|
||||
}
|
||||
if (use_ozone) {
|
||||
deps += [ "//ui/ozone" ]
|
||||
sources += [
|
||||
"//chrome/browser/extensions/global_shortcut_listener_ozone.cc",
|
||||
"//chrome/browser/extensions/global_shortcut_listener_ozone.h",
|
||||
@@ -191,7 +195,7 @@ static_library("chrome") {
|
||||
}
|
||||
|
||||
if (is_linux) {
|
||||
sources += [ "//chrome/browser/media/webrtc/window_icon_util_x11.cc" ]
|
||||
sources += [ "//chrome/browser/media/webrtc/window_icon_util_linux.cc" ]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,8 +257,12 @@ static_library("chrome") {
|
||||
"//chrome/browser/picture_in_picture/picture_in_picture_window_manager.h",
|
||||
"//chrome/browser/ui/views/overlay/back_to_tab_image_button.cc",
|
||||
"//chrome/browser/ui/views/overlay/back_to_tab_image_button.h",
|
||||
"//chrome/browser/ui/views/overlay/back_to_tab_label_button.cc",
|
||||
"//chrome/browser/ui/views/overlay/close_image_button.cc",
|
||||
"//chrome/browser/ui/views/overlay/close_image_button.h",
|
||||
"//chrome/browser/ui/views/overlay/constants.h",
|
||||
"//chrome/browser/ui/views/overlay/hang_up_button.cc",
|
||||
"//chrome/browser/ui/views/overlay/hang_up_button.h",
|
||||
"//chrome/browser/ui/views/overlay/overlay_window_views.cc",
|
||||
"//chrome/browser/ui/views/overlay/overlay_window_views.h",
|
||||
"//chrome/browser/ui/views/overlay/playback_image_button.cc",
|
||||
@@ -263,6 +271,10 @@ static_library("chrome") {
|
||||
"//chrome/browser/ui/views/overlay/resize_handle_button.h",
|
||||
"//chrome/browser/ui/views/overlay/skip_ad_label_button.cc",
|
||||
"//chrome/browser/ui/views/overlay/skip_ad_label_button.h",
|
||||
"//chrome/browser/ui/views/overlay/toggle_camera_button.cc",
|
||||
"//chrome/browser/ui/views/overlay/toggle_camera_button.h",
|
||||
"//chrome/browser/ui/views/overlay/toggle_microphone_button.cc",
|
||||
"//chrome/browser/ui/views/overlay/toggle_microphone_button.h",
|
||||
"//chrome/browser/ui/views/overlay/track_image_button.cc",
|
||||
"//chrome/browser/ui/views/overlay/track_image_button.h",
|
||||
]
|
||||
|
||||
@@ -90,7 +90,7 @@ CertificateManagerModel::~CertificateManagerModel() = default;
|
||||
int CertificateManagerModel::ImportFromPKCS12(
|
||||
PK11SlotInfo* slot_info,
|
||||
const std::string& data,
|
||||
const base::string16& password,
|
||||
const std::u16string& password,
|
||||
bool is_extractable,
|
||||
net::ScopedCERTCertificateList* imported_certs) {
|
||||
return cert_db_->ImportFromPKCS12(slot_info, data, password, is_extractable,
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "base/callback.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/strings/string16.h"
|
||||
#include "net/cert/nss_cert_database.h"
|
||||
|
||||
namespace content {
|
||||
@@ -46,7 +45,7 @@ class CertificateManagerModel {
|
||||
// Returns a net error code on failure.
|
||||
int ImportFromPKCS12(PK11SlotInfo* slot_info,
|
||||
const std::string& data,
|
||||
const base::string16& password,
|
||||
const std::u16string& password,
|
||||
bool is_extractable,
|
||||
net::ScopedCERTCertificateList* imported_certs);
|
||||
|
||||
|
||||
@@ -41,19 +41,18 @@ ipcMain.handle('bootstrap', (event) => {
|
||||
return isTrustedSender(event.sender) ? electronPath : null;
|
||||
});
|
||||
|
||||
async function createWindow () {
|
||||
async function createWindow (backgroundColor?: string) {
|
||||
await app.whenReady();
|
||||
|
||||
const options: Electron.BrowserWindowConstructorOptions = {
|
||||
width: 960,
|
||||
height: 620,
|
||||
autoHideMenuBar: true,
|
||||
backgroundColor: '#2f3241',
|
||||
backgroundColor,
|
||||
webPreferences: {
|
||||
preload: path.resolve(__dirname, 'preload.js'),
|
||||
contextIsolation: true,
|
||||
sandbox: true,
|
||||
enableRemoteModule: false
|
||||
sandbox: true
|
||||
},
|
||||
useContentSize: true,
|
||||
show: false
|
||||
@@ -96,7 +95,7 @@ export const loadURL = async (appUrl: string) => {
|
||||
};
|
||||
|
||||
export const loadFile = async (appPath: string) => {
|
||||
mainWindow = await createWindow();
|
||||
mainWindow = await createWindow(appPath === 'index.html' ? '#2f3241' : undefined);
|
||||
mainWindow.loadFile(appPath);
|
||||
mainWindow.focus();
|
||||
};
|
||||
|
||||
@@ -59,6 +59,7 @@ an issue:
|
||||
* [Using Native Node.js Modules](tutorial/using-native-node-modules.md)
|
||||
* [Performance Strategies](tutorial/performance.md)
|
||||
* [Security Strategies](tutorial/security.md)
|
||||
* [Process Sandboxing](tutorial/sandbox.md)
|
||||
* [Accessibility](tutorial/accessibility.md)
|
||||
* [Manually Enabling Accessibility Features](tutorial/accessibility.md#manually-enabling-accessibility-features)
|
||||
* [Testing and Debugging](tutorial/application-debugging.md)
|
||||
@@ -68,6 +69,7 @@ an issue:
|
||||
* [Testing on Headless CI Systems (Travis, Jenkins)](tutorial/testing-on-headless-ci.md)
|
||||
* [DevTools Extension](tutorial/devtools-extension.md)
|
||||
* [Automated Testing with a Custom Driver](tutorial/automated-testing-with-a-custom-driver.md)
|
||||
* [REPL](tutorial/repl.md)
|
||||
* [Distribution](tutorial/application-distribution.md)
|
||||
* [Supported Platforms](tutorial/support.md#supported-platforms)
|
||||
* [Code Signing](tutorial/code-signing.md)
|
||||
@@ -126,6 +128,8 @@ These individual tutorials expand on topics discussed in the guide above.
|
||||
* [ipcMain](api/ipc-main.md)
|
||||
* [Menu](api/menu.md)
|
||||
* [MenuItem](api/menu-item.md)
|
||||
* [MessageChannelMain](api/message-channel-main.md)
|
||||
* [MessagePortMain](api/message-port-main.md)
|
||||
* [net](api/net.md)
|
||||
* [netLog](api/net-log.md)
|
||||
* [nativeTheme](api/native-theme.md)
|
||||
@@ -135,6 +139,7 @@ These individual tutorials expand on topics discussed in the guide above.
|
||||
* [protocol](api/protocol.md)
|
||||
* [screen](api/screen.md)
|
||||
* [session](api/session.md)
|
||||
* [ShareMenu](api/share-menu.md)
|
||||
* [systemPreferences](api/system-preferences.md)
|
||||
* [TouchBar](api/touch-bar.md)
|
||||
* [Tray](api/tray.md)
|
||||
@@ -144,15 +149,14 @@ These individual tutorials expand on topics discussed in the guide above.
|
||||
### Modules for the Renderer Process (Web Page):
|
||||
|
||||
* [contextBridge](api/context-bridge.md)
|
||||
* [desktopCapturer](api/desktop-capturer.md)
|
||||
* [ipcRenderer](api/ipc-renderer.md)
|
||||
* [remote](api/remote.md)
|
||||
* [webFrame](api/web-frame.md)
|
||||
|
||||
### Modules for Both Processes:
|
||||
|
||||
* [clipboard](api/clipboard.md)
|
||||
* [crashReporter](api/crash-reporter.md)
|
||||
* [desktopCapturer](api/desktop-capturer.md)
|
||||
* [nativeImage](api/native-image.md)
|
||||
* [shell](api/shell.md)
|
||||
|
||||
|
||||
@@ -507,64 +507,6 @@ Returns:
|
||||
Emitted when `desktopCapturer.getSources()` is called in the renderer process of `webContents`.
|
||||
Calling `event.preventDefault()` will make it return empty sources.
|
||||
|
||||
### Event: 'remote-require' _Deprecated_
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `webContents` [WebContents](web-contents.md)
|
||||
* `moduleName` String
|
||||
|
||||
Emitted when `remote.require()` is called in the renderer process of `webContents`.
|
||||
Calling `event.preventDefault()` will prevent the module from being returned.
|
||||
Custom value can be returned by setting `event.returnValue`.
|
||||
|
||||
### Event: 'remote-get-global' _Deprecated_
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `webContents` [WebContents](web-contents.md)
|
||||
* `globalName` String
|
||||
|
||||
Emitted when `remote.getGlobal()` is called in the renderer process of `webContents`.
|
||||
Calling `event.preventDefault()` will prevent the global from being returned.
|
||||
Custom value can be returned by setting `event.returnValue`.
|
||||
|
||||
### Event: 'remote-get-builtin' _Deprecated_
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `webContents` [WebContents](web-contents.md)
|
||||
* `moduleName` String
|
||||
|
||||
Emitted when `remote.getBuiltin()` is called in the renderer process of `webContents`.
|
||||
Calling `event.preventDefault()` will prevent the module from being returned.
|
||||
Custom value can be returned by setting `event.returnValue`.
|
||||
|
||||
### Event: 'remote-get-current-window' _Deprecated_
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `webContents` [WebContents](web-contents.md)
|
||||
|
||||
Emitted when `remote.getCurrentWindow()` is called in the renderer process of `webContents`.
|
||||
Calling `event.preventDefault()` will prevent the object from being returned.
|
||||
Custom value can be returned by setting `event.returnValue`.
|
||||
|
||||
### Event: 'remote-get-current-web-contents' _Deprecated_
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `webContents` [WebContents](web-contents.md)
|
||||
|
||||
Emitted when `remote.getCurrentWebContents()` is called in the renderer process of `webContents`.
|
||||
Calling `event.preventDefault()` will prevent the object from being returned.
|
||||
Custom value can be returned by setting `event.returnValue`.
|
||||
|
||||
## Methods
|
||||
|
||||
The `app` object has the following methods:
|
||||
@@ -753,7 +695,8 @@ Overrides the current application's name.
|
||||
|
||||
### `app.getLocale()`
|
||||
|
||||
Returns `String` - The current application locale. Possible return values are documented [here](locales.md).
|
||||
Returns `String` - The current application locale, fetched using Chromium's `l10n_util` library.
|
||||
Possible return values are documented [here](https://source.chromium.org/chromium/chromium/src/+/master:ui/base/l10n/l10n_util.cc).
|
||||
|
||||
To set the locale, you'll want to use a command line switch at app startup, which may be found [here](https://github.com/electron/electron/blob/master/docs/api/command-line-switches.md).
|
||||
|
||||
@@ -929,6 +872,10 @@ re-add a removed item to a custom category earlier than that will result in the
|
||||
entire custom category being omitted from the Jump List. The list of removed
|
||||
items can be obtained using `app.getJumpListSettings()`.
|
||||
|
||||
**Note:** The maximum length of a Jump List item's `description` property is
|
||||
260 characters. Beyond this limit, the item will not be added to the Jump
|
||||
List, nor will it be displayed.
|
||||
|
||||
Here's a very simple example of creating a custom Jump List:
|
||||
|
||||
```javascript
|
||||
@@ -1480,19 +1427,6 @@ This is the user agent that will be used when no user agent is set at the
|
||||
app has the same user agent. Set to a custom value as early as possible
|
||||
in your app's initialization to ensure that your overridden value is used.
|
||||
|
||||
### `app.allowRendererProcessReuse`
|
||||
|
||||
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 `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
|
||||
which native modules you can use in the renderer process. For more information
|
||||
on the direction Electron is going with renderer process restarts and usage of
|
||||
native modules in the renderer process please check out this
|
||||
[Tracking Issue](https://github.com/electron/electron/issues/18397).
|
||||
|
||||
### `app.runningUnderRosettaTranslation` _macOS_ _Readonly_
|
||||
|
||||
A `Boolean` which when `true` indicates that the app is currently running
|
||||
|
||||
@@ -118,6 +118,9 @@ Returns `String` - The current update feed URL.
|
||||
Asks the server whether there is an update. You must call `setFeedURL` before
|
||||
using this API.
|
||||
|
||||
**Note:** If an update is available it will be downloaded automatically.
|
||||
Calling `autoUpdater.checkForUpdates()` twice will download the update two times.
|
||||
|
||||
### `autoUpdater.quitAndInstall()`
|
||||
|
||||
Restarts the app and installs the update after it has been downloaded. It
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
## Class: BrowserView
|
||||
|
||||
> Create and control views.
|
||||
|
||||
Process: [Main](../glossary.md#main-process)
|
||||
# BrowserView
|
||||
|
||||
A `BrowserView` can be used to embed additional web content into a
|
||||
[`BrowserWindow`](browser-window.md). It is like a child window, except that it is positioned
|
||||
relative to its owning window. It is meant to be an alternative to the
|
||||
`webview` tag.
|
||||
|
||||
## Class: BrowserView
|
||||
|
||||
> Create and control views.
|
||||
|
||||
Process: [Main](../glossary.md#main-process)
|
||||
|
||||
### Example
|
||||
|
||||
```javascript
|
||||
|
||||
@@ -14,7 +14,7 @@ const win = new BrowserWindow({ width: 800, height: 600 })
|
||||
win.loadURL('https://github.com')
|
||||
|
||||
// Or load a local HTML file
|
||||
win.loadURL(`file://${__dirname}/app/index.html`)
|
||||
win.loadFile('index.html')
|
||||
```
|
||||
|
||||
## Frameless window
|
||||
@@ -267,14 +267,12 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
||||
be the absolute file path to the script.
|
||||
When node integration is turned off, the preload script can reintroduce
|
||||
Node global symbols back to the global scope. See example
|
||||
[here](process.md#event-loaded).
|
||||
[here](context-bridge.md#exposing-node-global-symbols).
|
||||
* `sandbox` Boolean (optional) - If set, this will sandbox the renderer
|
||||
associated with the window, making it compatible with the Chromium
|
||||
OS-level sandbox and disabling the Node.js engine. This is not the same as
|
||||
the `nodeIntegration` option and the APIs available to the preload script
|
||||
are more limited. Read more about the option [here](sandbox-option.md).
|
||||
* `enableRemoteModule` Boolean (optional) - Whether to enable the [`remote`](remote.md) module.
|
||||
Default is `false`.
|
||||
are more limited. Read more about the option [here](../tutorial/sandbox.md).
|
||||
* `session` [Session](session.md#class-session) (optional) - Sets the session used by the
|
||||
page. Instead of passing the Session object directly, you can also choose to
|
||||
use the `partition` option instead, which accepts a partition string. When
|
||||
@@ -286,13 +284,6 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
||||
same `partition`. If there is no `persist:` prefix, the page will use an
|
||||
in-memory session. By assigning the same `partition`, multiple pages can share
|
||||
the same session. Default is the default session.
|
||||
* `affinity` String (optional) - When specified, web pages with the same
|
||||
`affinity` will run in the same renderer process. Note that due to reusing
|
||||
the renderer process, certain `webPreferences` options will also be shared
|
||||
between the web pages even when you specified different values for them,
|
||||
including but not limited to `preload`, `sandbox` and `nodeIntegration`.
|
||||
So it is suggested to use exact same `webPreferences` for web pages with
|
||||
the same `affinity`. _Deprecated_
|
||||
* `zoomFactor` Number (optional) - The default zoom factor of the page, `3.0` represents
|
||||
`300%`. Default is `1.0`.
|
||||
* `javascript` Boolean (optional) - Enables JavaScript support. Default is `true`.
|
||||
@@ -339,7 +330,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
||||
more details.
|
||||
* `contextIsolation` Boolean (optional) - Whether to run Electron APIs and
|
||||
the specified `preload` script in a separate JavaScript context. Defaults
|
||||
to `false`. The context that the `preload` script runs in will only have
|
||||
to `true`. The context that the `preload` script runs in will only have
|
||||
access to its own dedicated `document` and `window` globals, as well as
|
||||
its own set of JavaScript builtins (`Array`, `Object`, `JSON`, etc.),
|
||||
which are all invisible to the loaded content. The Electron API will only
|
||||
@@ -350,13 +341,9 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
||||
[Chrome Content Scripts][chrome-content-scripts]. 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
|
||||
experimental.
|
||||
`window.open()`. Defaults to `true`. Child windows will always have node
|
||||
integration disabled unless `nodeIntegrationInSubFrames` is true.
|
||||
* `webviewTag` Boolean (optional) - Whether to enable the [`<webview>` tag](webview-tag.md).
|
||||
Defaults to `false`. **Note:** The
|
||||
`preload` script configured for the `<webview>` will have node integration
|
||||
@@ -763,6 +750,10 @@ A `Boolean` property that determines whether the window is in simple (pre-Lion)
|
||||
|
||||
A `Boolean` property that determines whether the window is in fullscreen mode.
|
||||
|
||||
#### `win.focusable` _Windows_ _macOS_
|
||||
|
||||
A `Boolean` property that determines whether the window is focusable.
|
||||
|
||||
#### `win.visibleOnAllWorkspaces`
|
||||
|
||||
A `Boolean` property that determines whether the window is visible on all workspaces.
|
||||
@@ -1301,7 +1292,7 @@ can be be used to listen to changes to tablet mode.
|
||||
|
||||
#### `win.getMediaSourceId()`
|
||||
|
||||
Returns `String` - Window id in the format of DesktopCapturerSource's id. For example "window:1234:0".
|
||||
Returns `String` - Window id in the format of DesktopCapturerSource's id. For example "window:1324:0".
|
||||
|
||||
More precisely the format is `window:id:other_id` where `id` is `HWND` on
|
||||
Windows, `CGWindowID` (`uint64_t`) on macOS and `Window` (`unsigned long`) on
|
||||
@@ -1319,6 +1310,8 @@ The native type of the handle is `HWND` on Windows, `NSView*` on macOS, and
|
||||
|
||||
* `message` Integer
|
||||
* `callback` Function
|
||||
* `wParam` any - The `wParam` provided to the WndProc
|
||||
* `lParam` any - The `lParam` provided to the WndProc
|
||||
|
||||
Hooks a windows message. The `callback` is called when
|
||||
the message is received in the WndProc.
|
||||
@@ -1371,7 +1364,7 @@ Returns `Boolean` - Whether the window's document has been edited.
|
||||
|
||||
Returns `Promise<NativeImage>` - Resolves with a [NativeImage](native-image.md)
|
||||
|
||||
Captures a snapshot of the page within `rect`. Omitting `rect` will capture the whole visible page.
|
||||
Captures a snapshot of the page within `rect`. Omitting `rect` will capture the whole visible page. If the page is not visible, `rect` may be empty.
|
||||
|
||||
#### `win.loadURL(url[, options])`
|
||||
|
||||
@@ -1380,7 +1373,7 @@ Captures a snapshot of the page within `rect`. Omitting `rect` will capture the
|
||||
* `httpReferrer` (String | [Referrer](structures/referrer.md)) (optional) - An HTTP Referrer URL.
|
||||
* `userAgent` String (optional) - A user agent originating the request.
|
||||
* `extraHeaders` String (optional) - Extra headers separated by "\n"
|
||||
* `postData` ([UploadRawData[]](structures/upload-raw-data.md) | [UploadFile[]](structures/upload-file.md)) (optional)
|
||||
* `postData` ([UploadRawData](structures/upload-raw-data.md) | [UploadFile](structures/upload-file.md))[] (optional)
|
||||
* `baseURLForDataURL` String (optional) - Base URL (with trailing path separator) for files to be loaded by the data URL. This is needed only if the specified `url` is a data URL and needs to load other files.
|
||||
|
||||
Returns `Promise<void>` - the promise will resolve when the page has finished loading
|
||||
@@ -1679,6 +1672,10 @@ Changes whether the window can be focused.
|
||||
|
||||
On macOS it does not remove the focus from the window.
|
||||
|
||||
#### `win.isFocusable()` _macOS_ _Windows_
|
||||
|
||||
Returns whether the window can be focused.
|
||||
|
||||
#### `win.setParentWindow(parent)`
|
||||
|
||||
* `parent` BrowserWindow | null
|
||||
|
||||
@@ -66,11 +66,6 @@ Forces the maximum disk space to be used by the disk cache, in bytes.
|
||||
Enables caller stack logging for the following APIs (filtering events):
|
||||
|
||||
* `desktopCapturer.getSources()` / `desktop-capturer-get-sources`
|
||||
* `remote.require()` / `remote-require`
|
||||
* `remote.getGlobal()` / `remote-get-builtin`
|
||||
* `remote.getBuiltin()` / `remote-get-global`
|
||||
* `remote.getCurrentWindow()` / `remote-get-current-window`
|
||||
* `remote.getCurrentWebContents()` / `remote-get-current-web-contents`
|
||||
|
||||
### --enable-logging
|
||||
|
||||
@@ -80,6 +75,12 @@ This switch can not be used in `app.commandLine.appendSwitch` since it is parsed
|
||||
earlier than user's app is loaded, but you can set the `ELECTRON_ENABLE_LOGGING`
|
||||
environment variable to achieve the same effect.
|
||||
|
||||
## --force-fieldtrials=`trials`
|
||||
|
||||
Field trials to be forcefully enabled or disabled.
|
||||
|
||||
For example: `WebRTC-Audio-Red-For-Opus/Enabled/`
|
||||
|
||||
### --host-rules=`rules`
|
||||
|
||||
A comma-separated list of `rules` that control how hostnames are mapped.
|
||||
@@ -136,7 +137,8 @@ proxy server flags that are passed.
|
||||
|
||||
### --no-sandbox
|
||||
|
||||
Disables Chromium sandbox, which is now enabled by default.
|
||||
Disables the Chromium [sandbox](https://www.chromium.org/developers/design-documents/sandbox).
|
||||
Forces renderer process and Chromium helper processes to run un-sandboxed.
|
||||
Should only be used for testing.
|
||||
|
||||
### --proxy-bypass-list=`hosts`
|
||||
|
||||
@@ -33,7 +33,7 @@ page you load in your renderer executes code in this world.
|
||||
|
||||
### Isolated World
|
||||
|
||||
When `contextIsolation` is enabled in your `webPreferences`, your `preload` scripts run in an
|
||||
When `contextIsolation` is enabled in your `webPreferences` (this is the default behavior since Electron 12.0.0), your `preload` scripts run in an
|
||||
"Isolated World". You can read more about context isolation and what it affects in the
|
||||
[security](../tutorial/security.md#3-enable-context-isolation-for-remote-content) docs.
|
||||
|
||||
@@ -110,3 +110,22 @@ has been included below for completeness:
|
||||
| `Symbol` | N/A | ❌ | ❌ | Symbols cannot be copied across contexts so they are dropped |
|
||||
|
||||
If the type you care about is not in the above table, it is probably not supported.
|
||||
|
||||
### Exposing Node Global Symbols
|
||||
|
||||
The `contextBridge` can be used by the preload script to give your renderer access to Node APIs.
|
||||
The table of supported types described above also applies to Node APIs that you expose through `contextBridge`.
|
||||
Please note that many Node APIs grant access to local system resources.
|
||||
Be very cautious about which globals and APIs you expose to untrusted remote content.
|
||||
|
||||
```javascript
|
||||
const { contextBridge } = require('electron')
|
||||
const crypto = require('crypto')
|
||||
contextBridge.exposeInMainWorld('nodeCrypto', {
|
||||
sha256sum (data) {
|
||||
const hash = crypto.createHash('sha256')
|
||||
hash.update(data)
|
||||
return hash.digest('hex')
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
@@ -45,6 +45,8 @@ The following events are available on instances of `Cookies`:
|
||||
|
||||
#### Event: 'changed'
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `cookie` [Cookie](structures/cookie.md) - The cookie that was changed.
|
||||
* `cause` String - The cause of the change with one of the following values:
|
||||
|
||||
@@ -77,7 +77,8 @@ The `crashReporter` module has the following methods:
|
||||
### `crashReporter.start(options)`
|
||||
|
||||
* `options` Object
|
||||
* `submitURL` String - URL that crash reports will be sent to as POST.
|
||||
* `submitURL` String (optional) - URL that crash reports will be sent to as
|
||||
POST. Required unless `uploadToServer` is `false`.
|
||||
* `productName` String (optional) - Defaults to `app.name`.
|
||||
* `companyName` String (optional) _Deprecated_ - Deprecated alias for
|
||||
`{ globalExtra: { _companyName: ... } }`.
|
||||
|
||||
@@ -233,10 +233,6 @@ expanding and collapsing the dialog.
|
||||
be selected by default when the message box opens.
|
||||
* `title` String (optional) - Title of the message box, some platforms will not show it.
|
||||
* `detail` String (optional) - Extra information of the message.
|
||||
* `checkboxLabel` String (optional) - If provided, the message box will
|
||||
include a checkbox with the given label.
|
||||
* `checkboxChecked` Boolean (optional) - Initial checked state of the
|
||||
checkbox. `false` by default.
|
||||
* `icon` ([NativeImage](native-image.md) | String) (optional)
|
||||
* `cancelId` Integer (optional) - The index of the button to be used to cancel the dialog, via
|
||||
the `Esc` key. By default this is assigned to the first button with "cancel" or "no" as the
|
||||
|
||||
@@ -83,8 +83,10 @@ win.show()
|
||||
blur effect to the content below the window (i.e. other applications open on
|
||||
the user's system).
|
||||
* The window will not be transparent when DevTools is opened.
|
||||
* On Windows operating systems, transparent windows will not work when DWM is
|
||||
* On Windows operating systems,
|
||||
* transparent windows will not work when DWM is
|
||||
disabled.
|
||||
* transparent windows can not be maximized using the Windows system menu or by double clicking the title bar. The reasoning behind this can be seen on [this pull request](https://github.com/electron/electron/pull/28207).
|
||||
* On Linux, users have to put `--enable-transparent-visuals --disable-gpu` in
|
||||
the command line to disable GPU and allow ARGB to make transparent window,
|
||||
this is caused by an upstream bug that [alpha channel doesn't work on some
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
# Locales
|
||||
|
||||
> Locale values returned by `app.getLocale()`.
|
||||
|
||||
Electron uses Chromium's `l10n_util` library to fetch the locale. Possible
|
||||
values are listed below:
|
||||
|
||||
| Language Code | Language Name |
|
||||
|---------------|---------------|
|
||||
| af | Afrikaans |
|
||||
| am | Amharic |
|
||||
| ar | Arabic |
|
||||
| az | Azerbaijani |
|
||||
| be | Belarusian |
|
||||
| bg | Bulgarian |
|
||||
| bh | Bihari |
|
||||
| bn | Bengali |
|
||||
| br | Breton |
|
||||
| bs | Bosnian |
|
||||
| ca | Catalan |
|
||||
| co | Corsican |
|
||||
| cs | Czech |
|
||||
| cy | Welsh |
|
||||
| da | Danish |
|
||||
| de | German |
|
||||
| de-AT | German (Austria) |
|
||||
| de-CH | German (Switzerland) |
|
||||
| de-DE | German (Germany) |
|
||||
| el | Greek |
|
||||
| en | English |
|
||||
| en-AU | English (Australia) |
|
||||
| en-CA | English (Canada) |
|
||||
| en-GB | English (UK) |
|
||||
| en-NZ | English (New Zealand) |
|
||||
| en-US | English (US) |
|
||||
| en-ZA | English (South Africa) |
|
||||
| eo | Esperanto |
|
||||
| es | Spanish |
|
||||
| es-419 | Spanish (Latin America) |
|
||||
| et | Estonian |
|
||||
| eu | Basque |
|
||||
| fa | Persian |
|
||||
| fi | Finnish |
|
||||
| fil | Filipino |
|
||||
| fo | Faroese |
|
||||
| fr | French |
|
||||
| fr-CA | French (Canada) |
|
||||
| fr-CH | French (Switzerland) |
|
||||
| fr-FR | French (France) |
|
||||
| fy | Frisian |
|
||||
| ga | Irish |
|
||||
| gd | Scots Gaelic |
|
||||
| gl | Galician |
|
||||
| gn | Guarani |
|
||||
| gu | Gujarati |
|
||||
| ha | Hausa |
|
||||
| haw | Hawaiian |
|
||||
| he | Hebrew |
|
||||
| hi | Hindi |
|
||||
| hr | Croatian |
|
||||
| hu | Hungarian |
|
||||
| hy | Armenian |
|
||||
| ia | Interlingua |
|
||||
| id | Indonesian |
|
||||
| is | Icelandic |
|
||||
| it | Italian |
|
||||
| it-CH | Italian (Switzerland) |
|
||||
| it-IT | Italian (Italy) |
|
||||
| ja | Japanese |
|
||||
| jw | Javanese |
|
||||
| ka | Georgian |
|
||||
| kk | Kazakh |
|
||||
| km | Cambodian |
|
||||
| kn | Kannada |
|
||||
| ko | Korean |
|
||||
| ku | Kurdish |
|
||||
| ky | Kyrgyz |
|
||||
| la | Latin |
|
||||
| ln | Lingala |
|
||||
| lo | Laothian |
|
||||
| lt | Lithuanian |
|
||||
| lv | Latvian |
|
||||
| mk | Macedonian |
|
||||
| ml | Malayalam |
|
||||
| mn | Mongolian |
|
||||
| mo | Moldavian |
|
||||
| mr | Marathi |
|
||||
| ms | Malay |
|
||||
| mt | Maltese |
|
||||
| nb | Norwegian (Bokmal) |
|
||||
| ne | Nepali |
|
||||
| nl | Dutch |
|
||||
| nn | Norwegian (Nynorsk) |
|
||||
| no | Norwegian |
|
||||
| oc | Occitan |
|
||||
| om | Oromo |
|
||||
| or | Oriya |
|
||||
| pa | Punjabi |
|
||||
| pl | Polish |
|
||||
| ps | Pashto |
|
||||
| pt | Portuguese |
|
||||
| pt-BR | Portuguese (Brazil) |
|
||||
| pt-PT | Portuguese (Portugal) |
|
||||
| qu | Quechua |
|
||||
| rm | Romansh |
|
||||
| ro | Romanian |
|
||||
| ru | Russian |
|
||||
| sd | Sindhi |
|
||||
| sh | Serbo-Croatian |
|
||||
| si | Sinhalese |
|
||||
| sk | Slovak |
|
||||
| sl | Slovenian |
|
||||
| sn | Shona |
|
||||
| so | Somali |
|
||||
| sq | Albanian |
|
||||
| sr | Serbian |
|
||||
| st | Sesotho |
|
||||
| su | Sundanese |
|
||||
| sv | Swedish |
|
||||
| sw | Swahili |
|
||||
| ta | Tamil |
|
||||
| te | Telugu |
|
||||
| tg | Tajik |
|
||||
| th | Thai |
|
||||
| ti | Tigrinya |
|
||||
| tk | Turkmen |
|
||||
| to | Tonga |
|
||||
| tr | Turkish |
|
||||
| tt | Tatar |
|
||||
| tw | Twi |
|
||||
| ug | Uighur |
|
||||
| uk | Ukrainian |
|
||||
| ur | Urdu |
|
||||
| uz | Uzbek |
|
||||
| vi | Vietnamese |
|
||||
| xh | Xhosa |
|
||||
| yi | Yiddish |
|
||||
| yo | Yoruba |
|
||||
| zh | Chinese |
|
||||
| zh-CN | Chinese (Simplified) |
|
||||
| zh-TW | Chinese (Traditional) |
|
||||
| zu | Zulu |
|
||||
@@ -1,3 +1,5 @@
|
||||
# Menu
|
||||
|
||||
## Class: Menu
|
||||
|
||||
> Create native application menus and context menus.
|
||||
|
||||
@@ -9,12 +9,15 @@ channel messaging.
|
||||
|
||||
## Class: MessageChannelMain
|
||||
|
||||
> Channel interface for channel messaging in the main process.
|
||||
|
||||
Process: [Main](../glossary.md#main-process)
|
||||
|
||||
Example:
|
||||
|
||||
```js
|
||||
// Main process
|
||||
const { MessageChannelMain } = require('electron')
|
||||
const { port1, port2 } = new MessageChannelMain()
|
||||
w.webContents.postMessage('port', null, [port2])
|
||||
port1.postMessage({ some: 'message' })
|
||||
|
||||
@@ -14,6 +14,8 @@ channel messaging.
|
||||
|
||||
## Class: MessagePortMain
|
||||
|
||||
> Port interface for channel messaging in the main process.
|
||||
|
||||
Process: [Main](../glossary.md#main-process)
|
||||
|
||||
### Instance Methods
|
||||
|
||||
@@ -8,11 +8,11 @@ Process: [Main](../glossary.md#main-process)
|
||||
|
||||
The `powerMonitor` module emits the following events:
|
||||
|
||||
### Event: 'suspend' _macOS_ _Windows_
|
||||
### Event: 'suspend'
|
||||
|
||||
Emitted when the system is suspending.
|
||||
|
||||
### Event: 'resume' _macOS_ _Windows_
|
||||
### Event: 'resume'
|
||||
|
||||
Emitted when system is resuming.
|
||||
|
||||
|
||||
@@ -30,11 +30,13 @@ In sandboxed renderers the `process` object contains only a subset of the APIs:
|
||||
* `arch`
|
||||
* `platform`
|
||||
* `sandboxed`
|
||||
* `contextIsolated`
|
||||
* `type`
|
||||
* `version`
|
||||
* `versions`
|
||||
* `mas`
|
||||
* `windowsStore`
|
||||
* `contextId`
|
||||
|
||||
## Events
|
||||
|
||||
@@ -43,19 +45,6 @@ In sandboxed renderers the `process` object contains only a subset of the APIs:
|
||||
Emitted when Electron has loaded its internal initialization script and is
|
||||
beginning to load the web page or the main script.
|
||||
|
||||
It can be used by the preload script to add removed Node global symbols back to
|
||||
the global scope when node integration is turned off:
|
||||
|
||||
```javascript
|
||||
// preload.js
|
||||
const _setImmediate = setImmediate
|
||||
const _clearImmediate = clearImmediate
|
||||
process.once('loaded', () => {
|
||||
global.setImmediate = _setImmediate
|
||||
global.clearImmediate = _clearImmediate
|
||||
})
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
### `process.defaultApp` _Readonly_
|
||||
@@ -93,6 +82,11 @@ A `String` representing the path to the resources directory.
|
||||
A `Boolean`. When the renderer process is sandboxed, this property is `true`,
|
||||
otherwise it is `undefined`.
|
||||
|
||||
### `process.contextIsolated` _Readonly_
|
||||
|
||||
A `Boolean` that indicates whether the current renderer context has `contextIsolation` enabled.
|
||||
It is `undefined` in the main process.
|
||||
|
||||
### `process.throwDeprecation`
|
||||
|
||||
A `Boolean` that controls whether or not deprecation warnings will be thrown as
|
||||
@@ -133,6 +127,13 @@ A `String` representing Electron's version string.
|
||||
A `Boolean`. If the app is running as a Windows Store app (appx), this property is `true`,
|
||||
for otherwise it is `undefined`.
|
||||
|
||||
### `process.contextId` _Readonly_
|
||||
|
||||
A `String` (optional) representing a globally unique ID of the current JavaScript context.
|
||||
Each frame has its own JavaScript context. When contextIsolation is enabled, the isolated
|
||||
world also has a separate JavaScript context.
|
||||
This property is only available in the renderer process.
|
||||
|
||||
## Methods
|
||||
|
||||
The `process` object has the following methods:
|
||||
|
||||
@@ -1,217 +0,0 @@
|
||||
# remote
|
||||
|
||||
> Use main process modules from the renderer process.
|
||||
|
||||
Process: [Renderer](../glossary.md#renderer-process)
|
||||
|
||||
> ⚠️ WARNING ⚠️
|
||||
> The `remote` module is [deprecated](https://github.com/electron/electron/issues/21408).
|
||||
> Instead of `remote`, use [`ipcRenderer`](ipc-renderer.md) and
|
||||
> [`ipcMain`](ipc-main.md).
|
||||
>
|
||||
> Read more about why the `remote` module is deprecated [here](https://medium.com/@nornagon/electrons-remote-module-considered-harmful-70d69500f31).
|
||||
>
|
||||
> If you still want to use `remote` despite the performance and security
|
||||
> concerns, see [@electron/remote](https://github.com/electron/remote).
|
||||
|
||||
The `remote` module provides a simple way to do inter-process communication
|
||||
(IPC) between the renderer process (web page) and the main process.
|
||||
|
||||
In Electron, GUI-related modules (such as `dialog`, `menu` etc.) are only
|
||||
available in the main process, not in the renderer process. In order to use them
|
||||
from the renderer process, the `ipc` module is necessary to send inter-process
|
||||
messages to the main process. With the `remote` module, you can invoke methods
|
||||
of the main process object without explicitly sending inter-process messages,
|
||||
similar to Java's [RMI][rmi]. An example of creating a browser window from a
|
||||
renderer process:
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron').remote
|
||||
const win = new BrowserWindow({ width: 800, height: 600 })
|
||||
win.loadURL('https://github.com')
|
||||
```
|
||||
|
||||
**Note:** For the reverse (access the renderer process from the main process),
|
||||
you can use [webContents.executeJavaScript](web-contents.md#contentsexecutejavascriptcode-usergesture).
|
||||
|
||||
**Note:** The remote module can be disabled for security reasons in the following contexts:
|
||||
|
||||
* [`BrowserWindow`](browser-window.md) - by setting the `enableRemoteModule` option to `false`.
|
||||
* [`<webview>`](webview-tag.md) - by setting the `enableremotemodule` attribute to `false`.
|
||||
|
||||
## Remote Objects
|
||||
|
||||
Each object (including functions) returned by the `remote` module represents an
|
||||
object in the main process (we call it a remote object or remote function).
|
||||
When you invoke methods of a remote object, call a remote function, or create
|
||||
a new object with the remote constructor (function), you are actually sending
|
||||
synchronous inter-process messages.
|
||||
|
||||
In the example above, both [`BrowserWindow`](browser-window.md) and `win` were remote objects and
|
||||
`new BrowserWindow` didn't create a `BrowserWindow` object in the renderer
|
||||
process. Instead, it created a `BrowserWindow` object in the main process and
|
||||
returned the corresponding remote object in the renderer process, namely the
|
||||
`win` object.
|
||||
|
||||
**Note:** Only [enumerable properties][enumerable-properties] which are present
|
||||
when the remote object is first referenced are accessible via remote.
|
||||
|
||||
**Note:** Arrays and Buffers are copied over IPC when accessed via the `remote`
|
||||
module. Modifying them in the renderer process does not modify them in the main
|
||||
process and vice versa.
|
||||
|
||||
## Lifetime of Remote Objects
|
||||
|
||||
Electron makes sure that as long as the remote object in the renderer process
|
||||
lives (in other words, has not been garbage collected), the corresponding object
|
||||
in the main process will not be released. When the remote object has been
|
||||
garbage collected, the corresponding object in the main process will be
|
||||
dereferenced.
|
||||
|
||||
If the remote object is leaked in the renderer process (e.g. stored in a map but
|
||||
never freed), the corresponding object in the main process will also be leaked,
|
||||
so you should be very careful not to leak remote objects.
|
||||
|
||||
Primary value types like strings and numbers, however, are sent by copy.
|
||||
|
||||
## Passing callbacks to the main process
|
||||
|
||||
Code in the main process can accept callbacks from the renderer - for instance
|
||||
the `remote` module - but you should be extremely careful when using this
|
||||
feature.
|
||||
|
||||
First, in order to avoid deadlocks, the callbacks passed to the main process
|
||||
are called asynchronously. You should not expect the main process to
|
||||
get the return value of the passed callbacks.
|
||||
|
||||
For instance you can't use a function from the renderer process in an
|
||||
`Array.map` called in the main process:
|
||||
|
||||
```javascript
|
||||
// main process mapNumbers.js
|
||||
exports.withRendererCallback = (mapper) => {
|
||||
return [1, 2, 3].map(mapper)
|
||||
}
|
||||
|
||||
exports.withLocalCallback = () => {
|
||||
return [1, 2, 3].map(x => x + 1)
|
||||
}
|
||||
```
|
||||
|
||||
```javascript
|
||||
// renderer process
|
||||
const mapNumbers = require('electron').remote.require('./mapNumbers')
|
||||
const withRendererCb = mapNumbers.withRendererCallback(x => x + 1)
|
||||
const withLocalCb = mapNumbers.withLocalCallback()
|
||||
|
||||
console.log(withRendererCb, withLocalCb)
|
||||
// [undefined, undefined, undefined], [2, 3, 4]
|
||||
```
|
||||
|
||||
As you can see, the renderer callback's synchronous return value was not as
|
||||
expected, and didn't match the return value of an identical callback that lives
|
||||
in the main process.
|
||||
|
||||
Second, the callbacks passed to the main process will persist until the
|
||||
main process garbage-collects them.
|
||||
|
||||
For example, the following code seems innocent at first glance. It installs a
|
||||
callback for the `close` event on a remote object:
|
||||
|
||||
```javascript
|
||||
require('electron').remote.getCurrentWindow().on('close', () => {
|
||||
// window was closed...
|
||||
})
|
||||
```
|
||||
|
||||
But remember the callback is referenced by the main process until you
|
||||
explicitly uninstall it. If you do not, each time you reload your window the
|
||||
callback will be installed again, leaking one callback for each restart.
|
||||
|
||||
To make things worse, since the context of previously installed callbacks has
|
||||
been released, exceptions will be raised in the main process when the `close`
|
||||
event is emitted.
|
||||
|
||||
To avoid this problem, ensure you clean up any references to renderer callbacks
|
||||
passed to the main process. This involves cleaning up event handlers, or
|
||||
ensuring the main process is explicitly told to dereference callbacks that came
|
||||
from a renderer process that is exiting.
|
||||
|
||||
## Accessing built-in modules in the main process
|
||||
|
||||
The built-in modules in the main process are added as getters in the `remote`
|
||||
module, so you can use them directly like the `electron` module.
|
||||
|
||||
```javascript
|
||||
const app = require('electron').remote.app
|
||||
console.log(app)
|
||||
```
|
||||
|
||||
## Methods
|
||||
|
||||
The `remote` module has the following methods:
|
||||
|
||||
### `remote.getCurrentWindow()`
|
||||
|
||||
Returns [`BrowserWindow`](browser-window.md) - The window to which this web page
|
||||
belongs.
|
||||
|
||||
**Note:** Do not use `removeAllListeners` on [`BrowserWindow`](browser-window.md).
|
||||
Use of this can remove all [`blur`](https://developer.mozilla.org/en-US/docs/Web/Events/blur)
|
||||
listeners, disable click events on touch bar buttons, and other unintended
|
||||
consequences.
|
||||
|
||||
### `remote.getCurrentWebContents()`
|
||||
|
||||
Returns [`WebContents`](web-contents.md) - The web contents of this web page.
|
||||
|
||||
### `remote.getGlobal(name)`
|
||||
|
||||
* `name` String
|
||||
|
||||
Returns `any` - The global variable of `name` (e.g. `global[name]`) in the main
|
||||
process.
|
||||
|
||||
## Properties
|
||||
|
||||
### `remote.require`
|
||||
|
||||
A `NodeJS.Require` function equivalent to `require(module)` in the main process.
|
||||
Modules specified by their relative path will resolve relative to the entrypoint
|
||||
of the main process.
|
||||
|
||||
e.g.
|
||||
|
||||
```sh
|
||||
project/
|
||||
├── main
|
||||
│ ├── foo.js
|
||||
│ └── index.js
|
||||
├── package.json
|
||||
└── renderer
|
||||
└── index.js
|
||||
```
|
||||
|
||||
```js
|
||||
// main process: main/index.js
|
||||
const { app } = require('electron')
|
||||
app.whenReady().then(() => { /* ... */ })
|
||||
```
|
||||
|
||||
```js
|
||||
// some relative module: main/foo.js
|
||||
module.exports = 'bar'
|
||||
```
|
||||
|
||||
```js
|
||||
// renderer process: renderer/index.js
|
||||
const foo = require('electron').remote.require('./foo') // bar
|
||||
```
|
||||
|
||||
### `remote.process` _Readonly_
|
||||
|
||||
A `NodeJS.Process` object. The `process` object in the main process. This is the same as
|
||||
`remote.getGlobal('process')` but is cached.
|
||||
|
||||
[rmi]: https://en.wikipedia.org/wiki/Java_remote_method_invocation
|
||||
[enumerable-properties]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Enumerability_and_ownership_of_properties
|
||||
@@ -1,182 +0,0 @@
|
||||
# `sandbox` Option
|
||||
|
||||
> Create a browser window with a sandboxed renderer. With this
|
||||
option enabled, the renderer must communicate via IPC to the main process in order to access node APIs.
|
||||
|
||||
One of the key security features of Chromium is that all blink rendering/JavaScript
|
||||
code is executed within a sandbox. This sandbox uses OS-specific features to ensure
|
||||
that exploits in the renderer process cannot harm the system.
|
||||
|
||||
In other words, when the sandbox is enabled, the renderers can only make changes
|
||||
to the system by delegating tasks to the main process via IPC.
|
||||
[Here's](https://www.chromium.org/developers/design-documents/sandbox) more
|
||||
information about the sandbox.
|
||||
|
||||
Since a major feature in Electron is the ability to run Node.js in the
|
||||
renderer process (making it easier to develop desktop applications using web
|
||||
technologies), the sandbox is disabled by electron. This is because
|
||||
most Node.js APIs require system access. `require()` for example, is not
|
||||
possible without file system permissions, which are not available in a sandboxed
|
||||
environment.
|
||||
|
||||
Usually this is not a problem for desktop applications since the code is always
|
||||
trusted, but it makes Electron less secure than Chromium for displaying
|
||||
untrusted web content. For applications that require more security, the
|
||||
`sandbox` flag will force Electron to spawn a classic Chromium renderer that is
|
||||
compatible with the sandbox.
|
||||
|
||||
A sandboxed renderer doesn't have a Node.js environment running and doesn't
|
||||
expose Node.js JavaScript APIs to client code. The only exception is the preload script,
|
||||
which has access to a subset of the Electron renderer API.
|
||||
|
||||
Another difference is that sandboxed renderers don't modify any of the default
|
||||
JavaScript APIs. Consequently, some APIs such as `window.open` will work as they
|
||||
do in Chromium (i.e. they do not return a [`BrowserWindowProxy`](browser-window-proxy.md)).
|
||||
|
||||
## Example
|
||||
|
||||
To create a sandboxed window, pass `sandbox: true` to `webPreferences`:
|
||||
|
||||
```js
|
||||
let win
|
||||
app.whenReady().then(() => {
|
||||
win = new BrowserWindow({
|
||||
webPreferences: {
|
||||
sandbox: true
|
||||
}
|
||||
})
|
||||
win.loadURL('http://google.com')
|
||||
})
|
||||
```
|
||||
|
||||
In the above code the [`BrowserWindow`](browser-window.md) that was created has Node.js disabled and can communicate
|
||||
only via IPC. The use of this option stops Electron from creating a Node.js runtime in the renderer. Also,
|
||||
within this new window `window.open` follows the native behavior (by default Electron creates a [`BrowserWindow`](browser-window.md)
|
||||
and returns a proxy to this via `window.open`).
|
||||
|
||||
[`app.enableSandbox`](app.md#appenablesandbox) can be used to force `sandbox: true` for all `BrowserWindow` instances.
|
||||
|
||||
```js
|
||||
let win
|
||||
app.enableSandbox()
|
||||
app.whenReady().then(() => {
|
||||
// no need to pass `sandbox: true` since `app.enableSandbox()` was called.
|
||||
win = new BrowserWindow()
|
||||
win.loadURL('http://google.com')
|
||||
})
|
||||
```
|
||||
|
||||
## Preload
|
||||
|
||||
An app can make customizations to sandboxed renderers using a preload script.
|
||||
Here's an example:
|
||||
|
||||
```js
|
||||
let win
|
||||
app.whenReady().then(() => {
|
||||
win = new BrowserWindow({
|
||||
webPreferences: {
|
||||
sandbox: true,
|
||||
preload: path.join(app.getAppPath(), 'preload.js')
|
||||
}
|
||||
})
|
||||
win.loadURL('http://google.com')
|
||||
})
|
||||
```
|
||||
|
||||
and preload.js:
|
||||
|
||||
```js
|
||||
// This file is loaded whenever a javascript context is created. It runs in a
|
||||
// private scope that can access a subset of Electron renderer APIs. Without
|
||||
// contextIsolation enabled, it's possible to accidentally leak privileged
|
||||
// globals like ipcRenderer to web content.
|
||||
const { ipcRenderer } = require('electron')
|
||||
|
||||
const defaultWindowOpen = window.open
|
||||
|
||||
window.open = function customWindowOpen (url, ...args) {
|
||||
ipcRenderer.send('report-window-open', location.origin, url, args)
|
||||
return defaultWindowOpen(url + '?from_electron=1', ...args)
|
||||
}
|
||||
```
|
||||
|
||||
Important things to notice in the preload script:
|
||||
|
||||
- Even though the sandboxed renderer doesn't have Node.js running, it still has
|
||||
access to a limited node-like environment: `Buffer`, `process`, `setImmediate`,
|
||||
`clearImmediate` and `require` are available.
|
||||
- The preload script must be contained in a single script, but it is possible to have
|
||||
complex preload code composed with multiple modules by using a tool like
|
||||
webpack or browserify. An example of using browserify is below.
|
||||
|
||||
To create a browserify bundle and use it as a preload script, something like
|
||||
the following should be used:
|
||||
|
||||
```sh
|
||||
browserify preload/index.js \
|
||||
-x electron \
|
||||
--insert-global-vars=__filename,__dirname -o preload.js
|
||||
```
|
||||
|
||||
The `-x` flag should be used with any required module that is already exposed in
|
||||
the preload scope, and tells browserify to use the enclosing `require` function
|
||||
for it. `--insert-global-vars` will ensure that `process`, `Buffer` and
|
||||
`setImmediate` are also taken from the enclosing scope(normally browserify
|
||||
injects code for those).
|
||||
|
||||
Currently the `require` function provided in the preload scope exposes the
|
||||
following modules:
|
||||
|
||||
- `electron`
|
||||
- `crashReporter`
|
||||
- `desktopCapturer`
|
||||
- `ipcRenderer`
|
||||
- `nativeImage`
|
||||
- `webFrame`
|
||||
- `events`
|
||||
- `timers`
|
||||
- `url`
|
||||
|
||||
More may be added as needed to expose more Electron APIs in the sandbox.
|
||||
|
||||
## 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 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.
|
||||
@@ -197,9 +197,7 @@ be managed by using [ses.setPermissionCheckHandler(handler)](#sessetpermissionch
|
||||
with the `serial` permission.
|
||||
|
||||
Because this is an experimental feature it is disabled by default. To enable this feature, you
|
||||
will need to use the `--enable-features=ElectronSerialChooser` command line switch. Additionally
|
||||
because this is an experimental Chromium feature you will need to set `enableBlinkFeatures: 'Serial'`
|
||||
on the `webPreferences` property when opening a BrowserWindow.
|
||||
will need to use the `--enable-features=ElectronSerialChooser` command line switch.
|
||||
|
||||
```javascript
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
@@ -210,10 +208,7 @@ app.commandLine.appendSwitch('enable-features', 'ElectronSerialChooser')
|
||||
app.whenReady().then(() => {
|
||||
win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
enableBlinkFeatures: 'Serial'
|
||||
}
|
||||
height: 600
|
||||
})
|
||||
win.webContents.session.on('select-serial-port', (event, portList, webContents, callback) => {
|
||||
event.preventDefault()
|
||||
@@ -822,6 +817,11 @@ Returns `Extension[]` - A list of all loaded extensions.
|
||||
**Note:** This API cannot be called before the `ready` event of the `app` module
|
||||
is emitted.
|
||||
|
||||
#### `ses.getStoragePath()`
|
||||
|
||||
A `String | null` indicating the absolute file system path where data for this
|
||||
session is persisted on disk. For in memory sessions this returns `null`.
|
||||
|
||||
### Instance Properties
|
||||
|
||||
The following properties are available on instances of `Session`:
|
||||
@@ -835,6 +835,11 @@ code to the `setSpellCheckerLanguages` API that isn't in this array will result
|
||||
|
||||
A `Boolean` indicating whether builtin spell checker is enabled.
|
||||
|
||||
#### `ses.storagePath` _Readonly_
|
||||
|
||||
A `String | null` indicating the absolute file system path where data for this
|
||||
session is persisted on disk. For in memory sessions this returns `null`.
|
||||
|
||||
#### `ses.cookies` _Readonly_
|
||||
|
||||
A [`Cookies`](cookies.md) object for this session.
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
## Class: ShareMenu
|
||||
|
||||
> Create share menu on macOS.
|
||||
|
||||
Process: [Main](../glossary.md#main-process)
|
||||
# ShareMenu
|
||||
|
||||
The `ShareMenu` class creates [Share Menu][share-menu] on macOS, which can be
|
||||
used to share information from the current context to apps, social media
|
||||
@@ -11,6 +7,12 @@ accounts, and other services.
|
||||
For including the share menu as a submenu of other menus, please use the
|
||||
`shareMenu` role of [`MenuItem`](menu-item.md).
|
||||
|
||||
## Class: ShareMenu
|
||||
|
||||
> Create share menu on macOS.
|
||||
|
||||
Process: [Main](../glossary.md#main-process)
|
||||
|
||||
### `new ShareMenu(sharingItem)`
|
||||
|
||||
* `sharingItem` SharingItem - The item to share.
|
||||
|
||||
@@ -19,3 +19,7 @@
|
||||
property set then its `type` is assumed to be `tasks`. If the `name` property
|
||||
is set but the `type` property is omitted then the `type` is assumed to be
|
||||
`custom`.
|
||||
|
||||
**Note:** The maximum length of a Jump List item's `description` property is
|
||||
260 characters. Beyond this limit, the item will not be added to the Jump
|
||||
List, nor will it be displayed.
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* `title` String (optional) - The text to be displayed for the item in the Jump List.
|
||||
Should only be set if `type` is `task`.
|
||||
* `description` String (optional) - Description of the task (displayed in a tooltip).
|
||||
Should only be set if `type` is `task`.
|
||||
Should only be set if `type` is `task`. Maximum length 260 characters.
|
||||
* `iconPath` String (optional) - The absolute path to an icon to be displayed in a
|
||||
Jump List, which can be an arbitrary resource file that contains an icon
|
||||
(e.g. `.ico`, `.exe`, `.dll`). You can usually specify `process.execPath` to
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# PostBody Object
|
||||
|
||||
* `data` Array<[PostData](./post-data.md)> - The post data to be sent to the
|
||||
* `data` ([UploadRawData](upload-raw-data.md) | [UploadFile](upload-file.md))[] - The post data to be sent to the
|
||||
new window.
|
||||
* `contentType` String - The `content-type` header used for the data. One of
|
||||
`application/x-www-form-urlencoded` or `multipart/form-data`. Corresponds to
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
# PostData Object
|
||||
|
||||
* `type` String - One of the following:
|
||||
* `rawData` - The data is available as a `Buffer`, in the `rawData` field.
|
||||
* `file` - The object represents a file. The `filePath`, `offset`, `length`
|
||||
and `modificationTime` fields will be used to describe the file.
|
||||
* `blob` - The object represents a `Blob`. The `blobUUID` field will be used
|
||||
to describe the `Blob`.
|
||||
* `bytes` String (optional) - The raw bytes of the post data in a `Buffer`.
|
||||
Required for the `rawData` type.
|
||||
* `filePath` String (optional) - The path of the file being uploaded. Required
|
||||
for the `file` type.
|
||||
* `blobUUID` String (optional) - The `UUID` of the `Blob` being uploaded.
|
||||
Required for the `blob` type.
|
||||
* `offset` Integer (optional) - The offset from the beginning of the file being
|
||||
uploaded, in bytes. Only valid for `file` types.
|
||||
* `length` Integer (optional) - The length of the file being uploaded, in bytes.
|
||||
If set to `-1`, the whole file will be uploaded. Only valid for `file` types.
|
||||
* `modificationTime` Double (optional) - The modification time of the file
|
||||
represented by a double, which is the number of seconds since the `UNIX Epoch`
|
||||
(Jan 1, 1970). Only valid for `file` types.
|
||||
@@ -1,6 +1,6 @@
|
||||
# UploadFile Object
|
||||
|
||||
* `type` String - `file`.
|
||||
* `type` 'file' - `file`.
|
||||
* `filePath` String - Path of file to be uploaded.
|
||||
* `offset` Integer - Defaults to `0`.
|
||||
* `length` Integer - Number of bytes to read from `offset`.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# UploadRawData Object
|
||||
|
||||
* `type` String - `rawData`.
|
||||
* `type` 'rawData' - `rawData`.
|
||||
* `bytes` Buffer - Data to be uploaded.
|
||||
|
||||
12
docs/api/structures/user-default-types.md
Normal file
12
docs/api/structures/user-default-types.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# UserDefaultTypes Object
|
||||
|
||||
* `string` String
|
||||
* `boolean` Boolean
|
||||
* `integer` Number
|
||||
* `float` Number
|
||||
* `double` Number
|
||||
* `url` String
|
||||
* `array` Array\<unknown>
|
||||
* `dictionary` Record\<string, unknown>
|
||||
|
||||
This type is a helper alias, no object will never exist of this type.
|
||||
@@ -130,6 +130,8 @@ This is necessary for events such as `NSUserDefaultsDidChangeNotification`.
|
||||
* `userInfo` Record<String, unknown>
|
||||
* `object` String
|
||||
|
||||
Returns `Number` - The ID of this subscription
|
||||
|
||||
Same as `subscribeNotification`, but uses `NSWorkspace.sharedWorkspace.notificationCenter`.
|
||||
This is necessary for events such as `NSWorkspaceDidActivateApplicationNotification`.
|
||||
|
||||
@@ -157,13 +159,13 @@ Same as `unsubscribeNotification`, but removes the subscriber from `NSWorkspace.
|
||||
|
||||
Add the specified defaults to your application's `NSUserDefaults`.
|
||||
|
||||
### `systemPreferences.getUserDefault(key, type)` _macOS_
|
||||
### `systemPreferences.getUserDefault<Type extends keyof UserDefaultTypes>(key, type)` _macOS_
|
||||
|
||||
* `key` String
|
||||
* `type` String - Can be `string`, `boolean`, `integer`, `float`, `double`,
|
||||
* `type` Type - Can be `string`, `boolean`, `integer`, `float`, `double`,
|
||||
`url`, `array` or `dictionary`.
|
||||
|
||||
Returns `any` - The value of `key` in `NSUserDefaults`.
|
||||
Returns [`UserDefaultTypes[Type]`](structures/user-default-types.md) - The value of `key` in `NSUserDefaults`.
|
||||
|
||||
Some popular `key` and `type`s are:
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
# TouchBar
|
||||
|
||||
## Class: TouchBar
|
||||
|
||||
> Create TouchBar layouts for native macOS applications
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
# Tray
|
||||
|
||||
## Class: Tray
|
||||
|
||||
> Add icons and context menus to the system's notification area.
|
||||
|
||||
@@ -147,7 +147,8 @@ Returns:
|
||||
* `options` BrowserWindowConstructorOptions - The options which will be used for creating the new
|
||||
[`BrowserWindow`](browser-window.md).
|
||||
* `additionalFeatures` String[] - The non-standard features (features not handled
|
||||
by Chromium or Electron) given to `window.open()`.
|
||||
by Chromium or Electron) given to `window.open()`. Deprecated, and will now
|
||||
always be the empty array `[]`.
|
||||
* `referrer` [Referrer](structures/referrer.md) - The referrer that will be
|
||||
passed to the new window. May or may not result in the `Referer` header being
|
||||
sent, depending on the referrer policy.
|
||||
@@ -202,13 +203,11 @@ Returns:
|
||||
* `frameName` String - Name given to the created window in the
|
||||
`window.open()` call.
|
||||
* `options` BrowserWindowConstructorOptions - The options used to create the
|
||||
BrowserWindow. They are merged in increasing precedence: options inherited
|
||||
from the parent, parsed options from the `features` string from
|
||||
`window.open()`, and options given by
|
||||
BrowserWindow. They are merged in increasing precedence: parsed options
|
||||
from the `features` string from `window.open()`, security-related
|
||||
webPreferences inherited from the parent, and options given by
|
||||
[`webContents.setWindowOpenHandler`](web-contents.md#contentssetwindowopenhandlerhandler).
|
||||
Unrecognized options are not filtered out.
|
||||
* `additionalFeatures` String[] - The non-standard features (features not
|
||||
handled Chromium or Electron) _Deprecated_
|
||||
* `referrer` [Referrer](structures/referrer.md) - The referrer that will be
|
||||
passed to the new window. May or may not result in the `Referer` header
|
||||
being sent, depending on the referrer policy.
|
||||
@@ -375,6 +374,8 @@ win.webContents.on('will-prevent-unload', (event) => {
|
||||
})
|
||||
```
|
||||
|
||||
**Note:** This will be emitted for `BrowserViews` but will _not_ be respected - this is because we have chosen not to tie the `BrowserView` lifecycle to its owning BrowserWindow should one exist per the [specification](https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event).
|
||||
|
||||
#### Event: 'crashed' _Deprecated_
|
||||
|
||||
Returns:
|
||||
@@ -839,59 +840,6 @@ Returns:
|
||||
Emitted when `desktopCapturer.getSources()` is called in the renderer process.
|
||||
Calling `event.preventDefault()` will make it return empty sources.
|
||||
|
||||
#### Event: 'remote-require' _Deprecated_
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` IpcMainEvent
|
||||
* `moduleName` String
|
||||
|
||||
Emitted when `remote.require()` is called in the renderer process.
|
||||
Calling `event.preventDefault()` will prevent the module from being returned.
|
||||
Custom value can be returned by setting `event.returnValue`.
|
||||
|
||||
#### Event: 'remote-get-global' _Deprecated_
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` IpcMainEvent
|
||||
* `globalName` String
|
||||
|
||||
Emitted when `remote.getGlobal()` is called in the renderer process.
|
||||
Calling `event.preventDefault()` will prevent the global from being returned.
|
||||
Custom value can be returned by setting `event.returnValue`.
|
||||
|
||||
#### Event: 'remote-get-builtin' _Deprecated_
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` IpcMainEvent
|
||||
* `moduleName` String
|
||||
|
||||
Emitted when `remote.getBuiltin()` is called in the renderer process.
|
||||
Calling `event.preventDefault()` will prevent the module from being returned.
|
||||
Custom value can be returned by setting `event.returnValue`.
|
||||
|
||||
#### Event: 'remote-get-current-window' _Deprecated_
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` IpcMainEvent
|
||||
|
||||
Emitted when `remote.getCurrentWindow()` is called in the renderer process.
|
||||
Calling `event.preventDefault()` will prevent the object from being returned.
|
||||
Custom value can be returned by setting `event.returnValue`.
|
||||
|
||||
#### Event: 'remote-get-current-web-contents' _Deprecated_
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` IpcMainEvent
|
||||
|
||||
Emitted when `remote.getCurrentWebContents()` is called in the renderer process.
|
||||
Calling `event.preventDefault()` will prevent the object from being returned.
|
||||
Custom value can be returned by setting `event.returnValue`.
|
||||
|
||||
#### Event: 'preferred-size-changed'
|
||||
|
||||
Returns:
|
||||
@@ -914,7 +862,7 @@ in `webPreferences`.
|
||||
* `httpReferrer` (String | [Referrer](structures/referrer.md)) (optional) - An HTTP Referrer url.
|
||||
* `userAgent` String (optional) - A user agent originating the request.
|
||||
* `extraHeaders` String (optional) - Extra headers separated by "\n".
|
||||
* `postData` ([UploadRawData[]](structures/upload-raw-data.md) | [UploadFile[]](structures/upload-file.md)) (optional)
|
||||
* `postData` ([UploadRawData](structures/upload-raw-data.md) | [UploadFile](structures/upload-file.md))[] (optional)
|
||||
* `baseURLForDataURL` String (optional) - Base url (with trailing path separator) for files to be loaded by the data url. This is needed only if the specified `url` is a data url and needs to load other files.
|
||||
|
||||
Returns `Promise<void>` - the promise will resolve when the page has finished loading
|
||||
@@ -1184,14 +1132,27 @@ Ignore application menu shortcuts while this web contents is focused.
|
||||
* `url` String - The _resolved_ version of the URL passed to `window.open()`. e.g. opening a window with `window.open('foo')` will yield something like `https://the-origin/the/current/path/foo`.
|
||||
* `frameName` String - Name of the window provided in `window.open()`
|
||||
* `features` String - Comma separated list of window features provided to `window.open()`.
|
||||
* `disposition` String - Can be `default`, `foreground-tab`, `background-tab`,
|
||||
`new-window`, `save-to-disk` or `other`.
|
||||
* `referrer` [Referrer](structures/referrer.md) - The referrer that will be
|
||||
passed to the new window. May or may not result in the `Referer` header being
|
||||
sent, depending on the referrer policy.
|
||||
* `postBody` [PostBody](structures/post-body.md) (optional) - The post data that
|
||||
will be sent to the new window, along with the appropriate headers that will
|
||||
be set. If no post data is to be sent, the value will be `null`. Only defined
|
||||
when the window is being created by a form that set `target=_blank`.
|
||||
|
||||
Returns `{action: 'deny'} | {action: 'allow', overrideBrowserWindowOptions?: BrowserWindowConstructorOptions}` - `deny` cancels the creation of the new
|
||||
window. `allow` will allow the new window to be created. Specifying `overrideBrowserWindowOptions` allows customization of the created window.
|
||||
Returning an unrecognized value such as a null, undefined, or an object
|
||||
without a recognized 'action' value will result in a console error and have
|
||||
the same effect as returning `{action: 'deny'}`.
|
||||
|
||||
Called before creating a window when `window.open()` is called from the
|
||||
renderer. See [`window.open()`](window-open.md) for more details and how to use this in conjunction with `did-create-window`.
|
||||
Called before creating a window a new window is requested by the renderer, e.g.
|
||||
by `window.open()`, a link with `target="_blank"`, shift+clicking on a link, or
|
||||
submitting a form with `<form target="_blank">`. See
|
||||
[`window.open()`](window-open.md) for more details and how to use this in
|
||||
conjunction with `did-create-window`.
|
||||
|
||||
#### `contents.setAudioMuted(muted)`
|
||||
|
||||
@@ -1363,19 +1324,21 @@ Captures a snapshot of the page within `rect`. Omitting `rect` will capture the
|
||||
Returns `Boolean` - Whether this page is being captured. It returns true when the capturer count
|
||||
is large then 0.
|
||||
|
||||
#### `contents.incrementCapturerCount([size, stayHidden])`
|
||||
#### `contents.incrementCapturerCount([size, stayHidden, stayAwake])`
|
||||
|
||||
* `size` [Size](structures/size.md) (optional) - The preferred size for the capturer.
|
||||
* `stayHidden` Boolean (optional) - Keep the page hidden instead of visible.
|
||||
* `stayAwake` Boolean (optional) - Keep the system awake instead of allowing it to sleep.
|
||||
|
||||
Increase the capturer count by one. The page is considered visible when its browser window is
|
||||
hidden and the capturer count is non-zero. If you would like the page to stay hidden, you should ensure that `stayHidden` is set to true.
|
||||
|
||||
This also affects the Page Visibility API.
|
||||
|
||||
#### `contents.decrementCapturerCount([stayHidden])`
|
||||
#### `contents.decrementCapturerCount([stayHidden, stayAwake])`
|
||||
|
||||
* `stayHidden` Boolean (optional) - Keep the page in hidden state instead of visible.
|
||||
* `stayAwake` Boolean (optional) - Keep the system awake instead of allowing it to sleep.
|
||||
|
||||
Decrease the capturer count by one. The page will be set to hidden or occluded state when its
|
||||
browser window is hidden or occluded and the capturer count reaches zero. If you want to
|
||||
|
||||
@@ -182,3 +182,9 @@ This is not the same as the OS process ID; to read that use `frame.osProcessId`.
|
||||
An `Integer` representing the unique frame id in the current renderer process.
|
||||
Distinct `WebFrameMain` instances that refer to the same underlying frame will
|
||||
have the same `routingId`.
|
||||
|
||||
#### `frame.visibilityState` _Readonly_
|
||||
|
||||
A `string` representing the [visibility state](https://developer.mozilla.org/en-US/docs/Web/API/Document/visibilityState) of the frame.
|
||||
|
||||
See also how the [Page Visibility API](browser-window.md#page-visibility) is affected by other Electron APIs.
|
||||
|
||||
@@ -62,6 +62,11 @@ Sets the maximum and minimum pinch-to-zoom level.
|
||||
> webFrame.setVisualZoomLevelLimits(1, 3)
|
||||
> ```
|
||||
|
||||
> **NOTE**: Visual zoom only applies to pinch-to-zoom behavior. Cmd+/-/0 zoom shortcuts are
|
||||
> controlled by the 'zoomIn', 'zoomOut', and 'resetZoom' MenuItem roles in the application
|
||||
> Menu. To disable shortcuts, manually [define the Menu](./menu.md#examples) and omit zoom roles
|
||||
> from the definition.
|
||||
|
||||
### `webFrame.setSpellCheckProvider(language, provider)`
|
||||
|
||||
* `language` String
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
Electron's `webview` tag is based on [Chromium's `webview`][chrome-webview], which
|
||||
is undergoing dramatic architectural changes. This impacts the stability of `webviews`,
|
||||
including rendering, navigation, and event routing. We currently recommend to not
|
||||
use the `webview` tag and to consider alternatives, like `iframe`, Electron's `BrowserView`,
|
||||
use the `webview` tag and to consider alternatives, like `iframe`, [Electron's `BrowserView`](browser-view.md),
|
||||
or an architecture that avoids embedded content altogether.
|
||||
|
||||
## Enabling
|
||||
@@ -130,15 +130,6 @@ inside the `webview`. All your preloads will load for every iframe, you can
|
||||
use `process.isMainFrame` to determine if you are in the main frame or not.
|
||||
This option is disabled by default in the guest page.
|
||||
|
||||
### `enableremotemodule`
|
||||
|
||||
```html
|
||||
<webview src="http://www.google.com/" enableremotemodule="false"></webview>
|
||||
```
|
||||
|
||||
A `Boolean`. When this attribute is `false` the guest page in `webview` will not have access
|
||||
to the [`remote`](remote.md) module. The remote module is unavailable by default.
|
||||
|
||||
### `plugins`
|
||||
|
||||
```html
|
||||
@@ -274,7 +265,7 @@ webview.addEventListener('dom-ready', () => {
|
||||
* `httpReferrer` (String | [Referrer](structures/referrer.md)) (optional) - An HTTP Referrer url.
|
||||
* `userAgent` String (optional) - A user agent originating the request.
|
||||
* `extraHeaders` String (optional) - Extra headers separated by "\n"
|
||||
* `postData` ([UploadRawData[]](structures/upload-raw-data.md) | [UploadFile[]](structures/upload-file.md)) (optional)
|
||||
* `postData` ([UploadRawData](structures/upload-raw-data.md) | [UploadFile](structures/upload-file.md))[] (optional)
|
||||
* `baseURLForDataURL` String (optional) - Base url (with trailing path separator) for files to be loaded by the data url. This is needed only if the specified `url` is a data url and needs to load other files.
|
||||
|
||||
Returns `Promise<void>` - The promise will resolve when the page has finished loading
|
||||
|
||||
@@ -6,16 +6,15 @@ untrusted content within a renderer. Windows can be created from the renderer in
|
||||
* clicking on links or submitting forms adorned with `target=_blank`
|
||||
* JavaScript calling `window.open()`
|
||||
|
||||
In non-sandboxed renderers, or when `nativeWindowOpen` is false (the default), this results in the creation of a
|
||||
[`BrowserWindowProxy`](browser-window-proxy.md), a light wrapper around
|
||||
`BrowserWindow`.
|
||||
For same-origin content, the new window is created within the same process,
|
||||
enabling the parent to access the child window directly. This can be very
|
||||
useful for app sub-windows that act as preference panels, or similar, as the
|
||||
parent can render to the sub-window directly, as if it were a `div` in the
|
||||
parent. This is the same behavior as in the browser.
|
||||
|
||||
However, when the `sandbox` (or directly, `nativeWindowOpen`) option is set, a
|
||||
`Window` instance is created, as you'd expect in the browser. For same-origin
|
||||
content, the new window is created within the same process, enabling the parent
|
||||
to access the child window directly. This can be very useful for app sub-windows that act
|
||||
as preference panels, or similar, as the parent can render to the sub-window
|
||||
directly, as if it were a `div` in the parent.
|
||||
When `nativeWindowOpen` is set to false, `window.open` instead results in the
|
||||
creation of a [`BrowserWindowProxy`](browser-window-proxy.md), a light wrapper
|
||||
around `BrowserWindow`.
|
||||
|
||||
Electron pairs this native Chrome `Window` with a BrowserWindow under the hood.
|
||||
You can take advantage of all the customization available when creating a
|
||||
@@ -23,9 +22,8 @@ BrowserWindow in the main process by using `webContents.setWindowOpenHandler()`
|
||||
for renderer-created windows.
|
||||
|
||||
BrowserWindow constructor options are set by, in increasing precedence
|
||||
order: options inherited from the parent, parsed options
|
||||
from the `features` string from `window.open()`, security-related webPreferences
|
||||
inherited from the parent, and options given by
|
||||
order: parsed options from the `features` string from `window.open()`,
|
||||
security-related webPreferences inherited from the parent, and options given by
|
||||
[`webContents.setWindowOpenHandler`](web-contents.md#contentssetwindowopenhandlerhandler).
|
||||
Note that `webContents.setWindowOpenHandler` has final say and full privilege
|
||||
because it is invoked in the main process.
|
||||
@@ -64,53 +62,23 @@ window.open('https://github.com', '_blank', 'top=500,left=200,frame=false,nodeIn
|
||||
the parent window.
|
||||
* Non-standard features (that are not handled by Chromium or Electron) given in
|
||||
`features` will be passed to any registered `webContents`'s
|
||||
`did-create-window` event handler in the `additionalFeatures` argument.
|
||||
`did-create-window` event handler in the `options` argument.
|
||||
* `frameName` follows the specification of `windowName` located in the [native documentation](https://developer.mozilla.org/en-US/docs/Web/API/Window/open#parameters).
|
||||
|
||||
To customize or cancel the creation of the window, you can optionally set an
|
||||
override handler with `webContents.setWindowOpenHandler()` from the main
|
||||
process. Returning `false` cancels the window, while returning an object sets
|
||||
the `BrowserWindowConstructorOptions` used when creating the window. Note that
|
||||
this is more powerful than passing options through the feature string, as the
|
||||
renderer has more limited privileges in deciding security preferences than the
|
||||
main process.
|
||||
|
||||
### `BrowserWindowProxy` example
|
||||
|
||||
```javascript
|
||||
|
||||
// main.js
|
||||
const mainWindow = new BrowserWindow()
|
||||
|
||||
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
|
||||
if (url.startsWith('https://github.com/')) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
mainWindow.webContents.on('did-create-window', (childWindow) => {
|
||||
// For example...
|
||||
childWindow.webContents('will-navigate', (e) => {
|
||||
e.preventDefault()
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
```javascript
|
||||
// renderer.js
|
||||
const windowProxy = window.open('https://github.com/', null, 'minimizable=false')
|
||||
windowProxy.postMessage('hi', '*')
|
||||
```
|
||||
process. Returning `{ action: 'deny' }` cancels the window. Returning `{
|
||||
action: 'allow', overrideBrowserWindowOptions: { ... } }` will allow opening
|
||||
the window and setting the `BrowserWindowConstructorOptions` to be used when
|
||||
creating the window. Note that this is more powerful than passing options
|
||||
through the feature string, as the renderer has more limited privileges in
|
||||
deciding security preferences than the main process.
|
||||
|
||||
### Native `Window` example
|
||||
|
||||
```javascript
|
||||
// main.js
|
||||
const mainWindow = new BrowserWindow({
|
||||
webPreferences: {
|
||||
nativeWindowOpen: true
|
||||
}
|
||||
})
|
||||
const mainWindow = new BrowserWindow()
|
||||
|
||||
// In this example, only windows with the `about:blank` url will be created.
|
||||
// All other urls will be blocked.
|
||||
@@ -134,3 +102,33 @@ mainWindow.webContents.setWindowOpenHandler(({ url }) => {
|
||||
const childWindow = window.open('', 'modal')
|
||||
childWindow.document.write('<h1>Hello</h1>')
|
||||
```
|
||||
|
||||
### `BrowserWindowProxy` example
|
||||
|
||||
```javascript
|
||||
|
||||
// main.js
|
||||
const mainWindow = new BrowserWindow({
|
||||
webPreferences: { nativeWindowOpen: false }
|
||||
})
|
||||
|
||||
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
|
||||
if (url.startsWith('https://github.com/')) {
|
||||
return { action: 'allow' }
|
||||
}
|
||||
return { action: 'deny' }
|
||||
})
|
||||
|
||||
mainWindow.webContents.on('did-create-window', (childWindow) => {
|
||||
// For example...
|
||||
childWindow.webContents.on('will-navigate', (e) => {
|
||||
e.preventDefault()
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
```javascript
|
||||
// renderer.js
|
||||
const windowProxy = window.open('https://github.com/', null, 'minimizable=false')
|
||||
windowProxy.postMessage('hi', '*')
|
||||
```
|
||||
|
||||
@@ -14,7 +14,22 @@ This document uses the following convention to categorize breaking changes:
|
||||
|
||||
## Planned Breaking API Changes (14.0)
|
||||
|
||||
### API Changed: `window.(open)`
|
||||
### Removed: `app.allowRendererProcessReuse`
|
||||
|
||||
The `app.allowRendererProcessReuse` property will be removed as part of our plan to
|
||||
more closely align with Chromium's process model for security, performance and maintainability.
|
||||
|
||||
For more detailed information see [#18397](https://github.com/electron/electron/issues/18397).
|
||||
|
||||
### Removed: Browser Window Affinity
|
||||
|
||||
The `affinity` option when constructing a new `BrowserWindow` will be removed
|
||||
as part of our plan to more closely align with Chromium's process model for security,
|
||||
performance and maintainability.
|
||||
|
||||
For more detailed information see [#18397](https://github.com/electron/electron/issues/18397).
|
||||
|
||||
### API Changed: `window.open()`
|
||||
|
||||
The optional parameter `frameName` will no longer set the title of the window. This now follows the specification described by the [native documentation](https://developer.mozilla.org/en-US/docs/Web/API/Window/open#parameters) under the corresponding parameter `windowName`.
|
||||
|
||||
@@ -28,6 +43,63 @@ ensure your code works with this property enabled. It has been enabled by defau
|
||||
|
||||
You will be affected by this change if you use either `webFrame.executeJavaScript` or `webFrame.executeJavaScriptInIsolatedWorld`. You will need to ensure that values returned by either of those methods are supported by the [Context Bridge API](api/context-bridge.md#parameter--error--return-type-support) as these methods use the same value passing semantics.
|
||||
|
||||
### Default Changed: `nativeWindowOpen` defaults to `true`
|
||||
|
||||
Prior to Electron 14, `window.open` was by default shimmed to use
|
||||
`BrowserWindowProxy`. This meant that `window.open('about:blank')` did not work
|
||||
to open synchronously scriptable child windows, among other incompatibilities.
|
||||
`nativeWindowOpen` is no longer experimental, and is now the default.
|
||||
|
||||
See the documentation for [window.open in Electron](api/window-open.md)
|
||||
for more details.
|
||||
|
||||
### Removed: BrowserWindowConstructorOptions inheriting from parent windows
|
||||
|
||||
Prior to Electron 14, windows opened with `window.open` would inherit
|
||||
BrowserWindow constructor options such as `transparent` and `resizable` from
|
||||
their parent window. Beginning with Electron 14, this behavior is removed, and
|
||||
windows will not inherit any BrowserWindow constructor options from their
|
||||
parents.
|
||||
|
||||
Instead, explicitly set options for the new window with `setWindowOpenHandler`:
|
||||
|
||||
```js
|
||||
webContents.setWindowOpenHandler((details) => {
|
||||
return {
|
||||
action: 'allow',
|
||||
overrideBrowserWindowOptions: {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Removed: `additionalFeatures`
|
||||
|
||||
The deprecated `additionalFeatures` property in the `new-window` and
|
||||
`did-create-window` events of WebContents has been removed. Since `new-window`
|
||||
uses positional arguments, the argument is still present, but will always be
|
||||
the empty array `[]`. (Though note, the `new-window` event itself is
|
||||
deprecated, and is replaced by `setWindowOpenHandler`.) Bare keys in window
|
||||
features will now present as keys with the value `true` in the options object.
|
||||
|
||||
```js
|
||||
// Removed in Electron 14
|
||||
// Triggered by window.open('...', '', 'my-key')
|
||||
webContents.on('did-create-window', (window, details) => {
|
||||
if (details.additionalFeatures.includes('my-key')) {
|
||||
// ...
|
||||
}
|
||||
})
|
||||
|
||||
// Replace with
|
||||
webContents.on('did-create-window', (window, details) => {
|
||||
if (details.options['my-key']) {
|
||||
// ...
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Planned Breaking API Changes (13.0)
|
||||
|
||||
### API Changed: `session.setPermissionCheckHandler(handler)`
|
||||
@@ -136,6 +208,22 @@ systemPreferences.isHighContrastColorScheme()
|
||||
nativeTheme.shouldUseHighContrastColors
|
||||
```
|
||||
|
||||
### Deprecated: WebContents `new-window` event
|
||||
|
||||
The `new-window` event of WebContents has been deprecated. It is replaced by [`webContents.setWindowOpenHandler()`](api/web-contents.md#contentssetwindowopenhandlerhandler).
|
||||
|
||||
```js
|
||||
// Deprecated in Electron 13
|
||||
webContents.on('new-window', (event) => {
|
||||
event.preventDefault()
|
||||
})
|
||||
|
||||
// Replace with
|
||||
webContents.setWindowOpenHandler((details) => {
|
||||
return { action: 'deny' }
|
||||
})
|
||||
```
|
||||
|
||||
## Planned Breaking API Changes (12.0)
|
||||
|
||||
### Removed: Pepper Flash support
|
||||
@@ -160,6 +248,9 @@ the previous behavior, `contextIsolation: false` must be specified in WebPrefere
|
||||
|
||||
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.
|
||||
|
||||
Another implication is that `require()` cannot be used in the renderer process unless
|
||||
`nodeIntegration` is `true` and `contextIsolation` is `false`.
|
||||
|
||||
For more details see: https://github.com/electron/electron/issues/23506
|
||||
|
||||
### Removed: `crashReporter.getCrashesDirectory()`
|
||||
@@ -295,14 +386,6 @@ 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
|
||||
as part of our plan to more closely align with Chromium's process model for security,
|
||||
performance and maintainability.
|
||||
|
||||
For more detailed information see [#18397](https://github.com/electron/electron/issues/18397).
|
||||
|
||||
### Default Changed: `enableRemoteModule` defaults to `false`
|
||||
|
||||
In Electron 9, using the remote module without explicitly enabling it via the
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# Build Instructions
|
||||
|
||||
Follow the guidelines below for building Electron.
|
||||
Follow the guidelines below for building **Electron itself**, for the purposes of creating custom Electron binaries. For bundling and distributing your app code with the prebuilt Electron binaries, see the [application distribution][application-distribution] guide.
|
||||
|
||||
[application-distribution]: ../tutorial/application-distribution.md
|
||||
|
||||
## Platform prerequisites
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# Build Instructions (Linux)
|
||||
|
||||
Follow the guidelines below for building Electron on Linux.
|
||||
Follow the guidelines below for building **Electron itself** on Linux, for the purposes of creating custom Electron binaries. For bundling and distributing your app code with the prebuilt Electron binaries, see the [application distribution][application-distribution] guide.
|
||||
|
||||
[application-distribution]: ../tutorial/application-distribution.md
|
||||
|
||||
## Prerequisites
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# Build Instructions (macOS)
|
||||
|
||||
Follow the guidelines below for building Electron on macOS.
|
||||
Follow the guidelines below for building **Electron itself** on macOS, for the purposes of creating custom Electron binaries. For bundling and distributing your app code with the prebuilt Electron binaries, see the [application distribution][application-distribution] guide.
|
||||
|
||||
[application-distribution]: ../tutorial/application-distribution.md
|
||||
|
||||
## Prerequisites
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# Build Instructions (Windows)
|
||||
|
||||
Follow the guidelines below for building Electron on Windows.
|
||||
Follow the guidelines below for building **Electron itself** on Windows, for the purposes of creating custom Electron binaries. For bundling and distributing your app code with the prebuilt Electron binaries, see the [application distribution][application-distribution] guide.
|
||||
|
||||
[application-distribution]: ../tutorial/application-distribution.md
|
||||
|
||||
## Prerequisites
|
||||
|
||||
|
||||
@@ -33,8 +33,7 @@ contributing, and more. Please use the issue tracker for bugs only!
|
||||
To submit a bug report:
|
||||
|
||||
When opening a new issue in the [`electron/electron` issue tracker](https://github.com/electron/electron/issues/new/choose), users
|
||||
will be presented with [a template](https://github.com/electron/electron/blob/master/.github/ISSUE_TEMPLATE/Bug_report.md)
|
||||
that should be filled in.
|
||||
will be presented with a template that should be filled in.
|
||||
|
||||
If you believe that you have found a bug in Electron, please fill out the template
|
||||
to the best of your ability.
|
||||
|
||||
@@ -106,7 +106,6 @@ Common prefixes:
|
||||
* perf: A code change that improves performance
|
||||
* refactor: A code change that neither fixes a bug nor adds a feature
|
||||
* style: Changes that do not affect the meaning of the code (linting)
|
||||
* vendor: Bumping a dependency like libchromiumcontent or node
|
||||
|
||||
Other things to keep in mind when writing a commit message:
|
||||
|
||||
|
||||
@@ -83,8 +83,6 @@ Electron
|
||||
* **.github** - GitHub-specific config files including issues templates and CODEOWNERS.
|
||||
* **dist** - Temporary directory created by `script/create-dist.py` script
|
||||
when creating a distribution.
|
||||
* **external_binaries** - Downloaded binaries of third-party frameworks which
|
||||
do not support building with `gn`.
|
||||
* **node_modules** - Third party node modules used for building.
|
||||
* **npm** - Logic for installation of Electron via npm.
|
||||
* **out** - Temporary output directory of `ninja`.
|
||||
@@ -100,7 +98,4 @@ script/ - The set of all scripts Electron runs for a variety of purposes.
|
||||
└── uploaders/ - Uploads various release-related files during release.
|
||||
```
|
||||
|
||||
* **tools** - Helper scripts used by GN files.
|
||||
* Scripts put here should never be invoked by users directly, unlike those in `script`.
|
||||
* **typings** - TypeScript typings for Electron's internal code.
|
||||
* **vendor** - Source code for some third party dependencies.
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
<p>
|
||||
We are using node <script>document.write(process.versions.node)</script>,
|
||||
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||
and Electron <script>document.write(process.versions.electron)</script>.
|
||||
We are using Node.js <span id="node-version"></span>,
|
||||
Chromium <span id="chrome-version"></span>,
|
||||
and Electron <span id="electron-version"></span>.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,18 +1,27 @@
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
preload: path.join(__dirname, 'preload.js')
|
||||
}
|
||||
})
|
||||
|
||||
win.loadFile('index.html')
|
||||
}
|
||||
|
||||
app.whenReady().then(createWindow)
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
@@ -20,8 +29,3 @@ app.on('window-all-closed', () => {
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
|
||||
11
docs/fiddles/quick-start/preload.js
Normal file
11
docs/fiddles/quick-start/preload.js
Normal file
@@ -0,0 +1,11 @@
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
const replaceText = (selector, text) => {
|
||||
const element = document.getElementById(selector)
|
||||
if (element) element.innerText = text
|
||||
}
|
||||
|
||||
for (const type of ['chrome', 'node', 'electron']) {
|
||||
replaceText(`${type}-version`, process.versions[type])
|
||||
}
|
||||
})
|
||||
|
||||
@@ -190,7 +190,6 @@ it may be worth your time to shop around. Popular resellers include:
|
||||
|
||||
* [digicert](https://www.digicert.com/code-signing/microsoft-authenticode.htm)
|
||||
* [Sectigo](https://sectigo.com/ssl-certificates-tls/code-signing)
|
||||
* [GoDaddy](https://au.godaddy.com/web-security/code-signing-certificate)
|
||||
* Amongst others, please shop around to find one that suits your needs, Google
|
||||
is your friend 😄
|
||||
|
||||
|
||||
@@ -11,14 +11,19 @@ npm install electron --save-dev
|
||||
See the [Electron versioning doc][versioning] for info on how to
|
||||
manage Electron versions in your apps.
|
||||
|
||||
## Global Installation
|
||||
## Running Electron ad-hoc
|
||||
|
||||
You can also install the `electron` command globally in your `$PATH`:
|
||||
If you're in a pinch and would prefer to not use `npm install` in your local
|
||||
project, you can also run Electron ad-hoc using the [`npx`][npx] command runner
|
||||
bundled with `npm`:
|
||||
|
||||
```sh
|
||||
npm install electron -g
|
||||
npx electron .
|
||||
```
|
||||
|
||||
The above command will run the current working directory with Electron. Note that
|
||||
any dependencies in your app will not be installed.
|
||||
|
||||
## Customization
|
||||
|
||||
If you want to change the architecture that is downloaded (e.g., `ia32` on an
|
||||
@@ -178,6 +183,7 @@ If you need to force a re-download of the asset and the SHASUM file set the
|
||||
|
||||
[npm]: https://docs.npmjs.com
|
||||
[versioning]: ./electron-versioning.md
|
||||
[npx]: https://docs.npmjs.com/cli/v7/commands/npx
|
||||
[releases]: https://github.com/electron/electron/releases
|
||||
[proxy-env-10]: https://github.com/gajus/global-agent/blob/v2.1.5/README.md#environment-variables
|
||||
[proxy-env]: https://github.com/np-maintain/global-tunnel/blob/v2.7.1/README.md#auto-config
|
||||
|
||||
@@ -32,6 +32,7 @@ From a development perspective, an Electron application is essentially a Node.js
|
||||
my-electron-app/
|
||||
├── package.json
|
||||
├── main.js
|
||||
├── preload.js
|
||||
└── index.html
|
||||
```
|
||||
|
||||
@@ -55,45 +56,49 @@ The main script may look as follows:
|
||||
|
||||
```javascript fiddle='docs/fiddles/quick-start'
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
preload: path.join(__dirname, 'preload.js')
|
||||
}
|
||||
})
|
||||
|
||||
win.loadFile('index.html')
|
||||
}
|
||||
|
||||
app.whenReady().then(createWindow)
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
##### What is going on above?
|
||||
|
||||
1. Line 1: First, you import the `app` and `BrowserWindow` modules of the `electron` package to be able to manage your application's lifecycle events, as well as create and control browser windows.
|
||||
2. Line 3: After that, you define a function that creates a [new browser window](../api/browser-window.md#new-browserwindowoptions) with node integration enabled, loads `index.html` file into this window (line 12, we will discuss the file later).
|
||||
3. Line 15: You create a new browser window by invoking the `createWindow` function once the Electron application [is initialized](../api/app.md#appwhenready).
|
||||
4. Line 17: You add a new listener that tries to quit the application when it no longer has any open windows. This listener is a no-op on macOS due to the operating system's [window management behavior](https://support.apple.com/en-ca/guide/mac-help/mchlp2469/mac).
|
||||
5. Line 23: You add a new listener that creates a new browser window only if when the application has no visible windows after being activated. For example, after launching the application for the first time, or re-launching the already running application.
|
||||
2. Line 2: Second, you import the `path` package which provides utility functions for file paths.
|
||||
3. Line 4: After that, you define a function that creates a [new browser window](../api/browser-window.md#new-browserwindowoptions) with a preload script, loads `index.html` file into this window (line 13, we will discuss the file later).
|
||||
4. Line 16: You create a new browser window by invoking the `createWindow` function once the Electron application [is initialized](../api/app.md#appwhenready).
|
||||
5. Line 18: You add a new listener that creates a new browser window only if when the application has no visible windows after being activated. For example, after launching the application for the first time, or re-launching the already running application.
|
||||
6. Line 25: You add a new listener that tries to quit the application when it no longer has any open windows. This listener is a no-op on macOS due to the operating system's [window management behavior](https://support.apple.com/en-ca/guide/mac-help/mchlp2469/mac).
|
||||
|
||||
#### Create a web page
|
||||
|
||||
This is the web page you want to display once the application is initialized. This web page represents the Renderer process. You can create multiple browser windows, where each window uses its own independent Renderer. Each window can optionally be granted with full access to Node.js API through the `nodeIntegration` preference.
|
||||
This is the web page you want to display once the application is initialized. This web page represents the Renderer process. You can create multiple browser windows, where each window uses its own independent Renderer. You can optionally grant access to additional Node.js APIs by exposing them from your preload script.
|
||||
|
||||
The `index.html` page looks as follows:
|
||||
|
||||
@@ -108,14 +113,38 @@ The `index.html` page looks as follows:
|
||||
<body style="background: white;">
|
||||
<h1>Hello World!</h1>
|
||||
<p>
|
||||
We are using node <script>document.write(process.versions.node)</script>,
|
||||
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||
and Electron <script>document.write(process.versions.electron)</script>.
|
||||
We are using Node.js <span id="node-version"></span>,
|
||||
Chromium <span id="chrome-version"></span>,
|
||||
and Electron <span id="electron-version"></span>.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
#### Define a preload script
|
||||
|
||||
Your preload script (in our case, the `preload.js` file) acts as a bridge between Node.js and your web page. It allows you to expose specific APIs and behaviors to your web page rather than insecurely exposing the entire Node.js API. In this example we will use the preload script to read version information from the `process` object and update the web page with that info.
|
||||
|
||||
```javascript fiddle='docs/fiddles/quick-start'
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
const replaceText = (selector, text) => {
|
||||
const element = document.getElementById(selector)
|
||||
if (element) element.innerText = text
|
||||
}
|
||||
|
||||
for (const type of ['chrome', 'node', 'electron']) {
|
||||
replaceText(`${type}-version`, process.versions[type])
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
##### What's going on above?
|
||||
|
||||
1. On line 1: First you define an event listener that tells you when the web page has loaded
|
||||
2. On line 2: Second you define a utility function used to set the text of the placeholders in the `index.html`
|
||||
3. On line 7: Next you loop through the list of components whose version you want to display
|
||||
4. On line 8: Finally, you call `replaceText` to look up the version placeholders in `index.html` and set their text value to the values from `process.versions`
|
||||
|
||||
#### Modify your package.json file
|
||||
|
||||
Your Electron application uses the `package.json` file as the main entry point (as any other Node.js application). The main script of your application is `main.js`, so modify the `package.json` file accordingly:
|
||||
@@ -167,7 +196,8 @@ The simplest and the fastest way to distribute your newly created app is using
|
||||
1. Import Electron Forge to your app folder:
|
||||
|
||||
```sh
|
||||
npx @electron-forge/cli import
|
||||
npm install --save-dev @electron-forge/cli
|
||||
npx electron-forge import
|
||||
|
||||
✔ Checking your system
|
||||
✔ Initializing Git Repository
|
||||
@@ -282,7 +312,7 @@ ipcRenderer.invoke('perform-action', ...args)
|
||||
|
||||
##### Node.js API
|
||||
|
||||
> NOTE: To access the Node.js API from the Renderer process, you need to set the `nodeIntegration` preference to `true`.
|
||||
> NOTE: To access the Node.js API from the Renderer process, you need to set the `nodeIntegration` preference to `true` and the `contextIsolation` preference to `false`. Please note that access to the Node.js API in any renderer that loads remote content is not recommended for [security reasons](../tutorial/security.md#2-do-not-enable-nodejs-integration-for-remote-content).
|
||||
|
||||
Electron exposes full access to Node.js API and its modules both in the Main and the Renderer processes. For example, you can read all the files from the root directory:
|
||||
|
||||
|
||||
@@ -83,6 +83,22 @@ following code snippet to your menu template:
|
||||
}
|
||||
```
|
||||
|
||||
Make sure the application menu is added after the [`'ready'`](../api/app.md#event-ready)
|
||||
event and not before, or the menu item will be disabled:
|
||||
|
||||
```javascript
|
||||
const { app, Menu } = require('electron')
|
||||
|
||||
const template = [
|
||||
// Menu template here
|
||||
]
|
||||
const menu = Menu.buildFromTemplate(template)
|
||||
|
||||
app.whenReady().then(() => {
|
||||
Menu.setApplicationMenu(menu)
|
||||
})
|
||||
```
|
||||
|
||||
![macOS Recent Documents menu item][menu-item-image]
|
||||
|
||||
When a file is requested from the recent documents menu, the `open-file` event
|
||||
|
||||
@@ -1,27 +1,23 @@
|
||||
# REPL
|
||||
|
||||
Read-Eval-Print-Loop (REPL) is a simple, interactive computer programming
|
||||
environment that takes single user inputs (i.e. single expressions), evaluates
|
||||
them, and returns the result to the user.
|
||||
[Read-Eval-Print-Loop](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop) (REPL)
|
||||
is a simple, interactive computer programming environment that takes single user
|
||||
inputs (i.e. single expressions), evaluates them, and returns the result to the user.
|
||||
|
||||
The `repl` module provides a REPL implementation that can be accessed using:
|
||||
## Main process
|
||||
|
||||
* Assuming you have `electron` or `electron-prebuilt` installed as a local
|
||||
project dependency:
|
||||
Electron exposes the [Node.js `repl` module](https://nodejs.org/dist/latest/docs/api/repl.html)
|
||||
through the `--interactive` CLI flag. Assuming you have `electron` installed as a local project
|
||||
dependency, you should be able to access the REPL with the following command:
|
||||
|
||||
```sh
|
||||
./node_modules/.bin/electron --interactive
|
||||
```
|
||||
|
||||
* Assuming you have `electron` or `electron-prebuilt` installed globally:
|
||||
**Note:** `electron --interactive` is not available on Windows
|
||||
(see [electron/electron#5776](https://github.com/electron/electron/pull/5776) for more details).
|
||||
|
||||
```sh
|
||||
electron --interactive
|
||||
```
|
||||
## Renderer process
|
||||
|
||||
This only creates a REPL for the main process. You can use the Console
|
||||
tab of the Dev Tools to get a REPL for the renderer processes.
|
||||
|
||||
**Note:** `electron --interactive` is not available on Windows.
|
||||
|
||||
More information can be found in the [Node.js REPL docs](https://nodejs.org/dist/latest/docs/api/repl.html).
|
||||
You can use the DevTools Console tab to get a REPL for any renderer process.
|
||||
To learn more, read [the Chrome documentation](https://developer.chrome.com/docs/devtools/console/).
|
||||
|
||||
169
docs/tutorial/sandbox.md
Normal file
169
docs/tutorial/sandbox.md
Normal file
@@ -0,0 +1,169 @@
|
||||
# Process Sandboxing
|
||||
|
||||
One key security feature in Chromium is that processes can be executed within a sandbox.
|
||||
The sandbox limits the harm that malicious code can cause by limiting access to most
|
||||
system resources — sandboxed processes can only freely use CPU cycles and memory.
|
||||
In order to perform operations requiring additional privilege, sandboxed processes
|
||||
use dedicated communication channels to delegate tasks to more privileged processes.
|
||||
|
||||
In Chromium, sandboxing is applied to most processes other than the main process.
|
||||
This includes renderer processes, as well as utility processes such as the audio service,
|
||||
the GPU service and the network service.
|
||||
|
||||
See Chromium's [Sandbox design document][sandbox] for more information.
|
||||
|
||||
## Electron's sandboxing policies
|
||||
|
||||
Electron comes with a mixed sandbox environment, meaning sandboxed processes can run
|
||||
alongside privileged ones. By default, renderer processes are not sandboxed, but
|
||||
utility processes are. Note that as in Chromium, the main (browser) process is
|
||||
privileged and cannot be sandboxed.
|
||||
|
||||
Historically, this mixed sandbox approach was established because having Node.js available
|
||||
in the renderer is an extremely powerful tool for app developers. Unfortunately, this
|
||||
feature is also an equally massive security vulnerability.
|
||||
|
||||
Theoretically, unsandboxed renderers are not a problem for desktop applications that
|
||||
only display trusted code, but they make Electron less secure than Chromium for
|
||||
displaying untrusted web content. However, even purportedly trusted code may be
|
||||
dangerous — there are countless attack vectors that malicious actors can use, from
|
||||
cross-site scripting to content injection to man-in-the-middle attacks on remotely loaded
|
||||
websites, just to name a few. For this reason, we recommend enabling renderer sandboxing
|
||||
for the vast majority of cases under an abundance of caution.
|
||||
|
||||
<!--TODO: update this guide when #28466 is either solved or closed -->
|
||||
Note that there is an active discussion in the issue tracker to enable renderer sandboxing
|
||||
by default. See [#28466][issue-28466]) for details.
|
||||
|
||||
## Sandbox behaviour in Electron
|
||||
|
||||
Sandboxed processes in Electron behave _mostly_ in the same way as Chromium's do, but
|
||||
Electron has a few additional concepts to consider because it interfaces with Node.js.
|
||||
|
||||
### Renderer processes
|
||||
|
||||
When renderer processes in Electron are sandboxed, they behave in the same way as a
|
||||
regular Chrome renderer would. A sandboxed renderer won't have a Node.js
|
||||
environment initialized.
|
||||
|
||||
<!-- TODO(erickzhao): when we have a solid guide for IPC, link it here -->
|
||||
Therefore, when the sandbox is enabled, renderer processes can only perform privileged
|
||||
tasks (such as interacting with the filesystem, making changes to the system, or spawning
|
||||
subprocesses) by delegating these tasks to the main process via inter-process
|
||||
communication (IPC).
|
||||
|
||||
### Preload scripts
|
||||
|
||||
In order to allow renderer processes to communicate with the main process, preload
|
||||
scripts attached to sandboxed renderers will still have a polyfilled subset of Node.js
|
||||
APIs available. A `require` function similar to Node's `require` module is exposed,
|
||||
but can only import a subset of Electron and Node's built-in modules:
|
||||
|
||||
* `electron` (only renderer process modules)
|
||||
* [`events`](https://nodejs.org/api/events.html)
|
||||
* [`timers`](https://nodejs.org/api/timers.html)
|
||||
* [`url`](https://nodejs.org/api/url.html)
|
||||
|
||||
In addition, the preload script also polyfills certain Node.js primitives as globals:
|
||||
|
||||
* [`Buffer`](https://nodejs.org/api/Buffer.html)
|
||||
* [`process`](../api/process.md)
|
||||
* [`clearImmediate`](https://nodejs.org/api/timers.html#timers_clearimmediate_immediate)
|
||||
* [`setImmediate`](https://nodejs.org/api/timers.html#timers_setimmediate_callback_args)
|
||||
|
||||
Because the `require` function is a polyfill with limited functionality, you will not be
|
||||
able to use [CommonJS modules][commonjs] to separate your preload script into multiple
|
||||
files. If you need to split your preload code, use a bundler such as [webpack][webpack]
|
||||
or [Parcel][parcel].
|
||||
|
||||
Note that because the environment presented to the `preload` script is substantially
|
||||
more privileged than that of a sandboxed renderer, it is still possible to leak
|
||||
privileged APIs to untrusted code running in the renderer process unless
|
||||
[`contextIsolation`][contextIsolation] is enabled.
|
||||
|
||||
## Configuring the sandbox
|
||||
|
||||
### Enabling the sandbox for a single process
|
||||
|
||||
In Electron, renderer sandboxing can be enabled on a per-process basis with
|
||||
the `sandbox: true` preference in the [`BrowserWindow`][browser-window] constructor.
|
||||
|
||||
```js
|
||||
// main.js
|
||||
app.whenReady().then(() => {
|
||||
const win = new BrowserWindow({
|
||||
webPreferences: {
|
||||
sandbox: true
|
||||
}
|
||||
})
|
||||
win.loadURL('https://google.com')
|
||||
})
|
||||
```
|
||||
|
||||
### Enabling the sandbox globally
|
||||
|
||||
If you want to force sandboxing for all renderers, you can also use the
|
||||
[`app.enableSandbox`][enable-sandbox] API. Note that this API has to be called before the
|
||||
app's `ready` event.
|
||||
|
||||
```js
|
||||
// main.js
|
||||
app.enableSandbox()
|
||||
app.whenReady().then(() => {
|
||||
// no need to pass `sandbox: true` since `app.enableSandbox()` was called.
|
||||
const win = new BrowserWindow()
|
||||
win.loadURL('https://google.com')
|
||||
})
|
||||
```
|
||||
|
||||
### Disabling Chromium's sandbox (testing only)
|
||||
|
||||
You can also disable Chromium's sandbox entirely with the [`--no-sandbox`][no-sandbox]
|
||||
CLI flag, which will disable the sandbox for all processes (including utility processes).
|
||||
We highly recommend that you only use this flag for testing purposes, and **never**
|
||||
in production.
|
||||
|
||||
Note that the `sandbox: true` option will still disable the renderer's Node.js
|
||||
environment.
|
||||
|
||||
## A note on rendering untrusted content
|
||||
|
||||
Rendering untrusted content in Electron is still somewhat uncharted territory,
|
||||
though some apps are finding success (e.g. [Beaker Browser][beaker]).
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
[sandbox]: https://chromium.googlesource.com/chromium/src/+/master/docs/design/sandbox.md
|
||||
[issue-28466]: https://github.com/electron/electron/issues/28466
|
||||
[browser-window]: ../api/browser-window.md
|
||||
[enable-sandbox]: ../api/app.md#appenablesandbox
|
||||
[no-sandbox]: ../api/command-line-switches.md#--no-sandbox
|
||||
[commonjs]: https://nodejs.org/api/modules.html#modules_modules_commonjs_modules
|
||||
[webpack]: https://webpack.js.org/
|
||||
[parcel]: https://parceljs.org/
|
||||
[context-isolation]: ./context-isolation.md
|
||||
[beaker]: https://github.com/beakerbrowser/beaker
|
||||
@@ -44,7 +44,7 @@ Chromium shared library and Node.js. Vulnerabilities affecting these components
|
||||
may impact the security of your application. By updating Electron to the latest
|
||||
version, you ensure that critical vulnerabilities (such as *nodeIntegration bypasses*)
|
||||
are already patched and cannot be exploited in your application. For more information,
|
||||
see "[Use a current version of Electron](#17-use-a-current-version-of-electron)".
|
||||
see "[Use a current version of Electron](#15-use-a-current-version-of-electron)".
|
||||
|
||||
* **Evaluate your dependencies.** While NPM provides half a million reusable packages,
|
||||
it is your responsibility to choose trusted 3rd-party libraries. If you use outdated
|
||||
@@ -99,9 +99,7 @@ You should at least follow these steps to improve the security of your applicati
|
||||
12. [Disable or limit navigation](#12-disable-or-limit-navigation)
|
||||
13. [Disable or limit creation of new windows](#13-disable-or-limit-creation-of-new-windows)
|
||||
14. [Do not use `openExternal` with untrusted content](#14-do-not-use-openexternal-with-untrusted-content)
|
||||
15. [Disable the `remote` module](#15-disable-the-remote-module)
|
||||
16. [Filter the `remote` module](#16-filter-the-remote-module)
|
||||
17. [Use a current version of Electron](#17-use-a-current-version-of-electron)
|
||||
15. [Use a current version of Electron](#15-use-a-current-version-of-electron)
|
||||
|
||||
To automate the detection of misconfigurations and insecure patterns, it is
|
||||
possible to use
|
||||
@@ -665,134 +663,7 @@ const { shell } = require('electron')
|
||||
shell.openExternal('https://example.com/index.html')
|
||||
```
|
||||
|
||||
## 15) Disable the `remote` module
|
||||
|
||||
The `remote` module provides a way for the renderer processes to
|
||||
access APIs normally only available in the main process. Using it, a
|
||||
renderer can invoke methods of a main process object without explicitly sending
|
||||
inter-process messages. If your desktop application does not run untrusted
|
||||
content, this can be a useful way to have your renderer processes access and
|
||||
work with modules that are only available to the main process, such as
|
||||
GUI-related modules (dialogs, menus, etc.).
|
||||
|
||||
However, if your app can run untrusted content and even if you
|
||||
[sandbox][sandbox] your renderer processes accordingly, the `remote` module
|
||||
makes it easy for malicious code to escape the sandbox and have access to
|
||||
system resources via the higher privileges of the main process. Therefore,
|
||||
it should be disabled in such circumstances.
|
||||
|
||||
### Why?
|
||||
|
||||
`remote` uses an internal IPC channel to communicate with the main process.
|
||||
"Prototype pollution" attacks can grant malicious code access to the internal
|
||||
IPC channel, which can then be used to escape the sandbox by mimicking `remote`
|
||||
IPC messages and getting access to main process modules running with higher
|
||||
privileges.
|
||||
|
||||
Additionally, it's possible for preload scripts to accidentally leak modules to a
|
||||
sandboxed renderer. Leaking `remote` arms malicious code with a multitude
|
||||
of main process modules with which to perform an attack.
|
||||
|
||||
Disabling the `remote` module eliminates these attack vectors. Enabling
|
||||
context isolation also prevents the "prototype pollution" attacks from
|
||||
succeeding.
|
||||
|
||||
### How?
|
||||
|
||||
```js
|
||||
// Bad if the renderer can run untrusted content
|
||||
const mainWindow = new BrowserWindow({
|
||||
webPreferences: {
|
||||
enableRemoteModule: true
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
```js
|
||||
// Good
|
||||
const mainWindow = new BrowserWindow({
|
||||
webPreferences: {
|
||||
enableRemoteModule: false
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
```html
|
||||
<!-- Bad if the renderer can run untrusted content -->
|
||||
<webview enableremotemodule="true" src="page.html"></webview>
|
||||
|
||||
<!-- Good -->
|
||||
<webview enableremotemodule="false" src="page.html"></webview>
|
||||
```
|
||||
|
||||
> **Note:** The default value of `enableRemoteModule` is `false` starting
|
||||
> from Electron 10. For prior versions, you need to explicitly disable
|
||||
> the `remote` module by the means above.
|
||||
|
||||
## 16) Filter the `remote` module
|
||||
|
||||
If you cannot disable the `remote` module, you should filter the globals,
|
||||
Node, and Electron modules (so-called built-ins) accessible via `remote`
|
||||
that your application does not require. This can be done by blocking
|
||||
certain modules entirely and by replacing others with proxies that
|
||||
expose only the functionality that your app needs.
|
||||
|
||||
### Why?
|
||||
|
||||
Due to the system access privileges of the main process, functionality
|
||||
provided by the main process modules may be dangerous in the hands of
|
||||
malicious code running in a compromised renderer process. By limiting
|
||||
the set of accessible modules to the minimum that your app needs and
|
||||
filtering out the others, you reduce the toolset that malicious code
|
||||
can use to attack the system.
|
||||
|
||||
Note that the safest option is to
|
||||
[fully disable the remote module](#15-disable-the-remote-module). If
|
||||
you choose to filter access rather than completely disable the module,
|
||||
you must be very careful to ensure that no escalation of privilege is
|
||||
possible through the modules you allow past the filter.
|
||||
|
||||
### How?
|
||||
|
||||
```js
|
||||
const readOnlyFsProxy = require(/* ... */) // exposes only file read functionality
|
||||
|
||||
const allowedModules = new Set(['crypto'])
|
||||
const proxiedModules = new Map([['fs', readOnlyFsProxy]])
|
||||
const allowedElectronModules = new Set(['shell'])
|
||||
const allowedGlobals = new Set()
|
||||
|
||||
app.on('remote-require', (event, webContents, moduleName) => {
|
||||
if (proxiedModules.has(moduleName)) {
|
||||
event.returnValue = proxiedModules.get(moduleName)
|
||||
}
|
||||
if (!allowedModules.has(moduleName)) {
|
||||
event.preventDefault()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('remote-get-builtin', (event, webContents, moduleName) => {
|
||||
if (!allowedElectronModules.has(moduleName)) {
|
||||
event.preventDefault()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('remote-get-global', (event, webContents, globalName) => {
|
||||
if (!allowedGlobals.has(globalName)) {
|
||||
event.preventDefault()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('remote-get-current-window', (event, webContents) => {
|
||||
event.preventDefault()
|
||||
})
|
||||
|
||||
app.on('remote-get-current-web-contents', (event, webContents) => {
|
||||
event.preventDefault()
|
||||
})
|
||||
```
|
||||
|
||||
## 17) Use a current version of Electron
|
||||
## 15) Use a current version of Electron
|
||||
|
||||
You should strive for always using the latest available version of Electron.
|
||||
Whenever a new major version is released, you should attempt to update your
|
||||
@@ -821,5 +692,5 @@ which potential security issues are not as widely known.
|
||||
[window-open-handler]: ../api/web-contents.md#contentssetwindowopenhandlerhandler
|
||||
[will-navigate]: ../api/web-contents.md#event-will-navigate
|
||||
[open-external]: ../api/shell.md#shellopenexternalurl-options
|
||||
[sandbox]: ../api/sandbox-option.md
|
||||
[sandbox]: ../tutorial/sandbox.md
|
||||
[responsible-disclosure]: https://en.wikipedia.org/wiki/Responsible_disclosure
|
||||
|
||||
@@ -94,7 +94,7 @@ Following platforms are supported by Electron:
|
||||
### macOS
|
||||
|
||||
Only 64bit binaries are provided for macOS, and the minimum macOS version
|
||||
supported is macOS 10.10 (Yosemite).
|
||||
supported is macOS 10.11 (El Capitan).
|
||||
|
||||
Native support for Apple Silicon (`arm64`) devices was added in Electron 11.0.0.
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ match a public release, instruct `npm` to use the version of Node you have bundl
|
||||
with your custom build.
|
||||
|
||||
```sh
|
||||
npm rebuild --nodedir=/path/to/electron/vendor/node
|
||||
npm rebuild --nodedir=/path/to/src/out/Default/gen/node_headers
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
@@ -86,12 +86,12 @@ const driver = new webdriver.Builder()
|
||||
// The "9515" is the port opened by chrome driver.
|
||||
.usingServer('http://localhost:9515')
|
||||
.withCapabilities({
|
||||
chromeOptions: {
|
||||
'goog:chromeOptions': {
|
||||
// Here is the path to your Electron binary.
|
||||
binary: '/Path-to-Your-App.app/Contents/MacOS/Electron'
|
||||
}
|
||||
})
|
||||
.forBrowser('electron')
|
||||
.forBrowser('chrome') // note: use .forBrowser('electron') for selenium-webdriver <= 3.6.0
|
||||
.build()
|
||||
|
||||
driver.get('http://www.google.com')
|
||||
|
||||
@@ -73,7 +73,7 @@ template("electron_extra_paks") {
|
||||
"//components/resources",
|
||||
"//content:content_resources",
|
||||
"//content:dev_ui_content_resources",
|
||||
"//content/browser/resources/media:media_internals_resources",
|
||||
"//content/browser/resources/media:resources",
|
||||
"//content/browser/tracing:resources",
|
||||
"//content/browser/webrtc/resources",
|
||||
"//electron:resources",
|
||||
|
||||
@@ -51,6 +51,21 @@
|
||||
<message name="IDS_PICTURE_IN_PICTURE_SKIP_AD_CONTROL_TEXT" desc="Text label of the skip ad control button. The button appears when the user hovers over the Picture-in-Picture window.">
|
||||
Skip Ad
|
||||
</message>
|
||||
<message name="IDS_PICTURE_IN_PICTURE_MUTE_MICROPHONE_TEXT" desc="Text label of the mute microphone control button. The button appears when the user hovers over the Picture-in-Picture window.">
|
||||
Mute microphone
|
||||
</message>
|
||||
<message name="IDS_PICTURE_IN_PICTURE_UNMUTE_MICROPHONE_TEXT" desc="Text label of the unmute microphone control button. The button appears when the user hovers over the Picture-in-Picture window.">
|
||||
Unmute microphone
|
||||
</message>
|
||||
<message name="IDS_PICTURE_IN_PICTURE_TURN_ON_CAMERA_TEXT" desc="Text label of the turn on camera control button. The button appears when the user hovers over the Picture-in-Picture window.">
|
||||
Turn on camera
|
||||
</message>
|
||||
<message name="IDS_PICTURE_IN_PICTURE_TURN_OFF_CAMERA_TEXT" desc="Text label of the turn off camera control button. The button appears when the user hovers over the Picture-in-Picture window.">
|
||||
Turn off camera
|
||||
</message>
|
||||
<message name="IDS_PICTURE_IN_PICTURE_HANG_UP_TEXT" desc="Text label of the hang up control button. The button appears when the user hovers over the Picture-in-Picture window.">
|
||||
Hang up
|
||||
</message>
|
||||
<message name="IDS_PICTURE_IN_PICTURE_CLOSE_CONTROL_TEXT" desc="Text label of the close control button. The button appears when the user hovers over the Picture-in-Picture window.">
|
||||
Close
|
||||
</message>
|
||||
|
||||
@@ -29,7 +29,6 @@ auto_filenames = {
|
||||
"docs/api/incoming-message.md",
|
||||
"docs/api/ipc-main.md",
|
||||
"docs/api/ipc-renderer.md",
|
||||
"docs/api/locales.md",
|
||||
"docs/api/menu-item.md",
|
||||
"docs/api/menu.md",
|
||||
"docs/api/message-channel-main.md",
|
||||
@@ -43,8 +42,6 @@ auto_filenames = {
|
||||
"docs/api/power-save-blocker.md",
|
||||
"docs/api/process.md",
|
||||
"docs/api/protocol.md",
|
||||
"docs/api/remote.md",
|
||||
"docs/api/sandbox-option.md",
|
||||
"docs/api/screen.md",
|
||||
"docs/api/service-workers.md",
|
||||
"docs/api/session.md",
|
||||
@@ -105,7 +102,6 @@ auto_filenames = {
|
||||
"docs/api/structures/notification-response.md",
|
||||
"docs/api/structures/point.md",
|
||||
"docs/api/structures/post-body.md",
|
||||
"docs/api/structures/post-data.md",
|
||||
"docs/api/structures/printer-info.md",
|
||||
"docs/api/structures/process-memory-info.md",
|
||||
"docs/api/structures/process-metric.md",
|
||||
@@ -131,33 +127,26 @@ auto_filenames = {
|
||||
"docs/api/structures/upload-data.md",
|
||||
"docs/api/structures/upload-file.md",
|
||||
"docs/api/structures/upload-raw-data.md",
|
||||
"docs/api/structures/user-default-types.md",
|
||||
"docs/api/structures/web-source.md",
|
||||
]
|
||||
|
||||
sandbox_bundle_deps = [
|
||||
"lib/browser/api/module-names.ts",
|
||||
"lib/common/api/clipboard.ts",
|
||||
"lib/common/api/deprecate.ts",
|
||||
"lib/common/api/module-list.ts",
|
||||
"lib/common/api/shell.ts",
|
||||
"lib/common/define-properties.ts",
|
||||
"lib/common/ipc-messages.ts",
|
||||
"lib/common/remote/ipc-messages.ts",
|
||||
"lib/common/type-utils.ts",
|
||||
"lib/common/web-view-events.ts",
|
||||
"lib/common/web-view-methods.ts",
|
||||
"lib/common/webpack-globals-provider.ts",
|
||||
"lib/renderer/api/context-bridge.ts",
|
||||
"lib/renderer/api/crash-reporter.ts",
|
||||
"lib/renderer/api/desktop-capturer.ts",
|
||||
"lib/renderer/api/ipc-renderer.ts",
|
||||
"lib/renderer/api/native-image.ts",
|
||||
"lib/renderer/api/remote.ts",
|
||||
"lib/renderer/api/web-frame.ts",
|
||||
"lib/renderer/inspector.ts",
|
||||
"lib/renderer/ipc-renderer-internal-utils.ts",
|
||||
"lib/renderer/ipc-renderer-internal.ts",
|
||||
"lib/renderer/remote/callbacks-registry.ts",
|
||||
"lib/renderer/security-warnings.ts",
|
||||
"lib/renderer/web-frame-init.ts",
|
||||
"lib/renderer/web-view/guest-view-internal.ts",
|
||||
@@ -241,9 +230,6 @@ 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.ts",
|
||||
"lib/browser/remote/objects-registry.ts",
|
||||
"lib/browser/remote/server.ts",
|
||||
"lib/browser/rpc-server.ts",
|
||||
"lib/common/api/clipboard.ts",
|
||||
"lib/common/api/deprecate.ts",
|
||||
@@ -253,7 +239,6 @@ auto_filenames = {
|
||||
"lib/common/init.ts",
|
||||
"lib/common/ipc-messages.ts",
|
||||
"lib/common/parse-features-string.ts",
|
||||
"lib/common/remote/ipc-messages.ts",
|
||||
"lib/common/reset-search-paths.ts",
|
||||
"lib/common/type-utils.ts",
|
||||
"lib/common/web-view-events.ts",
|
||||
@@ -269,7 +254,6 @@ auto_filenames = {
|
||||
]
|
||||
|
||||
renderer_bundle_deps = [
|
||||
"lib/browser/api/module-names.ts",
|
||||
"lib/common/api/clipboard.ts",
|
||||
"lib/common/api/deprecate.ts",
|
||||
"lib/common/api/module-list.ts",
|
||||
@@ -277,12 +261,10 @@ auto_filenames = {
|
||||
"lib/common/define-properties.ts",
|
||||
"lib/common/init.ts",
|
||||
"lib/common/ipc-messages.ts",
|
||||
"lib/common/remote/ipc-messages.ts",
|
||||
"lib/common/reset-search-paths.ts",
|
||||
"lib/common/type-utils.ts",
|
||||
"lib/common/web-view-events.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",
|
||||
@@ -291,13 +273,11 @@ auto_filenames = {
|
||||
"lib/renderer/api/ipc-renderer.ts",
|
||||
"lib/renderer/api/module-list.ts",
|
||||
"lib/renderer/api/native-image.ts",
|
||||
"lib/renderer/api/remote.ts",
|
||||
"lib/renderer/api/web-frame.ts",
|
||||
"lib/renderer/init.ts",
|
||||
"lib/renderer/inspector.ts",
|
||||
"lib/renderer/ipc-renderer-internal-utils.ts",
|
||||
"lib/renderer/ipc-renderer-internal.ts",
|
||||
"lib/renderer/remote/callbacks-registry.ts",
|
||||
"lib/renderer/security-warnings.ts",
|
||||
"lib/renderer/web-frame-init.ts",
|
||||
"lib/renderer/web-view/guest-view-internal.ts",
|
||||
@@ -315,7 +295,6 @@ auto_filenames = {
|
||||
]
|
||||
|
||||
worker_bundle_deps = [
|
||||
"lib/browser/api/module-names.ts",
|
||||
"lib/common/api/clipboard.ts",
|
||||
"lib/common/api/deprecate.ts",
|
||||
"lib/common/api/module-list.ts",
|
||||
@@ -323,10 +302,8 @@ auto_filenames = {
|
||||
"lib/common/define-properties.ts",
|
||||
"lib/common/init.ts",
|
||||
"lib/common/ipc-messages.ts",
|
||||
"lib/common/remote/ipc-messages.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",
|
||||
@@ -335,11 +312,9 @@ auto_filenames = {
|
||||
"lib/renderer/api/ipc-renderer.ts",
|
||||
"lib/renderer/api/module-list.ts",
|
||||
"lib/renderer/api/native-image.ts",
|
||||
"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/worker/init.ts",
|
||||
"package.json",
|
||||
"tsconfig.electron.json",
|
||||
|
||||
@@ -404,6 +404,8 @@ filenames = {
|
||||
"shell/browser/native_window_observer.h",
|
||||
"shell/browser/net/asar/asar_url_loader.cc",
|
||||
"shell/browser/net/asar/asar_url_loader.h",
|
||||
"shell/browser/net/asar/asar_url_loader_factory.cc",
|
||||
"shell/browser/net/asar/asar_url_loader_factory.h",
|
||||
"shell/browser/net/cert_verifier_client.cc",
|
||||
"shell/browser/net/cert_verifier_client.h",
|
||||
"shell/browser/net/electron_url_loader_factory.cc",
|
||||
|
||||
@@ -532,15 +532,17 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
|
||||
return fs.readFile(realPath, options, callback);
|
||||
}
|
||||
|
||||
const buffer = Buffer.alloc(info.size);
|
||||
const fd = archive.getFd();
|
||||
if (!(fd >= 0)) {
|
||||
const error = createError(AsarError.NOT_FOUND, { asarPath, filePath });
|
||||
nextTick(callback, [error]);
|
||||
return;
|
||||
}
|
||||
|
||||
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.read(fd, buffer, 0, info.size, info.offset, (error: Error) => {
|
||||
callback(error, encoding ? buffer.toString(encoding) : buffer);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -573,19 +575,13 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
|
||||
}
|
||||
|
||||
const { encoding } = options;
|
||||
const buffer = Buffer.alloc(info.size);
|
||||
const fd = archive.getFd();
|
||||
if (!(fd >= 0)) throw createError(AsarError.NOT_FOUND, { asarPath, filePath });
|
||||
|
||||
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;
|
||||
fs.readSync(fd, buffer, 0, info.size, info.offset);
|
||||
return (encoding) ? buffer.toString(encoding) : buffer;
|
||||
};
|
||||
|
||||
const { readdir } = fs;
|
||||
@@ -697,17 +693,12 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
|
||||
return [str, str.length > 0];
|
||||
}
|
||||
|
||||
const buffer = Buffer.alloc(info.size);
|
||||
const fd = archive.getFd();
|
||||
if (!(fd >= 0)) return [];
|
||||
|
||||
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);
|
||||
fs.readSync(fd, buffer, 0, info.size, info.offset);
|
||||
const str = buffer.toString('utf8');
|
||||
return [str, str.length > 0];
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
import { deprecate, Menu } from 'electron/main';
|
||||
import { Menu } from 'electron/main';
|
||||
|
||||
const bindings = process._linkedBinding('electron_browser_app');
|
||||
const commandLine = process._linkedBinding('electron_common_command_line');
|
||||
@@ -63,6 +63,9 @@ Object.defineProperty(app, 'applicationMenu', {
|
||||
return execFile !== 'electron';
|
||||
})();
|
||||
|
||||
// The native implementation is not provided on non-windows platforms
|
||||
app.setAppUserModelId = app.setAppUserModelId || (() => {});
|
||||
|
||||
app._setDefaultAppPaths = (packagePath) => {
|
||||
// Set the user path according to application's name.
|
||||
app.setPath('userData', path.join(app.getPath('appData'), app.name!));
|
||||
@@ -129,7 +132,3 @@ for (const name of events) {
|
||||
webContents.emit(name, event, ...args);
|
||||
});
|
||||
}
|
||||
|
||||
// Deprecate allowRendererProcessReuse but only if they set it to false, no need to log if
|
||||
// they are setting it to true
|
||||
deprecate.removeProperty({ __proto__: app } as any, 'allowRendererProcessReuse', [false]);
|
||||
|
||||
@@ -37,6 +37,11 @@ Object.defineProperty(BaseWindow.prototype, 'simpleFullScreen', {
|
||||
set: function (simple) { this.setSimpleFullScreen(simple); }
|
||||
});
|
||||
|
||||
Object.defineProperty(BaseWindow.prototype, 'focusable', {
|
||||
get: function () { return this.isFocusable(); },
|
||||
set: function (focusable) { this.setFocusable(focusable); }
|
||||
});
|
||||
|
||||
Object.defineProperty(BaseWindow.prototype, 'kiosk', {
|
||||
get: function () { return this.isKiosk(); },
|
||||
set: function (kiosk) { this.setKiosk(kiosk); }
|
||||
|
||||
@@ -10,15 +10,15 @@ class CrashReporter {
|
||||
extra = {},
|
||||
globalExtra = {},
|
||||
ignoreSystemCrashHandler = false,
|
||||
submitURL,
|
||||
submitURL = '',
|
||||
uploadToServer = true,
|
||||
rateLimit = false,
|
||||
compress = true
|
||||
} = options || {};
|
||||
|
||||
if (submitURL == null) throw new Error('submitURL is a required option to crashReporter.start');
|
||||
if (uploadToServer && !submitURL) throw new Error('submitURL must be specified when uploadToServer is true');
|
||||
|
||||
if (!compress) {
|
||||
if (!compress && uploadToServer) {
|
||||
deprecate.log('Sending uncompressed crash reports is deprecated and will be removed in a future version of Electron. Set { compress: true } to opt-in to the new behavior. Crash reports will be uploaded gzipped, which most crash reporting servers support.');
|
||||
}
|
||||
|
||||
|
||||
@@ -2,11 +2,6 @@ import { app, BrowserWindow } from 'electron/main';
|
||||
import type { OpenDialogOptions, OpenDialogReturnValue, MessageBoxOptions, SaveDialogOptions, SaveDialogReturnValue, MessageBoxReturnValue, CertificateTrustDialogOptions } from 'electron/main';
|
||||
const dialogBinding = process._linkedBinding('electron_browser_dialog');
|
||||
|
||||
const DialogType = {
|
||||
OPEN: 'OPEN' as 'OPEN',
|
||||
SAVE: 'SAVE' as 'SAVE'
|
||||
};
|
||||
|
||||
enum SaveFileDialogProperties {
|
||||
createDirectory = 1 << 0,
|
||||
showHiddenFiles = 1 << 1,
|
||||
@@ -72,16 +67,6 @@ const setupSaveDialogProperties = (properties: (keyof typeof SaveFileDialogPrope
|
||||
return dialogProperties;
|
||||
};
|
||||
|
||||
const setupDialogProperties = (type: keyof typeof DialogType, properties: string[]): number => {
|
||||
if (type === DialogType.OPEN) {
|
||||
return setupOpenDialogProperties(properties as (keyof typeof OpenFileDialogProperties)[]);
|
||||
} else if (type === DialogType.SAVE) {
|
||||
return setupSaveDialogProperties(properties as (keyof typeof SaveFileDialogProperties)[]);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
const saveDialog = (sync: boolean, window: BrowserWindow | null, options?: SaveDialogOptions) => {
|
||||
checkAppInitialized();
|
||||
|
||||
@@ -115,7 +100,7 @@ const saveDialog = (sync: boolean, window: BrowserWindow | null, options?: SaveD
|
||||
nameFieldLabel,
|
||||
showsTagField,
|
||||
window,
|
||||
properties: setupDialogProperties(DialogType.SAVE, properties)
|
||||
properties: setupSaveDialogProperties(properties)
|
||||
};
|
||||
|
||||
return sync ? dialogBinding.showSaveDialogSync(settings) : dialogBinding.showSaveDialog(settings);
|
||||
@@ -156,7 +141,7 @@ const openDialog = (sync: boolean, window: BrowserWindow | null, options?: OpenD
|
||||
message,
|
||||
securityScopedBookmarks,
|
||||
window,
|
||||
properties: setupDialogProperties(DialogType.OPEN, properties)
|
||||
properties: setupOpenDialogProperties(properties)
|
||||
};
|
||||
|
||||
return (sync) ? dialogBinding.showOpenDialogSync(settings) : dialogBinding.showOpenDialog(settings);
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
// TODO: Figure out a way to not duplicate this information between here and module-list
|
||||
// It is currently duplicated as module-list "require"s all the browser API file and the
|
||||
// remote module in the renderer process depends on that file. As a result webpack
|
||||
// includes all the browser API files in the renderer process as well and we want to avoid that
|
||||
|
||||
// Browser side modules, please sort alphabetically.
|
||||
export const browserModuleNames = [
|
||||
'app',
|
||||
'autoUpdater',
|
||||
'BaseWindow',
|
||||
'BrowserView',
|
||||
'BrowserWindow',
|
||||
'contentTracing',
|
||||
'crashReporter',
|
||||
'dialog',
|
||||
'globalShortcut',
|
||||
'ipcMain',
|
||||
'inAppPurchase',
|
||||
'Menu',
|
||||
'MenuItem',
|
||||
'nativeImage',
|
||||
'nativeTheme',
|
||||
'net',
|
||||
'netLog',
|
||||
'MessageChannelMain',
|
||||
'Notification',
|
||||
'powerMonitor',
|
||||
'powerSaveBlocker',
|
||||
'protocol',
|
||||
'screen',
|
||||
'session',
|
||||
'ShareMenu',
|
||||
'systemPreferences',
|
||||
'TouchBar',
|
||||
'Tray',
|
||||
'View',
|
||||
'webContents',
|
||||
'WebContentsView',
|
||||
'webFrameMain'
|
||||
];
|
||||
|
||||
if (BUILDFLAG(ENABLE_DESKTOP_CAPTURER)) {
|
||||
browserModuleNames.push('desktopCapturer');
|
||||
}
|
||||
|
||||
if (BUILDFLAG(ENABLE_VIEWS_API)) {
|
||||
browserModuleNames.push(
|
||||
'ImageView'
|
||||
);
|
||||
}
|
||||
@@ -188,6 +188,11 @@ class ChunkedBodyStream extends Writable {
|
||||
this._downstream = pipe;
|
||||
if (this._pendingChunk) {
|
||||
const doneWriting = (maybeError: Error | void) => {
|
||||
// If the underlying request has been aborted, we honeslty don't care about the error
|
||||
// all work should cease as soon as we abort anyway, this error is probably a
|
||||
// "mojo pipe disconnected" error (code=9)
|
||||
if (this._clientRequest._aborted) return;
|
||||
|
||||
const cb = this._pendingCallback!;
|
||||
delete this._pendingCallback;
|
||||
delete this._pendingChunk;
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { app, ipcMain, session, deprecate, webFrameMain } from 'electron/main';
|
||||
import type { BrowserWindowConstructorOptions, MenuItem, MenuItemConstructorOptions, LoadURLOptions } from 'electron/main';
|
||||
import type { BrowserWindowConstructorOptions, LoadURLOptions } from 'electron/main';
|
||||
|
||||
import * as url from 'url';
|
||||
import * as path from 'path';
|
||||
import { openGuestWindow, makeWebPreferences } from '@electron/internal/browser/guest-window-manager';
|
||||
import { NavigationController } from '@electron/internal/browser/navigation-controller';
|
||||
import { openGuestWindow, makeWebPreferences, parseContentTypeFormat } from '@electron/internal/browser/guest-window-manager';
|
||||
import { ipcMainInternal } from '@electron/internal/browser/ipc-main-internal';
|
||||
import * as ipcMainUtils from '@electron/internal/browser/ipc-main-internal-utils';
|
||||
import { MessagePortMain } from '@electron/internal/browser/message-port-main';
|
||||
@@ -61,7 +60,7 @@ const PDFPageSizes: Record<string, ElectronInternal.MediaSize> = {
|
||||
width_microns: 279400,
|
||||
custom_display_name: 'Tabloid'
|
||||
}
|
||||
};
|
||||
} as const;
|
||||
|
||||
// The minimum micron size Chromium accepts is that where:
|
||||
// Per printing/units.h:
|
||||
@@ -94,6 +93,7 @@ const defaultPrintingSetting = {
|
||||
pagesPerSheet: 1,
|
||||
isFirstRequest: false,
|
||||
previewUIID: 0,
|
||||
// True, if the document source is modifiable. e.g. HTML and not PDF.
|
||||
previewModifiable: true,
|
||||
printToPDF: true,
|
||||
deviceName: 'Save as PDF',
|
||||
@@ -109,7 +109,7 @@ const defaultPrintingSetting = {
|
||||
printerType: 2,
|
||||
title: undefined as string | undefined,
|
||||
url: undefined as string | undefined
|
||||
};
|
||||
} as const;
|
||||
|
||||
// JavaScript implementations of WebContents.
|
||||
const binding = process._linkedBinding('electron_browser_web_contents');
|
||||
@@ -191,7 +191,7 @@ WebContents.prototype.executeJavaScriptInIsolatedWorld = async function (worldId
|
||||
|
||||
let pendingPromise: Promise<any> | undefined;
|
||||
WebContents.prototype.printToPDF = async function (options) {
|
||||
const printSettings = {
|
||||
const printSettings: Record<string, any> = {
|
||||
...defaultPrintingSetting,
|
||||
requestID: getNextId()
|
||||
};
|
||||
@@ -406,15 +406,89 @@ WebContents.prototype.loadFile = function (filePath, options = {}) {
|
||||
}));
|
||||
};
|
||||
|
||||
WebContents.prototype.loadURL = function (url, options) {
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
|
||||
const p = new Promise<void>((resolve, reject) => {
|
||||
const resolveAndCleanup = () => {
|
||||
removeListeners();
|
||||
resolve();
|
||||
};
|
||||
const rejectAndCleanup = (errorCode: number, errorDescription: string, url: string) => {
|
||||
const err = new Error(`${errorDescription} (${errorCode}) loading '${typeof url === 'string' ? url.substr(0, 2048) : url}'`);
|
||||
Object.assign(err, { errno: errorCode, code: errorDescription, url });
|
||||
removeListeners();
|
||||
reject(err);
|
||||
};
|
||||
const finishListener = () => {
|
||||
resolveAndCleanup();
|
||||
};
|
||||
const failListener = (event: Electron.Event, errorCode: number, errorDescription: string, validatedURL: string, isMainFrame: boolean) => {
|
||||
if (isMainFrame) {
|
||||
rejectAndCleanup(errorCode, errorDescription, validatedURL);
|
||||
}
|
||||
};
|
||||
|
||||
let navigationStarted = false;
|
||||
const navigationListener = (event: Electron.Event, url: string, isSameDocument: boolean, isMainFrame: boolean) => {
|
||||
if (isMainFrame) {
|
||||
if (navigationStarted && !isSameDocument) {
|
||||
// the webcontents has started another unrelated navigation in the
|
||||
// main frame (probably from the app calling `loadURL` again); reject
|
||||
// the promise
|
||||
// We should only consider the request aborted if the "navigation" is
|
||||
// actually navigating and not simply transitioning URL state in the
|
||||
// current context. E.g. pushState and `location.hash` changes are
|
||||
// considered navigation events but are triggered with isSameDocument.
|
||||
// We can ignore these to allow virtual routing on page load as long
|
||||
// as the routing does not leave the document
|
||||
return rejectAndCleanup(-3, 'ERR_ABORTED', url);
|
||||
}
|
||||
navigationStarted = true;
|
||||
}
|
||||
};
|
||||
const stopLoadingListener = () => {
|
||||
// By the time we get here, either 'finish' or 'fail' should have fired
|
||||
// if the navigation occurred. However, in some situations (e.g. when
|
||||
// attempting to load a page with a bad scheme), loading will stop
|
||||
// without emitting finish or fail. In this case, we reject the promise
|
||||
// with a generic failure.
|
||||
// TODO(jeremy): enumerate all the cases in which this can happen. If
|
||||
// the only one is with a bad scheme, perhaps ERR_INVALID_ARGUMENT
|
||||
// would be more appropriate.
|
||||
rejectAndCleanup(-2, 'ERR_FAILED', url);
|
||||
};
|
||||
const removeListeners = () => {
|
||||
this.removeListener('did-finish-load', finishListener);
|
||||
this.removeListener('did-fail-load', failListener);
|
||||
this.removeListener('did-start-navigation', navigationListener);
|
||||
this.removeListener('did-stop-loading', stopLoadingListener);
|
||||
this.removeListener('destroyed', stopLoadingListener);
|
||||
};
|
||||
this.on('did-finish-load', finishListener);
|
||||
this.on('did-fail-load', failListener);
|
||||
this.on('did-start-navigation', navigationListener);
|
||||
this.on('did-stop-loading', stopLoadingListener);
|
||||
this.on('destroyed', stopLoadingListener);
|
||||
});
|
||||
// Add a no-op rejection handler to silence the unhandled rejection error.
|
||||
p.catch(() => {});
|
||||
this._loadURL(url, options);
|
||||
this.emit('load-url', url, options);
|
||||
return p;
|
||||
};
|
||||
|
||||
WebContents.prototype.setWindowOpenHandler = function (handler: (details: Electron.HandlerDetails) => ({action: 'allow'} | {action: 'deny', overrideBrowserWindowOptions?: BrowserWindowConstructorOptions})) {
|
||||
this._windowOpenHandler = handler;
|
||||
};
|
||||
|
||||
WebContents.prototype._callWindowOpenHandler = function (event: Electron.Event, url: string, frameName: string, rawFeatures: string): BrowserWindowConstructorOptions | null {
|
||||
WebContents.prototype._callWindowOpenHandler = function (event: Electron.Event, details: Electron.HandlerDetails): BrowserWindowConstructorOptions | null {
|
||||
if (!this._windowOpenHandler) {
|
||||
return null;
|
||||
}
|
||||
const response = this._windowOpenHandler({ url, frameName, features: rawFeatures });
|
||||
const response = this._windowOpenHandler(details);
|
||||
|
||||
if (typeof response !== 'object') {
|
||||
event.preventDefault();
|
||||
@@ -432,7 +506,11 @@ WebContents.prototype._callWindowOpenHandler = function (event: Electron.Event,
|
||||
event.preventDefault();
|
||||
return null;
|
||||
} else if (response.action === 'allow') {
|
||||
if (typeof response.overrideBrowserWindowOptions === 'object' && response.overrideBrowserWindowOptions !== null) { return response.overrideBrowserWindowOptions; } else { return {}; }
|
||||
if (typeof response.overrideBrowserWindowOptions === 'object' && response.overrideBrowserWindowOptions !== null) {
|
||||
return response.overrideBrowserWindowOptions;
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
} else {
|
||||
event.preventDefault();
|
||||
console.error('The window open handler response must be an object with an \'action\' property of \'allow\' or \'deny\'.');
|
||||
@@ -470,24 +548,6 @@ const loggingEnabled = () => {
|
||||
|
||||
// Add JavaScript wrappers for WebContents class.
|
||||
WebContents.prototype._init = function () {
|
||||
// The navigation controller.
|
||||
const navigationController = new NavigationController(this);
|
||||
this.loadURL = navigationController.loadURL.bind(navigationController);
|
||||
this.getURL = navigationController.getURL.bind(navigationController);
|
||||
this.stop = navigationController.stop.bind(navigationController);
|
||||
this.reload = navigationController.reload.bind(navigationController);
|
||||
this.reloadIgnoringCache = navigationController.reloadIgnoringCache.bind(navigationController);
|
||||
this.canGoBack = navigationController.canGoBack.bind(navigationController);
|
||||
this.canGoForward = navigationController.canGoForward.bind(navigationController);
|
||||
this.canGoToIndex = navigationController.canGoToIndex.bind(navigationController);
|
||||
this.canGoToOffset = navigationController.canGoToOffset.bind(navigationController);
|
||||
this.clearHistory = navigationController.clearHistory.bind(navigationController);
|
||||
this.goBack = navigationController.goBack.bind(navigationController);
|
||||
this.goForward = navigationController.goForward.bind(navigationController);
|
||||
this.goToIndex = navigationController.goToIndex.bind(navigationController);
|
||||
this.goToOffset = navigationController.goToOffset.bind(navigationController);
|
||||
this.getActiveIndex = navigationController.getActiveIndex.bind(navigationController);
|
||||
this.length = navigationController.length.bind(navigationController);
|
||||
// Read off the ID at construction time, so that it's accessible even after
|
||||
// the underlying C++ WebContents is destroyed.
|
||||
const id = this.id;
|
||||
@@ -498,10 +558,6 @@ WebContents.prototype._init = function () {
|
||||
|
||||
this._windowOpenHandler = null;
|
||||
|
||||
// Every remote callback from renderer process would add a listener to the
|
||||
// render-view-deleted event, so ignore the listeners warning.
|
||||
this.setMaxListeners(0);
|
||||
|
||||
// Dispatch IPC messages to the ipc module.
|
||||
this.on('-ipc-message' as any, function (this: Electron.WebContents, event: Electron.IpcMainEvent, internal: boolean, channel: string, args: any[]) {
|
||||
addSenderFrameToEvent(event);
|
||||
@@ -546,18 +602,6 @@ WebContents.prototype._init = function () {
|
||||
ipcMain.emit(channel, event, message);
|
||||
});
|
||||
|
||||
// Handle context menu action request from pepper plugin.
|
||||
this.on('pepper-context-menu' as any, function (event: ElectronInternal.Event, params: {x: number, y: number, menu: Array<(MenuItemConstructorOptions) | (MenuItem)>}, callback: () => void) {
|
||||
// Access Menu via electron.Menu to prevent circular require.
|
||||
const menu = require('electron').Menu.buildFromTemplate(params.menu);
|
||||
menu.popup({
|
||||
window: event.sender.getOwnerBrowserWindow(),
|
||||
x: params.x,
|
||||
y: params.y,
|
||||
callback
|
||||
});
|
||||
});
|
||||
|
||||
this.on('crashed', (event, ...args) => {
|
||||
app.emit('renderer-process-crashed', event, this, ...args);
|
||||
});
|
||||
@@ -578,32 +622,56 @@ WebContents.prototype._init = function () {
|
||||
|
||||
if (this.getType() !== 'remote') {
|
||||
// Make new windows requested by links behave like "window.open".
|
||||
this.on('-new-window' as any, (event: ElectronInternal.Event, url: string, frameName: string, disposition: string,
|
||||
this.on('-new-window' as any, (event: ElectronInternal.Event, url: string, frameName: string, disposition: Electron.HandlerDetails['disposition'],
|
||||
rawFeatures: string, referrer: Electron.Referrer, postData: PostData) => {
|
||||
openGuestWindow({
|
||||
event,
|
||||
embedder: event.sender,
|
||||
disposition,
|
||||
const postBody = postData ? {
|
||||
data: postData,
|
||||
...parseContentTypeFormat(postData)
|
||||
} : undefined;
|
||||
const details: Electron.HandlerDetails = {
|
||||
url,
|
||||
frameName,
|
||||
features: rawFeatures,
|
||||
referrer,
|
||||
postData,
|
||||
overrideBrowserWindowOptions: {},
|
||||
windowOpenArgs: {
|
||||
url,
|
||||
frameName,
|
||||
features: rawFeatures
|
||||
}
|
||||
});
|
||||
postBody,
|
||||
disposition
|
||||
};
|
||||
const options = this._callWindowOpenHandler(event, details);
|
||||
if (!event.defaultPrevented) {
|
||||
openGuestWindow({
|
||||
event,
|
||||
embedder: event.sender,
|
||||
disposition,
|
||||
referrer,
|
||||
postData,
|
||||
overrideBrowserWindowOptions: options || {},
|
||||
windowOpenArgs: details
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
let windowOpenOverriddenOptions: BrowserWindowConstructorOptions | null = null;
|
||||
this.on('-will-add-new-contents' as any, (event: ElectronInternal.Event, url: string, frameName: string, rawFeatures: string) => {
|
||||
windowOpenOverriddenOptions = this._callWindowOpenHandler(event, url, frameName, rawFeatures);
|
||||
this.on('-will-add-new-contents' as any, (event: ElectronInternal.Event, url: string, frameName: string, rawFeatures: string, disposition: Electron.HandlerDetails['disposition'], referrer: Electron.Referrer, postData: PostData) => {
|
||||
const postBody = postData ? {
|
||||
data: postData,
|
||||
...parseContentTypeFormat(postData)
|
||||
} : undefined;
|
||||
const details: Electron.HandlerDetails = {
|
||||
url,
|
||||
frameName,
|
||||
features: rawFeatures,
|
||||
disposition,
|
||||
referrer,
|
||||
postBody
|
||||
};
|
||||
windowOpenOverriddenOptions = this._callWindowOpenHandler(event, details);
|
||||
if (!event.defaultPrevented) {
|
||||
const secureOverrideWebPreferences = windowOpenOverriddenOptions ? {
|
||||
// Allow setting of backgroundColor as a webPreference even though
|
||||
// it's technically a BrowserWindowConstructorOptions option because
|
||||
// we need to access it in the renderer at init time.
|
||||
backgroundColor: windowOpenOverriddenOptions.backgroundColor,
|
||||
transparent: windowOpenOverriddenOptions.transparent,
|
||||
...windowOpenOverriddenOptions.webPreferences
|
||||
} : undefined;
|
||||
this._setNextChildWebPreferences(
|
||||
|
||||
@@ -27,7 +27,7 @@ export const setDefaultApplicationMenu = () => {
|
||||
{
|
||||
label: 'Community Discussions',
|
||||
click: async () => {
|
||||
await shell.openExternal('https://discuss.atom.io/c/electron');
|
||||
await shell.openExternal('https://discord.gg/electron');
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -13,7 +13,7 @@ function isValid (options: Electron.SourcesOptions) {
|
||||
return Array.isArray(types);
|
||||
}
|
||||
|
||||
export const getSourcesImpl = (event: Electron.IpcMainEvent | null, args: Electron.SourcesOptions) => {
|
||||
export const getSourcesImpl = (sender: Electron.WebContents | null, args: Electron.SourcesOptions) => {
|
||||
if (!isValid(args)) throw new Error('Invalid options');
|
||||
|
||||
const captureWindow = args.types.includes('window');
|
||||
@@ -48,8 +48,8 @@ export const getSourcesImpl = (event: Electron.IpcMainEvent | null, args: Electr
|
||||
}
|
||||
// Remove from currentlyRunning once we resolve or reject
|
||||
currentlyRunning = currentlyRunning.filter(running => running.options !== options);
|
||||
if (event) {
|
||||
event.sender.removeListener('destroyed', stopRunning);
|
||||
if (sender) {
|
||||
sender.removeListener('destroyed', stopRunning);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -68,8 +68,8 @@ export const getSourcesImpl = (event: Electron.IpcMainEvent | null, args: Electr
|
||||
// If the WebContents is destroyed before receiving result, just remove the
|
||||
// reference to emit and the capturer itself so that it never dispatches
|
||||
// back to the renderer
|
||||
if (event) {
|
||||
event.sender.once('destroyed', stopRunning);
|
||||
if (sender) {
|
||||
sender.once('destroyed', stopRunning);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user