Merge pull request #5524 from atom/ks-defer-coffee-script-require

Minimize CoffeeScript requires
This commit is contained in:
Kevin Sawicki
2015-02-12 14:46:18 -08:00
9 changed files with 139 additions and 133 deletions

View File

@@ -24,8 +24,9 @@
"atom-keymap": "^3.1.2",
"bootstrap": "git+https://github.com/atom/bootstrap.git#6af81906189f1747fd6c93479e3d998ebe041372",
"clear-cut": "0.4.0",
"coffee-cash": "0.7.0",
"coffee-script": "1.8.0",
"coffeestack": "0.8.0",
"coffeestack": "^1.1",
"color": "^0.7.3",
"delegato": "^1",
"emissary": "^1.3.1",
@@ -35,10 +36,10 @@
"fstream": "0.1.24",
"fuzzaldrin": "^2.1",
"git-utils": "^3.0.0",
"grim": "1.1.1",
"grim": "1.1.2",
"guid": "0.0.10",
"jasmine-json": "~0.0",
"jasmine-tagged": "^1.1.3",
"jasmine-tagged": "^1.1.4",
"jquery": "^2.1.1",
"less-cache": "0.21",
"marked": "^0.3",
@@ -57,7 +58,7 @@
"scandal": "2.0.0",
"scoped-property-store": "^0.16.2",
"scrollbar-style": "^2.0.0",
"season": "^5.1.2",
"season": "^5.1.4",
"semver": "~4.2",
"serializable": "^1",
"service-hub": "^0.4.0",
@@ -93,7 +94,7 @@
"deprecation-cop": "0.36.0",
"dev-live-reload": "0.41.0",
"encoding-selector": "0.18.0",
"exception-reporting": "0.23.0",
"exception-reporting": "0.24.0",
"find-and-replace": "0.157.0",
"fuzzy-finder": "0.66.0",
"git-diff": "0.52.0",

View File

@@ -0,0 +1,28 @@
path = require 'path'
CSON = require 'season'
CoffeeCache = require 'coffee-cash'
to5 = require '../src/6to5'
CompileCache = require '../src/compile-cache'
describe "Compile Cache", ->
describe ".addPathToCache(filePath)", ->
it "adds the path to the correct CSON, CoffeeScript, or 6to5 cache", ->
spyOn(CSON, 'readFileSync').andCallThrough()
spyOn(CoffeeCache, 'addPathToCache').andCallThrough()
spyOn(to5, 'addPathToCache').andCallThrough()
CompileCache.addPathToCache(path.join(__dirname, 'fixtures', 'cson.cson'))
expect(CSON.readFileSync.callCount).toBe 1
expect(CoffeeCache.addPathToCache.callCount).toBe 0
expect(to5.addPathToCache.callCount).toBe 0
CompileCache.addPathToCache(path.join(__dirname, 'fixtures', 'coffee.coffee'))
expect(CSON.readFileSync.callCount).toBe 1
expect(CoffeeCache.addPathToCache.callCount).toBe 1
expect(to5.addPathToCache.callCount).toBe 0
CompileCache.addPathToCache(path.join(__dirname, 'fixtures', '6to5', 'double-quotes.js'))
expect(CSON.readFileSync.callCount).toBe 1
expect(CoffeeCache.addPathToCache.callCount).toBe 1
expect(to5.addPathToCache.callCount).toBe 1

1
spec/fixtures/cson.cson vendored Normal file
View File

@@ -0,0 +1 @@
a: 4

View File

