Browse Source

build: allow use of BUILDFLAG directives from within JS code (#20328)

Milan Burda 5 years ago
parent
commit
392ea320cf

+ 5 - 1
.eslintrc.json

@@ -27,7 +27,11 @@
     "sourceType": "module"
   },
   "globals": {
-    "standardScheme": "readonly"
+    "standardScheme": "readonly",
+    "BUILDFLAG": "readonly",
+    "ENABLE_DESKTOP_CAPTURER": "readonly",
+    "ENABLE_REMOTE_MODULE": "readonly",
+    "ENABLE_VIEWS_API": "readonly"
   },
   "overrides": [
     {

+ 50 - 0
build/webpack/webpack.config.base.js

@@ -20,6 +20,54 @@ class AccessDependenciesPlugin {
   }
 }
 
+const defines = {
+  BUILDFLAG: ' '
+}
+
+const buildFlagsPrefix = '--buildflags='
+const buildFlagArg = process.argv.find(arg => arg.startsWith(buildFlagsPrefix));
+
+if (buildFlagArg) {
+  const buildFlagPath = buildFlagArg.substr(buildFlagsPrefix.length)
+
+  const flagFile = fs.readFileSync(buildFlagPath, 'utf8')
+  for (const line of flagFile.split(/(\r\n|\r|\n)/g)) {
+    const flagMatch = line.match(/#define BUILDFLAG_INTERNAL_(.+?)\(\) \(([01])\)/)
+    if (flagMatch) {
+      const flagName = flagMatch[1];
+      const flagValue = flagMatch[2];
+      defines[flagName] = JSON.stringify(Boolean(parseInt(flagValue, 10)));
+    }
+  }
+}
+
+const ignoredModules = []
+
+if (defines['ENABLE_DESKTOP_CAPTURER'] === 'false') {
+  ignoredModules.push(
+    '@electron/internal/browser/desktop-capturer',
+    '@electron/internal/renderer/api/desktop-capturer'
+  )
+}
+
+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'
+  )
+}
+
+const alias = {}
+for (const ignoredModule of ignoredModules) {
+  alias[ignoredModule] = path.resolve(electronRoot, 'lib/common/dummy.js')
+}
+
 module.exports = ({
   alwaysHasNode,
   loadElectronFromAlternateTarget,
@@ -41,6 +89,7 @@ module.exports = ({
     },
     resolve: {
       alias: {
+        ...alias,
         '@electron/internal': path.resolve(electronRoot, 'lib'),
         'electron': path.resolve(electronRoot, 'lib', loadElectronFromAlternateTarget || target, 'api', 'exports', 'electron.ts'),
         // Force timers to resolve to our dependency that doens't use window.postMessage
@@ -78,6 +127,7 @@ module.exports = ({
       new webpack.ProvidePlugin({
         Promise: ['@electron/internal/common/webpack-globals-provider', 'Promise'],
       }),
+      new webpack.DefinePlugin(defines),
     ]
   })
 }

+ 2 - 0
build/webpack/webpack.gni

@@ -25,7 +25,9 @@ template("webpack_build") {
     args = [
       rebase_path(invoker.config_file),
       rebase_path(invoker.out_file),
+      "--buildflags=" + rebase_path("$target_gen_dir/buildflags/buildflags.h"),
     ]
+    deps += [ "buildflags" ]
 
     outputs = [ invoker.out_file ]
   }

+ 3 - 3
filenames.auto.gni

@@ -135,7 +135,7 @@ auto_filenames = {
   ]
 
   sandbox_bundle_deps = [
-    "lib/browser/api/module-keys.js",
+    "lib/browser/api/module-names.ts",
     "lib/common/api/clipboard.js",
     "lib/common/api/deprecate.ts",
     "lib/common/api/module-list.ts",
@@ -258,7 +258,7 @@ auto_filenames = {
   ]
 
   renderer_bundle_deps = [
-    "lib/browser/api/module-keys.js",
+    "lib/browser/api/module-names.ts",
     "lib/common/api/clipboard.js",
     "lib/common/api/deprecate.ts",
     "lib/common/api/module-list.ts",
@@ -300,7 +300,7 @@ auto_filenames = {
   ]
 
   worker_bundle_deps = [
-    "lib/browser/api/module-keys.js",
+    "lib/browser/api/module-names.ts",
     "lib/common/api/clipboard.js",
     "lib/common/api/deprecate.ts",
     "lib/common/api/module-list.ts",

+ 0 - 47
lib/browser/api/module-keys.js

@@ -1,47 +0,0 @@
-'use strict';
-
-// 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
-
-const features = process.electronBinding('features');
-
-// Browser side modules, please sort alphabetically.
-module.exports = [
-  { name: 'app' },
-  { name: 'autoUpdater' },
-  { name: 'BrowserView' },
-  { name: 'BrowserWindow' },
-  { name: 'contentTracing' },
-  { name: 'crashReporter' },
-  { name: 'dialog' },
-  { name: 'globalShortcut' },
-  { name: 'ipcMain' },
-  { name: 'inAppPurchase' },
-  { name: 'Menu' },
-  { name: 'MenuItem' },
-  { name: 'nativeTheme' },
-  { name: 'net' },
-  { name: 'netLog' },
-  { name: 'MessageChannelMain' },
-  { name: 'Notification' },
-  { name: 'powerMonitor' },
-  { name: 'powerSaveBlocker' },
-  { name: 'protocol' },
-  { name: 'screen' },
-  { name: 'session' },
-  { name: 'systemPreferences' },
-  { name: 'TopLevelWindow' },
-  { name: 'TouchBar' },
-  { name: 'Tray' },
-  { name: 'View' },
-  { name: 'webContents' },
-  { name: 'WebContentsView' }
-];
-
-if (features.isViewApiEnabled()) {
-  module.exports.push(
-    { name: 'ImageView' }
-  );
-}

+ 1 - 3
lib/browser/api/module-list.ts

@@ -1,7 +1,5 @@
 // TODO: Updating this file also required updating the module-keys file
 
-const features = process.electronBinding('features');
-
 // Browser side modules, please sort alphabetically.
 export const browserModuleList: ElectronInternal.ModuleEntry[] = [
   { name: 'app', loader: () => require('./app') },
@@ -35,7 +33,7 @@ export const browserModuleList: ElectronInternal.ModuleEntry[] = [
   { name: 'WebContentsView', loader: () => require('./web-contents-view') }
 ];
 
-if (features.isViewApiEnabled()) {
+if (BUILDFLAG(ENABLE_VIEWS_API)) {
   browserModuleList.push(
     { name: 'ImageView', loader: () => require('./views/image-view') }
   );

+ 43 - 0
lib/browser/api/module-names.ts

@@ -0,0 +1,43 @@
+// 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',
+  'BrowserView',
+  'BrowserWindow',
+  'contentTracing',
+  'crashReporter',
+  'dialog',
+  'globalShortcut',
+  'ipcMain',
+  'inAppPurchase',
+  'Menu',
+  'MenuItem',
+  'nativeTheme',
+  'net',
+  'netLog',
+  'MessageChannelMain',
+  'Notification',
+  'powerMonitor',
+  'powerSaveBlocker',
+  'protocol',
+  'screen',
+  'session',
+  'systemPreferences',
+  'TopLevelWindow',
+  'TouchBar',
+  'Tray',
+  'View',
+  'webContents',
+  'WebContentsView'
+];
+
+if (BUILDFLAG(ENABLE_VIEWS_API)) {
+  browserModuleNames.push(
+    'ImageView'
+  );
+}

+ 3 - 4
lib/browser/api/web-contents.js

@@ -1,6 +1,5 @@
 'use strict';
 
-const features = process.electronBinding('features');
 const { EventEmitter } = require('events');
 const electron = require('electron');
 const path = require('path');
@@ -341,7 +340,7 @@ WebContents.prototype.printToPDF = function (options) {
   printSettings.scaleFactor = Math.ceil(printSettings.scaleFactor) % 100;
   // PrinterType enum from //printing/print_job_constants.h
   printSettings.printerType = 2;
-  if (features.isPrintingEnabled()) {
+  if (this._printToPDF) {
     return this._printToPDF(printSettings);
   } else {
     const error = new Error('Printing feature is disabled');
@@ -375,7 +374,7 @@ WebContents.prototype.print = function (options = {}, callback) {
     }
   }
 
-  if (features.isPrintingEnabled()) {
+  if (this._print) {
     if (callback) {
       this._print(options, callback);
     } else {
@@ -387,7 +386,7 @@ WebContents.prototype.print = function (options = {}, callback) {
 };
 
 WebContents.prototype.getPrinters = function () {
-  if (features.isPrintingEnabled()) {
+  if (this._getPrinters) {
     return this._getPrinters();
   } else {
     console.error('Error: Printing feature is disabled.');

+ 1 - 3
lib/browser/init.ts

@@ -157,12 +157,10 @@ app._setDefaultAppPaths(packagePath);
 // Load the chrome devtools support.
 require('@electron/internal/browser/devtools');
 
-const features = process.electronBinding('features');
-
 // Load the chrome extension support.
 require('@electron/internal/browser/chrome-extension-shim');
 
-if (features.isRemoteModuleEnabled()) {
+if (BUILDFLAG(ENABLE_REMOTE_MODULE)) {
   require('@electron/internal/browser/remote/server');
 }
 

+ 2 - 3
lib/browser/rpc-server.js

@@ -5,7 +5,6 @@ const fs = require('fs');
 
 const eventBinding = process.electronBinding('event');
 const clipboard = process.electronBinding('clipboard');
-const features = process.electronBinding('features');
 
 const { ipcMainInternal } = require('@electron/internal/browser/ipc-main-internal');
 const ipcMainUtils = require('@electron/internal/browser/ipc-main-internal-utils');
@@ -60,7 +59,7 @@ ipcMainUtils.handleSync('ELECTRON_BROWSER_CLIPBOARD_SYNC', function (event, meth
   return typeUtils.serialize(electron.clipboard[method](...typeUtils.deserialize(args)));
 });
 
-if (features.isDesktopCapturerEnabled()) {
+if (BUILDFLAG(ENABLE_DESKTOP_CAPTURER)) {
   const desktopCapturer = require('@electron/internal/browser/desktop-capturer');
 
   ipcMainInternal.handle('ELECTRON_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', function (event, options, stack) {
@@ -76,7 +75,7 @@ if (features.isDesktopCapturerEnabled()) {
   });
 }
 
-const isRemoteModuleEnabled = features.isRemoteModuleEnabled()
+const isRemoteModuleEnabled = BUILDFLAG(ENABLE_REMOTE_MODULE)
   ? require('@electron/internal/browser/remote/server').isRemoteModuleEnabled
   : () => false;
 

+ 0 - 0
lib/common/dummy.js


+ 10 - 5
lib/renderer/api/module-list.ts

@@ -1,4 +1,3 @@
-const features = process.electronBinding('features');
 const v8Util = process.electronBinding('v8_util');
 
 const enableRemoteModule = v8Util.getHiddenValue<boolean>(global, 'enableRemoteModule');
@@ -11,10 +10,16 @@ export const rendererModuleList: ElectronInternal.ModuleEntry[] = [
   { name: 'webFrame', loader: () => require('./web-frame') }
 ];
 
-if (features.isDesktopCapturerEnabled()) {
-  rendererModuleList.push({ name: 'desktopCapturer', loader: () => require('./desktop-capturer') });
+if (BUILDFLAG(ENABLE_DESKTOP_CAPTURER)) {
+  rendererModuleList.push({
+    name: 'desktopCapturer',
+    loader: () => require('@electron/internal/renderer/api/desktop-capturer')
+  });
 }
 
-if (features.isRemoteModuleEnabled() && enableRemoteModule) {
-  rendererModuleList.push({ name: 'remote', loader: () => require('./remote') });
+if (BUILDFLAG(ENABLE_REMOTE_MODULE) && enableRemoteModule) {
+  rendererModuleList.push({
+    name: 'remote',
+    loader: () => require('@electron/internal/renderer/api/remote')
+  });
 }

+ 3 - 1
lib/renderer/api/remote.js

@@ -354,7 +354,9 @@ const addBuiltinProperty = (name) => {
 };
 
 const { commonModuleList } = require('@electron/internal/common/api/module-list');
-const browserModules = commonModuleList.concat(require('@electron/internal/browser/api/module-keys'));
+const { browserModuleNames } = require('@electron/internal/browser/api/module-names');
+
+const browserModules = commonModuleList.concat(browserModuleNames.map(name => ({ name })));
 
 // And add a helper receiver for each one.
 browserModules

+ 2 - 4
lib/sandboxed_renderer/api/module-list.ts

@@ -1,5 +1,3 @@
-const features = process.electronBinding('features');
-
 export const moduleList: ElectronInternal.ModuleEntry[] = [
   {
     name: 'contextBridge',
@@ -29,14 +27,14 @@ export const moduleList: ElectronInternal.ModuleEntry[] = [
   }
 ];
 
-if (features.isDesktopCapturerEnabled()) {
+if (BUILDFLAG(ENABLE_DESKTOP_CAPTURER)) {
   moduleList.push({
     name: 'desktopCapturer',
     loader: () => require('@electron/internal/renderer/api/desktop-capturer')
   });
 }
 
-if (features.isRemoteModuleEnabled() && process.isRemoteModuleEnabled) {
+if (BUILDFLAG(ENABLE_REMOTE_MODULE) && process.isRemoteModuleEnabled) {
   moduleList.push({
     name: 'remote',
     loader: () => require('@electron/internal/renderer/api/remote')

+ 1 - 0
shell/common/api/electron_api_v8_util.cc

@@ -9,6 +9,7 @@
 #include "electron/buildflags/buildflags.h"
 #include "shell/common/gin_converters/content_converter.h"
 #include "shell/common/gin_converters/gurl_converter.h"
+#include "shell/common/gin_converters/std_converter.h"
 #include "shell/common/gin_helper/dictionary.h"
 #include "shell/common/node_includes.h"
 #include "url/origin.h"

+ 6 - 0
typings/internal-ambient.d.ts

@@ -1,5 +1,11 @@
 declare var internalBinding: any;
 
+declare const BUILDFLAG: (flag: boolean) => boolean;
+
+declare const ENABLE_DESKTOP_CAPTURER: boolean;
+declare const ENABLE_REMOTE_MODULE: boolean;
+declare const ENABLE_VIEWS_API: boolean;
+
 declare namespace NodeJS {
   interface FeaturesBinding {
     isBuiltinSpellCheckerEnabled(): boolean;