From 7969d36b35a3829282dd8edfd5f77ae4e49bbbd4 Mon Sep 17 00:00:00 2001 From: Esa-Matti Suuronen Date: Sun, 2 Oct 2011 13:19:40 +0300 Subject: [PATCH] Integrate node-pile. This closes issue #79. --- examples/assets.coffee | 31 ++++++++ examples/views.coffee | 16 ++-- examples/views/layout.coffee | 4 +- package.json | 4 +- src/client.coffee | 2 +- src/zappa.coffee | 148 ++++++++++++++++++----------------- 6 files changed, 122 insertions(+), 83 deletions(-) create mode 100644 examples/assets.coffee diff --git a/examples/assets.coffee b/examples/assets.coffee new file mode 100644 index 0000000..bdf91cf --- /dev/null +++ b/examples/assets.coffee @@ -0,0 +1,31 @@ +require('./zappa') -> + + @enable 'serve jquery' + + @get "/": -> + @render 'index' + + @client -> + console.log "Hello, I will run on every page" + + @client namespaced: -> + console.log "I will run only where namespace 'namespaced' is" + + + @view index: -> + div -> + h1 -> "Hello, node-pile in Zappa!" + + @css ''' + h1 { + color: blue; + } + ''' + + @view layout: -> + doctype 5 + html -> + head -> + title "Hello Assets" + @renderStyleTags() + @renderScriptTags("namespaced") + body @body diff --git a/examples/views.coffee b/examples/views.coffee index fc1f62a..31931f0 100644 --- a/examples/views.coffee +++ b/examples/views.coffee @@ -2,17 +2,17 @@ require('./zappa') -> @get '/': -> @render 'index', foo: 'bar' - + '/eco': -> @render 'index.eco', foo: 'bar' - + '/jade': -> @render 'index.jade', foo: 'bar' @view index: -> h2 'CoffeeKup inline template' p @foo - + @view layout: -> doctype 5 html -> @@ -21,12 +21,12 @@ require('./zappa') -> body -> h1 'CoffeeKup inline layout' @body - + @view 'index.eco': '''

Eco inline template

<%= @foo %>