@@ -89,6 +89,7 @@ create6to5VersionAndOptionsDigest = (version, options) ->
updateDigestForJsonValue(shasum, options)
shasum.digest('hex')
cacheDir = null
jsCacheDir = null
getCachePath = (sourceCode) ->
@@ -96,8 +97,7 @@ getCachePath = (sourceCode) ->
unless jsCacheDir?
to5Version = require('6to5-core/package.json').version
cacheDir = path.join(process.env.ATOM_HOME, 'compile-cache')
jsCacheDir = path.join(cacheDir, 'js', '6to5', create6to5VersionAndOptionsDigest(to5Version, defaultOptions))
jsCacheDir = path.join(cacheDir, create6to5VersionAndOptionsDigest(to5Version, defaultOptions))
path.join(jsCacheDir, "#{digest}.js")
@@ -141,12 +141,19 @@ loadFile = (module, filePath) ->
register = ->
Object.defineProperty(require.extensions, '.js', {
enumerable: true
writable: false
value: loadFile
})
setCacheDirectory = (newCacheDir) ->
if cacheDir isnt newCacheDir
cacheDir = newCacheDir
jsCacheDir = null
module.exports =
register: register
setCacheDirectory: setCacheDirectory
getCacheMisses: -> stats.misses
getCacheHits: -> stats.hits

View File

@@ -15,6 +15,8 @@ process.on 'uncaughtException', (error={}) ->
start = ->
setupAtomHome()
setupCoffeeCache()
if process.platform is 'win32'
SquirrelUpdate = require './squirrel-update'
squirrelCommand = process.argv[1]
@@ -49,9 +51,7 @@ start = ->
else
path.resolve(pathToOpen)
setupCoffeeScript()
if args.devMode
require(path.join(args.resourcePath, 'src', 'coffee-cache')).register()
AtomApplication = require path.join(args.resourcePath, 'src', 'browser', 'atom-application')
else
AtomApplication = require './atom-application'
@@ -66,15 +66,6 @@ global.devResourcePath = path.normalize(global.devResourcePath) if global.devRes
setupCrashReporter = ->
crashReporter.start(productName: 'Atom', companyName: 'GitHub')
setupCoffeeScript = ->
CoffeeScript = null
require.extensions['.coffee'] = (module, filePath) ->
CoffeeScript ?= require('coffee-script')
coffee = fs.readFileSync(filePath, 'utf8')
js = CoffeeScript.compile(coffee, filename: filePath)
module._compile(js, filePath)
setupAtomHome = ->
return if process.env.ATOM_HOME
@@ -83,6 +74,15 @@ setupAtomHome = ->
atomHome = fs.realpathSync(atomHome)
process.env.ATOM_HOME = atomHome
setupCoffeeCache = ->
CoffeeCache = require 'coffee-cash'
cacheDir = path.join(process.env.ATOM_HOME, 'compile-cache')
# Use separate compile cache when sudo'ing as root to avoid permission issues
if process.env.USER is 'root' and process.env.SUDO_USER and process.env.SUDO_USER isnt process.env.USER
cacheDir = path.join(cacheDir, 'root')
CoffeeCache.setCacheDirectory(path.join(cacheDir, 'coffee'))
CoffeeCache.register()
parseCommandLine = ->
version = app.getVersion()
options = optimist(process.argv[1..])

View File

