[RFC] perf: use an internal module resolver to improve require performance (#14633)

* perf: use an internal module resolver instead of relative requires

* perf: memoize the results of getting exported Electron properties

* perf: make internal module changes consistent across sandboxed / bundled files
This commit is contained in:
Samuel Attard 2018-09-20 13:43:26 +10:00 committed by GitHub
parent 73d1b76b54
commit 54ef906832
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 156 additions and 73 deletions

View file

@ -1,13 +1,29 @@
const moduleList = require('../module-list')
const moduleList = require('@electron/internal/common/api/module-list')
// Attaches properties to |exports|.
exports.defineProperties = function (exports) {
exports.memoizedGetter = (getter) => {
/*
* It's ok to leak this value as it would be leaked by the global
* node module cache anyway at `Module._cache`. This memoization
* is dramatically faster than relying on nodes module cache however
*/
let memoizedValue = null
return () => {
if (memoizedValue === null) {
memoizedValue = getter()
}
return memoizedValue
}
}
// Attaches properties to |targetExports|.
exports.defineProperties = function (targetExports) {
const descriptors = {}
for (const module of moduleList) {
descriptors[module.name] = {
enumerable: !module.private,
get: () => require(`../${module.file}`)
get: exports.memoizedGetter(() => require(`@electron/internal/common/api/${module.file}`))
}
}
return Object.defineProperties(exports, descriptors)
return Object.defineProperties(targetExports, descriptors)
}

View file

@ -1,7 +1,7 @@
const timers = require('timers')
const util = require('util')
process.atomBinding = require('./atom-binding-setup')(process.binding, process.type)
process.atomBinding = require('@electron/internal/common/atom-binding-setup')(process.binding, process.type)
// setImmediate and process.nextTick makes use of uv_check and uv_prepare to
// run the callbacks, however since we only run uv loop on requests, the

View file

@ -24,6 +24,9 @@ Module._nodeModulePaths = function (from) {
}
}
const BASE_INTERNAL_PATH = path.resolve(__dirname, '..')
const INTERNAL_MODULE_PREFIX = '@electron/internal/'
// Patch Module._resolveFilename to always require the Electron API when
// require('electron') is done.
const electronPath = path.join(__dirname, '..', process.type, 'api', 'exports', 'electron.js')
@ -31,6 +34,9 @@ const originalResolveFilename = Module._resolveFilename
Module._resolveFilename = function (request, parent, isMain) {
if (request === 'electron') {
return electronPath
} else if (request.startsWith(INTERNAL_MODULE_PREFIX) && request.length > INTERNAL_MODULE_PREFIX.length) {
const slicedRequest = request.slice(INTERNAL_MODULE_PREFIX.length)
return path.resolve(BASE_INTERNAL_PATH, `${slicedRequest}${slicedRequest.endsWith('.js') ? '' : '.js'}`)
} else {
return originalResolveFilename(request, parent, isMain)
}