''' - + @view 'layout.eco': ''' @@ -38,12 +38,12 @@ require('./zappa') -> ''' - + @view 'index.jade': ''' h2 Jade inline template p= foo ''' - + @view 'layout.jade': ''' !!! 5 html @@ -52,4 +52,4 @@ require('./zappa') -> body h1 Jade inline layout != body - ''' \ No newline at end of file + ''' diff --git a/examples/views/layout.coffee b/examples/views/layout.coffee index eca30ea..33b1609 100644 --- a/examples/views/layout.coffee +++ b/examples/views/layout.coffee @@ -2,6 +2,8 @@ doctype 5 html -> head -> title 'CoffeeKup file layout' + @renderStyleTags() + @renderScriptTags() body -> h1 'CoffeeKup file layout' - @body \ No newline at end of file + @body diff --git a/package.json b/package.json index 7372986..f32975c 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "socket.io": "0.8.4", "coffeekup": "0.3.1", "node-uuid": "1.2.0", - "uglify-js": "1.1.0" + "pile": "0.2.1" }, "devDependencies": { "jsdom": "0.2.5", @@ -41,4 +41,4 @@ "Kris Molendyke ", "Rafael de Oleza Alomar " ] -} \ No newline at end of file +} diff --git a/src/client.coffee b/src/client.coffee index 9f1e1e8..91d7a41 100644 --- a/src/client.coffee +++ b/src/client.coffee @@ -88,4 +88,4 @@ skeleton = -> String(skeleton) .replace('version = null;', "version = '#{version}';") .replace('coffeescript_helpers = null;', "var coffeescript_helpers = '#{coffeescript_helpers}';") - .replace('settings = null;', "var settings = #{JSON.stringify settings};") \ No newline at end of file + .replace('settings = null;', "var settings = #{JSON.stringify settings};") diff --git a/src/zappa.coffee b/src/zappa.coffee index 95ab197..0b977a0 100644 --- a/src/zappa.coffee +++ b/src/zappa.coffee @@ -12,9 +12,13 @@ path = require 'path' uuid = require 'node-uuid' express = require 'express' socketio = require 'socket.io' +pile = require 'pile' +uglify = require 'uglify-js' + jquery = fs.readFileSync(__dirname + '/../vendor/jquery-1.6.4.min.js').toString() sammy = fs.readFileSync(__dirname + '/../vendor/sammy-0.7.0.min.js').toString() -uglify = require 'uglify-js' + + # Soft dependencies: jsdom = null @@ -38,11 +42,11 @@ coffeescript_helpers = """ } return -1; }; """.replace /\n/g, '' -minify = (js) -> - ast = uglify.parser.parse(js) - ast = uglify.uglify.ast_mangle(ast) - ast = uglify.uglify.ast_squeeze(ast) - uglify.uglify.gen_code(ast) +# Asset manager +jsAssets = pile.createJSManager() +cssAssets = pile.createCSSManager() + + # Shallow copy attributes from `sources` (array of objects) to `recipient`. # Does NOT overwrite attributes already present in `recipient`. @@ -54,11 +58,11 @@ copy_data_to = (recipient, sources) -> # Keep inline views at the module level and namespaced by app id # so that the monkeypatched express can look them up. views = {} - + # Monkeypatch express to support lookup of inline templates. Such is life. express.View.prototype.__defineGetter__ 'exists', -> # Path given by zappa: /path/to/appid/foo.bar. - + # Try appid/foo.bar in memory. p = @path.replace @root + '/', '' id = p.split('/')[0] @@ -95,7 +99,7 @@ express.View.prototype.__defineGetter__ 'contents', -> # Takes in a function and builds express/socket.io apps based on the rules contained in it. zappa.app = (func) -> context = {id: uuid(), zappa, express} - + context.root = path.dirname(module.parent.filename) # Storage for user-provided stuff. @@ -103,23 +107,44 @@ zappa.app = (func) -> ws_handlers = {} helpers = {} postrenders = {} - + app = context.app = express.createServer() io = context.io = socketio.listen(app) + app.configure -> + jsAssets.bind app + cssAssets.bind app + + app.configure "development", -> + jsAssets.liveUpdate(cssAssets, io) + # Reference to the zappa client, the value will be set later. client = null + # We have to change how @enable works, because these assets must be served + # before any @client etc. code will be added. This would need more proper + # rewrite. + buildinAssets = + "serve jquery": -> + jsAssets.addFile __dirname + '/../vendor/jquery-1.6.4.min.js' + "serve sammy": -> + jsAssets.addFile __dirname + '/../vendor/sammy-0.7.0.min.js' + "serve zappa": -> + jsAssets.addRaw ";#{coffeescript_helpers}(#{client})();" + # Zappa's default settings. app.set 'view engine', 'coffee' app.register '.coffee', zappa.adapter require('coffeekup').adapters.express, blacklist: ['format', 'autoescape', 'locals', 'hardcode', 'cache'] # Builds the applications's root scope. - + # Sets default view dir to @root (`path.dirname(module.parent.filename)`). app.set 'views', path.join(context.root, '/views') - + + # The stringified zappa client. + client = require('./client').build(zappa.version, coffeescript_helpers, app.settings) + for verb in ['get', 'post', 'put', 'del'] do (verb) -> context[verb] = -> @@ -129,35 +154,40 @@ zappa.app = (func) -> for k, v of arguments[0] route verb: verb, path: k, handler: v - context.client = (obj) -> - app.enable 'serve zappa' + handleNamespace = (fn) -> (pileName, obj=null) -> + if typeof pileName is "object" + fn.call context, pileName + else + # Call with default global pile + fn.call context, _global: pileName + + context.client = handleNamespace (obj) -> + context.enable "serve zappa" for k, v of obj js = ";zappa.run(#{v});" - js = minify(js) if app.settings['minify'] - route verb: 'get', path: k, handler: js, contentType: 'js' + jsAssets.addRaw k, js - context.coffee = (obj) -> + context.coffee = handleNamespace (obj) -> for k, v of obj js = ";#{coffeescript_helpers}(#{v})();" - js = minify(js) if app.settings['minify'] - route verb: 'get', path: k, handler: js, contentType: 'js' + jsAssets.addRaw k, js - context.js = (obj) -> + context.js = handleNamespace (obj) -> for k, v of obj js = String(v) - js = minify(js) if app.settings['minify'] - route verb: 'get', path: k, handler: js, contentType: 'js' + jsAssets.addRaw k, js - context.css = (obj) -> + context.css = handleNamespace (obj) -> for k, v of obj css = String(v) - route verb: 'get', path: k, handler: css, contentType: 'css' + cssAssets.addRaw k, css - context.stylus = (obj) -> - for k, v of obj + context.stylus = handleNamespace (obj) -> + for k, v of obj then do (k, v) -> css = require('stylus').render v, filename: k, (err, css) -> throw err if err - route verb: 'get', path: k, handler: css, contentType: 'css' + cssAssets.addRaw k, css + context.helper = (obj) -> for k, v of obj @@ -183,8 +213,9 @@ zappa.app = (func) -> context.set = (obj) -> for k, v of obj app.set k, v - - context.enable = -> + + context.enable = (value) -> + buildinAssets[value]?() app.enable i for i in arguments context.disable = -> @@ -200,25 +231,26 @@ zappa.app = (func) -> app.use wrappers[name](arg) else if typeof express[name] is 'function' app.use express[name](arg) - + for a in arguments switch typeof a when 'function' then app.use a when 'string' then use a when 'object' then use k, v for k, v of a - + context.configure = (p) -> if typeof p is 'function' then app.configure p else app.configure k, v for k, v of p - + + + context.settings = app.settings context.shared = (obj) -> - app.enable 'serve zappa' + context.enable "serve zappa" for k, v of obj js = ";zappa.run(#{v});" - js = minify(js) if app.settings['minify'] - route verb: 'get', path: k, handler: js, contentType: 'js' + jsAssets.addRaw js v.apply(context, [context]) context.include = (p) -> @@ -257,11 +289,11 @@ zappa.app = (func) -> # express.View.exists and express.View.contents can lookup # this app's inline templates. args[0] = context.id + '/' + args[0] - + # Make sure the second arg is an object. args[1] ?= {} args.splice 1, 0, {} if typeof args[1] is 'function' - + if app.settings['databag'] args[1].params = data @@ -293,15 +325,15 @@ zappa.app = (func) -> when 'this' then result = r.handler.apply(data, [ctx]) when 'param' then result = r.handler.apply(ctx, [data]) else result = r.handler.apply(ctx, [ctx]) - + res.contentType(r.contentType) if r.contentType? if typeof result is 'string' then res.send result else return result - + # Register socket.io handlers. io.sockets.on 'connection', (socket) -> c = {} - + build_ctx = -> ctx = app: app @@ -350,25 +382,6 @@ zappa.app = (func) -> # Go! func.apply(context, [context]) - # The stringified zappa client. - client = require('./client').build(zappa.version, coffeescript_helpers, app.settings) - - if app.settings['serve zappa'] - app.get '/zappa/zappa.js', (req, res) -> - js = ";#{coffeescript_helpers}(#{client})();" - js = minify(js) if app.settings['minify'] - res.contentType 'js' - res.send js - - if app.settings['serve jquery'] - app.get '/zappa/jquery.js', (req, res) -> - res.contentType 'js' - res.send jquery - - if app.settings['serve sammy'] - app.get '/zappa/sammy.js', (req, res) -> - res.contentType 'js' - res.send sammy if app.settings['default layout'] context.view layout: -> @@ -376,15 +389,7 @@ zappa.app = (func) -> html -> head -> title @title if @title - if @scripts - for s in @scripts - script src: s + '.js' - script(src: @script + '.js') if @script - if @stylesheets - for s in @stylesheets - link rel: 'stylesheet', href: s + '.css' - link(rel: 'stylesheet', href: @stylesheet + '.css') if @stylesheet - style @style if @style + @renderStyleTags() + @renderScriptTags() body @body context @@ -425,11 +430,11 @@ zappa.run = -> # Creates a zappa view adapter for templating engine `engine`. This adapter # can be used with `app.register` and creates params "shortcuts". -# +# # Zappa, by default, automatically sends all request params to templates, # but inside the `params` local. # -# This adapter adds a "root local" for each of these params, *only* +# This adapter adds a "root local" for each of these params, *only* # if a local with the same name doesn't exist already, *and* the name is not # in the optional blacklist. # @@ -453,4 +458,5 @@ module.exports = zappa.run module.exports.run = zappa.run module.exports.app = zappa.app module.exports.adapter = zappa.adapter -module.exports.version = zappa.version \ No newline at end of file +module.exports.version = zappa.version +