@@ -1,76 +0,0 @@
crypto = require 'crypto'
path = require 'path'
CoffeeScript = require 'coffee-script'
CSON = require 'season'
fs = require 'fs-plus'
cacheDir = path.join(process.env.ATOM_HOME, 'compile-cache')
stats =
hits: 0
misses: 0
# Use separate compile cache when sudo'ing as root to avoid permission issues
if process.env.USER is 'root' and process.env.SUDO_USER and process.env.SUDO_USER isnt process.env.USER
cacheDir = path.join(cacheDir, 'root')
coffeeCacheDir = path.join(cacheDir, 'coffee')
CSON.setCacheDir(path.join(cacheDir, 'cson'))
getCachePath = (coffee) ->
digest = crypto.createHash('sha1').update(coffee, 'utf8').digest('hex')
path.join(coffeeCacheDir, "#{digest}.js")
getCachedJavaScript = (cachePath) ->
if fs.isFileSync(cachePath)
try
cachedJavaScript = fs.readFileSync(cachePath, 'utf8')
stats.hits++
return cachedJavaScript
return
convertFilePath = (filePath) ->
if process.platform is 'win32'
filePath = "/#{path.resolve(filePath).replace(/\\/g, '/')}"
encodeURI(filePath)
compileCoffeeScript = (coffee, filePath, cachePath) ->
{js, v3SourceMap} = CoffeeScript.compile(coffee, filename: filePath, sourceMap: true)
stats.misses++
# Include source map in the web page environment.
if btoa? and JSON? and unescape? and encodeURIComponent?
js = "#{js}\n//# sourceMappingURL=data:application/json;base64,#{btoa unescape encodeURIComponent v3SourceMap}\n//# sourceURL=#{convertFilePath(filePath)}"
try
fs.writeFileSync(cachePath, js)
js
requireCoffeeScript = (module, filePath) ->
coffee = fs.readFileSync(filePath, 'utf8')
cachePath = getCachePath(coffee)
js = getCachedJavaScript(cachePath) ? compileCoffeeScript(coffee, filePath, cachePath)
module._compile(js, filePath)
module.exports =
cacheDir: cacheDir
register: ->
Object.defineProperty(require.extensions, '.coffee', {
writable: false
value: requireCoffeeScript
})
addPathToCache: (filePath) ->
switch path.extname(filePath)
when '.coffee'
content = fs.readFileSync(filePath, 'utf8')
cachePath = getCachePath(coffee)
compileCoffeeScript(coffee, filePath, cachePath)
when '.cson'
CSON.readFileSync(filePath)
when '.js'
require('./6to5').addPathToCache(filePath)
getCacheMisses: -> stats.misses
getCacheHits: -> stats.hits

26
src/compile-cache.coffee Normal file
View File

@@ -0,0 +1,26 @@
path = require 'path'
CSON = require 'season'
CoffeeCache = require 'coffee-cash'
to5 = require './6to5'
# This file is required directly by apm so that files can be cached during
# package install so that the first package load in Atom doesn't have to
# compile anything.
exports.addPathToCache = (filePath, atomHome) ->
atomHome ?= process.env.ATOM_HOME
cacheDir = path.join(atomHome, 'compile-cache')
# Use separate compile cache when sudo'ing as root to avoid permission issues
if process.env.USER is 'root' and process.env.SUDO_USER and process.env.SUDO_USER isnt process.env.USER
cacheDir = path.join(cacheDir, 'root')
CoffeeCache.setCacheDirectory(path.join(cacheDir, 'coffee'))
CSON.setCacheDir(path.join(cacheDir, 'cson'))
to5.setCacheDirectory(path.join(cacheDir, 'js'))
switch path.extname(filePath)
when '.coffee'
CoffeeCache.addPathToCache(filePath)
when '.cson'
CSON.readFileSync(filePath)
when '.js'
to5.addPathToCache(filePath)

View File

@@ -65,12 +65,15 @@ class Task
# * `taskPath` The {String} path to the CoffeeScript/JavaScript file that
# exports a single {Function} to execute.
constructor: (taskPath) ->
coffeeCacheRequire = "require('#{require.resolve('./coffee-cache')}').register();"
coffeeScriptRequire = "require('#{require.resolve('coffee-script')}').register();"
coffeeCacheRequire = "require('#{require.resolve('coffee-cash')}')"
coffeeCachePath = require('coffee-cash').getCacheDirectory()
coffeeStackRequire = "require('#{require.resolve('coffeestack')}')"
stackCachePath = require('coffeestack').getCacheDirectory()
taskBootstrapRequire = "require('#{require.resolve('./task-bootstrap')}');"
bootstrap = """
#{coffeeScriptRequire}
#{coffeeCacheRequire}
#{coffeeCacheRequire}.setCacheDirectory('#{coffeeCachePath}');
#{coffeeCacheRequire}.register();
#{coffeeStackRequire}.setCacheDirectory('#{stackCachePath}');
#{taskBootstrapRequire}
"""
bootstrap = bootstrap.replace(/\\/g, "\\\\")

