diff --git a/packages/client-app/spec/module-cache-spec.coffee b/packages/client-app/spec/module-cache-spec.coffee deleted file mode 100644 index 21cb5c2ac..000000000 --- a/packages/client-app/spec/module-cache-spec.coffee +++ /dev/null @@ -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 diff --git a/packages/client-app/src/module-cache.coffee b/packages/client-app/src/module-cache.coffee deleted file mode 100644 index cd7b24825..000000000 --- a/packages/client-app/src/module-cache.coffee +++ /dev/null @@ -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 diff --git a/packages/client-app/static/index.js b/packages/client-app/static/index.js index dc8fface8..e6c2917de 100644 --- a/packages/client-app/static/index.js +++ b/packages/client-app/static/index.js @@ -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',