mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-09-08 13:44:53 +08:00
Remove module cache, will re-evaluate if many plugins exist in the future
This commit is contained in:
parent
5809d9bf47
commit
f2104324be
3 changed files with 0 additions and 404 deletions
|
@ -1,93 +0,0 @@
|
|||
path = require 'path'
|
||||
Module = require 'module'
|
||||
fs = require 'fs-plus'
|
||||
temp = require 'temp'
|
||||
ModuleCache = require '../src/module-cache'
|
||||
|
||||
describe 'ModuleCache', ->
|
||||
beforeEach ->
|
||||
spyOn(Module, '_findPath').andCallThrough()
|
||||
|
||||
it 'resolves Electron module paths without hitting the filesystem', ->
|
||||
builtins = ModuleCache.cache.builtins
|
||||
expect(Object.keys(builtins).length).toBeGreaterThan 0
|
||||
|
||||
for builtinName, builtinPath of builtins
|
||||
expect(require.resolve(builtinName)).toBe builtinPath
|
||||
expect(fs.isFileSync(require.resolve(builtinName)))
|
||||
|
||||
expect(Module._findPath.callCount).toBe 0
|
||||
|
||||
it 'resolves relative core paths without hitting the filesystem', ->
|
||||
ModuleCache.add NylasEnv.getLoadSettings().resourcePath, {
|
||||
_nylasModuleCache:
|
||||
extensions:
|
||||
'.json': [
|
||||
path.join('spec', 'fixtures', 'module-cache', 'file.json')
|
||||
]
|
||||
}
|
||||
expect(require('./fixtures/module-cache/file.json').foo).toBe 'bar'
|
||||
expect(Module._findPath.callCount).toBe 0
|
||||
|
||||
it 'resolves module paths when a compatible version is provided by core', ->
|
||||
packagePath = fs.realpathSync(temp.mkdirSync('n1-package'))
|
||||
ModuleCache.add packagePath, {
|
||||
_nylasModuleCache:
|
||||
folders: [{
|
||||
paths: [
|
||||
''
|
||||
]
|
||||
dependencies:
|
||||
'underscore': '*'
|
||||
}]
|
||||
}
|
||||
ModuleCache.add NylasEnv.getLoadSettings().resourcePath, {
|
||||
_nylasModuleCache:
|
||||
dependencies: [{
|
||||
name: 'underscore'
|
||||
version: require('underscore/package.json').version
|
||||
path: path.join('node_modules', 'underscore', 'underscore.js')
|
||||
}]
|
||||
}
|
||||
|
||||
indexPath = path.join(packagePath, 'index.js')
|
||||
fs.writeFileSync indexPath, """
|
||||
exports.load = function() { require('underscore'); };
|
||||
"""
|
||||
|
||||
packageMain = require(indexPath)
|
||||
Module._findPath.reset()
|
||||
packageMain.load()
|
||||
expect(Module._findPath.callCount).toBe 0
|
||||
|
||||
it 'does not resolve module paths when no compatible version is provided by core', ->
|
||||
packagePath = fs.realpathSync(temp.mkdirSync('n1-package'))
|
||||
ModuleCache.add packagePath, {
|
||||
_nylasModuleCache:
|
||||
folders: [{
|
||||
paths: [
|
||||
''
|
||||
]
|
||||
dependencies:
|
||||
'underscore': '0.0.1'
|
||||
}]
|
||||
}
|
||||
ModuleCache.add NylasEnv.getLoadSettings().resourcePath, {
|
||||
_nylasModuleCache:
|
||||
dependencies: [{
|
||||
name: 'unknown-lib'
|
||||
version: require('underscore/package.json').version
|
||||
path: path.join('node_modules', 'underscore', 'underscore.js')
|
||||
}]
|
||||
}
|
||||
|
||||
indexPath = path.join(packagePath, 'index.js')
|
||||
fs.writeFileSync indexPath, """
|
||||
exports.load = function() { require('unknown-lib'); };
|
||||
"""
|
||||
|
||||
spyOn(process, 'cwd').andReturn('/') # Required when running this test from CLI
|
||||
packageMain = require(indexPath)
|
||||
Module._findPath.reset()
|
||||
expect(-> packageMain.load()).toThrow()
|
||||
expect(Module._findPath.callCount).toBe 1
|
|
@ -1,307 +0,0 @@
|
|||
Module = require 'module'
|
||||
path = require 'path'
|
||||
semver = require 'semver'
|
||||
|
||||
# Extend semver.Range to memoize matched versions for speed
|
||||
class Range extends semver.Range
|
||||
constructor: ->
|
||||
super
|
||||
@matchedVersions = new Set()
|
||||
@unmatchedVersions = new Set()
|
||||
|
||||
test: (version) ->
|
||||
return true if @matchedVersions.has(version)
|
||||
return false if @unmatchedVersions.has(version)
|
||||
|
||||
matches = super
|
||||
if matches
|
||||
@matchedVersions.add(version)
|
||||
else
|
||||
@unmatchedVersions.add(version)
|
||||
matches
|
||||
|
||||
nativeModules = process.binding('natives')
|
||||
|
||||
cache =
|
||||
builtins: {}
|
||||
debug: false
|
||||
dependencies: {}
|
||||
extensions: {}
|
||||
folders: {}
|
||||
ranges: {}
|
||||
registered: false
|
||||
resourcePath: null
|
||||
resourcePathWithTrailingSlash: null
|
||||
|
||||
# isAbsolute is inlined from fs-plus so that fs-plus itself can be required
|
||||
# from this cache.
|
||||
if process.platform is 'win32'
|
||||
isAbsolute = (pathToCheck) ->
|
||||
pathToCheck and (pathToCheck[1] is ':' or (pathToCheck[0] is '\\' and pathToCheck[1] is '\\'))
|
||||
else
|
||||
isAbsolute = (pathToCheck) ->
|
||||
pathToCheck and pathToCheck[0] is '/'
|
||||
|
||||
isCorePath = (pathToCheck) ->
|
||||
pathToCheck.startsWith(cache.resourcePathWithTrailingSlash)
|
||||
|
||||
loadDependencies = (modulePath, rootPath, rootMetadata, moduleCache) ->
|
||||
fs = require 'fs-plus'
|
||||
|
||||
for childPath in fs.listSync(path.join(modulePath, 'node_modules'))
|
||||
continue if path.basename(childPath) is '.bin'
|
||||
continue if rootPath is modulePath and rootMetadata.packageDependencies?.hasOwnProperty(path.basename(childPath))
|
||||
|
||||
childMetadataPath = path.join(childPath, 'package.json')
|
||||
continue unless fs.isFileSync(childMetadataPath)
|
||||
|
||||
childMetadata = JSON.parse(fs.readFileSync(childMetadataPath))
|
||||
if childMetadata?.version
|
||||
try
|
||||
mainPath = require.resolve(childPath)
|
||||
catch error
|
||||
mainPath = null
|
||||
|
||||
if mainPath
|
||||
moduleCache.dependencies.push
|
||||
name: childMetadata.name
|
||||
version: childMetadata.version
|
||||
path: path.relative(rootPath, mainPath)
|
||||
|
||||
loadDependencies(childPath, rootPath, rootMetadata, moduleCache)
|
||||
|
||||
return
|
||||
|
||||
loadFolderCompatibility = (modulePath, rootPath, rootMetadata, moduleCache) ->
|
||||
fs = require 'fs-plus'
|
||||
|
||||
metadataPath = path.join(modulePath, 'package.json')
|
||||
return unless fs.isFileSync(metadataPath)
|
||||
|
||||
dependencies = JSON.parse(fs.readFileSync(metadataPath))?.dependencies ? {}
|
||||
|
||||
for name, version of dependencies
|
||||
try
|
||||
new Range(version)
|
||||
catch error
|
||||
delete dependencies[name]
|
||||
|
||||
onDirectory = (childPath) ->
|
||||
path.basename(childPath) isnt 'node_modules'
|
||||
|
||||
extensions = ['.js', '.coffee', '.json', '.node']
|
||||
paths = {}
|
||||
onFile = (childPath) ->
|
||||
if path.extname(childPath) in extensions
|
||||
relativePath = path.relative(rootPath, path.dirname(childPath))
|
||||
paths[relativePath] = true
|
||||
fs.traverseTreeSync(modulePath, onFile, onDirectory)
|
||||
|
||||
paths = Object.keys(paths)
|
||||
if paths.length > 0 and Object.keys(dependencies).length > 0
|
||||
moduleCache.folders.push({paths, dependencies})
|
||||
|
||||
for childPath in fs.listSync(path.join(modulePath, 'node_modules'))
|
||||
continue if path.basename(childPath) is '.bin'
|
||||
continue if rootPath is modulePath and rootMetadata.packageDependencies?.hasOwnProperty(path.basename(childPath))
|
||||
|
||||
loadFolderCompatibility(childPath, rootPath, rootMetadata, moduleCache)
|
||||
|
||||
return
|
||||
|
||||
loadExtensions = (modulePath, rootPath, rootMetadata, moduleCache) ->
|
||||
fs = require 'fs-plus'
|
||||
extensions = ['.js', '.coffee', '.json', '.node']
|
||||
nodeModulesPath = path.join(rootPath, 'node_modules')
|
||||
|
||||
onFile = (filePath) ->
|
||||
filePath = path.relative(rootPath, filePath)
|
||||
segments = filePath.split(path.sep)
|
||||
return if 'test' in segments
|
||||
return if 'tests' in segments
|
||||
return if 'spec' in segments
|
||||
return if 'specs' in segments
|
||||
return if segments.length > 1 and not (segments[0] in ['lib', 'node_modules', 'src', 'static', 'vendor'])
|
||||
|
||||
extension = path.extname(filePath)
|
||||
if extension in extensions
|
||||
moduleCache.extensions[extension] ?= []
|
||||
moduleCache.extensions[extension].push(filePath)
|
||||
|
||||
onDirectory = (childPath) ->
|
||||
# Don't include extensions from bundled packages
|
||||
# These are generated and stored in the package's own metadata cache
|
||||
if rootMetadata.name is 'nylas'
|
||||
parentPath = path.dirname(childPath)
|
||||
if parentPath is nodeModulesPath
|
||||
packageName = path.basename(childPath)
|
||||
return false if rootMetadata.packageDependencies?.hasOwnProperty(packageName)
|
||||
|
||||
true
|
||||
|
||||
fs.traverseTreeSync(rootPath, onFile, onDirectory)
|
||||
|
||||
return
|
||||
|
||||
satisfies = (version, rawRange) ->
|
||||
unless parsedRange = cache.ranges[rawRange]
|
||||
parsedRange = new Range(rawRange)
|
||||
cache.ranges[rawRange] = parsedRange
|
||||
parsedRange.test(version)
|
||||
|
||||
resolveFilePath = (relativePath, parentModule) ->
|
||||
return unless relativePath
|
||||
return unless parentModule?.filename
|
||||
return unless relativePath[0] is '.' or isAbsolute(relativePath)
|
||||
|
||||
resolvedPath = path.resolve(path.dirname(parentModule.filename), relativePath)
|
||||
return unless isCorePath(resolvedPath)
|
||||
|
||||
extension = path.extname(resolvedPath)
|
||||
if extension
|
||||
return resolvedPath if cache.extensions[extension]?.has(resolvedPath)
|
||||
else
|
||||
for extension, paths of cache.extensions
|
||||
resolvedPathWithExtension = "#{resolvedPath}#{extension}"
|
||||
return resolvedPathWithExtension if paths.has(resolvedPathWithExtension)
|
||||
|
||||
return
|
||||
|
||||
resolveModulePath = (relativePath, parentModule) ->
|
||||
return unless relativePath
|
||||
return unless parentModule?.filename
|
||||
|
||||
return if nativeModules.hasOwnProperty(relativePath)
|
||||
return if relativePath[0] is '.'
|
||||
return if isAbsolute(relativePath)
|
||||
|
||||
folderPath = path.dirname(parentModule.filename)
|
||||
|
||||
range = cache.folders[folderPath]?[relativePath]
|
||||
unless range?
|
||||
if builtinPath = cache.builtins[relativePath]
|
||||
return builtinPath
|
||||
else
|
||||
return
|
||||
|
||||
candidates = cache.dependencies[relativePath]
|
||||
return unless candidates?
|
||||
|
||||
for version, resolvedPath of candidates
|
||||
if Module._cache.hasOwnProperty(resolvedPath) or isCorePath(resolvedPath)
|
||||
return resolvedPath if satisfies(version, range)
|
||||
|
||||
return
|
||||
|
||||
registerBuiltins = (devMode) ->
|
||||
electronRoot = path.join(process.resourcesPath, 'atom.asar')
|
||||
|
||||
commonRoot = path.join(electronRoot, 'common', 'api', 'lib')
|
||||
commonBuiltins = ['callbacks-registry', 'clipboard', 'crash-reporter', 'screen', 'shell']
|
||||
for builtin in commonBuiltins
|
||||
cache.builtins[builtin] = path.join(commonRoot, "#{builtin}.js")
|
||||
|
||||
rendererRoot = path.join(electronRoot, 'renderer', 'api', 'lib')
|
||||
rendererBuiltins = ['ipc', 'remote']
|
||||
for builtin in rendererBuiltins
|
||||
cache.builtins[builtin] = path.join(rendererRoot, "#{builtin}.js")
|
||||
|
||||
if cache.debug
|
||||
cache.findPathCount = 0
|
||||
cache.findPathTime = 0
|
||||
cache.loadCount = 0
|
||||
cache.requireTime = 0
|
||||
global.moduleCache = cache
|
||||
|
||||
originalLoad = Module::load
|
||||
Module::load = ->
|
||||
cache.loadCount++
|
||||
originalLoad.apply(this, arguments)
|
||||
|
||||
originalRequire = Module::require
|
||||
Module::require = ->
|
||||
startTime = Date.now()
|
||||
exports = originalRequire.apply(this, arguments)
|
||||
cache.requireTime += Date.now() - startTime
|
||||
exports
|
||||
|
||||
originalFindPath = Module._findPath
|
||||
Module._findPath = (request, paths) ->
|
||||
cacheKey = JSON.stringify({request, paths})
|
||||
cache.findPathCount++ unless Module._pathCache[cacheKey]
|
||||
|
||||
startTime = Date.now()
|
||||
foundPath = originalFindPath.apply(global, arguments)
|
||||
cache.findPathTime += Date.now() - startTime
|
||||
foundPath
|
||||
|
||||
exports.create = (modulePath) ->
|
||||
fs = require 'fs-plus'
|
||||
|
||||
modulePath = fs.realpathSync(modulePath)
|
||||
metadataPath = path.join(modulePath, 'package.json')
|
||||
metadata = JSON.parse(fs.readFileSync(metadataPath))
|
||||
|
||||
moduleCache =
|
||||
version: 1
|
||||
dependencies: []
|
||||
extensions: {}
|
||||
folders: []
|
||||
|
||||
loadDependencies(modulePath, modulePath, metadata, moduleCache)
|
||||
loadFolderCompatibility(modulePath, modulePath, metadata, moduleCache)
|
||||
loadExtensions(modulePath, modulePath, metadata, moduleCache)
|
||||
|
||||
metadata._nylasModuleCache = moduleCache
|
||||
fs.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2))
|
||||
|
||||
return
|
||||
|
||||
exports.register = ({resourcePath, devMode}={}) ->
|
||||
return if cache.registered
|
||||
|
||||
originalResolveFilename = Module._resolveFilename
|
||||
Module._resolveFilename = (relativePath, parentModule) ->
|
||||
resolvedPath = resolveModulePath(relativePath, parentModule)
|
||||
resolvedPath ?= resolveFilePath(relativePath, parentModule)
|
||||
resolvedPath ? originalResolveFilename(relativePath, parentModule)
|
||||
|
||||
cache.registered = true
|
||||
cache.resourcePath = resourcePath
|
||||
cache.resourcePathWithTrailingSlash = "#{resourcePath}#{path.sep}"
|
||||
registerBuiltins(devMode)
|
||||
|
||||
return
|
||||
|
||||
exports.add = (directoryPath, metadata) ->
|
||||
# path.join isn't used in this function for speed since path.join calls
|
||||
# path.normalize and all the paths are already normalized here.
|
||||
|
||||
unless metadata?
|
||||
try
|
||||
metadata = require("#{directoryPath}#{path.sep}package.json")
|
||||
catch error
|
||||
return
|
||||
|
||||
cacheToAdd = metadata?._nylasModuleCache
|
||||
return unless cacheToAdd?
|
||||
|
||||
for dependency in cacheToAdd.dependencies ? []
|
||||
cache.dependencies[dependency.name] ?= {}
|
||||
cache.dependencies[dependency.name][dependency.version] ?= "#{directoryPath}#{path.sep}#{dependency.path}"
|
||||
|
||||
for entry in cacheToAdd.folders ? []
|
||||
for folderPath in entry.paths
|
||||
if folderPath
|
||||
cache.folders["#{directoryPath}#{path.sep}#{folderPath}"] = entry.dependencies
|
||||
else
|
||||
cache.folders[directoryPath] = entry.dependencies
|
||||
|
||||
for extension, paths of cacheToAdd.extensions
|
||||
cache.extensions[extension] ?= new Set()
|
||||
for filePath in paths
|
||||
cache.extensions[extension].add("#{directoryPath}#{path.sep}#{filePath}")
|
||||
|
||||
return
|
||||
|
||||
exports.cache = cache
|
|
@ -43,10 +43,6 @@ function setupWindow (loadSettings) {
|
|||
var CompileCache = require('../src/compile-cache')
|
||||
CompileCache.setHomeDirectory(loadSettings.configDirPath)
|
||||
|
||||
var ModuleCache = require('../src/module-cache')
|
||||
ModuleCache.register(loadSettings)
|
||||
ModuleCache.add(loadSettings.resourcePath)
|
||||
|
||||
// Start the crash reporter before anything else.
|
||||
// require('crash-reporter').start({
|
||||
// productName: 'N1',
|
||||
|
|
Loading…
Add table
Reference in a new issue