View File

@@ -1,33 +1,17 @@
function registerRuntimeTranspilers() {
// This sets require.extensions['.coffee'].
require('coffee-script').register();
// This redefines require.extensions['.js'].
require('../src/6to5').register();
}
var fs = require('fs');
var path = require('path');
window.onload = function() {
try {
var startTime = Date.now();
var fs = require('fs');
var path = require('path');
// Ensure ATOM_HOME is always set before anything else is required
if (!process.env.ATOM_HOME) {
var home;
if (process.platform === 'win32') {
home = process.env.USERPROFILE;
} else {
home = process.env.HOME;
}
var atomHome = path.join(home, '.atom');
try {
atomHome = fs.realpathSync(atomHome);
} catch (error) {
// Ignore since the path might just not exist yet.
}
process.env.ATOM_HOME = atomHome;
setupAtomHome();
var cacheDir = path.join(process.env.ATOM_HOME, 'compile-cache');
// Use separate compile cache when sudo'ing as root to avoid permission issues
if (process.env.USER === 'root' && process.env.SUDO_USER && process.env.SUDO_USER !== process.env.USER) {
cacheDir = path.join(cacheDir, 'root');
}
// Skip "?loadSettings=".
@@ -45,10 +29,7 @@ window.onload = function() {
var devMode = loadSettings.devMode || !loadSettings.resourcePath.startsWith(process.resourcesPath + path.sep);
// Require before the module cache in dev mode
if (devMode) {
registerRuntimeTranspilers();
}
setupCoffeeCache(cacheDir);
ModuleCache = require('../src/module-cache');
ModuleCache.register(loadSettings);
@@ -65,11 +46,9 @@ window.onload = function() {
require('vm-compatibility-layer');
if (!devMode) {
registerRuntimeTranspilers();
}
require('../src/coffee-cache').register();
setupCsonCache(cacheDir);
setupSourceMapCache(cacheDir);
setup6to5(cacheDir);
require(loadSettings.bootstrapScript);
require('ipc').sendChannel('window-command', 'window:loaded');
@@ -78,8 +57,7 @@ window.onload = function() {
global.atom.loadTime = Date.now() - startTime;
console.log('Window load time: ' + global.atom.getWindowLoadTime() + 'ms');
}
}
catch (error) {
} catch (error) {
var currentWindow = require('remote').getCurrentWindow();
currentWindow.setSize(800, 600);
currentWindow.center();
@@ -88,3 +66,41 @@ window.onload = function() {
console.error(error.stack || error);
}
}
var setupCoffeeCache = function(cacheDir) {
var CoffeeCache = require('coffee-cash');
CoffeeCache.setCacheDirectory(path.join(cacheDir, 'coffee'));
CoffeeCache.register();
}
var setupAtomHome = function() {
if (!process.env.ATOM_HOME) {
var home;
if (process.platform === 'win32') {
home = process.env.USERPROFILE;
} else {
home = process.env.HOME;
}
var atomHome = path.join(home, '.atom');
try {
atomHome = fs.realpathSync(atomHome);
} catch (error) {
// Ignore since the path might just not exist yet.
}
process.env.ATOM_HOME = atomHome;
}
}
var setup6to5 = function(cacheDir) {
var to5 = require('../src/6to5');
to5.setCacheDirectory(path.join(cacheDir, 'js', '6to5'));
to5.register();
}
var setupCsonCache = function(cacheDir) {
require('season').setCacheDir(path.join(cacheDir, 'cson'));
}
var setupSourceMapCache = function(cacheDir) {
require('coffeestack').setCacheDirectory(path.join(cacheDir, 'coffee', 'source-maps'));
}