refactor: allow requiring modules with no side effects (#17496)

This commit is contained in:
Shelley Vohr 2019-04-29 17:46:08 -07:00 committed by Cheng Zhao
parent 4ee201c56e
commit 7b55ee9d36
10 changed files with 85 additions and 54 deletions

View file

@ -1,22 +1,25 @@
'use strict'
import { createLazyInstance } from '../utils'
const { EventEmitter } = require('events')
const { powerMonitor, PowerMonitor } = process.electronBinding('power_monitor')
const { createPowerMonitor, PowerMonitor } = process.electronBinding('power_monitor')
const { deprecate } = require('electron')
// PowerMonitor is an EventEmitter.
Object.setPrototypeOf(PowerMonitor.prototype, EventEmitter.prototype)
EventEmitter.call(powerMonitor)
const powerMonitor = createLazyInstance(createPowerMonitor, PowerMonitor, true)
// On Linux we need to call blockShutdown() to subscribe to shutdown event.
if (process.platform === 'linux') {
powerMonitor.on('newListener', (event) => {
powerMonitor.on('newListener', (event:string) => {
if (event === 'shutdown' && powerMonitor.listenerCount('shutdown') === 0) {
powerMonitor.blockShutdown()
}
})
powerMonitor.on('removeListener', (event) => {
powerMonitor.on('removeListener', (event: string) => {
if (event === 'shutdown' && powerMonitor.listenerCount('shutdown') === 0) {
powerMonitor.unblockShutdown()
}
@ -24,30 +27,21 @@ if (process.platform === 'linux') {
}
// TODO(nitsakh): Remove in 7.0
powerMonitor.querySystemIdleState = function (threshold, callback) {
powerMonitor.querySystemIdleState = function (threshold: number, callback: Function) {
deprecate.warn('powerMonitor.querySystemIdleState', 'powerMonitor.getSystemIdleState')
if (typeof threshold !== 'number') {
throw new Error('Must pass threshold as a number')
}
if (typeof callback !== 'function') {
throw new Error('Must pass callback as a function argument')
}
if (typeof threshold !== 'number') throw new Error('Must pass threshold as a number')
if (typeof callback !== 'function') throw new Error('Must pass callback as a function argument')
const idleState = this.getSystemIdleState(threshold)
process.nextTick(() => callback(idleState))
}
// TODO(nitsakh): Remove in 7.0
powerMonitor.querySystemIdleTime = function (callback) {
powerMonitor.querySystemIdleTime = function (callback: Function) {
deprecate.warn('powerMonitor.querySystemIdleTime', 'powerMonitor.getSystemIdleTime')
if (typeof callback !== 'function') {
throw new Error('Must pass function as an argument')
}
if (typeof callback !== 'function') throw new Error('Must pass function as an argument')
const idleTime = this.getSystemIdleTime()
process.nextTick(() => callback(idleTime))
}

View file

@ -1,10 +0,0 @@
'use strict'
const { EventEmitter } = require('events')
const { screen, Screen } = process.electronBinding('screen')
// Screen is an EventEmitter.
Object.setPrototypeOf(Screen.prototype, EventEmitter.prototype)
EventEmitter.call(screen)
module.exports = screen

10
lib/browser/api/screen.ts Normal file
View file

@ -0,0 +1,10 @@
'use strict'
import { createLazyInstance } from '../utils'
const { EventEmitter } = require('events')
const { Screen, createScreen } = process.electronBinding('screen')
// Screen is an EventEmitter.
Object.setPrototypeOf(Screen.prototype, EventEmitter.prototype)
module.exports = createLazyInstance(createScreen, Screen, true)

38
lib/browser/utils.ts Normal file
View file

@ -0,0 +1,38 @@
import { EventEmitter } from 'events'
/**
* Creates a lazy instance of modules that can't be required before the
* app 'ready' event by returning a proxy object to mitigate side effects
* on 'require'
*
* @param {Function} creator - Function that creates a new module instance
* @param {Object} holder - the object holding the module prototype
* @param {Boolean} isEventEmitter - whether or not the module is an EventEmitter
* @returns {Object} - a proxy object for the
*/
export function createLazyInstance (
creator: Function,
holder: Object,
isEventEmitter: Boolean
) {
let lazyModule: Object
const module: any = {}
for (const method in (holder as any).prototype) {
module[method] = (...args: any) => {
// create new instance of module at runtime if none exists
if (!lazyModule) {
lazyModule = creator()
if (isEventEmitter) EventEmitter.call(lazyModule as any)
}
// check for properties on the prototype chain that aren't functions
if (typeof (lazyModule as any)[method] !== 'function') {
return (lazyModule as any)[method]
}
return (lazyModule as any)[method](...args)
}
}
return module
}