Skip to content

Commit

Permalink
Improving performance of the css function in build mode (see js-kyle#15)
Browse files Browse the repository at this point in the history
  • Loading branch information
TrevorBurnham committed Oct 28, 2011
1 parent 9d59415 commit 63d8dd1
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 19 deletions.
16 changes: 11 additions & 5 deletions docs/assets.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<span class="nx">options</span><span class="p">.</span><span class="nx">buildsExpire</span> <span class="o">?=</span> <span class="kc">false</span>
<span class="nx">options</span><span class="p">.</span><span class="nx">minifyBuilds</span> <span class="o">?=</span> <span class="kc">true</span>

<span class="nv">connectAssets = </span><span class="k">new</span> <span class="nx">ConnectAssets</span> <span class="nx">options</span>
<span class="nv">connectAssets = module.exports.instance = </span><span class="k">new</span> <span class="nx">ConnectAssets</span> <span class="nx">options</span>
<span class="nx">connectAssets</span><span class="p">.</span><span class="nx">createHelpers</span> <span class="nx">options</span>
<span class="nx">connectAssets</span><span class="p">.</span><span class="nx">cache</span><span class="p">.</span><span class="nx">middleware</span>

Expand Down Expand Up @@ -65,10 +65,10 @@
<span class="k">try</span>
<span class="nv">stats = </span><span class="nx">fs</span><span class="p">.</span><span class="nx">statSync</span> <span class="nx">@absPath</span><span class="p">(</span><span class="nx">sourcePath</span><span class="p">)</span>
<span class="k">if</span> <span class="nx">ext</span> <span class="o">is</span> <span class="s1">&#39;css&#39;</span>
<span class="p">{</span><span class="nx">mtime</span><span class="p">}</span> <span class="o">=</span> <span class="nx">stats</span>
<span class="k">if</span> <span class="nx">timeEq</span> <span class="nx">mtime</span><span class="p">,</span> <span class="nx">@cache</span><span class="p">.</span><span class="nx">map</span><span class="p">[</span><span class="nx">route</span><span class="p">]</span><span class="o">?</span><span class="p">.</span><span class="nx">mtime</span>
<span class="nv">css = </span><span class="nx">@cache</span><span class="p">.</span><span class="nx">map</span><span class="p">[</span><span class="nx">route</span><span class="p">].</span><span class="nx">data</span>
<span class="nv">alreadyCached = </span><span class="kc">true</span>
<span class="k">else</span>
<span class="p">{</span><span class="nx">mtime</span><span class="p">}</span> <span class="o">=</span> <span class="nx">stats</span>
<span class="nv">css = </span><span class="nx">fs</span><span class="p">.</span><span class="nx">readFileSync</span> <span class="nx">@absPath</span><span class="p">(</span><span class="nx">sourcePath</span><span class="p">)</span>
<span class="k">else</span>
<span class="k">if</span> <span class="nx">timeEq</span> <span class="nx">stats</span><span class="p">.</span><span class="nx">mtime</span><span class="p">,</span> <span class="nx">@cssSourceFiles</span><span class="p">[</span><span class="nx">sourcePath</span><span class="p">]</span><span class="o">?</span><span class="p">.</span><span class="nx">mtime</span>
Expand All @@ -79,13 +79,19 @@
<span class="nv">source = </span><span class="nx">data</span><span class="p">.</span><span class="nx">toString</span> <span class="s1">&#39;utf8&#39;</span>
<span class="nv">css = </span><span class="nx">cssCompilers</span><span class="p">[</span><span class="nx">ext</span><span class="p">].</span><span class="nx">compileSync</span> <span class="nx">@absPath</span><span class="p">(</span><span class="nx">sourcePath</span><span class="p">),</span> <span class="nx">source</span>
<span class="k">if</span> <span class="nx">css</span> <span class="o">is</span> <span class="nx">@compiledCss</span><span class="p">[</span><span class="nx">sourcePath</span><span class="p">]</span><span class="o">?</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">toString</span> <span class="s1">&#39;utf8&#39;</span>
<span class="nv">mtime = </span><span class="nx">@compiledCss</span><span class="p">[</span><span class="nx">sourcePath</span><span class="p">].</span><span class="nx">mtime</span>
<span class="nv">alreadyCached = </span><span class="kc">true</span>
<span class="k">else</span>
<span class="nv">mtime = </span><span class="k">new</span> <span class="nb">Date</span>
<span class="nx">@compiledCss</span><span class="p">[</span><span class="nx">sourcePath</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="nv">data: </span><span class="k">new</span> <span class="nx">Buffer</span><span class="p">(</span><span class="nx">css</span><span class="p">),</span> <span class="nx">mtime</span><span class="p">}</span>

<span class="k">if</span> <span class="nx">@options</span><span class="p">.</span><span class="nx">build</span>
<span class="k">if</span> <span class="nx">alreadyCached</span> <span class="o">and</span> <span class="nx">@options</span><span class="p">.</span><span class="nx">build</span>
<span class="nv">filename = </span><span class="nx">@buildFilenames</span><span class="p">[</span><span class="nx">sourcePath</span><span class="p">]</span>
<span class="k">return</span> <span class="s2">&quot;/#{filename}&quot;</span>
<span class="k">else</span> <span class="k">if</span> <span class="nx">alreadyCached</span>
<span class="k">return</span> <span class="s2">&quot;/#{route}&quot;</span>
<span class="k">else</span> <span class="k">if</span> <span class="nx">@options</span><span class="p">.</span><span class="nx">build</span>
<span class="nv">filename = </span><span class="nx">@options</span><span class="p">.</span><span class="nx">buildFilenamer</span> <span class="nx">route</span><span class="p">,</span> <span class="nx">css</span>
<span class="nx">@buildFilenames</span><span class="p">[</span><span class="nx">sourcePath</span><span class="p">]</span> <span class="o">=</span> <span class="nx">filename</span>
<span class="nv">cacheFlags = </span><span class="p">{</span><span class="nv">expires: </span><span class="nx">@options</span><span class="p">.</span><span class="nx">buildsExpire</span><span class="p">,</span> <span class="nx">mtime</span><span class="p">}</span>
<span class="nx">@cache</span><span class="p">.</span><span class="nx">set</span> <span class="nx">filename</span><span class="p">,</span> <span class="nx">css</span><span class="p">,</span> <span class="nx">cacheFlags</span>
<span class="k">if</span> <span class="nx">@options</span><span class="p">.</span><span class="nx">buildDir</span>
Expand Down
18 changes: 12 additions & 6 deletions lib/assets.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 11 additions & 5 deletions src/assets.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ module.exports = (options = {}) ->
options.buildsExpire ?= false
options.minifyBuilds ?= true

connectAssets = new ConnectAssets options
connectAssets = module.exports.instance = new ConnectAssets options
connectAssets.createHelpers options
connectAssets.cache.middleware

Expand Down Expand Up @@ -79,10 +79,10 @@ class ConnectAssets
try
stats = fs.statSync @absPath(sourcePath)
if ext is 'css'
{mtime} = stats
if timeEq mtime, @cache.map[route]?.mtime
css = @cache.map[route].data
alreadyCached = true
else
{mtime} = stats
css = fs.readFileSync @absPath(sourcePath)
else
if timeEq stats.mtime, @cssSourceFiles[sourcePath]?.mtime
Expand All @@ -93,13 +93,19 @@ class ConnectAssets
source = data.toString 'utf8'
css = cssCompilers[ext].compileSync @absPath(sourcePath), source
if css is @compiledCss[sourcePath]?.data.toString 'utf8'
mtime = @compiledCss[sourcePath].mtime
alreadyCached = true
else
mtime = new Date
@compiledCss[sourcePath] = {data: new Buffer(css), mtime}

if @options.build
if alreadyCached and @options.build
filename = @buildFilenames[sourcePath]
return "/#{filename}"
else if alreadyCached
return "/#{route}"
else if @options.build
filename = @options.buildFilenamer route, css
@buildFilenames[sourcePath] = filename
cacheFlags = {expires: @options.buildsExpire, mtime}
@cache.set filename, css, cacheFlags
if @options.buildDir
Expand Down
18 changes: 18 additions & 0 deletions test/AbsoluteIntegration.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,24 @@ exports['Compiled stylesheets work from absolute options.src'] = (test) ->
test.equals body, expectedBody
test.done()

exports['Single .js files work from absolute options.src'] = (test) ->
test.equals js('js-dependency'), "<script src='/js/js-dependency.js'></script>"

request 'http://localhost:3590/js/js-dependency.js', (err, res, body) ->
throw err if err
expectedBody = '// Admit it: You need me.'
test.equals body, expectedBody
test.done()

exports['Single .coffee files work from absolute options.src'] = (test) ->
test.equals js('a'), "<script src='/js/a.js'></script>"

request 'http://localhost:3590/js/a.js', (err, res, body) ->
throw err if err
expectedBody = '(function() {\n alert(\'I require nothing!\');\n}).call(this);\n'
test.equals body, expectedBody
test.done()

exports['JS dependencies work from absolute options.src'] = (test) ->
jsTags = """<script src='/js/subdir/nested/hobbits.js'></script>
<script src='/js/tree-dependent.js'></script>
Expand Down
30 changes: 27 additions & 3 deletions test/ProductionIntegration.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,29 @@ app.listen 3589
exports['Far-future expires and MD5 hash strings are used for CSS'] = (test) ->
cssTag = "<link rel='stylesheet' href='/css/style-666055206709fc94e56e1a59caa615dd.css'>"
test.equals css('style'), cssTag
test.equals assets.instance.buildFilenames['css/style.styl'], 'css/style-666055206709fc94e56e1a59caa615dd.css'

request 'http://localhost:3589/css/style-666055206709fc94e56e1a59caa615dd.css', (err, res, body) ->
throw err if err
test.equals res.headers['content-type'], 'text/css'
test.equals res.headers['expires'], 'Wed, 01 Feb 2034 12:34:56 GMT'
test.equals body, 'textarea,input{border:1px solid #eee}\n'
test.done()

# test repeated requests
test.equals css('style'), cssTag
test.equals assets.instance.buildFilenames['css/style.styl'], 'css/style-666055206709fc94e56e1a59caa615dd.css'

request 'http://localhost:3589/css/style-666055206709fc94e56e1a59caa615dd.css', (err, res, body) ->
throw err if err
test.equals res.headers['content-type'], 'text/css'
test.equals res.headers['expires'], 'Wed, 01 Feb 2034 12:34:56 GMT'
test.equals body, 'textarea,input{border:1px solid #eee}\n'
test.done()

exports['JS dependencies are concatenated and minified'] = (test) ->
jsTag = "<script src='/js/dependent-057747a1cbabcbd2279e4f358bc4723f.js'></script>"
test.equals js('dependent'), jsTag
test.equals assets.instance.buildFilenames['js/dependent.coffee'], 'js/dependent-057747a1cbabcbd2279e4f358bc4723f.js'

request 'http://localhost:3589/js/dependent-057747a1cbabcbd2279e4f358bc4723f.js', (err, res, body) ->
throw err if err
Expand All @@ -28,5 +40,17 @@ exports['JS dependencies are concatenated and minified'] = (test) ->
(function(){this.proclamation="Everyone is counting on me!"}).call(this),alert("HEY"),function(){}.call(this)
'''
test.equals body, expectedBody
test.done()
app.close()

# test repeated requests
test.equals js('dependent'), jsTag
test.equals assets.instance.buildFilenames['js/dependent.coffee'], 'js/dependent-057747a1cbabcbd2279e4f358bc4723f.js'

request 'http://localhost:3589/js/dependent-057747a1cbabcbd2279e4f358bc4723f.js', (err, res, body) ->
throw err if err
test.equals res.headers['content-type'], 'application/javascript'
expectedBody = '''
(function(){this.proclamation="Everyone is counting on me!"}).call(this),alert("HEY"),function(){}.call(this)
'''
test.equals body, expectedBody
test.done()
app.close()

0 comments on commit 63d8dd1

Please sign in to comment.